Sort files chronologically + infinite scroll (#535)

This commit is contained in:
Montassar Ghanmy
2024-07-15 22:56:34 +01:00
committed by GitHub
parent 585da88b0d
commit e76da87916
25 changed files with 719 additions and 153 deletions
@@ -1,9 +1,9 @@
import { ToasterService } from '@features/global/services/toaster-service';
import useRouterCompany from '@features/router/hooks/use-router-company';
import { useCallback } from 'react';
import { useRecoilValue, useRecoilCallback } from 'recoil';
import { useRecoilValue, useRecoilCallback, useRecoilState } from 'recoil';
import { DriveApiClient } from '../api-client/api-client';
import { DriveItemAtom, DriveItemChildrenAtom } from '../state/store';
import { DriveItemAtom, DriveItemChildrenAtom, DriveItemPagination, DriveItemSort } from '../state/store';
import { BrowseFilter, DriveItem, DriveItemVersion } from '../types';
import { SharedWithMeFilterState } from '../state/shared-with-me-filter';
import Languages from 'features/global/services/languages-service';
@@ -16,18 +16,26 @@ import { useUserQuota } from 'features/users/hooks/use-user-quota';
export const useDriveActions = () => {
const companyId = useRouterCompany();
const sharedFilter = useRecoilValue(SharedWithMeFilterState);
const sortItem = useRecoilValue(DriveItemSort);
const [paginateItem, _] = useRecoilState(DriveItemPagination);
const { getQuota } = useUserQuota();
const refresh = useRecoilCallback(
({ set, snapshot }) =>
async (parentId: string) => {
async (parentId: string, resetPagination?: boolean) => {
if (parentId) {
const filter: BrowseFilter = {
company_id: companyId,
mime_type: sharedFilter.mimeType.value,
};
let pagination = await snapshot.getPromise(DriveItemPagination);
if (resetPagination) {
pagination = { page: 0, limit: pagination.limit };
set(DriveItemPagination, pagination);
}
try {
const details = await DriveApiClient.browse(companyId, parentId, filter);
const details = await DriveApiClient.browse(companyId, parentId, filter, sortItem, pagination);
set(DriveItemChildrenAtom(parentId), details.children);
set(DriveItemAtom(parentId), details);
for (const child of details.children) {
@@ -40,10 +48,12 @@ export const useDriveActions = () => {
return details;
} catch (e) {
ToasterService.error(Languages.t('hooks.use-drive-actions.unable_load_file'));
} finally {
set(DriveItemPagination, { page: pagination.limit, limit: pagination.limit });
}
}
},
[companyId],
[companyId, sortItem],
);
const create = useCallback(
@@ -54,7 +64,7 @@ export const useDriveActions = () => {
try {
const driveFile = await DriveApiClient.create(companyId, { item, version });
await refresh(driveFile.parent_id);
await refresh(driveFile.parent_id, true);
await getQuota();
return driveFile;
@@ -89,9 +99,9 @@ export const useDriveActions = () => {
);
const downloadZip = useCallback(
async (ids: string[]) => {
async (ids: string[], isDirectory?: boolean) => {
try {
const url = await DriveApiClient.getDownloadZipUrl(companyId, ids);
const url = await DriveApiClient.getDownloadZipUrl(companyId, ids, isDirectory);
(window as any).open(url, '_blank').focus();
} catch (e) {
ToasterService.error(Languages.t('hooks.use-drive-actions.unable_download_file'));
@@ -129,9 +139,9 @@ export const useDriveActions = () => {
async (update: Partial<DriveItem>, id: string, parentId: string) => {
try {
await DriveApiClient.update(companyId, id, update);
await refresh(id || '');
await refresh(parentId || '');
if (update?.parent_id !== parentId) await refresh(update?.parent_id || '');
await refresh(id || '', true);
await refresh(parentId || '', true);
if (update?.parent_id !== parentId) await refresh(update?.parent_id || '', true);
} catch (e) {
ToasterService.error(Languages.t('hooks.use-drive-actions.unable_update_file'));
}
@@ -156,5 +166,25 @@ export const useDriveActions = () => {
[refresh],
);
return { create, refresh, download, downloadZip, remove, restore, update, updateLevel };
const nextPage = useRecoilCallback(
({ snapshot }) =>
async (parentId: string) => {
const filter: BrowseFilter = {
company_id: companyId,
mime_type: sharedFilter.mimeType.value,
};
const pagination = await snapshot.getPromise(DriveItemPagination);
const details = await DriveApiClient.browse(
companyId,
parentId,
filter,
sortItem,
pagination
);
return details;
},
[paginateItem, refresh],
);
return { create, refresh, download, downloadZip, remove, restore, update, updateLevel, nextPage };
};
@@ -1,9 +1,9 @@
import { ToasterService } from '@features/global/services/toaster-service';
import { LoadingStateInitTrue } from '@features/global/state/atoms/Loading';
import useRouterCompany from '@features/router/hooks/use-router-company';
import { useCallback } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { DriveItemAtom, DriveItemChildrenAtom } from '../state/store';
import { useCallback, useState } from 'react';
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
import { DriveItemAtom, DriveItemChildrenAtom, DriveItemPagination } from '../state/store';
import { DriveItem } from '../types';
import { useDriveActions } from './use-drive-actions';
import { useDriveUpload } from './use-drive-upload';
@@ -17,8 +17,10 @@ import short from 'short-uuid';
export const useDriveItem = (id: string) => {
const companyId = useRouterCompany();
const item = useRecoilValue(DriveItemAtom(id));
const children = useRecoilValue(DriveItemChildrenAtom(id));
// const children = useRecoilValue(DriveItemChildrenAtom(id));
const [children, setChildren] = useRecoilState(DriveItemChildrenAtom(id));
const [loading, setLoading] = useRecoilState(LoadingStateInitTrue('useDriveItem-' + id));
const [_, setPaginateItem] = useRecoilState(DriveItemPagination);
const {
refresh: refreshItem,
create,
@@ -26,19 +28,20 @@ export const useDriveItem = (id: string) => {
updateLevel: _updateLevel,
remove: _remove,
restore: _restore,
nextPage,
} = useDriveActions();
const { uploadVersion: _uploadVersion } = useDriveUpload();
const refresh = useCallback(
async (parentId: string) => {
async (parentId: string, resetPagination?: boolean) => {
setLoading(true);
try {
await refreshItem(parentId);
setPaginateItem(prev => ({ ...prev, page: 0 }));
await refreshItem(parentId, resetPagination);
} finally {
setLoading(false);
}
},
[setLoading, refreshItem],
[id, setLoading, refreshItem],
);
const remove = useCallback(async () => {
@@ -100,6 +103,51 @@ export const useDriveItem = (id: string) => {
[companyId, id, setLoading, refresh, item?.item?.parent_id],
);
const loadNextPage = useRecoilCallback(
({ set, snapshot }) =>
async (id: string) => {
// get current pagination state
const pagination = await snapshot.getPromise(DriveItemPagination);
// if end is true, do not load more
if (pagination.lastPage === true) return;
setLoading(true);
try {
const details = await nextPage(id);
if (details.children.length === 0) {
set(DriveItemPagination, prev => ({
...prev,
lastPage: true,
}));
}
// set children and remove duplicates
setChildren(prev => [
...prev,
...details.children.filter(
(item, index, self) =>
index === self.findIndex(t => t.id === item.id),
),
]);
} catch (e) {
// set pagination end to true
set(DriveItemPagination, prev => ({
...prev,
lastPage: true,
}));
console.log('error loading next page: ', e);
ToasterService.error('Unable to load more items.');
} finally {
set(DriveItemPagination, prev => ({
...prev,
page: (prev.page + prev.limit),
}));
}
setLoading(false);
},
[id, nextPage],
);
const inTrash =
id.includes('trash') ||
item?.path?.some(i => i?.parent_id?.includes('trash')) ||
@@ -123,6 +171,7 @@ export const useDriveItem = (id: string) => {
updateLevel,
remove,
refresh,
loadNextPage,
};
};
@@ -29,11 +29,17 @@ export const useDrivePreviewModal = () => {
}
};
const openWithId: (id: string) => void = (id: string) => {
DriveApiClient.get(company, id).then((item) => {
open(item?.item);
});
}
const close = () => {
setStatus({ item: null, loading: true });
}
return { open, close, isOpen: !!status.item };
return { open, close, isOpen: !!status.item, openWithId };
};
export const useDrivePreview = () => {
@@ -50,7 +50,7 @@ export const useDriveUpload = () => {
// Create all directories
logger.debug("Start creating directories ...");
const filesPerParentId = await FileUploadService.createDirectories(tree.tree, context);
await refresh(context.parentId);
await refresh(context.parentId, true);
logger.debug("All directories created");
// Upload files into directories
@@ -90,7 +90,7 @@ export const useDriveUpload = () => {
},
});
}
await refresh(context.parentId);
await refresh(context.parentId, true);
};
const uploadFromUrl = (