diff --git a/public/arrow-left.svg b/public/arrow-left.svg new file mode 100644 index 00000000..225646e9 --- /dev/null +++ b/public/arrow-left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/icon/cancelIcon.svg b/public/icon/cancelIcon.svg new file mode 100644 index 00000000..678aaf2f --- /dev/null +++ b/public/icon/cancelIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/likeIcon.svg b/public/likeIcon.svg new file mode 100644 index 00000000..b88fa457 --- /dev/null +++ b/public/likeIcon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 00000000..fc1d4f6a --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/meatballIcon.svg b/public/meatballIcon.svg new file mode 100644 index 00000000..49a9368e --- /dev/null +++ b/public/meatballIcon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/none-epi.svg b/public/none-epi.svg new file mode 100644 index 00000000..4322d558 --- /dev/null +++ b/public/none-epi.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/placeLink.svg b/public/placeLink.svg new file mode 100644 index 00000000..1cdd89a7 --- /dev/null +++ b/public/placeLink.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/public/profile.svg b/public/profile.svg new file mode 100644 index 00000000..10fe1c70 --- /dev/null +++ b/public/profile.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/share.svg b/public/share.svg new file mode 100644 index 00000000..0ff446dd --- /dev/null +++ b/public/share.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/spinner.svg b/public/spinner.svg new file mode 100644 index 00000000..f65e5227 --- /dev/null +++ b/public/spinner.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/apis/epigram.ts b/src/apis/epigram.ts new file mode 100644 index 00000000..418d9bc6 --- /dev/null +++ b/src/apis/epigram.ts @@ -0,0 +1,75 @@ +import axios, { AxiosError } from 'axios'; +import { GetEpigramResponseType, EpigramRequestType } from '@/schema/epigram'; +import { DeleteEpigramType } from '@/types/epigram.types'; +import { AddEpigramResponseType, EditEpigramRequestType } from '@/schema/addEpigram'; +import httpClient from '.'; + +export const getEpigram = async (request: EpigramRequestType): Promise => { + const { id } = request; + + if (id === undefined) { + throw new Error('Epigram ID๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.'); + } + + try { + const response = await httpClient.get(`/epigrams/${id}`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + if (axiosError.response) { + throw new Error(`API ์—๋Ÿฌ: ${axiosError.response.status}`); + } else if (axiosError.request) { + throw new Error('์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } else { + throw new Error('์š”์ฒญ ์„ค์ • ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } else { + throw new Error('์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } +}; + +export const deleteEpigram = async (id: number): Promise => { + const response = await httpClient.delete(`/epigrams/${id}`); + return response.data; +}; + +// NOTE: ์—ํ”ผ๊ทธ๋žจ ์ˆ˜์ • api ํ•จ์ˆ˜ +export const patchEpigram = async (request: EditEpigramRequestType): Promise => { + const { id, ...data } = request; + const response = await httpClient.patch(`/epigrams/${id}`, data); + return response.data; +}; + +export const toggleEpigramLike = async (request: EpigramRequestType): Promise => { + const { id } = request; + + if (id === undefined) { + throw new Error('Epigram ID๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.'); + } + + try { + const response = await httpClient.post(`/epigrams/${id}/like`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + const axiosError = error as AxiosError; + if (axiosError.response?.status === 400) { + // ์ด๋ฏธ ์ข‹์•„์š”๋ฅผ ๋ˆŒ๋ €๋‹ค๋ฉด, ์ข‹์•„์š” ์ทจ์†Œ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. + const response = await httpClient.delete(`/epigrams/${id}/like`); + return response.data; + } + // ๊ทธ ์™ธ์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (axiosError.response) { + throw new Error(`API ์—๋Ÿฌ: ${axiosError.response.status}`); + } else if (axiosError.request) { + throw new Error('์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } else { + throw new Error('์š”์ฒญ ์„ค์ • ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } else { + throw new Error('์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } +}; diff --git a/src/apis/epigramComment.ts b/src/apis/epigramComment.ts index 4368fb9a..22de9af7 100644 --- a/src/apis/epigramComment.ts +++ b/src/apis/epigramComment.ts @@ -30,6 +30,14 @@ export const getEpigramComments = async (params: CommentRequestType): Promise => { + const { id, ...restParams } = params; + const response = await httpClient.get(`/users/${id}/comments`, { + params: restParams, + }); + return response.data; +}; + export const postComment = async (commentData: PostCommentRequest) => { const response = await httpClient.post('/comments', commentData); return response.data; diff --git a/src/apis/getRecentComments.ts b/src/apis/getRecentComments.ts index 5f83fcca..53b48b40 100644 --- a/src/apis/getRecentComments.ts +++ b/src/apis/getRecentComments.ts @@ -1,9 +1,10 @@ import type { GetRecentCommentsResponseType } from '@/schema/recentcomment'; import httpClient from './index'; -const getRecentComments = async (limit: number): Promise => { +const getRecentComments = async (cursor: number, limit: number): Promise => { const response = await httpClient.get('/comments', { params: { + cursor, limit, }, }); diff --git a/src/apis/getRecentEpigrams.ts b/src/apis/getRecentEpigrams.ts index a2fb9f52..04db411a 100644 --- a/src/apis/getRecentEpigrams.ts +++ b/src/apis/getRecentEpigrams.ts @@ -1,9 +1,10 @@ import type { GetRecentEpigramsResponseType } from '@/schema/recentEpigram'; import httpClient from './index'; -const getRecentEpigrams = async (limit: number): Promise => { +const getRecentEpigrams = async (cursor: number | null, limit: number): Promise => { const response = await httpClient.get('/epigrams', { params: { + cursor, limit, }, }); diff --git a/src/apis/postGoogleOauth.ts b/src/apis/postGoogleOauth.ts new file mode 100644 index 00000000..66e9e737 --- /dev/null +++ b/src/apis/postGoogleOauth.ts @@ -0,0 +1,11 @@ +import httpClient from '.'; + +const postGoogleOauth = async (code: string) => { + const response = await httpClient.post('/auth/signIn/GOOGLE', { + redirectUri: process.env.NEXT_PUBLIC_GOOGLE_REDIRECT_URI, + token: code, + }); + return response.data; +}; + +export default postGoogleOauth; diff --git a/src/apis/postNaverOauth.ts b/src/apis/postNaverOauth.ts new file mode 100644 index 00000000..56434bb0 --- /dev/null +++ b/src/apis/postNaverOauth.ts @@ -0,0 +1,12 @@ +import httpClient from '.'; + +const postNaverOauth = async (code: string, state: string) => { + const response = await httpClient.post('/auth/signIn/NAVER', { + state, + redirectUri: process.env.NEXT_PUBLIC_NAVER_REDIRECT_URI, + token: code, + }); + return response.data; +}; + +export default postNaverOauth; diff --git a/src/apis/queries.ts b/src/apis/queries.ts index 0010c375..1dde6fa6 100644 --- a/src/apis/queries.ts +++ b/src/apis/queries.ts @@ -1,10 +1,16 @@ import { createQueryKeyStore } from '@lukemorales/query-key-factory'; import { GetUserRequestType } from '@/schema/user'; +import { EpigramRequestType } from '@/schema/epigram'; +import { CommentRequestType } from '@/schema/comment'; import { GetMonthlyEmotionLogsRequestType } from '@/schema/emotion'; -import { getMe, getUser } from './user'; +import { GetEpigramsParamsType } from '@/schema/epigrams'; +import { getMe, getUser, getMyContentCount } from './user'; +import { getEpigram } from './epigram'; +import { getEpigramComments, getMyEpigramComments } from './epigramComment'; import getMonthlyEmotionLogs from './emotion'; +import getEpigrams from './getEpigrams'; -const quries = createQueryKeyStore({ +const queries = createQueryKeyStore({ user: { getMe: () => ({ queryKey: ['getMe'], @@ -14,6 +20,45 @@ const quries = createQueryKeyStore({ queryKey: [request], queryFn: () => getUser(request), }), + getMyContentCount: (request: GetUserRequestType) => ({ + queryKey: ['getMyContentCount', request], + queryFn: () => getMyContentCount(request), + }), + }, + // NOTE: Epigram ๊ด€๋ จ queryํ•จ์ˆ˜ + epigram: { + getEpigram: (request: EpigramRequestType) => ({ + queryKey: ['epigram', request.id, request], + queryFn: () => { + if (request.id === undefined) { + throw new Error('Epigram ID๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.'); + } + return getEpigram(request); + }, + enabled: request.id !== undefined, + }), + }, + epigramComment: { + getComments: (request: CommentRequestType) => ({ + queryKey: ['epigramComments', request], + queryFn: () => getEpigramComments(request), + }), + getMyComments: (request: CommentRequestType) => ({ + queryKey: ['myEpigramComments', request], + queryFn: () => getMyEpigramComments(request), + }), + }, + emotion: { + getMonthlyEmotionLogs: (request: GetMonthlyEmotionLogsRequestType) => ({ + queryKey: ['getMonthlyEmotionLogs', request], + queryFn: () => getMonthlyEmotionLogs(request), + }), + }, + epigrams: { + getEpigrams: (request: GetEpigramsParamsType) => ({ + queryKey: ['getEpigrams', request], + queryFn: () => getEpigrams(request), + }), }, emotion: { getMonthlyEmotionLogs: (request: GetMonthlyEmotionLogsRequestType) => ({ @@ -23,4 +68,4 @@ const quries = createQueryKeyStore({ }, }); -export default quries; +export default queries; diff --git a/src/apis/user.ts b/src/apis/user.ts index 5f924dea..a9210875 100644 --- a/src/apis/user.ts +++ b/src/apis/user.ts @@ -1,4 +1,4 @@ -import type { GetUserResponseType, GetUserRequestType, PatchMeRequestType, PostPresignedUrlRequestType, PostPresignedUrlResponseType } from '@/schema/user'; +import type { GetUserResponseType, GetUserRequestType, PatchMeRequestType, PostPresignedUrlRequestType, PostPresignedUrlResponseType, GetMyContentCountType } from '@/schema/user'; import httpClient from '.'; export const getMe = async (): Promise => { @@ -23,3 +23,17 @@ export const createPresignedUrl = async (request: PostPresignedUrlRequestType): const response = await httpClient.post('/images/upload', formData); return response.data; }; + +export const getMyContentCount = async (request: GetUserRequestType): Promise => { + const { id } = request; + + // ์—ํ”ผ๊ทธ๋žจ ์นด์šดํŠธ + const epigram = await httpClient.get(`/epigrams`, { params: { limit: 1, cursor: 0, writerId: id } }); + + // ๋Œ“๊ธ€ ์นด์šดํŠธ + const comment = await httpClient.get(`/users/${id}/comments`, { params: { limit: 1, cursor: 0 } }); + + const response = { epigramCount: epigram.data.totalCount, commentCount: comment.data.totalCount }; + + return response; +}; \ No newline at end of file diff --git a/src/components/Card/CommentCard.tsx b/src/components/Card/CommentCard.tsx index 45368d72..9dbdea2e 100644 --- a/src/components/Card/CommentCard.tsx +++ b/src/components/Card/CommentCard.tsx @@ -13,7 +13,7 @@ function CommentCard({ writer, content, createdAt, status }: CommentCardProps) {
- ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ + {`${writer.nickname}์˜{' '}
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index d342347f..14df0b93 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -18,9 +18,10 @@ import SHARE_ICON from '../../../public/icon/share-icon.svg'; // NOTE isButton ์ผ ๊ฒฝ์šฐ textInButton์˜ ๊ฐ’์„ ๋ฌด์กฐ๊ฑด ์ง€์ •ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. // NOTE SHARE_ICON ์ถ”๊ฐ€ ์‹œ ํ† ์ŠคํŠธ ๊ธฐ๋Šฅ๋„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ ์•„๋ž˜ ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”. +// TODO ์ƒˆ๋กœ ๋ฐ”๋€ ํ”ผ๊ทธ๋งˆ ์‹œ์•ˆ์œผ๋กœ ๋ฐ”๊ฟ€์ง€ ์ถ”ํ›„ ๊ฒฐ์ • + export interface HeaderProps { icon: 'back' | 'search' | ''; - routerPage: string; isLogo: boolean; insteadOfLogo: string; isProfileIcon: boolean; @@ -31,10 +32,15 @@ export interface HeaderProps { onClick: (e: React.MouseEvent) => void; } -function Header({ isLogo, icon, insteadOfLogo, isButton, isProfileIcon, isShareIcon, textInButton, routerPage, disabled, onClick }: HeaderProps) { +function Header({ isLogo, icon, insteadOfLogo, isButton, isProfileIcon, isShareIcon, textInButton, disabled, onClick }: HeaderProps) { const router = useRouter(); const { toast } = useToast(); + // ๋’ค๋กœ๊ฐ€๊ธฐ + const handleBack = () => { + router.back(); + }; + // ํŽ˜์ด์ง€ ์ด๋™ ํ•จ์ˆ˜ const handleNavigateTo = (path: string) => { router.push(path); @@ -65,7 +71,7 @@ function Header({ isLogo, icon, insteadOfLogo, isButton, isProfileIcon, isShareI
{icon === 'back' && ( - )} diff --git a/src/components/epigram/Comment/CommentItem.tsx b/src/components/epigram/Comment/CommentItem.tsx new file mode 100644 index 00000000..8d26f189 --- /dev/null +++ b/src/components/epigram/Comment/CommentItem.tsx @@ -0,0 +1,92 @@ +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 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'; + +interface CommentItemProps { + comment: CommentType; + status?: 'view' | 'edit'; + onEditComment: (id: number, content: string, isPrivate: boolean) => void; +} + +function CommentItem({ comment, status, onEditComment }: CommentItemProps) { + const deleteCommentMutation = useDeleteCommentMutation(); + const { toast } = useToast(); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + + const handleEditClick = () => { + onEditComment(comment.id, comment.content, comment.isPrivate); + }; + + // NOTE: ๋Œ“๊ธ€ ์‚ญ์ œ + const handleDeleteComment = async () => { + try { + await deleteCommentMutation.mutateAsync(comment.id); + setIsDeleteModalOpen(false); + toast({ + title: '๋Œ“๊ธ€์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.', + variant: 'destructive', + }); + } catch (error) { + toast({ + title: '๋Œ“๊ธ€ ์‚ญ์ œ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + variant: 'destructive', + }); + } + }; + + return ( +
+
+
+
+ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ +
+
+
+
+
+
{comment.writer.nickname}
+
+ {getCustomRelativeTime(comment.createdAt)} +
+
+ {status === 'edit' && ( +
+ + +
+ )} +
+
+ {comment.content} +
+
+
+ +
+ ); +} + +export default CommentItem; diff --git a/src/components/epigram/Comment/CommentList.tsx b/src/components/epigram/Comment/CommentList.tsx new file mode 100644 index 00000000..f1cccdc9 --- /dev/null +++ b/src/components/epigram/Comment/CommentList.tsx @@ -0,0 +1,72 @@ +import React, { useEffect, useRef, useCallback } from 'react'; +import { EpigramCommentProps } from '@/types/epigram.types'; +import useEpigramCommentsQuery from '@/hooks/useEpigramCommentsQueryHook'; +import NoComment from './NoComment'; +import CommentItem from './CommentItem'; + +interface CommentListProps extends Omit { + onEditComment: (id: number, content: string, isPrivate: boolean) => void; +} + +function CommentList({ epigramId, currentUserId, onEditComment }: CommentListProps) { + const { data, fetchNextPage, hasNextPage, isFetchingNextPage, status } = useEpigramCommentsQuery(epigramId); + + const observerRef = useRef(null); + const lastCommentRef = useRef(null); + + // NOTE: Observer ์ฝœ๋ฐฑ: ๋งˆ์ง€๋ง‰ ์š”์†Œ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๋ฉด ๋‹ค์Œ ํŽ˜์ด์ง€(๋Œ“๊ธ€ ์ตœ๋Œ€3๊ฐœ๋ฅผ ๋ฌถ์–ด 1ํŽ˜์ด์ง€ ์ทจ๊ธ‰) ๋กœ๋“œ + const handleObserver = useCallback( + (entries: IntersectionObserverEntry[]) => { + const [target] = entries; + if (target.isIntersecting && hasNextPage) { + fetchNextPage(); + } + }, + [fetchNextPage, hasNextPage], + ); + + useEffect(() => { + const options = { + root: null, + rootMargin: '20px', + threshold: 1.0, + }; + + observerRef.current = new IntersectionObserver(handleObserver, options); + + if (lastCommentRef.current) { + observerRef.current.observe(lastCommentRef.current); + } + + return () => { + // NOTE: effect๊ฐ€ ์‹คํ–‰๋˜๊ธฐ์ „์— ํ˜ธ์ถœํ•ด์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•ด์คŒ + if (observerRef.current) { + observerRef.current.disconnect(); + } + }; + }, [handleObserver]); + + if (status === 'pending') return
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...
; + if (status === 'error') return
์—๋Ÿฌ: ๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.
; + + const allComments = data?.pages.flatMap((page) => page.list) || []; + const totalCount = data?.pages[0]?.totalCount || 0; + + return ( +
+

๋Œ“๊ธ€({totalCount})

+ {allComments.length > 0 ? ( + <> + {allComments.map((comment) => ( + + ))} +
{isFetchingNextPage &&
๋” ๋งŽ์€ ๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...
}
+ + ) : ( + + )} +
+ ); +} + +export default CommentList; diff --git a/src/components/epigram/Comment/CommentTextarea.tsx b/src/components/epigram/Comment/CommentTextarea.tsx new file mode 100644 index 00000000..707ee760 --- /dev/null +++ b/src/components/epigram/Comment/CommentTextarea.tsx @@ -0,0 +1,132 @@ +import React, { useEffect } from 'react'; +import { Button } from '@/components/ui/button'; +import { Form, FormControl, FormField, FormItem } from '@/components/ui/form'; +import Label from '@/components/ui/label'; +import Switch from '@/components/ui/switch'; +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 usePostCommentMutation from '@/hooks/usePostCommentHook'; +import usePatchCommentMutation from '@/hooks/usePatchCommentHook'; + +interface CommentTextareaProps { + epigramId: number; + editingComment: { id: number; content: string; isPrivate: boolean } | null; + onEditComplete: () => void; +} + +function CommentTextarea({ epigramId, editingComment, onEditComplete }: CommentTextareaProps) { + const postCommentMutation = usePostCommentMutation(); + const patchCommentMutation = usePatchCommentMutation(); + + const form = useForm({ + resolver: zodResolver(CommentFormSchema), + defaultValues: { + content: '', + isPrivate: false, + }, + }); + + // NOTE: ์ˆ˜์ •์ค‘์ธ์ง€ ์ƒˆ๋Œ“๊ธ€์ž‘์„ฑ์ค‘์ธ์ง€์˜ ์ƒํƒœ๊ฐ€ ๋ณ€ํ™œ๋•Œ ํผ ์ดˆ๊ธฐํ™” + useEffect(() => { + if (editingComment !== null) { + form.reset({ + content: editingComment.content, + isPrivate: editingComment.isPrivate, + }); + } else { + form.reset({ + content: '', + isPrivate: false, + }); + } + }, [editingComment, form]); + + const onSubmit = (values: CommentFormValues) => { + if (editingComment) { + // NOTE: ๋Œ“๊ธ€ ์ˆ˜์ • ์‹œ + patchCommentMutation.mutate( + { commentId: editingComment.id, ...values }, + { + onSuccess: () => { + form.reset({ content: '', isPrivate: false }); + onEditComplete(); + }, + }, + ); + } else { + // NOTE: ์ƒˆ ๋Œ“๊ธ€ ์ž‘์„ฑ ์‹œ + const commentData = { + epigramId, + ...values, + }; + postCommentMutation.mutate(commentData, { + onSuccess: () => { + form.reset({ content: '', isPrivate: false }); + }, + }); + } + }; + + // NOTE: ์ˆ˜์ • ์ทจ์†Œ + const handleCancel = () => { + form.reset(); + onEditComplete(); + }; + + return ( +
+ + ( + + +
+