SimplifiedPageTreeItem.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import type { FC } from 'react';
  2. import { useCallback } from 'react';
  3. import path from 'path';
  4. import type { IPageToDeleteWithMeta } from '@growi/core/dist/interfaces';
  5. import { getIdStringForRef } from '@growi/core/dist/interfaces';
  6. import { pathUtils } from '@growi/core/dist/utils';
  7. import { useTranslation } from 'next-i18next';
  8. import { useRouter } from 'next/router';
  9. import { toastSuccess } from '~/client/util/toastr';
  10. import { ROOT_PAGE_VIRTUAL_ID } from '~/constants/page-tree';
  11. import type { IPageForItem } from '~/interfaces/page';
  12. import type { OnDeletedFunction, OnDuplicatedFunction } from '~/interfaces/ui';
  13. import { useCurrentPagePath, useFetchCurrentPage } from '~/states/page';
  14. import { usePageTreeInformationUpdate } from '~/states/page-tree-update';
  15. import { usePageDeleteModalActions } from '~/states/ui/modal/page-delete';
  16. import type { IPageForPageDuplicateModal } from '~/states/ui/modal/page-duplicate';
  17. import { usePageDuplicateModalActions } from '~/states/ui/modal/page-duplicate';
  18. import { mutateAllPageInfo } from '~/stores/page';
  19. import { mutatePageTree, mutatePageList } from '~/stores/page-listing';
  20. import { mutateSearching } from '~/stores/search';
  21. import type { TreeItemProps } from '../../TreeItem';
  22. import { TreeItemLayout } from '../../TreeItem';
  23. import { CountBadgeForPageTreeItem } from './CountBadgeForPageTreeItem';
  24. import { usePageItemControl } from './use-page-item-control';
  25. import styles from './PageTreeItem.module.scss';
  26. const moduleClass = styles['page-tree-item'] ?? '';
  27. export const simplifiedPageTreeItemSize = 40; // in px
  28. export const SimplifiedPageTreeItem: FC<TreeItemProps> = ({
  29. item,
  30. targetPath,
  31. targetPathOrId,
  32. isWipPageShown,
  33. isEnableActions = false,
  34. isReadOnlyUser = false,
  35. onToggle,
  36. }) => {
  37. const { t } = useTranslation();
  38. const router = useRouter();
  39. const itemData = item.getItemData();
  40. const currentPagePath = useCurrentPagePath();
  41. const { fetchCurrentPage } = useFetchCurrentPage();
  42. const { open: openDuplicateModal } = usePageDuplicateModalActions();
  43. const { open: openDeleteModal } = usePageDeleteModalActions();
  44. const { notifyUpdateItems } = usePageTreeInformationUpdate();
  45. const onClickDuplicateMenuItem = useCallback((page: IPageForPageDuplicateModal) => {
  46. const duplicatedHandler: OnDuplicatedFunction = (fromPath) => {
  47. toastSuccess(t('duplicated_pages', { fromPath }));
  48. mutatePageTree();
  49. mutateSearching();
  50. mutatePageList();
  51. // Notify headless-tree update
  52. const parentId = itemData.parent != null ? getIdStringForRef(itemData.parent) : ROOT_PAGE_VIRTUAL_ID;
  53. notifyUpdateItems([parentId]);
  54. };
  55. openDuplicateModal(page, { onDuplicated: duplicatedHandler });
  56. }, [openDuplicateModal, t, notifyUpdateItems, itemData.parent]);
  57. const onClickDeleteMenuItem = useCallback((page: IPageToDeleteWithMeta) => {
  58. const onDeletedHandler: OnDeletedFunction = (pathOrPathsToDelete, isRecursively, isCompletely) => {
  59. if (typeof pathOrPathsToDelete !== 'string') {
  60. return;
  61. }
  62. if (isCompletely) {
  63. toastSuccess(t('deleted_pages_completely', { path: pathOrPathsToDelete }));
  64. }
  65. else {
  66. toastSuccess(t('deleted_pages', { path: pathOrPathsToDelete }));
  67. }
  68. mutatePageTree();
  69. mutateSearching();
  70. mutatePageList();
  71. mutateAllPageInfo();
  72. if (currentPagePath === pathOrPathsToDelete) {
  73. fetchCurrentPage({ force: true });
  74. router.push(isCompletely ? path.dirname(pathOrPathsToDelete) : `/trash${pathOrPathsToDelete}`);
  75. }
  76. // Notify headless-tree update
  77. const parentId = itemData.parent != null ? getIdStringForRef(itemData.parent) : ROOT_PAGE_VIRTUAL_ID;
  78. notifyUpdateItems([parentId]);
  79. };
  80. openDeleteModal([page], { onDeleted: onDeletedHandler });
  81. }, [openDeleteModal, t, currentPagePath, fetchCurrentPage, router, itemData.parent, notifyUpdateItems]);
  82. const { Control } = usePageItemControl();
  83. const itemSelectedHandler = useCallback((page: IPageForItem) => {
  84. if (page.path == null || page._id == null) return;
  85. const link = pathUtils.returnPathForURL(page.path, page._id);
  86. router.push(link);
  87. }, [router]);
  88. const itemSelectedByWheelClickHandler = useCallback((page: IPageForItem) => {
  89. if (page.path == null || page._id == null) return;
  90. const url = pathUtils.returnPathForURL(page.path, page._id);
  91. window.open(url, '_blank');
  92. }, []);
  93. return (
  94. <TreeItemLayout
  95. className={moduleClass}
  96. item={item}
  97. targetPath={targetPath}
  98. targetPathOrId={targetPathOrId ?? undefined}
  99. isWipPageShown={isWipPageShown}
  100. isEnableActions={isEnableActions}
  101. isReadOnlyUser={isReadOnlyUser}
  102. onClick={itemSelectedHandler}
  103. onWheelClick={itemSelectedByWheelClickHandler}
  104. onToggle={onToggle}
  105. onClickDuplicateMenuItem={onClickDuplicateMenuItem}
  106. onClickDeleteMenuItem={onClickDeleteMenuItem}
  107. customEndComponents={[CountBadgeForPageTreeItem]}
  108. customHoveredEndComponents={[Control]}
  109. />
  110. );
  111. };