Comments.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import React, { useEffect, useMemo, useRef } from 'react';
  2. import type { IRevisionHasId } from '@growi/core';
  3. import { pagePathUtils } from '@growi/core/dist/utils';
  4. import { useTranslation } from 'next-i18next';
  5. import dynamic from 'next/dynamic';
  6. import { debounce } from 'throttle-debounce';
  7. import { useCurrentUser } from '~/stores-universal/context';
  8. import { useSWRxPageComment } from '~/stores/comment';
  9. import { useIsTrashPage, useSWRMUTxPageInfo } from '~/stores/page';
  10. const { isTopPage } = pagePathUtils;
  11. const PageComment = dynamic(() => import('~/client/components/PageComment').then(mod => mod.PageComment), { ssr: false });
  12. const CommentEditorPre = dynamic(() => import('./PageComment/CommentEditor').then(mod => mod.CommentEditorPre), { ssr: false });
  13. type CommentsProps = {
  14. pageId: string,
  15. pagePath: string,
  16. revision: IRevisionHasId,
  17. onLoaded?: () => void,
  18. }
  19. export const Comments = (props: CommentsProps): JSX.Element => {
  20. const {
  21. pageId, pagePath, revision, onLoaded,
  22. } = props;
  23. const { t } = useTranslation('');
  24. const { mutate } = useSWRxPageComment(pageId);
  25. const { trigger: mutatePageInfo } = useSWRMUTxPageInfo(pageId);
  26. const { data: isDeleted } = useIsTrashPage();
  27. const { data: currentUser } = useCurrentUser();
  28. const pageCommentParentRef = useRef<HTMLDivElement>(null);
  29. const onLoadedDebounced = useMemo(() => debounce(500, () => onLoaded?.()), [onLoaded]);
  30. useEffect(() => {
  31. const parent = pageCommentParentRef.current;
  32. if (parent == null) return;
  33. const observer = new MutationObserver(() => {
  34. onLoadedDebounced();
  35. });
  36. observer.observe(parent, { childList: true, subtree: true });
  37. // no cleanup function -- 2023.07.31 Yuki Takei
  38. // see: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe
  39. // > You can call observe() multiple times on the same MutationObserver
  40. // > to watch for changes to different parts of the DOM tree and/or different types of changes.
  41. }, [onLoadedDebounced]);
  42. const isTopPagePath = isTopPage(pagePath);
  43. if (pageId == null || isTopPagePath) {
  44. return <></>;
  45. }
  46. const onCommentButtonClickHandler = () => {
  47. mutate();
  48. mutatePageInfo();
  49. };
  50. return (
  51. <div className="page-comments-row mt-5 py-4 border-top d-edit-none d-print-none">
  52. <h4 className="mb-3">{t('page_comment.comments')}</h4>
  53. <div id="page-comments-list" className="page-comments-list" ref={pageCommentParentRef}>
  54. <PageComment
  55. pageId={pageId}
  56. pagePath={pagePath}
  57. revision={revision}
  58. currentUser={currentUser}
  59. isReadOnly={false}
  60. />
  61. </div>
  62. {!isDeleted && (
  63. <div id="page-comment-write">
  64. <CommentEditorPre
  65. pageId={pageId}
  66. onCommented={onCommentButtonClickHandler}
  67. revisionId={revision._id}
  68. />
  69. </div>
  70. )}
  71. </div>
  72. );
  73. };