List.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. 'use client';
  2. import '../style.scss';
  3. import React, { useMemo } from 'react';
  4. import Loading from '@/app/component/Loading';
  5. import { BoardResponse } from '@/types/response/forum/board';
  6. import { PostResponse } from '@/types/response/forum/post';
  7. import { CommentListResponse } from '@/types/response/forum/comment';
  8. import { type CommentItem } from '@/types/forum/comment';
  9. import useEquippedItems from '@/hooks/useEquippedItems';
  10. import WriteForm from './WriteForm';
  11. import Item from './Item';
  12. type Props = {
  13. _board: BoardResponse,
  14. _post: PostResponse,
  15. _data: CommentListResponse;
  16. loading: boolean;
  17. replyTargetID: number|null;
  18. onReply: (commentID: number) => void;
  19. onDelete: (commentID: number, parentID?: number) => void;
  20. onSuccess: (comment?: CommentItem) => void;
  21. canWriteReply?: boolean;
  22. }
  23. export default function List({ _board, _post, _data, loading, replyTargetID, onReply, onSuccess, onDelete, canWriteReply } : Props)
  24. {
  25. // 댓글 작성자(대댓글 포함) ID 를 모아 장착 지위 아이템 배치 조회 (배지/닉네임 이펙트 렌더용)
  26. const authorIDs = useMemo(() => {
  27. const ids: number[] = [];
  28. for (const c of _data.list) {
  29. ids.push(c.memberID);
  30. for (const ch of c.children ?? []) {
  31. ids.push(ch.memberID);
  32. }
  33. }
  34. return ids;
  35. }, [_data.list]);
  36. const equippedMap = useEquippedItems(authorIDs);
  37. return (
  38. <>
  39. {loading ? (
  40. <Loading type={2} />
  41. ) : (
  42. <>
  43. {_data.total > 0 && (
  44. <article className="comment-list">
  45. <ol>
  46. {_data.list.map((row) => {
  47. return (
  48. <React.Fragment key={row.id}>
  49. <Item
  50. _board={_board}
  51. _post={_post}
  52. _comment={row}
  53. equippedItems={equippedMap[row.memberID]}
  54. isReplying={replyTargetID === row.id}
  55. onReply={() => onReply(row.id)}
  56. onDelete={onDelete}
  57. onSuccess={onSuccess}
  58. canWriteReply={canWriteReply}
  59. >
  60. {/* row에 대한 답글 폼(토글) */}
  61. {canWriteReply !== false && replyTargetID === row.id && (
  62. <WriteForm
  63. _board={_board}
  64. _post={_post}
  65. _comment={row}
  66. onSuccess={onSuccess}
  67. onCancel={() => onReply(row.id)}
  68. />
  69. )}
  70. </Item>
  71. {/* 대댓글 목록 */}
  72. {Array.isArray(row.children) && row.children.length > 0 && (
  73. <li>
  74. <ol className="pl-[72px]">
  75. {row.children.map((ch) => (
  76. <Item
  77. key={ch.id}
  78. _board={_board}
  79. _post={_post}
  80. _comment={ch}
  81. equippedItems={equippedMap[ch.memberID]}
  82. onReply={() => onReply(ch.id)}
  83. onDelete={onDelete}
  84. onSuccess={onSuccess}
  85. canWriteReply={canWriteReply}
  86. >
  87. {canWriteReply !== false && replyTargetID != null && replyTargetID === ch.id && (
  88. <WriteForm
  89. _board={_board}
  90. _post={_post}
  91. _comment={ch}
  92. onSuccess={onSuccess}
  93. onCancel={() => onReply(ch.id)}
  94. />
  95. )}
  96. </Item>
  97. ))}
  98. </ol>
  99. </li>
  100. )}
  101. </React.Fragment>
  102. )
  103. })}
  104. </ol>
  105. </article>
  106. )}
  107. </>
  108. )}
  109. </>
  110. );
  111. }