Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FE-54✨ 댓글 수정 로직 변경 #163

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions src/components/epigram/Comment/CommentItem.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,36 @@
import React, { useState } from 'react';
import Image from 'next/image';
import { CommentType } from '@/schema/comment';
import { sizeStyles, textSizeStyles, gapStyles, paddingStyles, contentWidthStyles } from '@/styles/CommentCardStyles';
import { textSizeStyles, gapStyles, paddingStyles, contentWidthStyles } from '@/styles/CommentCardStyles';
import getCustomRelativeTime from '@/lib/dateUtils';
import useDeleteCommentMutation from '@/hooks/useDeleteCommentHook';
import { useToast } from '@/components/ui/use-toast';
import { Button } from '@/components/ui/button';
import DeleteAlertModal from '../DeleteAlertModal';
import CommentTextarea from './CommentTextarea';

interface CommentItemProps {
comment: CommentType;
status?: 'view' | 'edit';
onEditComment: (id: number, content: string, isPrivate: boolean) => void;
onEditComment: (id: number) => void;
isEditing: boolean;
epigramId: number;
}

function CommentItem({ comment, status, onEditComment }: CommentItemProps) {
function CommentItem({ comment, status, onEditComment, isEditing, epigramId }: CommentItemProps) {
const deleteCommentMutation = useDeleteCommentMutation();
const { toast } = useToast();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);

const handleEditClick = () => {
onEditComment(comment.id, comment.content, comment.isPrivate);
onEditComment(comment.id);
};

// NOTE: 댓글 삭제
// NOTE: 수정 중일 때(isEditing===true) CommentTextarea를 수정모드로 렌더링
if (isEditing) {
return <CommentTextarea epigramId={epigramId} editingComment={comment} onEditComplete={() => onEditComment(0)} />;
}

const handleDeleteComment = async () => {
try {
await deleteCommentMutation.mutateAsync(comment.id);
Expand All @@ -42,9 +49,9 @@ function CommentItem({ comment, status, onEditComment }: CommentItemProps) {

return (
<div
className={`bg-slate-100 border-t border-slate-300 flex-col justify-start items-start gap-2.5 inline-flex ${sizeStyles.sm} ${sizeStyles.md} ${sizeStyles.lg} ${paddingStyles.sm} ${paddingStyles.md} ${paddingStyles.lg}`}
className={`h-auto bg-slate-100 border-t border-slate-300 flex-col justify-start items-start gap-2.5 inline-flex w-[360px] md:w-[384px] lg:w-[640px] ${paddingStyles.sm} ${paddingStyles.md} ${paddingStyles.lg}`}
>
<div className='justify-start items-start gap-4 inline-flex'>
<div className='h-full justify-start items-start gap-4 inline-flex'>
<div className='w-12 h-12 relative'>
<div className='w-12 h-12 bg-zinc-300 rounded-full overflow-hidden flex items-center justify-center'>
<Image src={comment.writer.image || '/ProfileTestImage.jpg'} alt='프로필 이미지' layout='fill' objectFit='cover' className='rounded-full' />
Expand Down Expand Up @@ -79,7 +86,7 @@ function CommentItem({ comment, status, onEditComment }: CommentItemProps) {
)}
</div>
<div
className={`w-full text-zinc-800 font-normal font-pretendard ${textSizeStyles.sm.content} ${textSizeStyles.md.content} ${textSizeStyles.lg.content} ${contentWidthStyles.sm} ${contentWidthStyles.md} ${contentWidthStyles.lg}`}
className={`w-full text-zinc-800 font-normal font-pretendard whitespace-pre ${textSizeStyles.sm.content} ${textSizeStyles.md.content} ${textSizeStyles.lg.content} ${contentWidthStyles.sm} ${contentWidthStyles.md} ${contentWidthStyles.lg}`}
>
{comment.content}
</div>
Expand Down
16 changes: 11 additions & 5 deletions src/components/epigram/Comment/CommentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import NoComment from './NoComment';
import CommentItem from './CommentItem';

interface CommentListProps extends Omit<EpigramCommentProps, 'userImage'> {
onEditComment: (id: number, content: string, isPrivate: boolean) => void;
onEditComment: (id: number) => void;
editingCommentId: number | null;
}

function CommentList({ epigramId, currentUserId, onEditComment }: CommentListProps) {
function CommentList({ epigramId, currentUserId, onEditComment, editingCommentId }: CommentListProps) {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, status } = useEpigramCommentsQuery(epigramId);

const observerRef = useRef<IntersectionObserver | null>(null);
const lastCommentRef = useRef<HTMLDivElement | null>(null);

// NOTE: Observer 콜백: 마지막 요소가 화면에 보이면 다음 페이지(댓글 최대3개를 묶어 1페이지 취급) 로드
const handleObserver = useCallback(
(entries: IntersectionObserverEntry[]) => {
const [target] = entries;
Expand All @@ -39,7 +39,6 @@ function CommentList({ epigramId, currentUserId, onEditComment }: CommentListPro
}

return () => {
// NOTE: effect가 실행되기전에 호출해서 메모리 누수를 방지해줌
if (observerRef.current) {
observerRef.current.disconnect();
}
Expand All @@ -58,7 +57,14 @@ function CommentList({ epigramId, currentUserId, onEditComment }: CommentListPro
{allComments.length > 0 ? (
<>
{allComments.map((comment) => (
<CommentItem key={comment.id} comment={comment} status={comment.writer.id === currentUserId ? 'edit' : 'view'} onEditComment={onEditComment} />
<CommentItem
key={comment.id}
comment={comment}
status={comment.writer.id === currentUserId ? 'edit' : 'view'}
onEditComment={onEditComment}
isEditing={editingCommentId === comment.id}
epigramId={epigramId}
/>
))}
<div ref={lastCommentRef}>{isFetchingNextPage && <div>더 많은 댓글을 불러오는 중...</div>}</div>
</>
Expand Down
18 changes: 11 additions & 7 deletions src/components/epigram/Comment/CommentTextarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { Textarea } from '@/components/ui/textarea';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import Image from 'next/image';
import { CommentFormSchema, CommentFormValues } from '@/schema/comment';
import { CommentFormSchema, CommentFormValues, CommentType } from '@/schema/comment';
import usePostCommentMutation from '@/hooks/usePostCommentHook';
import usePatchCommentMutation from '@/hooks/usePatchCommentHook';

interface CommentTextareaProps {
epigramId: number;
editingComment: { id: number; content: string; isPrivate: boolean } | null;
editingComment?: CommentType;
onEditComplete: () => void;
}

Expand All @@ -29,9 +29,8 @@ function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentT
},
});

// NOTE: 수정중인지 새댓글작성중인지의 상태가 변활때 폼 초기화
useEffect(() => {
if (editingComment !== null) {
if (editingComment) {
form.reset({
content: editingComment.content,
isPrivate: editingComment.isPrivate,
Expand All @@ -46,7 +45,6 @@ function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentT

const onSubmit = (values: CommentFormValues) => {
if (editingComment) {
// NOTE: 댓글 수정 시
patchCommentMutation.mutate(
{ commentId: editingComment.id, ...values },
{
Expand All @@ -57,7 +55,6 @@ function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentT
},
);
} else {
// NOTE: 새 댓글 작성 시
const commentData = {
epigramId,
...values,
Expand All @@ -70,7 +67,13 @@ function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentT
}
};

// NOTE: 수정 취소
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
form.handleSubmit(onSubmit)();
}
};

const handleCancel = () => {
form.reset();
onEditComplete();
Expand All @@ -91,6 +94,7 @@ function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentT
editingComment ? 'border-black' : 'border-line-200'
}`}
placeholder='100자 이내로 입력해 주세요.'
onKeyDown={handleKeyDown}
{...field}
/>
{editingComment && (
Expand Down
20 changes: 6 additions & 14 deletions src/pageLayout/Epigram/EpigramComment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,11 @@ import { EpigramCommentProps } from '@/types/epigram.types';
import Image from 'next/image';

function EpigramComment({ epigramId, currentUserId, userImage }: EpigramCommentProps) {
// NOTE: 현재 수정 중인 댓글 상태, null이면 댓글 수정이 아닌 새 댓글 작성 취급
const [editingComment, setEditingComment] = useState<{ id: number; content: string; isPrivate: boolean } | null>(null);

const handleEditComment = (id: number, content: string, isPrivate: boolean) => {
setEditingComment({ id, content, isPrivate });
};

const handleEditComplete = () => {
setEditingComment(null);
};
// NOTE: 수정상태를 수정중인 댓글의 ID로 변경
const [editingCommentId, setEditingCommentId] = useState<number | null>(null);

return (
// NOTE: 댓글부분 height 수정
<div className='bg-slate-100 flex justify-center min-h-screen'>
<div className='bg-slate-100 flex justify-center'>
<div className='w-80 md:w-96 lg:w-[640px] pt-6 lg:pt-12'>
<h3 className='text-base lg:text-xl font-semibold'>댓글 작성</h3>
<div className={`flex flex-col gap-4 lg:gap-6 ${paddingStyles.sm} ${paddingStyles.md} ${paddingStyles.lg}`}>
Expand All @@ -31,10 +22,11 @@ function EpigramComment({ epigramId, currentUserId, userImage }: EpigramCommentP
<Image src='/profile.svg' alt='기본 프로필 사진' width={48} height={48} />
)}
</div>
<CommentTextarea epigramId={epigramId} editingComment={editingComment} onEditComplete={handleEditComplete} />
{/* NOTE: editingCommentId을 null로 바꿈으로써 수정중인 상태가 아니라는걸 알림 */}
<CommentTextarea epigramId={epigramId} onEditComplete={() => setEditingCommentId(null)} />
</div>
</div>
<CommentList epigramId={epigramId} currentUserId={currentUserId} onEditComment={handleEditComment} />
<CommentList epigramId={epigramId} currentUserId={currentUserId} editingCommentId={editingCommentId} onEditComment={setEditingCommentId} />
</div>
</div>
);
Expand Down
Loading