TrashPageList.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import React, { useMemo, useCallback } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import dynamic from 'next/dynamic';
  4. import { toastSuccess } from '~/client/util/apiNotification';
  5. import {
  6. IPageHasId,
  7. } from '~/interfaces/page';
  8. import { IPagingResult } from '~/interfaces/paging-result';
  9. import { useShowPageLimitationXL } from '~/stores/context';
  10. import { useEmptyTrashModal } from '~/stores/modal';
  11. import { useSWRxPageInfoForList, useSWRxPageList } from '~/stores/page-listing';
  12. import { MenuItemType } from './Common/Dropdown/PageItemControl';
  13. import CustomNavAndContents from './CustomNavigation/CustomNavAndContents';
  14. import { DescendantsPageListProps } from './DescendantsPageList';
  15. import EmptyTrashButton from './EmptyTrashButton';
  16. import PageListIcon from './Icons/PageListIcon';
  17. const DescendantsPageList = dynamic<DescendantsPageListProps>(() => import('./DescendantsPageList').then(mod => mod.DescendantsPageList), { ssr: false });
  18. const convertToIDataWithMeta = (page) => {
  19. return { data: page };
  20. };
  21. const useEmptyTrashButton = () => {
  22. const { data: limit } = useShowPageLimitationXL();
  23. const { data: pagingResult, mutate: mutatePageLists } = useSWRxPageList('/trash', 1, limit);
  24. const { t } = useTranslation();
  25. const { open: openEmptyTrashModal } = useEmptyTrashModal();
  26. const pageIds = pagingResult?.items?.map(page => page._id);
  27. const { injectTo } = useSWRxPageInfoForList(pageIds, null, true, true);
  28. const calculateDeletablePages = useCallback((pagingResult?: IPagingResult<IPageHasId>) => {
  29. if (pagingResult == null) { return undefined }
  30. const dataWithMetas = pagingResult.items.map(page => convertToIDataWithMeta(page));
  31. const pageWithMetas = injectTo(dataWithMetas);
  32. return pageWithMetas.filter(page => page.meta?.isAbleToDeleteCompletely);
  33. }, [injectTo]);
  34. const deletablePages = calculateDeletablePages(pagingResult);
  35. const onEmptiedTrashHandler = useCallback(() => {
  36. toastSuccess(t('empty_trash'));
  37. mutatePageLists();
  38. }, [t, mutatePageLists]);
  39. const emptyTrashClickHandler = useCallback(() => {
  40. if (deletablePages == null) { return }
  41. openEmptyTrashModal(deletablePages, { onEmptiedTrash: onEmptiedTrashHandler, canDeleteAllPages: pagingResult?.totalCount === deletablePages.length });
  42. }, [deletablePages, onEmptiedTrashHandler, openEmptyTrashModal, pagingResult?.totalCount]);
  43. const emptyTrashButton = useMemo(() => {
  44. return <EmptyTrashButton onEmptyTrashButtonClick={emptyTrashClickHandler} disableEmptyButton={deletablePages?.length === 0} />;
  45. }, [emptyTrashClickHandler, deletablePages?.length]);
  46. return emptyTrashButton;
  47. };
  48. const DescendantsPageListForTrash = (): JSX.Element => {
  49. const { data: limit } = useShowPageLimitationXL();
  50. return (
  51. <DescendantsPageList
  52. path="/trash"
  53. limit={limit}
  54. forceHideMenuItems={[MenuItemType.RENAME]}
  55. />
  56. );
  57. };
  58. export const TrashPageList = (): JSX.Element => {
  59. const { t } = useTranslation();
  60. const emptyTrashButton = useEmptyTrashButton();
  61. const navTabMapping = useMemo(() => {
  62. return {
  63. pagelist: {
  64. Icon: PageListIcon,
  65. Content: DescendantsPageListForTrash,
  66. i18n: t('page_list'),
  67. index: 0,
  68. },
  69. };
  70. }, [t]);
  71. return (
  72. <div data-testid="trash-page-list" className="mt-5 d-edit-none">
  73. <CustomNavAndContents navTabMapping={navTabMapping} navRightElement={emptyTrashButton} />
  74. </div>
  75. );
  76. };
  77. TrashPageList.displayName = 'TrashPageList';