TextInputForPageTitleAndPath.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { FC, useCallback } from 'react';
  2. import nodePath from 'path';
  3. import { pathUtils } from '@growi/core/dist/utils';
  4. import { useTranslation } from 'next-i18next';
  5. import { apiv3Put } from '~/client/util/apiv3-client';
  6. import { ValidationTarget } from '~/client/util/input-validator';
  7. import { toastSuccess, toastError } from '~/client/util/toastr';
  8. import { useSWRMUTxCurrentPage } from '~/stores/page';
  9. import { mutatePageTree, mutatePageList } from '~/stores/page-listing';
  10. import { mutateSearching } from '~/stores/search';
  11. import ClosableTextInput from '../Common/ClosableTextInput';
  12. type Props = {
  13. currentPagePath
  14. currentPage
  15. stateHandler
  16. inputValue
  17. }
  18. export const TextInputForPageTitleAndPath: FC<Props> = (props) => {
  19. const {
  20. currentPagePath, currentPage, stateHandler, inputValue,
  21. } = props;
  22. const { t } = useTranslation();
  23. const { trigger: mutateCurrentPage } = useSWRMUTxCurrentPage();
  24. const { isRenameInputShown, setRenameInputShown } = stateHandler;
  25. const onClickInputValueHandler = () => {
  26. setRenameInputShown(true);
  27. };
  28. const page = currentPage;
  29. const onRenamed = useCallback((fromPath: string | undefined, toPath: string) => {
  30. mutatePageTree();
  31. mutateSearching();
  32. mutatePageList();
  33. if (currentPagePath === fromPath || currentPagePath === toPath) {
  34. mutateCurrentPage();
  35. }
  36. }, [currentPagePath, mutateCurrentPage]);
  37. if (currentPage == null) {
  38. return <></>;
  39. }
  40. const onPressEnterForRenameHandler = async(inputText: string) => {
  41. const parentPath = pathUtils.addTrailingSlash(nodePath.dirname(page.path ?? ''));
  42. const newPagePath = nodePath.resolve(parentPath, inputText);
  43. if (newPagePath === page.path) {
  44. setRenameInputShown(false);
  45. return;
  46. }
  47. try {
  48. setRenameInputShown(false);
  49. await apiv3Put('/pages/rename', {
  50. pageId: page._id,
  51. revisionId: page.revision._id,
  52. newPagePath,
  53. });
  54. if (onRenamed != null) {
  55. onRenamed(page.path, newPagePath);
  56. }
  57. toastSuccess(t('renamed_pages', { path: page.path }));
  58. }
  59. catch (err) {
  60. setRenameInputShown(true);
  61. toastError(err);
  62. }
  63. };
  64. return (
  65. <>
  66. {isRenameInputShown ? (
  67. <div className="flex-fill">
  68. <ClosableTextInput
  69. value={inputValue}
  70. placeholder={t('Input page name')}
  71. onClickOutside={() => { setRenameInputShown(false) }}
  72. onPressEnter={onPressEnterForRenameHandler}
  73. validationTarget={ValidationTarget.PAGE}
  74. />
  75. </div>
  76. ) : (
  77. <div onClick={onClickInputValueHandler}>{inputValue}</div>
  78. )}
  79. </>
  80. );
  81. };