diff --git a/client/src/components/post/detail/PostComment.tsx b/client/src/components/post/detail/PostComment.tsx index 3e21efc..f0a0cb6 100644 --- a/client/src/components/post/detail/PostComment.tsx +++ b/client/src/components/post/detail/PostComment.tsx @@ -5,6 +5,7 @@ import { Stack, Avatar, Typography } from "@mui/material"; import dayjs from "dayjs"; import Link from "next/link"; import PostCommentDropdown from "./PostCommentDropdown"; +import useDeleteCommentMutation from "@/queries/post/comment/useDeleteCommentMutation"; type Props = { content: string; @@ -13,6 +14,8 @@ type Props = { userPk: string; profileImg?: string; createdAt: string; + commentPk: string; + postPk: string; }; const PostComment = ({ @@ -22,10 +25,13 @@ const PostComment = ({ createdAt, profileImg, userPk, + postPk, + commentPk, }: Props) => { const { data: myData } = useMyInfoQuery(); const isMyComment = userPk === String(myData?.userNo); + const { mutateAsync: onDelete } = useDeleteCommentMutation(); return ( @@ -50,7 +56,17 @@ const PostComment = ({ {dayjs(createdAt).format("MM.DD")} - {isMyComment && } + {isMyComment && ( + { + onDelete({ + commentPk: String(commentPk), + postPk: String(postPk), + }); + }} + onEdit={() => {}} + /> + )} {content} diff --git a/client/src/components/post/detail/PostCommentDropdown.tsx b/client/src/components/post/detail/PostCommentDropdown.tsx index 734c0c4..c2b957e 100644 --- a/client/src/components/post/detail/PostCommentDropdown.tsx +++ b/client/src/components/post/detail/PostCommentDropdown.tsx @@ -2,7 +2,15 @@ import { ButtonBase, Menu, MenuItem } from "@mui/material"; import { MoreVertOutlined } from "@mui/icons-material"; import { useState } from "react"; -const PostCommentDropdown = () => { +interface PostCommentDropdownInterface { + onDelete: () => void; + onEdit: () => void; +} + +const PostCommentDropdown = ({ + onDelete, + onEdit, +}: PostCommentDropdownInterface) => { const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); @@ -13,23 +21,15 @@ const PostCommentDropdown = () => { const handleClose = () => { setAnchorEl(null); }; - + return ( <> - { - if (confirm("정말 삭제하시겠습니까?")) { - console.log("눌림"); - } - }} - > - 삭제 - - 수정 + {onDelete && 삭제} + {onEdit && 수정} ); diff --git a/client/src/components/post/detail/PostCommentList.tsx b/client/src/components/post/detail/PostCommentList.tsx index e9c71f1..81938d7 100644 --- a/client/src/components/post/detail/PostCommentList.tsx +++ b/client/src/components/post/detail/PostCommentList.tsx @@ -22,8 +22,7 @@ const PostCommentList = ({ postNo }: Props) => { nickname, userId, profileImgUrls, - }, - i + } ) => ( { profileImg={profileImgUrls?.[0]?.attachUrl} userId={userId} userPk={String(createdBy)} + commentPk={String(commentNo)} + postPk={postNo} key={commentNo} /> ) diff --git a/client/src/const/serverPath.ts b/client/src/const/serverPath.ts index 15aa942..30f8ca2 100644 --- a/client/src/const/serverPath.ts +++ b/client/src/const/serverPath.ts @@ -15,7 +15,7 @@ export const MY_INFO = "/user/me" as const; /** * 유저정보를 수정하는 path */ -export const PATCH_USER_INFO = '/user' as const +export const PATCH_USER_INFO = "/user" as const; /** * 쿠키를 심어주는 로그인 BFF @@ -33,7 +33,16 @@ export const POST_LIST = "/posts" as const; /** * 게시물 pk 를 입력받아 댓글을 조회,생성 하는 URL */ -export const POST_COMMENT = (pk:string) => `${POST_LIST}/${pk}/comments` +export const POST_COMMENT = (pk: string) => `${POST_LIST}/${pk}/comments`; + +/** + * 게시글Pk와 댓글 PK를 입력받아 댓글 삭제를 요청하는 URL + * @param postPk + * @param commentPk + * @returns + */ +export const DELETE_COMMENT = (postPk: string, commentPk: string) => + `${POST_LIST}/${postPk}/comments/${commentPk}`; /** * 게시물리스트를 받아오거나, 작성하는 Path 버전2 (Breaking Change) @@ -71,8 +80,6 @@ export const REMOVE_FILE = (attachNo: string) => `/attach/${attachNo}` as const; */ export const GET_ALCOHOL_LIST = "/alcohols" as const; - - /** * 포스트의 PK를 입력받아 해당 PK의 게시글의 좋아요 취소를 요청 * @param id 게시글의 PK diff --git a/client/src/queries/post/comment/useDeleteCommentMutation.ts b/client/src/queries/post/comment/useDeleteCommentMutation.ts new file mode 100644 index 0000000..59f13e7 --- /dev/null +++ b/client/src/queries/post/comment/useDeleteCommentMutation.ts @@ -0,0 +1,59 @@ +import { DELETE_COMMENT } from "@/const/serverPath"; +import useAxiosPrivate from "@/hooks/useAxiosPrivate"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { commentQueryKey } from "./useGetCommentQuery"; +import PostCommentListInterface from "@/types/post/PostCommentInterface"; +import { useErrorHandler } from "@/utils/errorHandler"; + +const useDeleteCommentMutation = () => { + const queryClient = useQueryClient(); + const errorHandler = useErrorHandler(); + + return useMutation({ + mutationFn: ({ postPk, commentPk }: deleteCommentInterface) => + deleteComment({ postPk, commentPk }), + + onMutate({ commentPk,postPk }) { + queryClient.cancelQueries({ queryKey: commentQueryKey.byId(commentPk) }); + + const querySnapShot = queryClient.getQueryData( + commentQueryKey.byId(postPk) + ); + + queryClient.setQueryData( + commentQueryKey.byId(postPk), + (prev) => ({ + list: (prev?.list ?? []).filter( + ({commentNo}) => String(commentNo) !== String(commentPk) + ), + totalCount: (prev?.totalCount ?? 0) - 1, + }) + ); + return { querySnapShot }; + }, + onError(err, queryFnParams, context) { + errorHandler(err); + queryClient.setQueryData( + commentQueryKey.byId(queryFnParams.postPk), + context?.querySnapShot + ); + }, + onSuccess(_data, variables) { + queryClient.invalidateQueries({ + queryKey: commentQueryKey.byId(variables.postPk), + }); + }, + }); +}; + +interface deleteCommentInterface { + postPk: string; + commentPk: string; +} +const deleteComment = async ({ postPk, commentPk }: deleteCommentInterface) => { + const axiosPrivate = useAxiosPrivate(); + const { data } = await axiosPrivate.delete(DELETE_COMMENT(postPk, commentPk)); + return data; +}; + +export default useDeleteCommentMutation;