From 697ac34f65afeb1ea430558bbd52029923e96ed2 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 9 May 2025 17:25:59 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EB=8C=93?= =?UTF-8?q?=EA=B8=80=20=EB=93=B1=EB=A1=9D=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/features/package.json | 1 + .../src/app/providers/app-provider.tsx | 4 + .../entities/comment/api/comment-service.ts | 31 ++++ .../features/src/entities/comment/index.ts | 9 ++ .../comment/model/comment-interface.ts | 54 +++++++ .../src/entities/post/model/post-interface.ts | 2 +- apps/common/features/src/shared/config/api.ts | 1 + .../src/widgets/post/ui/post-comment.tsx | 147 ++++++++++++++++++ .../features/src/widgets/post/ui/post.tsx | 86 +++++----- pnpm-lock.yaml | 21 +++ 10 files changed, 314 insertions(+), 42 deletions(-) create mode 100644 apps/common/features/src/entities/comment/api/comment-service.ts create mode 100644 apps/common/features/src/entities/comment/index.ts create mode 100644 apps/common/features/src/entities/comment/model/comment-interface.ts create mode 100644 apps/common/features/src/widgets/post/ui/post-comment.tsx diff --git a/apps/common/features/package.json b/apps/common/features/package.json index 8423560be..b9acdc511 100644 --- a/apps/common/features/package.json +++ b/apps/common/features/package.json @@ -19,6 +19,7 @@ "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-slot": "^1.1.2", "@tanstack/react-query": "^5.67.1", + "@tanstack/react-query-devtools": "^5.75.5", "@tanstack/react-table": "^8.21.2", "@tinymce/tinymce-react": "^6.1.0", "axios": "^1.8.1", diff --git a/apps/common/features/src/app/providers/app-provider.tsx b/apps/common/features/src/app/providers/app-provider.tsx index afe4ee651..6d7cb4480 100644 --- a/apps/common/features/src/app/providers/app-provider.tsx +++ b/apps/common/features/src/app/providers/app-provider.tsx @@ -1,6 +1,7 @@ "use client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { ConfirmProvider } from "@frontend-opensource/use-react-hooks"; import { AuthWrapper } from "@/entities/auth"; import { MenuWrapper } from "@/entities/menu"; @@ -25,6 +26,9 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => { +
+ +
); }; diff --git a/apps/common/features/src/entities/comment/api/comment-service.ts b/apps/common/features/src/entities/comment/api/comment-service.ts new file mode 100644 index 000000000..7fb0b5655 --- /dev/null +++ b/apps/common/features/src/entities/comment/api/comment-service.ts @@ -0,0 +1,31 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import { + commentFormSchema, + type Comment, + type CommentService, + type CommentList, + type CommentParams, + type CommentFormData, +} from "../model/comment-interface"; + +export class CommentApiService implements CommentService { + public async getComments(params: CommentParams): Promise { + const response = await client.get( + `${ENDPOINT.BOARD_SERVICE.POSTS_COMMENTS}`, + { params }, + ); + return response.data; + } + + public async createComment(data: CommentFormData): Promise { + const validatedData = commentFormSchema.parse(data); + const response = await client.post( + `${ENDPOINT.BOARD_SERVICE.POSTS_COMMENTS}`, + validatedData, + ); + return response.data; + } +} + +export const CommentApi = new CommentApiService(); diff --git a/apps/common/features/src/entities/comment/index.ts b/apps/common/features/src/entities/comment/index.ts new file mode 100644 index 000000000..376ec62e4 --- /dev/null +++ b/apps/common/features/src/entities/comment/index.ts @@ -0,0 +1,9 @@ +export { CommentApi } from "./api/comment-service"; +export { + commentFormSchema, + commentUpdateFormSchema, + type Comment, + type CommentList, + type CommentParams, + type CommentFormData, +} from "./model/comment-interface"; diff --git a/apps/common/features/src/entities/comment/model/comment-interface.ts b/apps/common/features/src/entities/comment/model/comment-interface.ts new file mode 100644 index 000000000..ea22af65b --- /dev/null +++ b/apps/common/features/src/entities/comment/model/comment-interface.ts @@ -0,0 +1,54 @@ +import { z } from "zod"; +import type { PageableList, PageableParams } from "@/shared/model"; + +export interface CommentParams extends PageableParams { + keywordType?: string; + keyword?: string; + pstNo: number; + delYn?: string; +} + +export interface Comment { + cmntEvl: number; + pstNo: number; + cmntNo: number; + cmntCn: string; + wrtrNm: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; +} + +export const commentFormSchema = z.object({ + pstNo: z.number(), + cmntCn: z.string(), + wrtrNm: z.string().nullish(), + cmntPswd: z.string(), + cmntEvl: z.number().nullish(), +}); + +export const commentUpdateFormSchema = commentFormSchema.omit({ + pstNo: true, +}); + +export type CommentList = PageableList; +export type CommentFormData = z.infer; +export type CommentUpdateFormData = z.infer; + +export interface CommentService { + getComments(params: CommentParams): Promise; + createComment(data: CommentFormData): Promise; + // updateComment( + // bbsId: number, + // pstNo: number, + // cmntNo: number, + // data: CommentUpdateFormData, + // ): Promise; + // deleteComment( + // bbsId: number, + // pstNo: number, + // cmntNo: number, + // cmntPswd: string, + // ): Promise; +} 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 16a2f4de2..fb77b2c43 100644 --- a/apps/common/features/src/entities/post/model/post-interface.ts +++ b/apps/common/features/src/entities/post/model/post-interface.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { type PageableList, type PageableParams } from "@/shared/model"; +import type { PageableList, PageableParams } from "@/shared/model"; export interface PostParams extends PageableParams { keywordType?: string; diff --git a/apps/common/features/src/shared/config/api.ts b/apps/common/features/src/shared/config/api.ts index 1ab27e341..69bd31b2c 100644 --- a/apps/common/features/src/shared/config/api.ts +++ b/apps/common/features/src/shared/config/api.ts @@ -38,6 +38,7 @@ export const ENDPOINT = { BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs", POSTS_USER: "/board-service/api/v1/posts/user", + POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts", }, }; diff --git a/apps/common/features/src/widgets/post/ui/post-comment.tsx b/apps/common/features/src/widgets/post/ui/post-comment.tsx new file mode 100644 index 000000000..b7a55a6ca --- /dev/null +++ b/apps/common/features/src/widgets/post/ui/post-comment.tsx @@ -0,0 +1,147 @@ +import dayjs from "dayjs"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { Button, Input, Textarea } from "@common/components"; +import { + CommentApi, + commentFormSchema, + type CommentFormData, +} from "@/entities/comment"; +import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form"; +import { useAlertStore, useUserStore } from "@/shared/lib"; +import { ENDPOINT } from "@/shared/config"; + +function PostComment({ pstNo }: { pstNo: number }) { + const queryClient = useQueryClient(); + const { setMessage: alert } = useAlertStore((state) => state); + const { userInfo } = useUserStore((state) => state); + + const { data: comments } = useQuery({ + queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_COMMENTS, pstNo], + queryFn: () => CommentApi.getComments({ pstNo }), + enabled: !!pstNo, + }); + + const { mutate: createComment } = useMutation({ + mutationFn: (data: CommentFormData) => CommentApi.createComment(data), + onSuccess: () => { + alert("댓글이 등록되었습니다."); + form.setValue("cmntCn", ""); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_COMMENTS], + }); + }, + }); + + const form = useForm({ + resolver: zodResolver(commentFormSchema), + values: { + pstNo, + cmntCn: "", + wrtrNm: userInfo?.userName ?? "", + cmntPswd: userInfo?.userUnqId ?? "", + }, + }); + + const onSubmit = (data: CommentFormData) => { + createComment(data); + }; + + return ( +
+
+ + ( + + +