diff --git a/backend/services/FolderService/index.ts b/backend/services/FolderService/index.ts index 2b30d65..5dfa7a3 100644 --- a/backend/services/FolderService/index.ts +++ b/backend/services/FolderService/index.ts @@ -98,7 +98,7 @@ class FolderService { let searchQuery = query.search || ""; const parent = query.parent || "/"; - let sortBy = query.sortby || "DEFAULT"; + let sortBy = query.sortBy || "DEFAULT"; const type = query.type; const storageType = query.storageType || undefined; const folderSearch = query.folder_search || undefined; diff --git a/src/components/ContextMenu/index.jsx b/src/components/ContextMenu/index.jsx index e45b41b..714d34a 100644 --- a/src/components/ContextMenu/index.jsx +++ b/src/components/ContextMenu/index.jsx @@ -2,22 +2,21 @@ import classNames from "classnames"; import React, { useEffect, useRef } from "react"; import Swal from "sweetalert2"; import { deleteFile, renameFile, downloadFile } from "../../api/filesAPI"; -import { useFiles, useQuickFiles } from "../../hooks/files"; -import { useFolders } from "../../hooks/folders"; +import { useFilesClient, useQuickFilesClient } from "../../hooks/files"; +import { useFoldersClient } from "../../hooks/folders"; import { useDispatch } from "react-redux"; import { setMoverID } from "../../actions/mover"; import { setShareSelected } from "../../actions/selectedItem"; -import { startRenameFolder } from "../../actions/folders"; import { deleteFolder, renameFolder } from "../../api/foldersAPI"; const ContextMenu = (props) => { - const { invalidateFilesCache } = useFiles(); - const { invalidateFoldersCache } = useFolders(); - const { invalidateQuickFilesCache } = useQuickFiles(); + const { invalidateFilesCache } = useFilesClient(); + const { invalidateFoldersCache } = useFoldersClient(); + const { invalidateQuickFilesCache } = useQuickFilesClient(); const dispatch = useDispatch(); const wrapperRef = useRef(); const liClassname = - "flex w-full px-[20px] py-[12px] items-center font-normal justify-start no-underline transition-all duration-400 ease-in-out hover:bg-[#f6f5fd] hover:text-[#3c85ee] hover:font-medium"; + "flex w-full px-[20px] py-[12px] items-center font-normal text-[#637381] justify-start no-underline transition-all duration-400 ease-in-out text- hover:bg-[#f6f5fd] hover:text-[#3c85ee] hover:font-medium"; const spanClassname = "inline-flex mr-[18px]"; const renameItem = async () => { diff --git a/src/components/Dataform/index.jsx b/src/components/Dataform/index.jsx index c3edf78..1d262c1 100644 --- a/src/components/Dataform/index.jsx +++ b/src/components/Dataform/index.jsx @@ -1,31 +1,48 @@ import QuickAccess from "../QuickAccess"; import Folders from "../Folders"; import { useFiles } from "../../hooks/files"; +import { useInfiniteScroll } from "../../hooks/infiniteScroll"; import Files from "../Files"; +import { useEffect, useState } from "react"; +import SpinnerPage from "../SpinnerPage"; -const DataForm = (props) => { - const { fetchNextPage: filesFetchNextPage, invalidateFilesCache } = - useFiles(); +const DataForm = () => { + const { + fetchNextPage: filesFetchNextPage, + isFetchingNextPage, + data: fileList, + } = useFiles(); + const { sentinelRef, reachedIntersect } = useInfiniteScroll(); + const [initialLoad, setInitialLoad] = useState(true); + + useEffect(() => { + if (initialLoad) { + setInitialLoad(false); + return; + } else if (!fileList) { + return; + } + if (reachedIntersect) { + filesFetchNextPage(); + } + }, [reachedIntersect, initialLoad]); return (
- - + +
+ + {/* TODO: Change this spinner name */} + {isFetchingNextPage && ( +
+ +
+ )}
); }; diff --git a/src/components/FileItem/index.jsx b/src/components/FileItem/index.jsx index b0540c1..99ef091 100644 --- a/src/components/FileItem/index.jsx +++ b/src/components/FileItem/index.jsx @@ -80,7 +80,7 @@ const FileItem = (props) => { > {/* */} -
+
{

- {moment(props.file.uploadDate).format("L")} + {moment(props.file.uploadDate).format("MM/DD/YY hh:mma")}

-
- -
+ {contextMenuState.selected && ( +
+ +
+ )} + {/* */}

- Modified + Created

diff --git a/src/components/FolderItem/index.jsx b/src/components/FolderItem/index.jsx index c5dcbb4..d8f99d3 100644 --- a/src/components/FolderItem/index.jsx +++ b/src/components/FolderItem/index.jsx @@ -50,7 +50,7 @@ const FolderItem = (props) => { return (
{ onTouchMove={onTouchMove} onTouchEnd={onTouchEnd} > -
- -
+ {contextMenuState.selected && ( +
+ +
+ )} +
{

diff --git a/src/components/Folders/index.jsx b/src/components/Folders/index.jsx index 13b4c9e..09ee665 100644 --- a/src/components/Folders/index.jsx +++ b/src/components/Folders/index.jsx @@ -2,15 +2,16 @@ import { useDispatch, useSelector } from "react-redux"; import { useFolders } from "../../hooks/folders"; import { setSortBy } from "../../actions/filter"; import FolderItem from "../FolderItem"; +import { useCallback, useEffect } from "react"; const Folder = () => { const { data: folders } = useFolders(); const sortBy = useSelector((state) => state.filter.sortBy); const parent = useSelector((state) => state.parent.parent); const dispatch = useDispatch(); - console.log("sortBy", sortBy); + console.log("rerenderfolder", sortBy); - const switchOrderSortBy = () => { + const switchOrderSortBy = useCallback(() => { let newSortBy = ""; switch (sortBy) { case "date_asc": { @@ -37,29 +38,32 @@ const Folder = () => { console.log("new sortBy", newSortBy); dispatch(setSortBy(newSortBy)); - }; + }, [setSortBy, dispatch]); - const switchTypeOrderBy = (e) => { - const value = e.target.value; + const switchTypeOrderBy = useCallback( + (e) => { + const value = e.target.value; - let newSortBy = "date_desc"; + let newSortBy = "date_desc"; - if (value === "date") { - if (sortBy.includes("asc")) { - newSortBy = "date_asc"; - } else { - newSortBy = "date_desc"; + if (value === "date") { + if (sortBy.includes("asc")) { + newSortBy = "date_asc"; + } else { + newSortBy = "date_desc"; + } + } else if (value === "name") { + if (sortBy.includes("asc")) { + newSortBy = "alp_asc"; + } else { + newSortBy = "alp_desc"; + } } - } else if (value === "name") { - if (sortBy.includes("asc")) { - newSortBy = "alp_asc"; - } else { - newSortBy = "alp_desc"; - } - } - dispatch(setSortBy(newSortBy)); - }; + dispatch(setSortBy(newSortBy)); + }, + [setSortBy, dispatch] + ); return (

{
{ { parent: params.id || "/", search: "", - sortBy: sortBy, + sortBy, limit: undefined, }, ], @@ -35,6 +35,17 @@ export const useFiles = () => { } ); + const testFunction = () => { + console.log("this is a test function"); + }; + + return { ...filesReactQuery, testFunction }; +}; + +export const useFilesClient = () => { + const params = useParams(); + // TODO: Remove any + const sortBy = useSelector((state: any) => state.filter.sortBy); const filesReactClientQuery = useQueryClient(); const invalidateFilesCache = () => { @@ -44,23 +55,23 @@ export const useFiles = () => { { parent: params.id || "/", search: "", - sortBy: undefined, + sortBy, limit: undefined, }, ], }); }; - const testFunction = () => { - console.log("this is a test function"); - }; - - return { ...filesReactQuery, testFunction, invalidateFilesCache }; + return { ...filesReactClientQuery, invalidateFilesCache }; }; export const useQuickFiles = () => { const quickFilesQuery = useQuery("quickFiles", getQuickFilesList); + return { ...quickFilesQuery }; +}; + +export const useQuickFilesClient = () => { const quickFilesReactClientQuery = useQueryClient(); const invalidateQuickFilesCache = () => { @@ -69,7 +80,7 @@ export const useQuickFiles = () => { }); }; - return { ...quickFilesQuery, invalidateQuickFilesCache }; + return { ...quickFilesReactClientQuery, invalidateQuickFilesCache }; }; interface thumbnailState { diff --git a/src/hooks/folders.ts b/src/hooks/folders.ts index c445189..03e3899 100644 --- a/src/hooks/folders.ts +++ b/src/hooks/folders.ts @@ -1,37 +1,48 @@ import { useQuery, useQueryClient } from "react-query"; import { useParams } from "react-router-dom"; import { getFoldersList } from "../api/foldersAPI"; +import { useSelector } from "react-redux"; export const useFolders = () => { const params = useParams(); + const sortBy = useSelector((state: any) => state.filter.sortBy); const foldersReactQuery = useQuery( [ "folders", { parent: params.id || "/", search: "", - sortBy: undefined, + sortBy, limit: undefined, }, ], getFoldersList ); - const filesReactClientQuery = useQueryClient(); + return { ...foldersReactQuery }; +}; + +export const useFoldersClient = () => { + const params = useParams(); + const sortBy = useSelector((state: any) => state.filter.sortBy); + const foldersReactClientQuery = useQueryClient(); const invalidateFoldersCache = () => { - filesReactClientQuery.invalidateQueries({ + foldersReactClientQuery.invalidateQueries({ queryKey: [ "folders", { parent: params.id || "/", search: "", - sortBy: undefined, + sortBy, limit: undefined, }, ], }); }; - return { ...foldersReactQuery, invalidateFoldersCache }; + return { + ...foldersReactClientQuery, + invalidateFoldersCache, + }; }; diff --git a/src/hooks/infiniteScroll.ts b/src/hooks/infiniteScroll.ts new file mode 100644 index 0000000..5fa7f66 --- /dev/null +++ b/src/hooks/infiniteScroll.ts @@ -0,0 +1,43 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + +// TODO: Fix anys +export const useInfiniteScroll = () => { + const [reachedIntersect, setReachedIntersect] = useState(false); + const observer = useRef() as any; + const sentinelRef = useRef(); + + const handleObserver = useCallback( + (entries: any) => { + const target = entries[0]; + if (target.isIntersecting) { + setReachedIntersect(true); + } else if (reachedIntersect) { + setReachedIntersect(false); + } + }, + [reachedIntersect] + ); + + useEffect(() => { + if (observer.current) { + observer.current.disconnect(); + } + + observer.current = new IntersectionObserver(handleObserver, { + root: null, + rootMargin: undefined, + threshold: 0.1, + }); + if (sentinelRef.current) { + observer.current.observe(sentinelRef.current); + } + + return () => { + if (sentinelRef.current) { + observer.current.disconnect(); + } + }; + }, [handleObserver]); + + return { reachedIntersect, sentinelRef, observer }; +}; diff --git a/src/styles/components/_Sharemenu.scss b/src/styles/components/_Sharemenu.scss index ddcf532..cf0a321 100644 --- a/src/styles/components/_Sharemenu.scss +++ b/src/styles/components/_Sharemenu.scss @@ -1,176 +1,174 @@ .sharemenu { + width: 425px; + height: 230px; + position: fixed; + background: white; + left: calc(70% - 425px); + box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.302), + 0 1px 3px 1px rgba(60, 64, 67, 0.149); + border: 1px solid transparent; + border-radius: 6px; + z-index: 1; + left: 0; + right: 0; + margin: 0 auto; + display: flex; + flex-direction: column; + text-align: center; + justify-content: center; + align-items: center; - width: 425px; - height: 230px; - position: fixed; - background: white; - left: calc(70% - 425px); - box-shadow: 0 1px 2px 0 rgba(60,64,67,0.302), 0 1px 3px 1px rgba(60,64,67,0.149); - border: 1px solid transparent; - border-radius: 6px; - z-index: 1; - left: 0; - right: 0; - margin: 0 auto; - display: flex; - flex-direction: column; - text-align: center; - justify-content: center; - align-items: center; - - @media (max-width: $desktop-breakpoint) { - width: 100%; - height: 100%; - top: 0; - z-index: 2; - } + @media (max-width: $desktop-breakpoint) { + width: 100%; + height: 100%; + top: 0; + z-index: 2; + } } .sharemenu--gone { - display: none; + display: none; } .sharemenu--block { - width: 100% + width: 100%; } .sharemenu__title { - color: black; - max-width: 88%; - overflow: hidden; - text-overflow: ellipsis; - /* margin-left: 5px; */ - margin-right: 5px; - font-size: 13.5px; - font-weight: 200; - white-space: nowrap; + color: black; + max-width: 88%; + overflow: hidden; + text-overflow: ellipsis; + /* margin-left: 5px; */ + margin-right: 5px; + font-size: 13.5px; + font-weight: 200; + white-space: nowrap; - @media (max-width: $desktop-breakpoint) { - max-width: 80%; - } + @media (max-width: $desktop-breakpoint) { + max-width: 80%; + } } .sharemenu__subtitle { - color: black; + color: black; } .sharemenu__button__public { + color: white; + background: #3c85ed; + border: none; + display: inline-block; + text-decoration: none; + line-height: 1; + border-radius: 2px; + width: 29%; + height: 37px; + padding: 3px; - color: white; - background: #3c85ed; - border: none; - display: inline-block; - text-decoration: none; - line-height: 1; - border-radius: 2px; - width: 29%; - height: 37px; - padding: 3px; + &:hover { + background: darken(#3c85ed, 10); + color: darken(white, 10); + } - &:hover { - background: darken(#3c85ed, 10); - color: darken(white, 10) - } - - @media (max-width: $desktop-breakpoint) { - width: 36%; - height: 47px; - } - + @media (max-width: $desktop-breakpoint) { + width: 36%; + height: 47px; + } } .sharemenu__close-button { - width: 25px; - position: absolute; - top: 1px; - left: 1px; - opacity: 0.8; + width: 25px; + position: absolute; + top: 1px; + left: 1px; + opacity: 0.8; - @media (max-width: $desktop-breakpoint) { - width: 42px; - } + @media (max-width: $desktop-breakpoint) { + width: 42px; + } } .sharemenu__button__one { - color: white; - background: #3c85ed; - font-size: $font-size-large; - padding: $s-size; - border: none; - display: inline-block; - text-decoration: none; - line-height: 1; - border-radius: $small-border; + color: white; + background: #3c85ed; + font-size: $font-size-large; + padding: $s-size; + border: none; + display: inline-block; + text-decoration: none; + line-height: 1; + border-radius: $small-border; - &:hover { - background: darken(#3c85ed, 10); - color: darken(white, 10) - } + &:hover { + background: darken(#3c85ed, 10); + color: darken(white, 10); + } } .sharemenu__button__done { - color: white; - background: #3c85ed; - font-size: $font-size-large; - padding: $s-size; - border: none; - display: inline-block; - text-decoration: none; - line-height: 1; - border-radius: $small-border; + color: white; + background: #3c85ed; + font-size: $font-size-large; + padding: $s-size; + border: none; + display: inline-block; + text-decoration: none; + line-height: 1; + border-radius: $small-border; - &:hover { - background: darken(#3c85ed, 10); - color: darken(white, 10) - } + &:hover { + background: darken(#3c85ed, 10); + color: darken(white, 10); + } } .sharemenu__link__wrapper { - width: 100%; - display: flex; - flex-direction: row; - justify-content: center; + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; - @media (max-width: $desktop-breakpoint) { - height: 49px; - } + @media (max-width: $desktop-breakpoint) { + height: 49px; + } } .sharemenu__image { - width: 27px; - margin-left: 10px; - margin-right: 5px; + width: 27px; + margin-left: 10px; + margin-right: 5px; } .spinner-image { - border: 3px solid white; - border-top: 3px solid #3498db; - border-radius: 50%; - width: 40px; - height: 40px; - // margin-left: 50%; - text-align: center; - animation: spin 2s linear infinite; + border: 3px solid white; + border-top: 3px solid #3498db; + border-radius: 50%; + width: 40px; + height: 40px; + // margin-left: 50%; + text-align: center; + animation: spin 2s linear infinite; } - + .spinner-image-grey { - border: 3px solid lightgray; - border-top: 3px solid #3498db; + border: 3px solid lightgray; + border-top: 3px solid #3498db; } .share-model-spinner-wrapper { - margin-top: 10px; - margin-bottom: 10px; - display: flex; - justify-content: center; - align-items: center; + margin-top: 10px; + margin-bottom: 10px; + display: flex; + justify-content: center; + align-items: center; } .share-model-share-buttons-wrapper { - margin-top: 12px; - margin-bottom: 4px; + margin-top: 12px; + margin-bottom: 4px; } .share-button__wrapper { - margin-bottom: 11px; -} \ No newline at end of file + margin-bottom: 11px; +}