added navigation scroll restore logic
This commit is contained in:
@@ -3,103 +3,117 @@ import Folders from "../Folders/Folders";
|
||||
import { useFiles, useQuickFiles, useUploader } from "../../hooks/files";
|
||||
import { useInfiniteScroll } from "../../hooks/infiniteScroll";
|
||||
import Files from "../Files/Files";
|
||||
import { memo, useCallback, useEffect, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import Spinner from "../Spinner/Spinner";
|
||||
import { useAppDispatch } from "../../hooks/store";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { useParams } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { useDragAndDrop } from "../../hooks/utils";
|
||||
import MultiSelectBar from "../MultiSelectBar/MultiSelectBar";
|
||||
import { useFolders } from "../../hooks/folders";
|
||||
|
||||
const DataForm = memo(() => {
|
||||
const {
|
||||
fetchNextPage: filesFetchNextPage,
|
||||
isFetchingNextPage,
|
||||
data: fileList,
|
||||
isLoading: isLoadingFiles,
|
||||
} = useFiles();
|
||||
const { isLoading: isLoadingFolders } = useFolders();
|
||||
const { isLoading: isLoadingQuickItems } = useQuickFiles();
|
||||
const dispatch = useAppDispatch();
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const params = useParams();
|
||||
const { uploadFiles } = useUploader();
|
||||
const DataForm = memo(
|
||||
({ scrollDivRef }: { scrollDivRef: React.RefObject<HTMLDivElement> }) => {
|
||||
const {
|
||||
fetchNextPage: filesFetchNextPage,
|
||||
isFetchingNextPage,
|
||||
data: fileList,
|
||||
isLoading: isLoadingFiles,
|
||||
} = useFiles();
|
||||
const { isLoading: isLoadingFolders } = useFolders();
|
||||
const { isLoading: isLoadingQuickItems } = useQuickFiles();
|
||||
const dispatch = useAppDispatch();
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const params = useParams();
|
||||
const { uploadFiles } = useUploader();
|
||||
const navigationMap = useAppSelector((state) => {
|
||||
return state.selected.navigationMap[window.location.pathname];
|
||||
});
|
||||
|
||||
const isLoading = isLoadingFiles || isLoadingFolders || isLoadingQuickItems;
|
||||
const isLoading = isLoadingFiles || isLoadingFolders || isLoadingQuickItems;
|
||||
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
setInitialLoad(false);
|
||||
return;
|
||||
} else if (!fileList) {
|
||||
return;
|
||||
}
|
||||
if (reachedIntersect && !isFetchingNextPage) {
|
||||
filesFetchNextPage();
|
||||
}
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
setInitialLoad(false);
|
||||
return;
|
||||
} else if (!fileList) {
|
||||
return;
|
||||
}
|
||||
if (reachedIntersect && !isFetchingNextPage) {
|
||||
filesFetchNextPage();
|
||||
}
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
|
||||
const addFile = useCallback(
|
||||
(files: FileList) => {
|
||||
uploadFiles(files);
|
||||
},
|
||||
[params.id]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!isLoading && navigationMap) {
|
||||
scrollDivRef.current?.scrollTo(0, navigationMap.scrollTop);
|
||||
} else if (!isLoading) {
|
||||
scrollDivRef.current?.scrollTo(0, 0);
|
||||
}
|
||||
}, [isLoading, navigationMap, window.location.pathname]);
|
||||
|
||||
const {
|
||||
isDraggingFile,
|
||||
onDragDropEvent,
|
||||
onDragEvent,
|
||||
onDragEnterEvent,
|
||||
stopDrag,
|
||||
} = useDragAndDrop(addFile);
|
||||
const addFile = useCallback(
|
||||
(files: FileList) => {
|
||||
uploadFiles(files);
|
||||
},
|
||||
[params.id]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"w-full px-2.5 desktopMode:px-10 py-6 overflow-y-scroll",
|
||||
{
|
||||
"opacity-50": isDraggingFile,
|
||||
}
|
||||
)}
|
||||
onDrop={onDragDropEvent}
|
||||
onDragOver={onDragEvent}
|
||||
onDragLeave={onDragEvent}
|
||||
onDragEnter={onDragEnterEvent}
|
||||
onMouseLeave={stopDrag}
|
||||
>
|
||||
{!isLoading && (
|
||||
<div>
|
||||
<div className="fixed bottom-0 flex justify-center items-center right-0 left-0 z-10">
|
||||
<MultiSelectBar />
|
||||
const {
|
||||
isDraggingFile,
|
||||
onDragDropEvent,
|
||||
onDragEvent,
|
||||
onDragEnterEvent,
|
||||
stopDrag,
|
||||
} = useDragAndDrop(addFile);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"w-full px-2.5 desktopMode:px-10 py-6 overflow-y-scroll",
|
||||
{
|
||||
"opacity-50": isDraggingFile,
|
||||
}
|
||||
)}
|
||||
onDrop={onDragDropEvent}
|
||||
onDragOver={onDragEvent}
|
||||
onDragLeave={onDragEvent}
|
||||
onDragEnter={onDragEnterEvent}
|
||||
onMouseLeave={stopDrag}
|
||||
ref={scrollDivRef}
|
||||
>
|
||||
{!isLoading && (
|
||||
<div>
|
||||
<div className="fixed bottom-0 flex justify-center items-center right-0 left-0 z-10">
|
||||
<MultiSelectBar />
|
||||
</div>
|
||||
|
||||
<QuickAccess />
|
||||
|
||||
<Folders scrollDivRef={scrollDivRef} />
|
||||
|
||||
<Files />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<QuickAccess />
|
||||
{isLoading && (
|
||||
<div className="w-full flex justify-center items-center h-full">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
{/* @ts-ignore */}
|
||||
<div ref={sentinelRef} className="h-1"></div>
|
||||
|
||||
<Folders />
|
||||
|
||||
<Files />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isLoading && (
|
||||
<div className="w-full flex justify-center items-center h-full">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
{/* @ts-ignore */}
|
||||
<div ref={sentinelRef} className="h-1"></div>
|
||||
|
||||
{/* TODO: Change this spinner name */}
|
||||
{isFetchingNextPage && (
|
||||
<div className="w-full flex justify-center items-center mt-4">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
{/* TODO: Change this spinner name */}
|
||||
{isFetchingNextPage && (
|
||||
<div className="w-full flex justify-center items-center mt-4">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default DataForm;
|
||||
|
||||
@@ -6,16 +6,21 @@ import { useNavigate } from "react-router-dom";
|
||||
import mobilecheck from "../../utils/mobileCheck";
|
||||
import moment from "moment";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMainSelect, setMultiSelectMode } from "../../reducers/selected";
|
||||
import {
|
||||
addNavigationMap,
|
||||
setMainSelect,
|
||||
setMultiSelectMode,
|
||||
} from "../../reducers/selected";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import { FolderInterface } from "../../types/folders";
|
||||
|
||||
interface FolderItemProps {
|
||||
folder: FolderInterface;
|
||||
scrollDivRef: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const FolderItem: React.FC<FolderItemProps> = memo((props) => {
|
||||
const { folder } = props;
|
||||
const { folder, scrollDivRef } = props;
|
||||
const elementSelected = useAppSelector((state) => {
|
||||
if (state.selected.mainSection.type !== "folder") return false;
|
||||
return state.selected.mainSection.id === folder._id;
|
||||
@@ -77,6 +82,12 @@ const FolderItem: React.FC<FolderItemProps> = memo((props) => {
|
||||
}
|
||||
|
||||
if (singleClickFolders || currentDate - lastSelected.current < 1500) {
|
||||
dispatch(
|
||||
addNavigationMap({
|
||||
url: window.location.pathname,
|
||||
scrollTop: scrollDivRef.current?.scrollTop || 0,
|
||||
})
|
||||
);
|
||||
if (isTrash) {
|
||||
navigate(`/folder-trash/${folder._id}`);
|
||||
} else {
|
||||
|
||||
+124
-118
@@ -6,137 +6,143 @@ import { useUtils } from "../../hooks/utils";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setSortBy } from "../../reducers/filter";
|
||||
|
||||
const Folders = memo(() => {
|
||||
const { data: folders } = useFolders(false);
|
||||
const { isHome, isTrash, isSearch } = useUtils();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const dispatch = useAppDispatch();
|
||||
const Folders = memo(
|
||||
({ scrollDivRef }: { scrollDivRef: React.RefObject<HTMLDivElement> }) => {
|
||||
const { data: folders } = useFolders(false);
|
||||
const { isHome, isTrash, isSearch } = useUtils();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const switchOrderSortBy = useCallback(() => {
|
||||
let newSortBy = "";
|
||||
switch (sortBy) {
|
||||
case "date_asc": {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
case "date_desc": {
|
||||
newSortBy = "date_asc";
|
||||
break;
|
||||
}
|
||||
case "alp_asc": {
|
||||
newSortBy = "alp_desc";
|
||||
break;
|
||||
}
|
||||
case "alp_desc": {
|
||||
newSortBy = "alp_asc";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
}, [sortBy]);
|
||||
|
||||
const switchTypeOrderBy = useCallback(
|
||||
(e: any) => {
|
||||
const value = e.target.value;
|
||||
|
||||
let newSortBy = "date_desc";
|
||||
|
||||
if (value === "date") {
|
||||
if (sortBy.includes("asc")) {
|
||||
newSortBy = "date_asc";
|
||||
} else {
|
||||
const switchOrderSortBy = useCallback(() => {
|
||||
let newSortBy = "";
|
||||
switch (sortBy) {
|
||||
case "date_asc": {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
} else if (value === "name") {
|
||||
if (sortBy.includes("asc")) {
|
||||
newSortBy = "alp_asc";
|
||||
} else {
|
||||
case "date_desc": {
|
||||
newSortBy = "date_asc";
|
||||
break;
|
||||
}
|
||||
case "alp_asc": {
|
||||
newSortBy = "alp_desc";
|
||||
break;
|
||||
}
|
||||
case "alp_desc": {
|
||||
newSortBy = "alp_asc";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
},
|
||||
[sortBy]
|
||||
);
|
||||
}, [sortBy]);
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (isTrash) {
|
||||
return "Trash";
|
||||
} else if (isSearch) {
|
||||
return "Search";
|
||||
} else {
|
||||
return folders?.length === 0 ? "No Folders" : "Folders";
|
||||
}
|
||||
}, [isHome, isTrash, isSearch, folders?.length]);
|
||||
const switchTypeOrderBy = useCallback(
|
||||
(e: any) => {
|
||||
const value = e.target.value;
|
||||
|
||||
return (
|
||||
<div className="mt-8 select-none">
|
||||
<div className="flex flex-row mb-5 justify-between items-center">
|
||||
<h2
|
||||
className={classNames(
|
||||
"m-0 text-xl font-medium"
|
||||
// isHome || isTrash ? "block" : "invisible"
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
<svg
|
||||
className="h-3 w-3 cursor-pointer animate"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={
|
||||
sortBy === "date_desc" || sortBy === "alp_desc"
|
||||
? { transform: "scaleY(-1)" }
|
||||
: {}
|
||||
let 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";
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
},
|
||||
[sortBy]
|
||||
);
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (isTrash) {
|
||||
return "Trash";
|
||||
} else if (isSearch) {
|
||||
return "Search";
|
||||
} else {
|
||||
return folders?.length === 0 ? "No Folders" : "Folders";
|
||||
}
|
||||
}, [isHome, isTrash, isSearch, folders?.length]);
|
||||
|
||||
return (
|
||||
<div className="mt-8 select-none">
|
||||
<div className="flex flex-row mb-5 justify-between items-center">
|
||||
<h2
|
||||
className={classNames(
|
||||
"m-0 text-xl font-medium"
|
||||
// isHome || isTrash ? "block" : "invisible"
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
<svg
|
||||
className="h-3 w-3 cursor-pointer animate"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={
|
||||
sortBy === "date_desc" || sortBy === "alp_desc"
|
||||
? { transform: "scaleY(-1)" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<g id="upload">
|
||||
<path
|
||||
id="Path"
|
||||
d="M5.58035 2.51616L3.20339 0.139199C3.01776 -0.0463997 2.71681 -0.0463997 2.53119 0.139199L0.154195 2.51616C-0.0282007 2.70502 -0.0229639 3.00597 0.165894 3.18836C0.350128 3.3663 0.642189 3.3663 0.826423 3.18836L2.39191 1.62288V9.50781C2.39191 9.77037 2.60475 9.98321 2.86731 9.98321C3.12988 9.98321 3.34272 9.77037 3.34272 9.50781V1.6229L4.90821 3.18839C5.09706 3.37079 5.39801 3.36555 5.58041 3.17669C5.75829 2.99246 5.75829 2.7004 5.58035 2.51616Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<select
|
||||
className="text-sm font-medium appearance-none bg-white"
|
||||
onChange={switchTypeOrderBy}
|
||||
value={
|
||||
sortBy === "alp_desc" || sortBy === "alp_asc" ? "name" : "date"
|
||||
}
|
||||
>
|
||||
<g id="upload">
|
||||
<path
|
||||
id="Path"
|
||||
d="M5.58035 2.51616L3.20339 0.139199C3.01776 -0.0463997 2.71681 -0.0463997 2.53119 0.139199L0.154195 2.51616C-0.0282007 2.70502 -0.0229639 3.00597 0.165894 3.18836C0.350128 3.3663 0.642189 3.3663 0.826423 3.18836L2.39191 1.62288V9.50781C2.39191 9.77037 2.60475 9.98321 2.86731 9.98321C3.12988 9.98321 3.34272 9.77037 3.34272 9.50781V1.6229L4.90821 3.18839C5.09706 3.37079 5.39801 3.36555 5.58041 3.17669C5.75829 2.99246 5.75829 2.7004 5.58035 2.51616Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<select
|
||||
className="text-sm font-medium appearance-none bg-white"
|
||||
onChange={switchTypeOrderBy}
|
||||
value={
|
||||
sortBy === "alp_desc" || sortBy === "alp_asc" ? "name" : "date"
|
||||
}
|
||||
>
|
||||
<option value="date">Modified</option>
|
||||
<option value="name">Name</option>
|
||||
</select>
|
||||
<option value="date">Modified</option>
|
||||
<option value="name">Name</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fit,minmax(47%,45%))] xs:grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-[16px]",
|
||||
folders?.length === 1
|
||||
? "justify-normal"
|
||||
: "justify-center xs:justify-normal"
|
||||
)}
|
||||
>
|
||||
{folders?.map((folder) => (
|
||||
<FolderItem
|
||||
folder={folder}
|
||||
key={folder._id}
|
||||
scrollDivRef={scrollDivRef}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fit,minmax(47%,45%))] xs:grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-[16px]",
|
||||
folders?.length === 1
|
||||
? "justify-normal"
|
||||
: "justify-center xs:justify-normal"
|
||||
)}
|
||||
>
|
||||
{folders?.map((folder) => (
|
||||
<FolderItem folder={folder} key={folder._id} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Folders;
|
||||
|
||||
@@ -10,8 +10,13 @@ import { closeDrawer } from "../../reducers/leftSection";
|
||||
import SettingsIcon from "../../icons/SettingsIcon";
|
||||
import ChevronSolid from "../../icons/ChevronSolid";
|
||||
import HomeIconOutline from "../../icons/HomeIconOutline";
|
||||
import { addNavigationMap } from "../../reducers/selected";
|
||||
|
||||
const LeftSection = () => {
|
||||
const LeftSection = ({
|
||||
scrollDivRef,
|
||||
}: {
|
||||
scrollDivRef: React.RefObject<HTMLDivElement>;
|
||||
}) => {
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const leftSectionOpen = useAppSelector((state) => state.leftSection.drawOpen);
|
||||
const { isHome, isHomeFolder, isTrash, isMedia, isSettings } = useUtils();
|
||||
@@ -33,21 +38,45 @@ const LeftSection = () => {
|
||||
|
||||
const goHome = () => {
|
||||
dispatch(closeDrawer());
|
||||
dispatch(
|
||||
addNavigationMap({
|
||||
url: window.location.pathname,
|
||||
scrollTop: scrollDivRef.current?.scrollTop || 0,
|
||||
})
|
||||
);
|
||||
navigate("/home");
|
||||
};
|
||||
|
||||
const goTrash = () => {
|
||||
dispatch(closeDrawer());
|
||||
dispatch(
|
||||
addNavigationMap({
|
||||
url: window.location.pathname,
|
||||
scrollTop: scrollDivRef.current?.scrollTop || 0,
|
||||
})
|
||||
);
|
||||
navigate("/trash");
|
||||
};
|
||||
|
||||
const goMedia = () => {
|
||||
dispatch(closeDrawer());
|
||||
dispatch(
|
||||
addNavigationMap({
|
||||
url: window.location.pathname,
|
||||
scrollTop: scrollDivRef.current?.scrollTop || 0,
|
||||
})
|
||||
);
|
||||
navigate("/media");
|
||||
};
|
||||
|
||||
const goSettings = () => {
|
||||
dispatch(closeDrawer());
|
||||
dispatch(
|
||||
addNavigationMap({
|
||||
url: window.location.pathname,
|
||||
scrollTop: scrollDivRef.current?.scrollTop || 0,
|
||||
})
|
||||
);
|
||||
navigate("/settings");
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import DataForm from "../Dataform/Dataform";
|
||||
import RightSection from "../RightSection/RightSection";
|
||||
import { memo } from "react";
|
||||
import { memo, useRef } from "react";
|
||||
import LeftSection from "../LeftSection/LeftSection";
|
||||
import { useUtils } from "../../hooks/utils";
|
||||
import Medias from "../Medias/Medias";
|
||||
@@ -20,6 +20,7 @@ const MainSection = memo(() => {
|
||||
const moveModalItemType = useAppSelector(
|
||||
(state) => state.selected.moveModal.type
|
||||
);
|
||||
const scrollDivRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isMediaSelected =
|
||||
popupModalItem?.metadata.isVideo || popupModalItem?.metadata.hasThumbnail;
|
||||
@@ -40,9 +41,13 @@ const MainSection = memo(() => {
|
||||
{moveModalItemType && <MoverPopup />}
|
||||
|
||||
<div className="flex flex-row dynamic-height w-screen pt-16">
|
||||
<LeftSection />
|
||||
<LeftSection scrollDivRef={scrollDivRef} />
|
||||
|
||||
{!isMedia ? <DataForm /> : <Medias />}
|
||||
{!isMedia ? (
|
||||
<DataForm scrollDivRef={scrollDivRef} />
|
||||
) : (
|
||||
<Medias scrollDivRef={scrollDivRef} />
|
||||
)}
|
||||
|
||||
<RightSection />
|
||||
</div>
|
||||
|
||||
+133
-116
@@ -7,133 +7,150 @@ import { useInfiniteScroll } from "../../hooks/infiniteScroll";
|
||||
import { useAppDispatch, useAppSelector } from "../../hooks/store";
|
||||
import { setMediaFilter, setSortBy } from "../../reducers/filter";
|
||||
|
||||
const Medias = memo(() => {
|
||||
const {
|
||||
data: files,
|
||||
isFetchingNextPage,
|
||||
fetchNextPage: filesFetchNextPage,
|
||||
} = useFiles();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const mediaFilter = useAppSelector((state) => state.filter.mediaFilter);
|
||||
const dispatch = useAppDispatch();
|
||||
const Medias = memo(
|
||||
({ scrollDivRef }: { scrollDivRef: React.RefObject<HTMLDivElement> }) => {
|
||||
const {
|
||||
data: files,
|
||||
isFetchingNextPage,
|
||||
fetchNextPage: filesFetchNextPage,
|
||||
} = useFiles();
|
||||
const [initialLoad, setInitialLoad] = useState(true);
|
||||
const { sentinelRef, reachedIntersect } = useInfiniteScroll();
|
||||
const sortBy = useAppSelector((state) => state.filter.sortBy);
|
||||
const mediaFilter = useAppSelector((state) => state.filter.mediaFilter);
|
||||
const navigationMap = useAppSelector((state) => {
|
||||
return state.selected.navigationMap[window.location.pathname];
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
setInitialLoad(false);
|
||||
return;
|
||||
} else if (!files) {
|
||||
return;
|
||||
}
|
||||
if (reachedIntersect && !isFetchingNextPage) {
|
||||
filesFetchNextPage();
|
||||
}
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const switchOrderSortBy = useCallback(() => {
|
||||
let newSortBy = "";
|
||||
switch (sortBy) {
|
||||
case "date_asc": {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
useEffect(() => {
|
||||
if (initialLoad) {
|
||||
setInitialLoad(false);
|
||||
return;
|
||||
} else if (!files) {
|
||||
return;
|
||||
}
|
||||
case "date_desc": {
|
||||
newSortBy = "date_asc";
|
||||
break;
|
||||
if (reachedIntersect && !isFetchingNextPage) {
|
||||
filesFetchNextPage();
|
||||
}
|
||||
case "alp_asc": {
|
||||
newSortBy = "alp_desc";
|
||||
break;
|
||||
}, [reachedIntersect, initialLoad, isFetchingNextPage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialLoad && navigationMap) {
|
||||
scrollDivRef.current?.scrollTo(0, navigationMap.scrollTop);
|
||||
} else if (!initialLoad) {
|
||||
scrollDivRef.current?.scrollTo(0, 0);
|
||||
}
|
||||
case "alp_desc": {
|
||||
newSortBy = "alp_asc";
|
||||
break;
|
||||
}, [initialLoad, navigationMap, window.location.pathname]);
|
||||
|
||||
const switchOrderSortBy = useCallback(() => {
|
||||
let newSortBy = "";
|
||||
switch (sortBy) {
|
||||
case "date_asc": {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
case "date_desc": {
|
||||
newSortBy = "date_asc";
|
||||
break;
|
||||
}
|
||||
case "alp_asc": {
|
||||
newSortBy = "alp_desc";
|
||||
break;
|
||||
}
|
||||
case "alp_desc": {
|
||||
newSortBy = "alp_asc";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
newSortBy = "date_desc";
|
||||
break;
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
}, [sortBy]);
|
||||
|
||||
const mediaFilterOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
dispatch(setMediaFilter(value));
|
||||
};
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (mediaFilter === "all") {
|
||||
return "Photos and Videos";
|
||||
} else if (mediaFilter === "photos") {
|
||||
return "Photos";
|
||||
} else if (mediaFilter === "videos") {
|
||||
return "Videos";
|
||||
}
|
||||
}
|
||||
}, [mediaFilter]);
|
||||
|
||||
dispatch(setSortBy(newSortBy));
|
||||
}, [sortBy]);
|
||||
|
||||
const mediaFilterOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
dispatch(setMediaFilter(value));
|
||||
};
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (mediaFilter === "all") {
|
||||
return "Photos and Videos";
|
||||
} else if (mediaFilter === "photos") {
|
||||
return "Photos";
|
||||
} else if (mediaFilter === "videos") {
|
||||
return "Videos";
|
||||
}
|
||||
}, [mediaFilter]);
|
||||
|
||||
return (
|
||||
<div className="w-full p-[17px_15px] desktopMode:p-[17px_40px] overflow-y-scroll select-none">
|
||||
<div className="flex flex-row mb-5 justify-between items-center mt-2">
|
||||
<h2 className={classNames("m-0 text-xl font-medium")}>{title}</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
<svg
|
||||
className="h-3 w-3 cursor-pointer animate"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={
|
||||
sortBy === "date_desc" || sortBy === "alp_desc"
|
||||
? { transform: "scaleY(-1)" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<g id="upload">
|
||||
<path
|
||||
id="Path"
|
||||
d="M5.58035 2.51616L3.20339 0.139199C3.01776 -0.0463997 2.71681 -0.0463997 2.53119 0.139199L0.154195 2.51616C-0.0282007 2.70502 -0.0229639 3.00597 0.165894 3.18836C0.350128 3.3663 0.642189 3.3663 0.826423 3.18836L2.39191 1.62288V9.50781C2.39191 9.77037 2.60475 9.98321 2.86731 9.98321C3.12988 9.98321 3.34272 9.77037 3.34272 9.50781V1.6229L4.90821 3.18839C5.09706 3.37079 5.39801 3.36555 5.58041 3.17669C5.75829 2.99246 5.75829 2.7004 5.58035 2.51616Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<select
|
||||
className="text-sm font-medium appearance-none bg-white"
|
||||
onChange={mediaFilterOnChange}
|
||||
value={mediaFilter}
|
||||
>
|
||||
<option value="all">All</option>
|
||||
<option value="photos">Photos</option>
|
||||
<option value="videos">Videos</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-[10px]"
|
||||
)}
|
||||
className="w-full p-[17px_15px] desktopMode:p-[17px_40px] overflow-y-scroll select-none"
|
||||
ref={scrollDivRef}
|
||||
>
|
||||
<div className="fixed bottom-0 flex justify-center items-center right-0 left-0 z-10">
|
||||
<MultiSelectBar />
|
||||
<div className="flex flex-row mb-5 justify-between items-center mt-2">
|
||||
<h2 className={classNames("m-0 text-xl font-medium")}>{title}</h2>
|
||||
<div className="flex flex-row items-center">
|
||||
<a className="mr-2" onClick={switchOrderSortBy}>
|
||||
<svg
|
||||
className="h-3 w-3 cursor-pointer animate"
|
||||
width="6"
|
||||
height="10"
|
||||
viewBox="0 0 6 10"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style={
|
||||
sortBy === "date_desc" || sortBy === "alp_desc"
|
||||
? { transform: "scaleY(-1)" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<g id="upload">
|
||||
<path
|
||||
id="Path"
|
||||
d="M5.58035 2.51616L3.20339 0.139199C3.01776 -0.0463997 2.71681 -0.0463997 2.53119 0.139199L0.154195 2.51616C-0.0282007 2.70502 -0.0229639 3.00597 0.165894 3.18836C0.350128 3.3663 0.642189 3.3663 0.826423 3.18836L2.39191 1.62288V9.50781C2.39191 9.77037 2.60475 9.98321 2.86731 9.98321C3.12988 9.98321 3.34272 9.77037 3.34272 9.50781V1.6229L4.90821 3.18839C5.09706 3.37079 5.39801 3.36555 5.58041 3.17669C5.75829 2.99246 5.75829 2.7004 5.58035 2.51616Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<select
|
||||
className="text-sm font-medium appearance-none bg-white"
|
||||
onChange={mediaFilterOnChange}
|
||||
value={mediaFilter}
|
||||
>
|
||||
<option value="all">All</option>
|
||||
<option value="photos">Photos</option>
|
||||
<option value="videos">Videos</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{files?.pages.map((filePage, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{filePage.map((file) => (
|
||||
<MediaItem file={file} key={file._id} />
|
||||
))}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div
|
||||
className={classNames(
|
||||
"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-[10px]"
|
||||
)}
|
||||
>
|
||||
<div className="fixed bottom-0 flex justify-center items-center right-0 left-0 z-10">
|
||||
<MultiSelectBar />
|
||||
</div>
|
||||
{files?.pages.map((filePage, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{filePage.map((file) => (
|
||||
<MediaItem file={file} key={file._id} />
|
||||
))}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
{/* @ts-ignore */}
|
||||
<div ref={sentinelRef} className="h-1"></div>
|
||||
</div>
|
||||
{/* @ts-ignore */}
|
||||
<div ref={sentinelRef} className="h-1"></div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Medias;
|
||||
|
||||
@@ -30,6 +30,12 @@ export interface SelectedStateType {
|
||||
file: FileInterface | null;
|
||||
};
|
||||
moveModal: MoveStateType;
|
||||
navigationMap: {
|
||||
[key: string]: {
|
||||
url: string;
|
||||
scrollTop: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const initialState: SelectedStateType = {
|
||||
@@ -54,6 +60,7 @@ const initialState: SelectedStateType = {
|
||||
file: null,
|
||||
folder: null,
|
||||
},
|
||||
navigationMap: {},
|
||||
};
|
||||
|
||||
const selectedSlice = createSlice({
|
||||
@@ -143,6 +150,20 @@ const selectedSlice = createSlice({
|
||||
folder: null,
|
||||
};
|
||||
},
|
||||
addNavigationMap: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
url: string;
|
||||
scrollTop: number;
|
||||
}>
|
||||
) => {
|
||||
const navigationMap = state.navigationMap;
|
||||
navigationMap[action.payload.url] = {
|
||||
url: action.payload.url,
|
||||
scrollTop: action.payload.scrollTop,
|
||||
};
|
||||
state.navigationMap = navigationMap;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -157,6 +178,7 @@ export const {
|
||||
resetShareModal,
|
||||
setMoveModal,
|
||||
resetMoveModal,
|
||||
addNavigationMap,
|
||||
} = selectedSlice.actions;
|
||||
|
||||
export default selectedSlice.reducer;
|
||||
|
||||
Reference in New Issue
Block a user