PageSelectModal.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import type { FC } from 'react';
  2. import {
  3. Suspense, useState, useCallback,
  4. } from 'react';
  5. import nodePath from 'path';
  6. import { pathUtils } from '@growi/core/dist/utils';
  7. import { useTranslation } from 'next-i18next';
  8. import {
  9. Modal, ModalHeader, ModalBody, ModalFooter, Button,
  10. } from 'reactstrap';
  11. import SimpleBar from 'simplebar-react';
  12. import type { IPageForItem } from '~/interfaces/page';
  13. import { useTargetAndAncestors, useIsGuestUser, useIsReadOnlyUser } from '~/stores-universal/context';
  14. import { usePageSelectModal } from '~/stores/modal';
  15. import { useSWRxCurrentPage } from '~/stores/page';
  16. import { ItemsTree } from '../ItemsTree';
  17. import ItemsTreeContentSkeleton from '../ItemsTree/ItemsTreeContentSkeleton';
  18. import { usePagePathRenameHandler } from '../PageEditor/page-path-rename-utils';
  19. import { TreeItemForModal } from './TreeItemForModal';
  20. export const PageSelectModal: FC = () => {
  21. const {
  22. data: PageSelectModalData,
  23. close: closeModal,
  24. } = usePageSelectModal();
  25. const isOpened = PageSelectModalData?.isOpened ?? false;
  26. const [clickedParentPagePath, setClickedParentPagePath] = useState<string | null>(null);
  27. const { t } = useTranslation();
  28. const { data: isGuestUser } = useIsGuestUser();
  29. const { data: isReadOnlyUser } = useIsReadOnlyUser();
  30. const { data: targetAndAncestorsData } = useTargetAndAncestors();
  31. const { data: currentPage } = useSWRxCurrentPage();
  32. const pagePathRenameHandler = usePagePathRenameHandler(currentPage);
  33. const onClickTreeItem = useCallback((page: IPageForItem) => {
  34. const parentPagePath = page.path;
  35. if (parentPagePath == null) {
  36. return <></>;
  37. }
  38. setClickedParentPagePath(parentPagePath);
  39. }, []);
  40. const onClickCancel = useCallback(() => {
  41. setClickedParentPagePath(null);
  42. closeModal();
  43. }, [closeModal]);
  44. const onClickDone = useCallback(() => {
  45. if (clickedParentPagePath != null) {
  46. const currentPageTitle = nodePath.basename(currentPage?.path ?? '') || '/';
  47. const newPagePath = nodePath.resolve(clickedParentPagePath, currentPageTitle);
  48. pagePathRenameHandler(newPagePath);
  49. }
  50. closeModal();
  51. }, [clickedParentPagePath, closeModal, currentPage?.path, pagePathRenameHandler]);
  52. const parentPagePath = pathUtils.addTrailingSlash(nodePath.dirname(currentPage?.path ?? ''));
  53. const targetPathOrId = clickedParentPagePath || parentPagePath;
  54. const targetPath = clickedParentPagePath || parentPagePath;
  55. if (isGuestUser == null) {
  56. return <></>;
  57. }
  58. return (
  59. <Modal
  60. isOpen={isOpened}
  61. toggle={closeModal}
  62. centered
  63. >
  64. <ModalHeader toggle={closeModal}>{t('page_select_modal.select_page_location')}</ModalHeader>
  65. <ModalBody className="p-0">
  66. <Suspense fallback={<ItemsTreeContentSkeleton />}>
  67. <SimpleBar style={{ maxHeight: 'calc(85vh - 133px)' }}> {/* 133px = 63px(ModalHeader) + 70px(ModalFooter) */}
  68. <div className="p-3">
  69. <ItemsTree
  70. CustomTreeItem={TreeItemForModal}
  71. isEnableActions={!isGuestUser}
  72. isReadOnlyUser={!!isReadOnlyUser}
  73. targetPath={targetPath}
  74. targetPathOrId={targetPathOrId}
  75. targetAndAncestorsData={targetAndAncestorsData}
  76. onClickTreeItem={onClickTreeItem}
  77. />
  78. </div>
  79. </SimpleBar>
  80. </Suspense>
  81. </ModalBody>
  82. <ModalFooter>
  83. <Button color="secondary" onClick={onClickCancel}>{t('Cancel')}</Button>
  84. <Button color="primary" onClick={onClickDone}>{t('Done')}</Button>
  85. </ModalFooter>
  86. </Modal>
  87. );
  88. };