diff --git a/apps/cs/src/entities/content/api/contents-service.ts b/apps/cs/src/entities/content/api/contents-service.ts index 792ffd92e..355a04b1a 100644 --- a/apps/cs/src/entities/content/api/contents-service.ts +++ b/apps/cs/src/entities/content/api/contents-service.ts @@ -67,6 +67,15 @@ export class ContentsApiService implements ContentsService { `${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}`, ); } + + public async requestApprove( + contsSn: number, + contsVer: number, + ): Promise { + await client.put( + `${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}/approveRequest`, + ); + } } export const ContentsApi = new ContentsApiService(); diff --git a/apps/cs/src/entities/content/index.ts b/apps/cs/src/entities/content/index.ts index 6bf6ebd45..2446dd716 100644 --- a/apps/cs/src/entities/content/index.ts +++ b/apps/cs/src/entities/content/index.ts @@ -1,6 +1,6 @@ export { ContentsApi } from "./api/contents-service"; export { - CONTENTS_APPROVAL_STATUS, + CONTENTS_APPROVE_STATUS, contentsFormSchema, type Contents, type ContentsParams, diff --git a/apps/cs/src/entities/content/model/contents-interface.ts b/apps/cs/src/entities/content/model/contents-interface.ts index b77c28742..0048b0906 100644 --- a/apps/cs/src/entities/content/model/contents-interface.ts +++ b/apps/cs/src/entities/content/model/contents-interface.ts @@ -1,14 +1,14 @@ import { z } from "zod"; import type { PageableList, PageableParams } from "@/shared/model"; -export const CONTENTS_APPROVAL_STATUS = { +export const CONTENTS_APPROVE_STATUS = { DRAFT: "01", REQUESTED: "02", APPROVED: "99", } as const; -export type ContentsApprovalStatus = - (typeof CONTENTS_APPROVAL_STATUS)[keyof typeof CONTENTS_APPROVAL_STATUS]; +export type ContentsApproveStatus = + (typeof CONTENTS_APPROVE_STATUS)[keyof typeof CONTENTS_APPROVE_STATUS]; export interface ContentsParams extends PageableParams { contsTtl?: string; @@ -19,7 +19,7 @@ export interface ContentsParams extends PageableParams { export interface ContentsVersionParams extends PageableParams { contsSn?: number; contsCn?: string; - aprvCd?: string; + aprvCd?: ContentsApproveStatus; cclCd?: string; koglCd?: string; tag?: string; @@ -54,7 +54,11 @@ export const contentsDetailSchema = z.object({ contsTtl: z.string(), contsCn: z.string(), contsRmrk: z.string().nullish(), - aprvCd: z.string(), + aprvCd: z.enum([ + CONTENTS_APPROVE_STATUS.DRAFT, + CONTENTS_APPROVE_STATUS.REQUESTED, + CONTENTS_APPROVE_STATUS.APPROVED, + ]), cclCd: z.string().nullish(), koglCd: z.string().nullish(), tag: z.string().nullish(), @@ -91,4 +95,5 @@ export interface ContentsService { data: ContentsFormData, ): Promise; deleteContents(contsSn: number, contsVer: number): Promise; + requestApprove(contsSn: number, contsVer: number): Promise; } diff --git a/apps/cs/src/pages/contents/ui/modify-page.tsx b/apps/cs/src/pages/contents/ui/modify-page.tsx index ab11d62ee..82738dfff 100644 --- a/apps/cs/src/pages/contents/ui/modify-page.tsx +++ b/apps/cs/src/pages/contents/ui/modify-page.tsx @@ -1,13 +1,14 @@ "use client"; import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; import { ENDPOINT } from "@/shared/config"; import { useAlertStore } from "@/shared/lib/use-alert-store"; import { - CONTENTS_APPROVAL_STATUS, + CONTENTS_APPROVE_STATUS, ContentsApi, contentsFormSchema, type ContentsFormData, @@ -19,9 +20,13 @@ import { SelectValue, SelectContent, SelectItem, + Button, } from "@common/components/ui"; function ModifyPage({ sequential }: { sequential: string }) { + const contsSn = Number(sequential); + + const { confirm } = useConfirm(); const queryClient = useQueryClient(); const { setMessage: alert } = useAlertStore((state) => state); @@ -31,7 +36,7 @@ function ModifyPage({ sequential }: { sequential: string }) { >({}); const { data: contentsVersionList } = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, sequential], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, contsSn], queryFn: () => ContentsApi.getContentsVersionList({ contsSn: contsSn, @@ -51,14 +56,14 @@ function ModifyPage({ sequential }: { sequential: string }) { onSuccess: () => { alert("수정되었습니다."); queryClient.invalidateQueries({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, sequential], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, contsSn], }); }, }); const { mutateAsync: updateContents } = useMutation({ mutationFn: (data: ContentsFormData) => - ContentsApi.updateContents(contsSn, contentsDetail?.contsVer ?? 0, data), + ContentsApi.updateContents(contsSn, contentsVersion, data), onSuccess: () => { alert("수정되었습니다."); }, @@ -69,7 +74,17 @@ function ModifyPage({ sequential }: { sequential: string }) { onSuccess: () => { alert("삭제되었습니다."); queryClient.invalidateQueries({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, sequential], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, contsSn], + }); + }, + }); + + const { mutateAsync: requestApprove } = useMutation({ + mutationFn: () => ContentsApi.requestApprove(contsSn, contentsVersion), + onSuccess: () => { + alert("승인 요청이 완료되었습니다."); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS, contentsVersion], }); }, }); @@ -79,9 +94,18 @@ function ModifyPage({ sequential }: { sequential: string }) { values: contentsDetail, }); - const contsSn = Number(sequential); + const isDraftContents = + contentsDetail?.aprvCd === CONTENTS_APPROVE_STATUS.DRAFT; + const isRequestedContents = + contentsDetail?.aprvCd === CONTENTS_APPROVE_STATUS.REQUESTED; const isApprovedContents = - contentsDetail?.aprvCd === CONTENTS_APPROVAL_STATUS.APPROVED; + contentsDetail?.aprvCd === CONTENTS_APPROVE_STATUS.APPROVED; + + const onRequestApprove = async () => { + const message = + "승인 요청하면 더이상 내용을 수정할 수 없습니다.\n요청하시겠습니까?"; + if (await confirm(message)) requestApprove(); + }; useEffect(() => { if (!contentsVersionList?.content?.length) return; @@ -89,11 +113,7 @@ function ModifyPage({ sequential }: { sequential: string }) { const latestContent = contentsVersionList?.content[0]; if (!latestContent) return; - if (latestContent?.contsVer > 1) { - setDisabledFields({ - contsTtl: true, - }); - } + if (latestContent?.contsVer > 1) setDisabledFields({ contsTtl: true }); setContentsVersion(latestContent?.contsVer ?? 0); }, [contentsVersionList?.content]); @@ -101,7 +121,7 @@ function ModifyPage({ sequential }: { sequential: string }) {

템플릿 수정

-
+
+ {isDraftContents && ( + + )} + {isRequestedContents && ( + <> + + + + )}
-

{message}

+

+ {message} +