got infinite scrolling working

This commit is contained in:
subnub
2024-06-23 19:18:32 -04:00
parent da3cbb4723
commit a425e5be6d
12 changed files with 298 additions and 206 deletions
+1 -1
View File
@@ -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;
+6 -7
View File
@@ -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 () => {
+32 -15
View File
@@ -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 (
<div className="w-full p-[65px_40px] overflow-y-scroll">
<QuickAccess />
<button
className="p-2 bg-blue-500 rounded-md text-white"
onClick={filesFetchNextPage}
>
Next page
</button>
<button
className="p-2 bg-blue-500 rounded-md text-white ml-4"
onClick={invalidateFilesCache}
>
Refresh
</button>
<Folders />
<Files />
<div ref={sentinelRef} className="h-1"></div>
{/* TODO: Change this spinner name */}
{isFetchingNextPage && (
<div className="w-full flex justify-center items-center mt-4">
<SpinnerPage />
</div>
)}
</div>
);
};
+18 -12
View File
@@ -80,7 +80,7 @@ const FileItem = (props) => {
>
{/* <ContextMenu parent={props.metadata.parent} contextSelected={props.state.contextSelected} closeContext={props.closeContext} downloadFile={props.downloadFile} file={props} changeEditNameMode={props.changeEditNameMode} closeEditNameMode={props.closeEditNameMode} changeDeleteMode={props.changeDeleteMode} startMovingFile={props.startMovingFile}/> */}
<td className="p-5">
<div className="flex items-center fileTextXL:w-[600px] w-[100px] xxs:w-[200px] xs:w-[300px] fileTextXSM:w-[500px] fileTextLG:w-[500px] fileTextMD:w-[300px] mobileMode:w-[200px]">
<div className="flex items-center fileTextXL:w-[560px] w-[60px] xxs:w-[160px] xs:w-[260px] fileTextXSM:w-[460px] fileTextLG:w-[440px] fileTextMD:w-[240px] mobileMode:w-[160px]">
<span className="inline-flex items-center mr-[15px] max-w-[27px] min-w-[27px] min-h-[27px] max-h-[27px]">
<div
className="h-[27px] w-[27px] bg-red-500 rounded-[3px] flex flex-row justify-center items-center"
@@ -101,24 +101,30 @@ const FileItem = (props) => {
</td>
<td className="p-5 hidden fileListShowDetails:table-cell">
<p className="text-center">
{moment(props.file.uploadDate).format("L")}
{moment(props.file.uploadDate).format("MM/DD/YY hh:mma")}
</p>
</td>
<td>
<div className="flex justify-center items-center">
<div onClick={clickStopPropagation}>
<ContextMenu
gridMode={false}
quickItemMode={false}
contextSelected={contextMenuState}
closeContext={closeContextMenu}
file={file}
/>
</div>
{contextMenuState.selected && (
<div onClick={clickStopPropagation}>
<ContextMenu
gridMode={false}
quickItemMode={false}
contextSelected={contextMenuState}
closeContext={closeContextMenu}
file={file}
/>
</div>
)}
{/* <ContextMenu parent={props.metadata.parent} contextSelected={props.state.contextSelected} closeContext={props.closeContext} downloadFile={props.downloadFile} file={props} changeEditNameMode={props.changeEditNameMode} closeEditNameMode={props.closeEditNameMode} changeDeleteMode={props.changeDeleteMode} startMovingFile={props.startMovingFile}/> */}
<a onClick={onContextMenu}>
<svg
class="w-4 h-4 text-[#919eab]"
className={classNames(
"w-4 h-4",
elementSelected ? "text-white" : "text-[#919eab]"
)}
aria-hidden="true"
focusable="false"
data-prefix="fas"
+1 -1
View File
@@ -105,7 +105,7 @@ const Files = () => {
</th>
<th className="hidden fileListShowDetails:table-cell">
<p className="text-[#212b36] text-sm font-medium mb-2">
Modified
Created
</p>
</th>
<th>
+15 -12
View File
@@ -50,7 +50,7 @@ const FolderItem = (props) => {
return (
<div
className={classNames(
"p-[12px] border border-[#ebe9f9] rounded-[4px] overflow-hidden cursor-pointer animate",
"p-[12px] border border-[#ebe9f9] rounded-[4px] overflow-hidden w-48 cursor-pointer animate",
{
"bg-[#3c85ee]": elementSelected,
}
@@ -61,16 +61,19 @@ const FolderItem = (props) => {
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}
>
<div onClick={clickStopPropagation}>
<ContextMenu
gridMode={true}
folderMode={true}
quickItemMode={props.folder.parent !== "/"}
contextSelected={contextMenuState}
closeContext={closeContextMenu}
folder={props.folder}
/>
</div>
{contextMenuState.selected && (
<div onClick={clickStopPropagation}>
<ContextMenu
gridMode={true}
folderMode={true}
quickItemMode={props.folder.parent !== "/"}
contextSelected={contextMenuState}
closeContext={closeContextMenu}
folder={props.folder}
/>
</div>
)}
<div>
<svg
className={classNames(
@@ -102,7 +105,7 @@ const FolderItem = (props) => {
</div>
<p
className={classNames(
"m-0 mt-2 text-[#637381] font-normal max-w-full whitespace-nowrap text-xs animate",
"m-0 mt-2 font-normal max-w-full whitespace-nowrap text-xs animate",
elementSelected ? "text-white" : "text-[#637381]"
)}
>
+25 -21
View File
@@ -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 (
<div
@@ -73,7 +77,7 @@ const Folder = () => {
<div className="flex flex-row items-center">
<a className="mr-2" onClick={switchOrderSortBy}>
<svg
className="h-3 w-3 cursor-pointer"
className="h-3 w-3 cursor-pointer animate"
width="6"
height="10"
viewBox="0 0 6 10"
+1 -1
View File
@@ -14,7 +14,7 @@ class LeftSection extends React.Component {
render() {
return (
<div
className="menu__block p-6 hidden mobileMode:block"
className="menu__block p-6 hidden mobileMode:block border-r"
ref={this.props.leftSectionRef}
style={
this.props.leftSectionMode === ""
+19 -8
View File
@@ -18,7 +18,7 @@ export const useFiles = () => {
{
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 {
+16 -5
View File
@@ -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,
};
};
+43
View File
@@ -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 };
};
+121 -123
View File
@@ -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;
}
margin-bottom: 11px;
}