feat: 메뉴 삭제 로직 작업

This commit is contained in:
2025-03-27 15:23:01 +09:00
parent 0fa026e11b
commit ae5597b1f3
5 changed files with 105 additions and 71 deletions
@@ -35,6 +35,13 @@ export class MenuApiService implements MenuService {
return response.data;
}
public async deleteMenu(menuCd: number): Promise<void> {
const response = await client.delete<void>(
`${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`,
);
return response.data;
}
public async getTreeMenuList(siteId: string): Promise<TreeMenu[]> {
const response = await client.get<TreeMenu[]>(
`${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree`,
@@ -75,6 +75,7 @@ export interface MenuService {
menuCd: number,
data: Omit<MenuFormData, "siteId">,
) => Promise<void>;
deleteMenu: (menuCd: number) => Promise<void>;
getTreeMenuList: (siteId: string) => Promise<TreeMenu[]>;
modifyTreeMenu: (siteId: string, data: TreeNode[]) => Promise<void>;
modifyMenuName: (menuCd: number, name: string) => Promise<void>;
+2 -2
View File
@@ -25,7 +25,7 @@ interface MenuFormProps {
menuCd: number;
data: Omit<MenuFormData, "siteId">;
}) => void;
handleDelete?: () => void;
handleDelete?: (menuCd: number) => void;
}
function MenuForm({
@@ -73,7 +73,7 @@ function MenuForm({
const onDelete = () => {
handleConfirm(async () => {
if (await confirm("삭제하시겠습니까?")) {
handleDelete?.();
handleDelete?.(menuCd!);
}
});
};
+4 -1
View File
@@ -90,7 +90,10 @@ function MenuNode({
"diveicon di-arrow-forward mr-2 text-base text-label",
isOpen && "rotate-90",
)}
onClick={handleToggle}
onClick={(e) => {
e.stopPropagation();
handleToggle();
}}
/>
)}
<span className="text-[1.4rem] font-medium text-label">{text}</span>
+91 -68
View File
@@ -4,6 +4,7 @@ import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import type { NodeModel } from "@minoru/react-dnd-treeview";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
Button,
@@ -16,6 +17,7 @@ import {
import { SiteApi } from "@/entities/site";
import { ENDPOINT } from "@/shared/config";
import { PageLayout } from "@/shared/ui/page-layout";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
import { useAlertStore } from "@/shared/lib/use-alert-store";
import type { TreeMenu } from "../model/menu-interface";
import { MenuApi } from "../api/menu-service";
@@ -31,8 +33,10 @@ import { generateTreeData } from "../lib/utils";
function MenuPage() {
const queryClient = useQueryClient();
const { setMessage: alert } = useAlertStore((state) => state);
const { confirm } = useConfirm();
const [siteId, setSiteId] = useState("");
const [onConfirm, setOnConfirm] = useState(false);
const [selectedMenu, setSelectedMenu] = useState<TreeMenu | null>(null);
const [additionalNode, setAdditionalNode] =
useState<NodeModel<TreeMenu> | null>(null);
@@ -72,7 +76,7 @@ function MenuPage() {
onSuccess: () => {
alert("저장되었습니다.");
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS],
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
},
});
@@ -88,7 +92,17 @@ function MenuPage() {
onSuccess: () => {
alert("수정되었습니다.");
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS],
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
},
});
const { mutate: deleteMenu } = useMutation({
mutationFn: (menuCd: number) => MenuApi.deleteMenu(menuCd),
onSuccess: () => {
alert("삭제되었습니다.");
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
},
});
@@ -132,17 +146,14 @@ function MenuPage() {
...additionalNodeForm.getValues(),
prntMenuCd,
});
resetAdditionalNode();
};
const resetAdditionalNode = () => {
additionalNodeForm.setValue("menuKornNm", "");
setAdditionalNode(null);
};
const handleAdditionalNodeCancel = () => {
additionalNodeForm.setValue("menuKornNm", "");
setAdditionalNode(null);
};
const handleDelete = async () => {};
const handleSiteIdChange = (value: string) => {
form.setValue("siteId", value);
additionalNodeForm.setValue("siteId", value);
@@ -162,6 +173,14 @@ function MenuPage() {
additionalNodeForm.setValue("levelNo", (node.data.levelNo ?? 0) + 1);
};
const handleNodeDelete = async () => {
setOnConfirm(true);
if (await confirm("삭제하시겠습니까?")) {
setOnConfirm(false);
deleteMenu(selectedMenu!.menuCd!);
}
};
const handleAddMenu = () => {
if (additionalNode) return;
setAdditionalNode({
@@ -176,66 +195,70 @@ function MenuPage() {
: (treeData ?? []);
return (
<PageLayout pageTitle="메뉴 관리">
<div className="card flex !min-h-[calc(100vh-16.8rem)] gap-2">
<div className="card card-border w-[24rem]">
<Select value={siteId} onValueChange={handleSiteIdChange}>
<SelectTrigger>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
{options?.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
{siteId && (
<>
<div className="my-4 flex gap-2">
<Button
size="sm"
color="primary"
className="flex-1"
onClick={handleAddMenu}
>
메뉴 추가
</Button>
<Button
size="sm"
color="red"
className="flex-1"
onClick={handleDelete}
>
메뉴 삭제
</Button>
</div>
<div className="card card-border !mx-0">
<MenuTree
tree={tree}
siteId={siteId}
selectedMenu={selectedMenu}
additionalNodeForm={additionalNodeForm}
onSelectNode={handleNodeSelect}
onAdditionalNodeSave={handleAdditionalNodeSave}
onAdditionalNodeCancel={handleAdditionalNodeCancel}
/>
</div>
</>
)}
<>
<PageLayout pageTitle="메뉴 관리">
<div className="card flex !min-h-[calc(100vh-16.8rem)] gap-2">
<div className="card card-border w-[24rem]">
<Select value={siteId} onValueChange={handleSiteIdChange}>
<SelectTrigger>
<SelectValue placeholder="선택하세요" />
</SelectTrigger>
<SelectContent>
{options?.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
{siteId && (
<>
<div className="my-4 flex gap-2">
<Button
size="sm"
color="primary"
className="flex-1"
onClick={handleAddMenu}
>
메뉴 추가
</Button>
<Button
size="sm"
color="red"
className="flex-1"
onClick={handleNodeDelete}
disabled={!selectedMenu}
>
메뉴 삭제
</Button>
</div>
<div className="card card-border !mx-0">
<MenuTree
tree={tree}
siteId={siteId}
selectedMenu={selectedMenu}
additionalNodeForm={additionalNodeForm}
onSelectNode={handleNodeSelect}
onAdditionalNodeSave={handleAdditionalNodeSave}
onAdditionalNodeCancel={resetAdditionalNode}
/>
</div>
</>
)}
</div>
<div className="card card-border flex-1">
<MenuForm
form={form}
menuCd={selectedMenu?.menuCd}
handleCreate={createMenu}
handleModify={modifyMenu}
handleDelete={deleteMenu}
/>
</div>
</div>
<div className="card card-border flex-1">
<MenuForm
form={form}
menuCd={selectedMenu?.menuCd}
handleCreate={createMenu}
handleModify={modifyMenu}
handleDelete={handleDelete}
/>
</div>
</div>
</PageLayout>
</PageLayout>
<ConfirmDialog open={onConfirm} />
</>
);
}