Comments.tsx 3.0 KB

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