PageEditorModeManager.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import React, { type ReactNode, useCallback } from 'react';
  2. import { Origin } from '@growi/core';
  3. import { useTranslation } from 'next-i18next';
  4. import { useCreatePageAndTransit } from '~/client/services/create-page';
  5. import { toastError } from '~/client/util/toastr';
  6. import { useIsNotFound, useCurrentPageYjsDraft } from '~/stores/page';
  7. import { EditorMode, useEditorMode, useIsDeviceLargerThanMd } from '~/stores/ui';
  8. import { shouldCreateWipPage } from '../../utils/should-create-wip-page';
  9. import styles from './PageEditorModeManager.module.scss';
  10. type PageEditorModeButtonProps = {
  11. currentEditorMode: EditorMode,
  12. editorMode: EditorMode,
  13. children?: ReactNode,
  14. isBtnDisabled?: boolean,
  15. onClick?: () => void,
  16. }
  17. const PageEditorModeButton = React.memo((props: PageEditorModeButtonProps) => {
  18. const {
  19. currentEditorMode, isBtnDisabled, editorMode, children, onClick,
  20. } = props;
  21. const classNames = ['btn py-1 px-2 d-flex align-items-center justify-content-center'];
  22. if (currentEditorMode === editorMode) {
  23. classNames.push('active');
  24. }
  25. if (isBtnDisabled) {
  26. classNames.push('disabled');
  27. }
  28. return (
  29. <button
  30. type="button"
  31. className={classNames.join(' ')}
  32. onClick={onClick}
  33. data-testid={`${editorMode}-button`}
  34. >
  35. {children}
  36. </button>
  37. );
  38. });
  39. type Props = {
  40. editorMode: EditorMode | undefined,
  41. isBtnDisabled: boolean,
  42. path?: string,
  43. }
  44. export const PageEditorModeManager = (props: Props): JSX.Element => {
  45. const {
  46. editorMode = EditorMode.View,
  47. isBtnDisabled,
  48. path,
  49. } = props;
  50. const { t } = useTranslation('commons');
  51. const { data: isNotFound } = useIsNotFound();
  52. const { mutate: mutateEditorMode } = useEditorMode();
  53. const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
  54. const { data: currentPageYjsDraft } = useCurrentPageYjsDraft();
  55. const { isCreating, createAndTransit } = useCreatePageAndTransit();
  56. const editButtonClickedHandler = useCallback(async() => {
  57. if (isNotFound == null || isNotFound === false) {
  58. mutateEditorMode(EditorMode.Editor);
  59. return;
  60. }
  61. try {
  62. await createAndTransit(
  63. { path, wip: shouldCreateWipPage(path), origin: Origin.View },
  64. { shouldCheckPageExists: true },
  65. );
  66. }
  67. catch (err) {
  68. toastError(t('toaster.create_failed', { target: path }));
  69. }
  70. }, [createAndTransit, isNotFound, mutateEditorMode, path, t]);
  71. const _isBtnDisabled = isCreating || isBtnDisabled;
  72. return (
  73. <>
  74. <div
  75. className={`btn-group grw-page-editor-mode-manager ${styles['grw-page-editor-mode-manager']}`}
  76. role="group"
  77. aria-label="page-editor-mode-manager"
  78. id="grw-page-editor-mode-manager"
  79. >
  80. {(isDeviceLargerThanMd || editorMode !== EditorMode.View) && (
  81. <PageEditorModeButton
  82. currentEditorMode={editorMode}
  83. editorMode={EditorMode.View}
  84. isBtnDisabled={_isBtnDisabled}
  85. onClick={() => mutateEditorMode(EditorMode.View)}
  86. >
  87. <span className="material-symbols-outlined fs-4">play_arrow</span>{t('View')}
  88. </PageEditorModeButton>
  89. )}
  90. {(isDeviceLargerThanMd || editorMode === EditorMode.View) && (
  91. <PageEditorModeButton
  92. currentEditorMode={editorMode}
  93. editorMode={EditorMode.Editor}
  94. isBtnDisabled={_isBtnDisabled}
  95. onClick={editButtonClickedHandler}
  96. >
  97. <span className="material-symbols-outlined me-1 fs-5">edit_square</span>{t('Edit')}
  98. { currentPageYjsDraft?.hasYjsDraft && <span className="position-absolute top-0 start-100 translate-middle p-1 bg-primary rounded-circle" />}
  99. </PageEditorModeButton>
  100. )}
  101. </div>
  102. </>
  103. );
  104. };