diff --git a/apps/cs/app/(with-base-layout)/bbs/register/[id]/page.tsx b/apps/cs/app/(with-base-layout)/bbs/register/[id]/page.tsx new file mode 100644 index 000000000..07cc78b6f --- /dev/null +++ b/apps/cs/app/(with-base-layout)/bbs/register/[id]/page.tsx @@ -0,0 +1,10 @@ +import { ModifyPage as VModifyPage } from "@/pages/bbs"; + +export default async function ModifyPage({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + return ; +} diff --git a/apps/cs/app/(with-base-layout)/bbs/register/page.tsx b/apps/cs/app/(with-base-layout)/bbs/register/page.tsx new file mode 100644 index 000000000..3e74aef97 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/bbs/register/page.tsx @@ -0,0 +1,2 @@ +import { CreatePage } from "@/pages/bbs"; +export default CreatePage; diff --git a/apps/cs/src/entities/board/api/board-service.ts b/apps/cs/src/entities/board/api/board-service.ts index 2ba0f55fd..150ff677a 100644 --- a/apps/cs/src/entities/board/api/board-service.ts +++ b/apps/cs/src/entities/board/api/board-service.ts @@ -1,6 +1,8 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; import type { + Board, + BoardFormData, BoardList, BoardParams, BoardPopupList, @@ -26,6 +28,33 @@ export class BoardApiService implements BoardService { ); return response.data; } + + public async getBoardInfo(bbsId: string): Promise { + const response = await client.get( + `${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`, + ); + return response.data; + } + + public async createBoard(data: BoardFormData): Promise { + const response = await client.post( + `${ENDPOINT.BOARD_SERVICE.BBS}`, + data, + ); + return response.data; + } + + public async updateBoard(bbsId: string, data: BoardFormData): Promise { + const response = await client.put( + `${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`, + data, + ); + return response.data; + } + + public async deleteBoard(bbsId: string): Promise { + await client.delete(`${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`); + } } export const BoardApi = new BoardApiService(); diff --git a/apps/cs/src/entities/board/index.ts b/apps/cs/src/entities/board/index.ts index 73229695f..f9ef1b610 100644 --- a/apps/cs/src/entities/board/index.ts +++ b/apps/cs/src/entities/board/index.ts @@ -1,6 +1,8 @@ export { BoardApi } from "./api/board-service"; export { + boardFormSchema, type Board, + type BoardFormData, type BoardParams, type BoardPopup, } from "./model/board-interface"; diff --git a/apps/cs/src/entities/board/model/board-interface.ts b/apps/cs/src/entities/board/model/board-interface.ts index ccfebdaed..1ed8f1d9f 100644 --- a/apps/cs/src/entities/board/model/board-interface.ts +++ b/apps/cs/src/entities/board/model/board-interface.ts @@ -1,3 +1,4 @@ +import { z } from "zod"; import type { PageableList, PageableParams } from "@/shared/model"; export const BOARD_TYPE = { @@ -62,10 +63,34 @@ export interface BoardPopup extends Board { pstCnt: number; } +export const boardFormSchema = z.object({ + bbsTypeCd: z.string(), + bbsNm: z.string(), + bbsExpln: z.string(), + rfrncUseYn: z.string(), + atflUseYn: z.string(), + atflMaxCnt: z.number().nullish(), + atflMaxFileSz: z.number().nullish(), + ansUseYn: z.string(), + ansUseAuthrt: z.string().nullish(), + cmntUseYn: z.string(), + dgstfnEvlUseYn: z.string(), + smsUseYn: z.string(), + upndFixUseYn: z.string(), + pstgPrdUseYn: z.string(), + popupUseYn: z.string(), + useYn: z.string(), +}); + export type BoardList = PageableList; export type BoardPopupList = PageableList; +export type BoardFormData = z.infer; export interface BoardService { getBoardList: (params: BoardParams) => Promise; getBoardPopupList: (params: BoardPopupParams) => Promise; + getBoardInfo: (bbsId: string) => Promise; + createBoard: (data: BoardFormData) => Promise; + updateBoard: (bbsId: string, data: BoardFormData) => Promise; + deleteBoard: (bbsId: string) => Promise; } diff --git a/apps/cs/src/pages/bbs/index.ts b/apps/cs/src/pages/bbs/index.ts index acdf5e213..bed839012 100644 --- a/apps/cs/src/pages/bbs/index.ts +++ b/apps/cs/src/pages/bbs/index.ts @@ -1 +1,3 @@ export { BbsPage } from "./ui/bbs-page"; +export { CreatePage } from "./ui/create-page"; +export { ModifyPage } from "./ui/modify-page"; diff --git a/apps/cs/src/pages/bbs/ui/bbs-form.tsx b/apps/cs/src/pages/bbs/ui/bbs-form.tsx new file mode 100644 index 000000000..ac2b5ebd5 --- /dev/null +++ b/apps/cs/src/pages/bbs/ui/bbs-form.tsx @@ -0,0 +1,447 @@ +"use client"; + +import type { UseFormReturn } from "react-hook-form"; +import { + Input, + Label, + RadioGroup, + RadioGroupItem, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from "@common/components"; +import { FormWrapper } from "@/widgets/form-wrapper"; +import { CodeSelect } from "@/entities/code"; +import type { Board, BoardFormData } from "@/entities/board"; +import { FormControl, FormField, FormItem } from "@/shared/ui/form"; + +type BbsFormProps = { + form: UseFormReturn; + bbsId?: string; + handleSave: (data: BoardFormData) => Promise; +}; + +function BbsForm({ form, bbsId, ...props }: BbsFormProps) { + return ( + +
+ + + + + + + + 게시판명 + + ( + + + + + + )} + /> + + + + 게시판 설명 + + ( + + + + + + )} + /> + + + + 게시판 유형 + + ( + + + + + + )} + /> + + + + 참조 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 첨부파일 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 첨부파일 최대 개수 + + ( + + + { + const value = e.target.value; + if (isNaN(Number(value))) return; + field.onChange(value === "" ? null : Number(value)); + }} + className="w-[12rem] !text-[1.3rem]" + placeholder="최대 개수 입력" + disabled={form.watch("atflUseYn") === "N"} + /> + + + )} + /> + + + + 첨부파일 최대 크기 + + ( + + + { + const value = e.target.value; + if (isNaN(Number(value))) return; + field.onChange(value === "" ? null : Number(value)); + }} + className="w-[12rem] !text-[1.3rem]" + placeholder="최대 크기 입력" + disabled={form.watch("atflUseYn") === "N"} + /> + + + )} + /> + + + + 답글 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 답글 사용 권한 + + ( + + + + + + )} + /> + + + + 댓글 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 게시물평가 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 팝업 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + SMS알림 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 상단고정 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 게시기간 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 사용 여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+
+
+
+
+ ); +} + +export { BbsForm }; diff --git a/apps/cs/src/pages/bbs/ui/bbs-page.tsx b/apps/cs/src/pages/bbs/ui/bbs-page.tsx index 393ee957b..89562cb9c 100644 --- a/apps/cs/src/pages/bbs/ui/bbs-page.tsx +++ b/apps/cs/src/pages/bbs/ui/bbs-page.tsx @@ -70,7 +70,9 @@ function BbsPage() { refetch(); }; - const handleRowClick = (row: Board) => {}; + const handleRowClick = (row: Board) => { + router.push(`/bbs/register/${row.bbsId}`); + }; useEffect(() => { refetch(); diff --git a/apps/cs/src/pages/bbs/ui/create-page.tsx b/apps/cs/src/pages/bbs/ui/create-page.tsx new file mode 100644 index 000000000..bb710c33b --- /dev/null +++ b/apps/cs/src/pages/bbs/ui/create-page.tsx @@ -0,0 +1,55 @@ +"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 { + BoardApi, + boardFormSchema, + type BoardFormData, +} from "@/entities/board"; +import { BbsForm } from "./bbs-form"; + +function CreatePage() { + const router = useRouter(); + const { setMessage: alert } = useAlertStore((state) => state); + + const { mutateAsync: createBoard } = useMutation({ + mutationFn: (data: BoardFormData) => BoardApi.createBoard(data), + onSuccess: () => { + alert("등록되었습니다.", router.back); + }, + }); + + const form = useForm({ + resolver: zodResolver(boardFormSchema), + defaultValues: { + bbsTypeCd: "", + bbsNm: "", + bbsExpln: "", + rfrncUseYn: "Y", + atflUseYn: "Y", + ansUseYn: "Y", + cmntUseYn: "Y", + dgstfnEvlUseYn: "Y", + smsUseYn: "Y", + upndFixUseYn: "Y", + pstgPrdUseYn: "Y", + popupUseYn: "Y", + useYn: "Y", + }, + }); + + return ( +
+
+

게시판 등록

+
+ +
+ ); +} + +export { CreatePage }; diff --git a/apps/cs/src/pages/bbs/ui/modify-page.tsx b/apps/cs/src/pages/bbs/ui/modify-page.tsx new file mode 100644 index 000000000..f411cbd5c --- /dev/null +++ b/apps/cs/src/pages/bbs/ui/modify-page.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { ENDPOINT } from "@/shared/config"; +import { + BoardApi, + boardFormSchema, + type BoardFormData, +} from "@/entities/board"; +import { BbsForm } from "./bbs-form"; + +function ModifyPage({ bbsId }: { bbsId: string }) { + const { setMessage: alert } = useAlertStore((state) => state); + + const { data: boardInfo } = useQuery({ + queryKey: [ENDPOINT.BOARD_SERVICE.BBS, bbsId], + queryFn: () => BoardApi.getBoardInfo(bbsId), + }); + + const { mutateAsync: updateBoard } = useMutation({ + mutationFn: (data: BoardFormData) => BoardApi.updateBoard(bbsId, data), + onSuccess: () => { + alert("수정되었습니다."); + }, + }); + + const form = useForm({ + resolver: zodResolver(boardFormSchema), + values: boardInfo, + }); + + return ( +
+
+

게시판 수정

+
+ +
+ ); +} + +export { ModifyPage }; diff --git a/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx b/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx index 5b6edb3bc..071b299ee 100644 --- a/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx +++ b/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx @@ -54,7 +54,7 @@ function FormWrapper({ - {isModifyMode && ( + {isModifyMode && handleDelete && (