feat: 콘텐츠 승인 요청 작업

This commit is contained in:
2025-04-18 16:56:20 +09:00
parent c6814a65f9
commit fa183f9d92
5 changed files with 66 additions and 21 deletions
@@ -67,6 +67,15 @@ export class ContentsApiService implements ContentsService {
`${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}`,
);
}
public async requestApprove(
contsSn: number,
contsVer: number,
): Promise<void> {
await client.put(
`${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}/approveRequest`,
);
}
}
export const ContentsApi = new ContentsApiService();
+1 -1
View File
@@ -1,6 +1,6 @@
export { ContentsApi } from "./api/contents-service";
export {
CONTENTS_APPROVAL_STATUS,
CONTENTS_APPROVE_STATUS,
contentsFormSchema,
type Contents,
type ContentsParams,
@@ -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<void>;
deleteContents(contsSn: number, contsVer: number): Promise<void>;
requestApprove(contsSn: number, contsVer: number): Promise<void>;
}
+43 -14
View File
@@ -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 }) {
<div className="card card-border !mb-0 !mt-6">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">템플릿 수정</h3>
<div>
<div className="flex items-center gap-2">
<Select
value={contentsVersion.toString()}
onValueChange={(value) => {
@@ -122,6 +142,15 @@ function ModifyPage({ sequential }: { sequential: string }) {
))}
</SelectContent>
</Select>
{isDraftContents && (
<Button onClick={onRequestApprove}>승인요청</Button>
)}
{isRequestedContents && (
<>
<Button>승인</Button>
<Button color="gray">반려</Button>
</>
)}
</div>
</div>
<ContentsForm
+3 -1
View File
@@ -24,7 +24,9 @@ function ConfirmDialog({
<Dialog open={isOpen ?? isGlobalOpen} onOpenChange={onCancel}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem] text-foreground">{message}</p>
<p className="whitespace-pre-line text-center text-[1.4rem] text-foreground">
{message}
</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>