NewPageInput.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import React, { FC, useCallback, useEffect } from 'react';
  2. import nodePath from 'path';
  3. import { pathUtils, pagePathUtils } from '@growi/core/dist/utils';
  4. import { useTranslation } from 'next-i18next';
  5. import { apiv3Post } from '~/client/util/apiv3-client';
  6. import { ValidationTarget } from '~/client/util/input-validator';
  7. import { toastWarning, toastError, toastSuccess } from '~/client/util/toastr';
  8. import ClosableTextInput from '~/components/Common/ClosableTextInput';
  9. import { useSWRxPageChildren } from '~/stores/page-listing';
  10. import { usePageTreeDescCountMap } from '~/stores/ui';
  11. import { NewPageCreateButtonProps } from './NewPageCreateButton';
  12. import { NotDraggableForClosableTextInput } from './SimpleItem';
  13. type NewPageInputProps = NewPageCreateButtonProps & {isEnableActions: boolean};
  14. export const NewPageInput: FC<NewPageInputProps> = (props) => {
  15. const { t } = useTranslation();
  16. const {
  17. page, isEnableActions, currentChildren, stateHandlers, isNewPageInputShown, setNewPageInputShown,
  18. } = props;
  19. const { isOpen, setIsOpen, setCreating } = stateHandlers;
  20. const { mutate: mutateChildren } = useSWRxPageChildren(isOpen ? page._id : null);
  21. const { getDescCount } = usePageTreeDescCountMap();
  22. const descendantCount = getDescCount(page._id) || page.descendantCount || 0;
  23. const isChildrenLoaded = currentChildren?.length > 0;
  24. const hasDescendants = descendantCount > 0 || isChildrenLoaded;
  25. const onPressEnterForCreateHandler = async(inputText: string) => {
  26. setNewPageInputShown(false);
  27. // closeNewPageInput();
  28. const parentPath = pathUtils.addTrailingSlash(page.path as string);
  29. const newPagePath = nodePath.resolve(parentPath, inputText);
  30. const isCreatable = pagePathUtils.isCreatablePage(newPagePath);
  31. if (!isCreatable) {
  32. toastWarning(t('you_can_not_create_page_with_this_name'));
  33. return;
  34. }
  35. try {
  36. setCreating(true);
  37. await apiv3Post('/pages/', {
  38. path: newPagePath,
  39. body: undefined,
  40. grant: page.grant,
  41. // grantUserGroupId: page.grantedGroup,
  42. grantUserGroupIds: page.grantedGroups,
  43. });
  44. mutateChildren();
  45. if (!hasDescendants) {
  46. setIsOpen(true);
  47. }
  48. toastSuccess(t('successfully_saved_the_page'));
  49. }
  50. catch (err) {
  51. toastError(err);
  52. }
  53. finally {
  54. setCreating(false);
  55. }
  56. };
  57. const onPressEscHandler = useCallback((event) => {
  58. if (event.keyCode === 27) {
  59. setNewPageInputShown(false);
  60. }
  61. }, []);
  62. useEffect(() => {
  63. document.addEventListener('keydown', onPressEscHandler, false);
  64. return () => {
  65. document.removeEventListener('keydown', onPressEscHandler, false);
  66. };
  67. }, [onPressEscHandler]);
  68. return (
  69. <>
  70. {isEnableActions && isNewPageInputShown && (
  71. <NotDraggableForClosableTextInput>
  72. <ClosableTextInput
  73. placeholder={t('Input page name')}
  74. onClickOutside={() => { setNewPageInputShown(false) }}
  75. onPressEnter={onPressEnterForCreateHandler}
  76. validationTarget={ValidationTarget.PAGE}
  77. />
  78. </NotDraggableForClosableTextInput>
  79. )}
  80. </>
  81. );
  82. };