Skip to content

Commit fb62d35

Browse files
committed
Feat: 게시글 삭제 #65
1 parent cf055a0 commit fb62d35

File tree

7 files changed

+78
-24
lines changed

7 files changed

+78
-24
lines changed

components/ui/BoardCard/BoardCardPackage/BoardCardDropdown.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,29 @@ import DotsIcon from 'public/DotsIcon.svg';
22
import copyToClipBoard from '@/utils/copyToClipBoard';
33
import useAddBookmark from '@/hooks/mutations/useAddBookmark';
44
import useDeleteBookmark from '@/hooks/mutations/useDeleteBookmark';
5+
import useDeleteBoard from '@/hooks/mutations/useDeleteBoard';
56
import { Dropdown } from '../../ui';
67

78
export default function PostCardDropdown({
89
boardId, // TODO : 북마크 되어있는지 확인
9-
// isBookmarked,
10+
isMyBoard, // isBookmarked,
1011
}: {
1112
boardId: number;
13+
isMyBoard: boolean;
1214
// isBookmarked: boolean;
1315
}) {
1416
const { mutate: addBookmark } = useAddBookmark();
1517
const { mutate: deleteBookmark } = useDeleteBookmark();
18+
const { mutate: deleteBoard } = useDeleteBoard(boardId);
19+
1620
const handleBookmark = () => {
1721
// if (isBookmarked) {
1822
deleteBookmark(boardId);
1923
// } else {
2024
// addBookmark(boardId);
2125
// }
2226
};
27+
2328
return (
2429
<Dropdown>
2530
<Dropdown.Trigger>
@@ -30,6 +35,9 @@ export default function PostCardDropdown({
3035
<Dropdown.Item event={() => copyToClipBoard(window.location.href)}>
3136
공유하기
3237
</Dropdown.Item>
38+
{isMyBoard ? (
39+
<Dropdown.Item event={() => deleteBoard()}>삭제하기</Dropdown.Item>
40+
) : null}
3341
</Dropdown.Menu>
3442
</Dropdown>
3543
);
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,30 @@
11
import useRelativeTime from '@/hooks/common/useRelativeTime';
2+
import { Board } from '@/types/types';
3+
import useGetUserInfo from '@/hooks/queries/useGetUserInfo';
24
import Avatar from '../../Avatar';
35
import FlexBox from '../../FlexBox';
46
import BoardCardDropdown from './BoardCardDropdown';
57

6-
export default function BoardCardHeader({
7-
userName,
8-
userImage,
9-
createdDate,
10-
boardId,
11-
}: {
12-
userName: string;
13-
userImage: string;
14-
createdDate: string;
15-
boardId: number;
16-
}) {
8+
export default function BoardCardHeader({ board }: { board: Board }) {
9+
const { data: user } = useGetUserInfo();
10+
1711
return (
1812
<FlexBox justify="between" className="w-full">
1913
<FlexBox className="gap-[10px]">
20-
<Avatar size="xl" image={userImage} name={String(userName)} />
14+
<Avatar size="xl" image={board.userImageUrl} name={board.writer} />
2115
<FlexBox direction="column" align="start" className="gap-1">
2216
<FlexBox className="gap-2">
23-
<div className="header4 text-grey-800">{userName}</div>
17+
<div className="header4 text-grey-800">{board.writer}</div>
2418
</FlexBox>
2519
<div className="caption2 text-grey-400">
26-
{useRelativeTime(createdDate)}
20+
{useRelativeTime(board.createdDate)}
2721
</div>
2822
</FlexBox>
2923
</FlexBox>
30-
<BoardCardDropdown boardId={boardId} />
24+
<BoardCardDropdown
25+
boardId={board.id}
26+
isMyBoard={board.userId === user?.userId}
27+
/>
3128
</FlexBox>
3229
);
3330
}

components/ui/BoardCard/FeedBoardCard.tsx

+1-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ export default function FeedBoardCard({
1616
justify="between"
1717
className="max-h-[500px] p-9 rounded-[10px] border-[1px] border-grey-200 gap-4"
1818
>
19-
<BoardCard.Header
20-
userName={board.writer}
21-
createdDate={board.createdDate}
22-
userImage={board.userImageUrl}
23-
boardId={board.id}
24-
/>
19+
<BoardCard.Header board={board} />
2520
<BoardCard.Content
2621
type="mainPC"
2722
content={board.content}

hooks/mutations/useDeleteBoard.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { deleteBoard } from '@/service/board';
2+
import Toast from '@/utils/notification';
3+
import { useMutation, useQueryClient } from '@tanstack/react-query';
4+
5+
export default function useDeleteComment(boardId: number) {
6+
const queryClient = useQueryClient();
7+
const { mutate, isLoading } = useMutation({
8+
mutationFn: () => deleteBoard(boardId),
9+
onSuccess: () => {
10+
Toast.success('게시글이 성공적으로 삭제 되었습니다.');
11+
queryClient.invalidateQueries(['boardList']);
12+
},
13+
onError: () => {
14+
Toast.error('게시글을 삭제하지 못했습니다. 잠시후 다시 시도해주세요.🥲');
15+
},
16+
});
17+
return { mutate, isLoading };
18+
}

hooks/mutations/useDeleteComment.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { deleteComment } from '@/service/board';
22
import Toast from '@/utils/notification';
3-
import { useMutation } from '@tanstack/react-query';
3+
import { useMutation, useQueryClient } from '@tanstack/react-query';
44

55
export default function useDeleteComment() {
6+
const queryClient = useQueryClient();
7+
68
const { mutate, isLoading } = useMutation({
79
mutationFn: ({ boardId, replyId }: { boardId: number; replyId: number }) =>
810
deleteComment(boardId, replyId),
911
onSuccess: () => {
1012
Toast.success('댓글이 성공적으로 삭제 되었습니다.');
13+
queryClient.invalidateQueries(['boardList']);
1114
},
1215
onError: () => {
1316
Toast.error('댓글을 삭제하지 못했습니다. 잠시후 다시 시도해주세요.🥲');

service/board.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,32 @@ export async function getBoardList(pageParam: number) {
3535
}
3636
}
3737

38+
export async function deleteBoard(boardId: number) {
39+
const url = `/endpoint/api/board/remove/${boardId}`;
40+
try {
41+
const response = await fetch(url, {
42+
method: 'DELETE',
43+
credentials: 'include',
44+
headers: {
45+
'Content-Type': 'application/json',
46+
},
47+
});
48+
if (response.status === 401) {
49+
throw new AuthError('로그인이 필요한 서비스입니다.');
50+
}
51+
if (!response.ok) {
52+
throw new Error(`서버오류:${response.status}`);
53+
}
54+
return await response.json();
55+
} catch (error) {
56+
if (error instanceof AuthError) {
57+
window.location.replace('/auth/login');
58+
alert(error.message);
59+
}
60+
throw error;
61+
}
62+
}
63+
3864
export async function postComment(postCommentData: PostCommentType) {
3965
const url = `endpoint/api/reply/register`;
4066
const response = await fetch(url, {
@@ -77,7 +103,13 @@ export async function getCommentList(
77103
export async function deleteComment(boardId: number, replyId: number) {
78104
const url = `/endpoint/api/reply/remove/${boardId}/${replyId}`;
79105
try {
80-
const response = await fetch(url);
106+
const response = await fetch(url, {
107+
method: 'DELETE',
108+
credentials: 'include',
109+
headers: {
110+
'Content-Type': 'application/json',
111+
},
112+
});
81113
if (response.status === 401) {
82114
throw new AuthError('로그인이 필요한 서비스입니다.');
83115
}

types/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface SidebarProps {
1212
}
1313

1414
export interface Board {
15+
userId: string;
1516
id: number;
1617
title: string;
1718
content: string;

0 commit comments

Comments
 (0)