Comments.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import React, { useEffect, useRef } from 'react';
  2. import { type IRevisionHasId, pagePathUtils } from '@growi/core';
  3. import dynamic from 'next/dynamic';
  4. import { ROOT_ELEM_ID as PageCommentRootElemId, type PageCommentProps } from '~/components/PageComment';
  5. import { useSWRxPageComment } from '~/stores/comment';
  6. import { useIsTrashPage } from '~/stores/page';
  7. import { useCurrentUser } from '../stores/context';
  8. import type { CommentEditorProps } from './PageComment/CommentEditor';
  9. const { isTopPage } = pagePathUtils;
  10. const PageComment = dynamic<PageCommentProps>(() => import('~/components/PageComment').then(mod => mod.PageComment), { ssr: false });
  11. const CommentEditor = dynamic<CommentEditorProps>(() => import('./PageComment/CommentEditor').then(mod => mod.CommentEditor), { ssr: false });
  12. export type CommentsProps = {
  13. pageId: string,
  14. pagePath: string,
  15. revision: IRevisionHasId,
  16. onLoaded?: () => void,
  17. }
  18. export const Comments = (props: CommentsProps): JSX.Element => {
  19. const {
  20. pageId, pagePath, revision, onLoaded,
  21. } = props;
  22. const { mutate } = useSWRxPageComment(pageId);
  23. const { data: isDeleted } = useIsTrashPage();
  24. const { data: currentUser } = useCurrentUser();
  25. const pageCommentParentRef = useRef<HTMLDivElement>(null);
  26. useEffect(() => {
  27. const parent = pageCommentParentRef.current;
  28. if (parent == null) return;
  29. const observerCallback = (mutationRecords:MutationRecord[]) => {
  30. mutationRecords.forEach((record:MutationRecord) => {
  31. const target = record.target as HTMLElement;
  32. for (const child of Array.from(target.children)) {
  33. const childId = (child as HTMLElement).id;
  34. if (childId === PageCommentRootElemId) {
  35. onLoaded?.();
  36. break;
  37. }
  38. }
  39. });
  40. };
  41. const observer = new MutationObserver(observerCallback);
  42. observer.observe(parent, { childList: true });
  43. return () => {
  44. observer.disconnect();
  45. };
  46. }, [onLoaded]);
  47. const isTopPagePath = isTopPage(pagePath);
  48. if (pageId == null || isTopPagePath) {
  49. return <></>;
  50. }
  51. return (
  52. <div className="page-comments-row mt-5 py-4 d-edit-none d-print-none">
  53. <div className="container-lg">
  54. <div id="page-comments-list" className="page-comments-list" ref={pageCommentParentRef}>
  55. <PageComment
  56. pageId={pageId}
  57. pagePath={pagePath}
  58. revision={revision}
  59. currentUser={currentUser}
  60. isReadOnly={false}
  61. titleAlign="left"
  62. hideIfEmpty={false}
  63. />
  64. </div>
  65. { !isDeleted && (
  66. <div id="page-comment-write">
  67. <CommentEditor
  68. pageId={pageId}
  69. isForNewComment
  70. onCommentButtonClicked={mutate}
  71. revisionId={revision._id}
  72. />
  73. </div>
  74. )}
  75. </div>
  76. </div>
  77. );
  78. };