diff --git a/apps/common/features/app/(with-base-layout)/pst/bbsnotice/[bbsId]/[pstNo]/modify/page.tsx b/apps/common/features/app/(with-base-layout)/pst/bbsnotice/[bbsId]/[pstNo]/modify/page.tsx
new file mode 100644
index 000000000..86f0ca871
--- /dev/null
+++ b/apps/common/features/app/(with-base-layout)/pst/bbsnotice/[bbsId]/[pstNo]/modify/page.tsx
@@ -0,0 +1,10 @@
+import { ModifyPage } from "@/pages/notice";
+
+export default async function PstBbsNoticePostModifyPage({
+ params,
+}: {
+ params: Promise<{ bbsId: string; pstNo: string }>;
+}) {
+ const { bbsId, pstNo } = await params;
+ return ;
+}
diff --git a/apps/common/features/src/entities/post/api/post-service.ts b/apps/common/features/src/entities/post/api/post-service.ts
index 04034bc78..96c0377fc 100644
--- a/apps/common/features/src/entities/post/api/post-service.ts
+++ b/apps/common/features/src/entities/post/api/post-service.ts
@@ -1,10 +1,13 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
+ Post,
PostInfo,
PostList,
PostParams,
PostService,
+ PostFormData,
+ PostUpdateFormData,
} from "../model/post-interface";
export class PostApiService implements PostService {
@@ -22,6 +25,26 @@ export class PostApiService implements PostService {
return response.data;
}
+ public async createPost(data: PostFormData): Promise {
+ const response = await client.post(
+ `${ENDPOINT.BOARD_SERVICE.POSTS}`,
+ data,
+ );
+ return response.data;
+ }
+
+ public async updatePost(
+ bbsId: string,
+ pstNo: string,
+ data: PostUpdateFormData,
+ ): Promise {
+ const response = await client.put(
+ `${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
+ data,
+ );
+ return response.data;
+ }
+
public async deletePost(bbsId: string, pstNo: string): Promise {
await client.delete(`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`);
}
diff --git a/apps/common/features/src/entities/post/index.ts b/apps/common/features/src/entities/post/index.ts
index 933fb0a51..d2b94ba84 100644
--- a/apps/common/features/src/entities/post/index.ts
+++ b/apps/common/features/src/entities/post/index.ts
@@ -1,7 +1,11 @@
export { PostApi } from "./api/post-service";
-export type {
- Post,
- PostList,
- PostParams,
- PostService,
+export {
+ postFormSchema,
+ postUpdateFormSchema,
+ type Post,
+ type PostList,
+ type PostParams,
+ type PostService,
+ type PostFormData,
+ type PostUpdateFormData,
} from "./model/post-interface";
diff --git a/apps/common/features/src/entities/post/model/post-interface.ts b/apps/common/features/src/entities/post/model/post-interface.ts
index ec9021fad..7a7f95108 100644
--- a/apps/common/features/src/entities/post/model/post-interface.ts
+++ b/apps/common/features/src/entities/post/model/post-interface.ts
@@ -1,3 +1,4 @@
+import { z } from "zod";
import {
type PageableList,
type PageableParams,
@@ -38,10 +39,39 @@ export interface PostInfo extends Post {
mdfr: string;
}
+export const postFormSchema = z.object({
+ bbsId: z.number(),
+ pstTtl: z.string(),
+ pstCn: z.string().nullish(),
+ rfrncUrl: z.string().nullish(),
+ popupYn: z.string().nullish(),
+ upndFixYn: z.string().nullish(),
+ prdPstgYn: z.string().nullish(),
+ pstPswd: z.string(),
+ wrtrNm: z.string().nullish(),
+ wrtrCplc: z.string().nullish(),
+ atflCd: z.string().nullish(),
+ parentPstNo: z.number().nullish(),
+});
+
+export const postUpdateFormSchema = postFormSchema.omit({
+ bbsId: true,
+ pstPswd: true,
+ parentPstNo: true,
+});
+
export type PostList = PageableList;
+export type PostFormData = z.infer;
+export type PostUpdateFormData = z.infer;
export interface PostService {
getPostList(params: PostParams): Promise;
getPostInfo(bbsId: string, pstNo: string): Promise;
+ createPost(data: PostFormData): Promise;
+ updatePost(
+ bbsId: string,
+ pstNo: string,
+ data: PostUpdateFormData,
+ ): Promise;
deletePost(bbsId: string, pstNo: string): Promise;
}
diff --git a/apps/common/features/src/pages/notice/index.ts b/apps/common/features/src/pages/notice/index.ts
index c75abbdc8..f904f2695 100644
--- a/apps/common/features/src/pages/notice/index.ts
+++ b/apps/common/features/src/pages/notice/index.ts
@@ -1,2 +1,3 @@
export { NoticePage } from "./ui/notice-page";
export { NoticePost } from "./ui/notice-post";
+export { ModifyPage } from "./ui/modify-page";
diff --git a/apps/common/features/src/pages/notice/ui/create-page.tsx b/apps/common/features/src/pages/notice/ui/create-page.tsx
new file mode 100644
index 000000000..7e49ac6f4
--- /dev/null
+++ b/apps/common/features/src/pages/notice/ui/create-page.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useMutation } from "@tanstack/react-query";
+import { useAlertStore } from "@/shared/lib/use-alert-store";
+import { postFormSchema, type PostFormData } from "@/entities/post";
+import { PostApi } from "@/entities/post";
+import { NoticeForm } from "./notice-form";
+import { NoticeLayout } from "./notice-layout";
+
+function CreatePage() {
+ const router = useRouter();
+ const { setMessage: alert } = useAlertStore((state) => state);
+
+ const { mutateAsync: createPost } = useMutation({
+ mutationFn: (data: PostFormData) => PostApi.createPost(data),
+ onSuccess: () => {
+ alert("등록되었습니다.", router.back);
+ },
+ });
+
+ const form = useForm({
+ resolver: zodResolver(postFormSchema),
+ defaultValues: {
+ bbsId: 0,
+ pstTtl: "",
+ pstPswd: "",
+ },
+ });
+
+ return (
+
+
+
+ );
+}
+
+export { CreatePage };
diff --git a/apps/common/features/src/pages/notice/ui/modify-page.tsx b/apps/common/features/src/pages/notice/ui/modify-page.tsx
new file mode 100644
index 000000000..590485f36
--- /dev/null
+++ b/apps/common/features/src/pages/notice/ui/modify-page.tsx
@@ -0,0 +1,49 @@
+"use client";
+
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useMutation, useQuery } from "@tanstack/react-query";
+import {
+ PostApi,
+ postUpdateFormSchema,
+ type PostUpdateFormData,
+} from "@/entities/post";
+import { ENDPOINT } from "@/shared/config";
+import { useAlertStore } from "@/shared/lib/use-alert-store";
+import { NoticeForm } from "./notice-form";
+import { NoticeLayout } from "./notice-layout";
+
+function ModifyPage({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
+ const { setMessage: alert } = useAlertStore((state) => state);
+
+ const { data: postInfo } = useQuery({
+ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS, bbsId, pstNo],
+ queryFn: () => PostApi.getPostInfo(bbsId, pstNo),
+ });
+
+ const { mutateAsync: updatePost } = useMutation({
+ mutationFn: (data: PostUpdateFormData) =>
+ PostApi.updatePost(bbsId, pstNo, data),
+ onSuccess: () => {
+ alert("수정되었습니다.");
+ },
+ });
+
+ const form = useForm({
+ resolver: zodResolver(postUpdateFormSchema),
+ values: postInfo,
+ });
+
+ return (
+
+
+
+ );
+}
+
+export { ModifyPage };
diff --git a/apps/common/features/src/pages/notice/ui/notice-form.tsx b/apps/common/features/src/pages/notice/ui/notice-form.tsx
new file mode 100644
index 000000000..cacc68787
--- /dev/null
+++ b/apps/common/features/src/pages/notice/ui/notice-form.tsx
@@ -0,0 +1,262 @@
+import type { UseFormReturn, FieldPath } from "react-hook-form";
+import type { Post, PostFormData, PostUpdateFormData } from "@/entities/post";
+import {
+ Input,
+ Label,
+ RadioGroup,
+ RadioGroupItem,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableRow,
+ Textarea,
+ Button,
+} from "@common/components";
+import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form";
+
+type NoticeFormProps = {
+ form: UseFormReturn;
+ handleSave: (data: T) => Promise;
+};
+
+function NoticeForm({
+ form,
+ handleSave,
+}: NoticeFormProps) {
+ const onSubmit = async (data: T) => {
+ await handleSave(data);
+ };
+
+ return (
+
+
+ );
+}
+
+export { NoticeForm };
diff --git a/apps/common/features/src/widgets/post/ui/post-action.tsx b/apps/common/features/src/widgets/post/ui/post-action.tsx
index 3756fd1aa..c08c75694 100644
--- a/apps/common/features/src/widgets/post/ui/post-action.tsx
+++ b/apps/common/features/src/widgets/post/ui/post-action.tsx
@@ -1,4 +1,4 @@
-import { useRouter } from "next/navigation";
+import { useRouter, usePathname } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { Button } from "@common/components";
@@ -12,6 +12,8 @@ type PostActionProps = {
function PostAction({ children, bbsId, pstNo }: PostActionProps) {
const router = useRouter();
+ const pathname = usePathname();
+
const { confirm } = useConfirm();
const { mutate: deletePost } = useMutation({
@@ -37,7 +39,11 @@ function PostAction({ children, bbsId, pstNo }: PostActionProps) {
>
목록
-