Item.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. 'use client';
  2. import '../style.scss';
  3. import Image from 'next/image';
  4. import { useState, useEffect } from 'react';
  5. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
  6. import { faThumbsUp as nThumbsUp, faThumbsDown as nThumbsDown, faFlag as nFlag, faPenToSquare, faTrashCan } from '@fortawesome/free-regular-svg-icons';
  7. import { faThumbsUp as yThumbsUp, faFlag as yFlag, faArrowRotateRight, faEllipsisVertical } from '@fortawesome/free-solid-svg-icons';
  8. import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
  9. import { throwError, loginCheck, formatDate } from '@/lib/utils/client';
  10. import useAuth from '@/hooks/useAuth';
  11. import { type CommentItem } from '@/types/forum/comment';
  12. import BoardResponse from '@/dtos/response/forum/board/boardResponse';
  13. import PostResponse from '@/dtos/response/forum/post/postResponse';
  14. import EditForm from './EditForm';
  15. import { fetchCommentDelete } from '@/lib/api/forum/comment';
  16. type Props = {
  17. board: BoardResponse; // 게시판 정보
  18. post: PostResponse; // 게시글 정보
  19. comment: CommentItem; // 댓글 정보
  20. isReplying?: boolean; // 답글 버튼 클릭 여부
  21. onReply: () => void; // 답글 버튼 클릭 시
  22. onDelete: () => void; // 삭제 후
  23. onSuccess: () => void; // 수정/삭제 후
  24. }
  25. export default function Item({ comment, isReplying, board, post, onReply, onSuccess, onDelete } : Props)
  26. {
  27. const { isAuthenticated } = useAuth();
  28. const [error, setError] = useState<string|null>(null);
  29. const [loading, setLoading] = useState<boolean>(false);
  30. const [isEditing, setIsEditing] = useState<boolean>(false);
  31. useEffect(() => {
  32. if (!comment) {
  33. setIsEditing(false);
  34. }
  35. }, [comment]);
  36. const handleStartEdit = () => {
  37. if (!loginCheck(isAuthenticated)) {
  38. return;
  39. }
  40. setIsEditing(true);
  41. };
  42. const handleCancelEdit = () => {
  43. setIsEditing(false);
  44. };
  45. const handleEditSuccess = () => {
  46. setIsEditing(false);
  47. if (typeof onSuccess === 'function') {
  48. onSuccess();
  49. }
  50. };
  51. const handleDelete = () => {
  52. setIsEditing(false);
  53. if (confirm("댓글을 삭제하시겠습니까?")) {
  54. setLoading(true);
  55. // 댓글 삭제 호출
  56. fetchCommentDelete(comment.id).then((res) => {
  57. throwError(res);
  58. // 삭제 성공 시 해당 댓글 영역 삭제
  59. onDelete();
  60. }).catch(err => {
  61. setError(err.message);
  62. }).finally(() => {
  63. setLoading(false);
  64. });
  65. }
  66. };
  67. const writerThumb = (comment.writer.thumbnail ?? '/resources/thumb.gif');
  68. const writerName = (comment.writer.name || comment.writer.sid);
  69. const createdAt = formatDate(comment.createdAt);
  70. return (
  71. <li className={comment.isSecret ? 'is-secret' : ''}>
  72. <div>
  73. <Image src={writerThumb} alt={writerName} width={72} height={0} />
  74. </div>
  75. <div>
  76. <ul>
  77. <li>{writerName}</li>
  78. <li>{createdAt}</li>
  79. </ul>
  80. </div>
  81. <div>
  82. <DropdownMenu>
  83. <DropdownMenuTrigger>
  84. <FontAwesomeIcon icon={faEllipsisVertical}/>
  85. </DropdownMenuTrigger>
  86. <DropdownMenuContent>
  87. {/*
  88. <DropdownMenuItem><FontAwesomeIcon icon={nFlag} className="mr-2"/> 신고</DropdownMenuItem>
  89. */}
  90. <DropdownMenuItem onClick={handleStartEdit}>
  91. <FontAwesomeIcon icon={faPenToSquare} className="mr-2"/> 수정
  92. </DropdownMenuItem>
  93. <DropdownMenuItem onClick={handleDelete}>
  94. <FontAwesomeIcon icon={faTrashCan} className="mr-2"/> 삭제
  95. </DropdownMenuItem>
  96. </DropdownMenuContent>
  97. </DropdownMenu>
  98. </div>
  99. <div>
  100. <ul>
  101. <li>
  102. {isEditing ? (
  103. <EditForm
  104. board={board}
  105. post={post}
  106. comment={comment}
  107. onSuccess={handleEditSuccess}
  108. onCancel={handleCancelEdit}
  109. />
  110. ) : (
  111. <ul>
  112. <li>
  113. {comment.mention && (
  114. <span className="mention">@{comment.mention.rawHandle} </span>
  115. )}
  116. {comment.content}
  117. </li>
  118. </ul>
  119. )}
  120. </li>
  121. </ul>
  122. </div>
  123. {!isEditing && (
  124. <div>
  125. {/*
  126. <button type="button" title="좋아요"><FontAwesomeIcon icon={nThumbsUp} /></button>
  127. <button type="button" title="싫어요"><FontAwesomeIcon icon={nThumbsDown} /></button>
  128. */}
  129. <button
  130. type="button"
  131. title="답글"
  132. onClick={onReply}
  133. >
  134. {isReplying ? '답글 접기' : '답글'}
  135. </button>
  136. </div>
  137. )}
  138. </li>
  139. );
  140. }