feat: 게시판 상세 및 삭제 기능 작업

This commit is contained in:
2025-04-29 19:56:56 +09:00
parent 50b97a466e
commit 8a9e4bbf96
10 changed files with 176 additions and 16 deletions
@@ -0,0 +1,10 @@
import { NoticePost } from "@/pages/notice";
export default async function PstBbsNoticePostPage({
params,
}: {
params: Promise<{ bbsId: string; pstNo: string }>;
}) {
const { bbsId, pstNo } = await params;
return <NoticePost bbsId={bbsId} pstNo={pstNo} />;
}
@@ -1,6 +1,7 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
PostInfo,
PostList,
PostParams,
PostService,
@@ -13,6 +14,17 @@ export class PostApiService implements PostService {
});
return response.data;
}
public async getPostInfo(bbsId: string, pstNo: string): Promise<PostInfo> {
const response = await client.get<PostInfo>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
);
return response.data;
}
public async deletePost(bbsId: string, pstNo: string): Promise<void> {
await client.delete(`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`);
}
}
export const PostApi = new PostApiService();
@@ -31,8 +31,17 @@ export interface Post {
rgtrNm: string;
}
export interface PostInfo extends Post {
pstCn: string;
rgtr: string;
mdfcnDt: string;
mdfr: string;
}
export type PostList = PageableList<Post>;
export interface PostService {
getPostList(params: PostParams): Promise<PostList>;
getPostInfo(bbsId: string, pstNo: string): Promise<PostInfo>;
deletePost(bbsId: string, pstNo: string): Promise<void>;
}
@@ -1 +1,2 @@
export { NoticePage } from "./ui/notice-page";
export { NoticePost } from "./ui/notice-post";
@@ -0,0 +1,26 @@
"use client";
import { useEffect, useState } from "react";
import type { Board } from "@/entities/board";
import { PageLayout } from "@/shared/ui/page-layout";
import { useLocalStorage } from "@frontend-opensource/use-react-hooks";
function NoticeLayout({ children }: { children: React.ReactNode }) {
const [bbsInfo, setBbsInfo] = useState<Board | null>(null);
const [storedBbsInfo] = useLocalStorage("bbs-info", "");
useEffect(() => {
if (storedBbsInfo) setBbsInfo(JSON.parse(storedBbsInfo));
}, [storedBbsInfo]);
return (
<PageLayout
title={bbsInfo?.bbsNm ?? ""}
menuPaths={["서비스관리", "게시판관리"]}
>
{children}
</PageLayout>
);
}
export { NoticeLayout };
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import {
getCoreRowModel,
@@ -9,7 +9,6 @@ import {
type PaginationState,
type RowSelectionState,
} from "@tanstack/react-table";
import { useLocalStorage } from "@frontend-opensource/use-react-hooks";
import {
Button,
DataTable,
@@ -21,16 +20,14 @@ import {
SelectTrigger,
SelectValue,
} from "@common/components/ui";
import type { Board } from "@/entities/board";
import { PostApi, type Post, type PostParams } from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { PageLayout } from "@/shared/ui/page-layout";
import { columns } from "../model/notice-table-columns";
import { NoticeLayout } from "./notice-layout";
function NoticePage({ bbsId }: { bbsId: string }) {
const router = useRouter();
const [storedBbsInfo] = useLocalStorage("bbs-info", "");
const [bbsInfo, setBbsInfo] = useState<Board | null>(null);
const pathname = usePathname();
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [postParams, setPostParams] = useState<PostParams>({
keywordType: "title",
@@ -75,22 +72,15 @@ function NoticePage({ bbsId }: { bbsId: string }) {
};
const handleRowClick = (row: Post) => {
router.push(`/bbs/register/${row.bbsId}`);
router.push(`${pathname}/${row.pstNo}`);
};
useEffect(() => {
refetch();
}, [pagination]);
useEffect(() => {
if (storedBbsInfo) setBbsInfo(JSON.parse(storedBbsInfo));
}, [storedBbsInfo]);
return (
<PageLayout
title={bbsInfo?.bbsNm ?? ""}
menuPaths={["서비스관리", "게시판관리"]}
>
<NoticeLayout>
<div className="card card-border !mt-6">
<div className="card card-border">
<form onSubmit={handleSubmit} className="flex items-center gap-2 p-2">
@@ -175,7 +165,7 @@ function NoticePage({ bbsId }: { bbsId: string }) {
</div>
</div>
</div>
</PageLayout>
</NoticeLayout>
);
}
@@ -0,0 +1,14 @@
"use client";
import { Post } from "@/widgets/post";
import { NoticeLayout } from "./notice-layout";
function NoticePost({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
return (
<NoticeLayout>
<Post bbsId={bbsId} pstNo={pstNo} />
</NoticeLayout>
);
}
export { NoticePost };
@@ -0,0 +1 @@
export { Post } from "./ui/post";
@@ -0,0 +1,51 @@
import { useRouter } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { Button } from "@common/components/ui";
import { PostApi } from "@/entities/post";
type PostActionProps = {
bbsId: string;
pstNo: string;
children: React.ReactNode;
};
function PostAction({ children, bbsId, pstNo }: PostActionProps) {
const router = useRouter();
const { confirm } = useConfirm();
const { mutate: deletePost } = useMutation({
mutationFn: () => PostApi.deletePost(bbsId, pstNo),
onSuccess: () => {
router.back();
},
});
const onDelete = async () => {
if (await confirm("삭제하시겠습니까?")) deletePost();
};
return (
<div>
{children}
<div className="flex justify-center gap-4 pb-12 pt-10">
<Button
size="lg"
color="white"
type="button"
onClick={() => router.back()}
>
목록
</Button>
<Button size="lg" type="submit">
수정
</Button>
<Button size="lg" color="red" type="button" onClick={onDelete}>
삭제
</Button>
</div>
</div>
);
}
export { PostAction };
@@ -0,0 +1,46 @@
"use client";
import dayjs from "dayjs";
import { useQuery } from "@tanstack/react-query";
import { PostApi } from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { PostAction } from "./post-action";
function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
const { data: postData } = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS],
queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
});
return (
<PostAction bbsId={bbsId} pstNo={pstNo}>
<div className="card card-border !p-8">
<h3 className="text-[2rem] font-bold">{postData?.pstTtl}</h3>
<div className="card !m-0 !mt-8 bg-accent">
<ul className="flex gap-8 p-4 text-xl text-label">
<li>
작성자: <b>{postData?.wrtrNm}</b>
</li>
<li>
등록일: <b>{dayjs(postData?.regDt).format("YYYY-MM-DD")}</b>
</li>
<li>
조회수: <b>{postData?.inqNocs}</b>
</li>
</ul>
</div>
<hr className="mt-8" />
<div
className="min-h-[40rem] p-8"
dangerouslySetInnerHTML={{ __html: postData?.pstCn ?? "" }}
/>
<hr className="mt-8" />
<div className="flex items-center gap-4 p-8">
<span>첨부파일</span>
</div>
</div>
</PostAction>
);
}
export { Post };