"use client"; import React, { useState, useEffect } from "react"; import { menuApi } from "@/lib/api/menu"; import type { MenuItem } from "@/lib/api/menu"; import { MenuTable } from "./MenuTable"; import { MenuFormModal } from "./MenuFormModal"; import { Button } from "@/components/ui/button"; import { LoadingSpinner, LoadingOverlay } from "@/components/common/LoadingSpinner"; import { toast } from "sonner"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { useMenu } from "@/contexts/MenuContext"; import { getMenuTextSync, MENU_MANAGEMENT_KEYS, useMenuManagementText, setTranslationCache, } from "@/lib/utils/multilang"; import { useMultiLang } from "@/hooks/useMultiLang"; import { apiClient } from "@/lib/api/client"; type MenuType = "admin" | "user"; export const MenuManagement: React.FC = () => { const { adminMenus, userMenus, refreshMenus } = useMenu(); const [selectedMenuType, setSelectedMenuType] = useState("admin"); const [loading, setLoading] = useState(false); const [deleting, setDeleting] = useState(false); const [formModalOpen, setFormModalOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [selectedMenuId, setSelectedMenuId] = useState(""); const [selectedMenus, setSelectedMenus] = useState>(new Set()); // 다국어 텍스트 훅 사용 const { getMenuText } = useMenuManagementText(); const { userLang } = useMultiLang({ companyCode: "*" }); // 다국어 텍스트 상태 const [uiTexts, setUiTexts] = useState>({}); const [uiTextsLoading, setUiTextsLoading] = useState(false); // 회사 목록 상태 const [companies, setCompanies] = useState>([]); const [selectedCompany, setSelectedCompany] = useState("all"); const [searchText, setSearchText] = useState(""); const [expandedMenus, setExpandedMenus] = useState>(new Set()); const [companySearchText, setCompanySearchText] = useState(""); const [isCompanyDropdownOpen, setIsCompanyDropdownOpen] = useState(false); const [formData, setFormData] = useState({ menuId: "", parentId: "", menuType: "", level: 0, parentCompanyCode: "", }); // 초기 로딩 useEffect(() => { loadCompanies(); }, []); // 빈 의존성 배열로 한 번만 실행 // 컴포넌트 마운트 시 및 userLang 변경 시 다국어 텍스트 로드 useEffect(() => { if (!uiTextsLoading) { loadUITexts(); } }, [userLang]); // userLang 변경 시마다 실행 // 컴포넌트 마운트 시 강제로 번역 로드 (userLang이 아직 설정되지 않았을 수 있음) useEffect(() => { const timer = setTimeout(() => { if (!uiTextsLoading && Object.keys(uiTexts).length === 0) { console.log("🔄 컴포넌트 마운트 후 강제 번역 로드"); loadUITexts(); } }, 100); // 100ms 후 실행 return () => clearTimeout(timer); }, []); // 컴포넌트 마운트 시 한 번만 실행 // 번역 로드 이벤트 감지 useEffect(() => { const handleTranslationLoaded = (event: CustomEvent) => { const { key, text, userLang: loadedLang } = event.detail; if (loadedLang === userLang) { setUiTexts((prev) => ({ ...prev, [key]: text })); } }; window.addEventListener("translation-loaded", handleTranslationLoaded as EventListener); return () => { window.removeEventListener("translation-loaded", handleTranslationLoaded as EventListener); }; }, [userLang]); // 드롭다운 외부 클릭 시 닫기 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const target = event.target as Element; if (!target.closest(".company-dropdown")) { setIsCompanyDropdownOpen(false); setCompanySearchText(""); } }; if (isCompanyDropdownOpen) { document.addEventListener("mousedown", handleClickOutside); } return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [isCompanyDropdownOpen]); const loadMenus = async (showLoading = true) => { console.log(`📋 메뉴 목록 조회 시작 (showLoading: ${showLoading})`); try { if (showLoading) { setLoading(true); } await refreshMenus(); console.log(`📋 메뉴 목록 조회 성공`); } catch (error) { console.error("❌ 메뉴 목록 조회 실패:", error); toast.error(getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_ERROR_LOAD_MENU_LIST)); } finally { if (showLoading) { setLoading(false); } } }; // 회사 목록 조회 const loadCompanies = async () => { console.log(`🏢 회사 목록 조회 시작`); try { const response = await apiClient.get("/admin/companies"); if (response.data.success) { console.log("🏢 회사 목록 응답:", response.data); const companyList = response.data.data.map((company: any) => ({ code: company.company_code || company.companyCode, name: company.company_name || company.companyName, })); console.log("🏢 변환된 회사 목록:", companyList); setCompanies(companyList); } } catch (error) { console.error("❌ 회사 목록 조회 실패:", error); } }; // 다국어 텍스트 로드 함수 const loadUITexts = async () => { if (uiTextsLoading) return; // 이미 로딩 중이면 중단 // userLang이 없으면 기본값 사용 const currentUserLang = userLang || "KR"; console.log("🌐 UI 다국어 텍스트 로드 시작", { currentUserLang }); setUiTextsLoading(true); const texts: Record = {}; try { const textPromises = [ getMenuText(MENU_MANAGEMENT_KEYS.TITLE), getMenuText(MENU_MANAGEMENT_KEYS.DESCRIPTION), getMenuText(MENU_MANAGEMENT_KEYS.MENU_TYPE_TITLE), getMenuText(MENU_MANAGEMENT_KEYS.MENU_TYPE_ADMIN), getMenuText(MENU_MANAGEMENT_KEYS.MENU_TYPE_USER), getMenuText(MENU_MANAGEMENT_KEYS.ADMIN_MENU), getMenuText(MENU_MANAGEMENT_KEYS.USER_MENU), getMenuText(MENU_MANAGEMENT_KEYS.ADMIN_DESCRIPTION), getMenuText(MENU_MANAGEMENT_KEYS.USER_DESCRIPTION), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_ADD), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_ADD_TOP_LEVEL), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_ADD_SUB), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_EDIT), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_DELETE), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_DELETE_SELECTED), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_DELETE_SELECTED_COUNT), getMenuText(MENU_MANAGEMENT_KEYS.BUTTON_DELETE_PROCESSING), getMenuText(MENU_MANAGEMENT_KEYS.FILTER_RESET), getMenuText(MENU_MANAGEMENT_KEYS.LIST_TOTAL), getMenuText(MENU_MANAGEMENT_KEYS.LIST_SEARCH_RESULT), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_NAME), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_URL), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_TYPE), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_STATUS), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_COMPANY), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_SEQUENCE), getMenuText(MENU_MANAGEMENT_KEYS.TABLE_HEADER_ACTIONS), // 추가 키들 - 실제 UI에서 사용되는 모든 키들 getMenuText("menu.list.title"), getMenuText("filter.company"), getMenuText("filter.company.all"), getMenuText("filter.search"), getMenuText("filter.search.placeholder"), getMenuText("status.unspecified"), getMenuText("status.active"), getMenuText("filter.company.common"), getMenuText("modal.menu.register.title"), getMenuText("form.menu.type"), getMenuText("form.menu.type.admin"), getMenuText("form.menu.type.user"), getMenuText("form.status"), getMenuText("form.status.active"), getMenuText("form.status.inactive"), getMenuText("form.company"), getMenuText("form.company.select"), getMenuText("form.company.common"), getMenuText("form.company.submenu.note"), getMenuText("form.lang.key"), getMenuText("form.lang.key.select"), getMenuText("form.menu.name"), getMenuText("form.menu.name.placeholder"), getMenuText("form.menu.url"), getMenuText("form.menu.url.placeholder"), getMenuText("form.menu.description"), getMenuText("form.menu.description.placeholder"), getMenuText("form.menu.sequence"), getMenuText("button.cancel"), getMenuText("button.register"), // 테이블 헤더 관련 추가 키들 getMenuText("table.header.menu.name"), getMenuText("table.header.sequence"), getMenuText("table.header.company"), getMenuText("table.header.menu.url"), getMenuText("table.header.status"), getMenuText("table.header.actions"), // 액션 버튼 관련 추가 키들 getMenuText("button.add"), getMenuText("button.add.sub"), getMenuText("button.edit"), getMenuText("button.delete"), // 페이지 제목 관련 getMenuText("page.title.menu.management"), getMenuText("page.description.menu.management"), getMenuText("section.title.menu.type"), getMenuText("section.title.admin.menu.list"), ]; const results = await Promise.all(textPromises); // 결과를 키와 매핑 const keys = [ MENU_MANAGEMENT_KEYS.TITLE, MENU_MANAGEMENT_KEYS.DESCRIPTION, MENU_MANAGEMENT_KEYS.MENU_TYPE_TITLE, MENU_MANAGEMENT_KEYS.MENU_TYPE_ADMIN, MENU_MANAGEMENT_KEYS.MENU_TYPE_USER, MENU_MANAGEMENT_KEYS.ADMIN_MENU, MENU_MANAGEMENT_KEYS.USER_MENU, MENU_MANAGEMENT_KEYS.ADMIN_DESCRIPTION, MENU_MANAGEMENT_KEYS.USER_DESCRIPTION, MENU_MANAGEMENT_KEYS.BUTTON_ADD, MENU_MANAGEMENT_KEYS.BUTTON_ADD_TOP_LEVEL, MENU_MANAGEMENT_KEYS.BUTTON_ADD_SUB, MENU_MANAGEMENT_KEYS.BUTTON_EDIT, MENU_MANAGEMENT_KEYS.BUTTON_DELETE, MENU_MANAGEMENT_KEYS.BUTTON_DELETE_SELECTED, MENU_MANAGEMENT_KEYS.BUTTON_DELETE_SELECTED_COUNT, MENU_MANAGEMENT_KEYS.BUTTON_DELETE_PROCESSING, MENU_MANAGEMENT_KEYS.FILTER_RESET, MENU_MANAGEMENT_KEYS.LIST_TOTAL, MENU_MANAGEMENT_KEYS.LIST_SEARCH_RESULT, MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_NAME, MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_URL, MENU_MANAGEMENT_KEYS.TABLE_HEADER_MENU_TYPE, MENU_MANAGEMENT_KEYS.TABLE_HEADER_STATUS, MENU_MANAGEMENT_KEYS.TABLE_HEADER_COMPANY, MENU_MANAGEMENT_KEYS.TABLE_HEADER_SEQUENCE, MENU_MANAGEMENT_KEYS.TABLE_HEADER_ACTIONS, // 추가 키들 - 실제 UI에서 사용되는 모든 키들 "menu.list.title", "filter.company", "filter.company.all", "filter.search", "filter.search.placeholder", "status.unspecified", "status.active", "filter.company.common", "modal.menu.register.title", "form.menu.type", "form.menu.type.admin", "form.menu.type.user", "form.status", "form.status.active", "form.status.inactive", "form.company", "form.company.select", "form.company.common", "form.company.submenu.note", "form.lang.key", "form.lang.key.select", "form.menu.name", "form.menu.name.placeholder", "form.menu.url", "form.menu.url.placeholder", "form.menu.description", "form.menu.description.placeholder", "form.menu.sequence", "button.cancel", "button.register", // 테이블 헤더 관련 추가 키들 "table.header.menu.name", "table.header.sequence", "table.header.company", "table.header.menu.url", "table.header.status", "table.header.actions", // 액션 버튼 관련 추가 키들 "button.add", "button.add.sub", "button.edit", "button.delete", // 페이지 제목 관련 "page.title.menu.management", "page.description.menu.management", "section.title.menu.type", "section.title.admin.menu.list", ]; keys.forEach((key, index) => { texts[key] = results[index]; }); setUiTexts(texts); // 번역 텍스트를 캐시에 저장 setTranslationCache(currentUserLang, texts); console.log("🌐 UI 다국어 텍스트 로드 완료:", texts); } catch (error) { console.error("❌ UI 다국어 텍스트 로드 실패:", error); } finally { setUiTextsLoading(false); } }; // UI 텍스트 가져오기 함수 const getUIText = async ( key: string, params?: Record, fallback?: string, ): Promise => { // uiTexts에서 먼저 찾기 let text = uiTexts[key]; // uiTexts에 없으면 비동기적으로 API 호출 if (!text) { try { text = await getMenuText(key); // 새로운 텍스트를 uiTexts에 추가 setUiTexts((prev) => ({ ...prev, [key]: text })); } catch (error) { console.error(`❌ 키 "${key}" 번역 실패:`, error); text = fallback || key; } } // 파라미터 치환 if (params && text) { Object.entries(params).forEach(([paramKey, paramValue]) => { text = text!.replace(`{${paramKey}}`, String(paramValue)); }); } return text || key; }; // 동기 버전 (기존 호환성을 위해) const getUITextSync = (key: string, params?: Record, fallback?: string): string => { let text = uiTexts[key]; if (!text) { text = fallback || key; } // 파라미터 치환 if (params && text) { Object.entries(params).forEach(([paramKey, paramValue]) => { text = text!.replace(`{${paramKey}}`, String(paramValue)); }); } return text || key; }; // 다국어 API 테스트 함수 const testMultiLangAPI = async () => { console.log("🧪 다국어 API 테스트 시작"); try { const text = await getMenuText(MENU_MANAGEMENT_KEYS.ADMIN_MENU); console.log("🧪 다국어 API 테스트 결과:", text); } catch (error) { console.error("❌ 다국어 API 테스트 실패:", error); } }; // 대문자 키를 소문자 키로 변환하는 함수 const convertMenuData = (data: any[]): MenuItem[] => { return data.map((item) => ({ objid: item.OBJID || item.objid, parent_obj_id: item.PARENT_OBJ_ID || item.parent_obj_id, menu_name_kor: item.MENU_NAME_KOR || item.menu_name_kor, menu_url: item.MENU_URL || item.menu_url, menu_desc: item.MENU_DESC || item.menu_desc, seq: item.SEQ || item.seq, menu_type: item.MENU_TYPE || item.menu_type, status: item.STATUS || item.status, lev: item.LEV || item.lev, lpad_menu_name_kor: item.LPAD_MENU_NAME_KOR || item.lpad_menu_name_kor, status_title: item.STATUS_TITLE || item.status_title, writer: item.WRITER || item.writer, regdate: item.REGDATE || item.regdate, company_code: item.COMPANY_CODE || item.company_code, company_name: item.COMPANY_NAME || item.company_name, })); }; const handleAddTopLevelMenu = () => { setFormData({ menuId: "", parentId: "0", // 최상위 메뉴는 parentId가 0 menuType: getMenuTypeValue(), level: 1, // 최상위 메뉴는 level 1 parentCompanyCode: "", // 최상위 메뉴는 상위 회사 정보 없음 }); setFormModalOpen(true); }; const handleAddMenu = (parentId: string, menuType: string, level: number) => { // 상위 메뉴의 회사 정보 찾기 const currentMenus = selectedMenuType === "admin" ? adminMenus : userMenus; const parentMenu = currentMenus.find((menu) => menu.objid === parentId); setFormData({ menuId: "", parentId, menuType, level: level + 1, parentCompanyCode: parentMenu?.company_code || "", }); setFormModalOpen(true); }; const handleEditMenu = (menuId: string) => { setFormData({ menuId, parentId: "", menuType: "", level: 0, parentCompanyCode: "", }); setFormModalOpen(true); }; const handleMenuSelectionChange = (menuId: string, checked: boolean) => { const newSelected = new Set(selectedMenus); if (checked) { newSelected.add(menuId); } else { newSelected.delete(menuId); } setSelectedMenus(newSelected); }; const handleSelectAllMenus = (checked: boolean) => { const currentMenus = selectedMenuType === "admin" ? adminMenus : userMenus; if (checked) { // 모든 메뉴 선택 (최상위 메뉴 포함) setSelectedMenus(new Set(currentMenus.map((menu) => menu.objid || menu.OBJID || ""))); } else { setSelectedMenus(new Set()); } }; const handleDeleteSelectedMenus = async () => { if (selectedMenus.size === 0) { toast.error(getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_VALIDATION_SELECT_MENU_DELETE)); return; } if (!confirm(getMenuTextSync(MENU_MANAGEMENT_KEYS.MODAL_DELETE_BATCH_DESCRIPTION, { count: selectedMenus.size }))) { return; } setDeleting(true); try { const menuIds = Array.from(selectedMenus); console.log("삭제할 메뉴 IDs:", menuIds); toast.info(getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_DELETE_PROCESSING)); const response = await menuApi.deleteMenusBatch(menuIds); console.log("삭제 API 응답:", response); console.log("응답 구조:", { success: response.success, data: response.data, message: response.message, }); if (response.success && response.data) { const { deletedCount, failedCount } = response.data; console.log("삭제 결과:", { deletedCount, failedCount }); // 선택된 메뉴 초기화 setSelectedMenus(new Set()); // 메뉴 목록 즉시 새로고침 (로딩 상태 없이) console.log("메뉴 목록 새로고침 시작"); await loadMenus(false); // 전역 메뉴 상태도 업데이트 await refreshMenus(); console.log("메뉴 목록 새로고침 완료"); // 삭제 결과 메시지 if (failedCount === 0) { toast.success( getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_DELETE_BATCH_SUCCESS, { count: deletedCount }), ); } else { toast.success( getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_DELETE_BATCH_PARTIAL, { success: deletedCount, failed: failedCount, }), ); } } else { console.error("삭제 실패:", response); toast.error(response.message || "메뉴 삭제에 실패했습니다."); } } catch (error) { console.error("메뉴 삭제 중 오류:", error); toast.error(getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_DELETE_FAILED)); } finally { setDeleting(false); } }; const confirmDelete = async () => { try { const response = await menuApi.deleteMenu(selectedMenuId); if (response.success) { toast.success(response.message); await loadMenus(false); } else { toast.error(response.message); } } catch (error) { toast.error("메뉴 삭제에 실패했습니다."); } finally { setDeleteDialogOpen(false); setSelectedMenuId(""); } }; const handleToggleStatus = async (menuId: string) => { try { const response = await menuApi.toggleMenuStatus(menuId); if (response.success) { toast.success(response.message); await loadMenus(false); // 메뉴 목록 새로고침 // 전역 메뉴 상태도 업데이트 await refreshMenus(); } else { toast.error(response.message); } } catch (error) { console.error("메뉴 상태 토글 오류:", error); toast.error(getMenuTextSync(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_STATUS_TOGGLE_FAILED)); } }; const handleFormSuccess = () => { loadMenus(false); // 전역 메뉴 상태도 업데이트 refreshMenus(); }; const getCurrentMenus = () => { const currentMenus = selectedMenuType === "admin" ? adminMenus : userMenus; // 검색어 필터링 let filteredMenus = currentMenus; if (searchText.trim()) { const searchLower = searchText.toLowerCase(); filteredMenus = currentMenus.filter((menu) => { const menuName = (menu.menu_name_kor || menu.MENU_NAME_KOR || "").toLowerCase(); const menuUrl = (menu.menu_url || menu.MENU_URL || "").toLowerCase(); return menuName.includes(searchLower) || menuUrl.includes(searchLower); }); } // 회사 필터링 if (selectedCompany !== "all") { filteredMenus = filteredMenus.filter((menu) => { const menuCompanyCode = menu.company_code || menu.COMPANY_CODE || ""; return menuCompanyCode === selectedCompany; }); } return filteredMenus; }; // 메뉴 타입 변경 시 선택된 메뉴 초기화 const handleMenuTypeChange = (type: MenuType) => { setSelectedMenuType(type); setSelectedMenus(new Set()); // 선택된 메뉴 초기화 setExpandedMenus(new Set()); // 메뉴 타입 변경 시 확장 상태 초기화 }; const handleToggleExpand = (menuId: string) => { const newExpandedMenus = new Set(expandedMenus); if (newExpandedMenus.has(menuId)) { newExpandedMenus.delete(menuId); } else { newExpandedMenus.add(menuId); } setExpandedMenus(newExpandedMenus); }; const getMenuTypeString = () => { return selectedMenuType === "admin" ? getMenuTextSync(MENU_MANAGEMENT_KEYS.MENU_TYPE_ADMIN) : getMenuTextSync(MENU_MANAGEMENT_KEYS.MENU_TYPE_USER); }; const getMenuTypeValue = () => { return selectedMenuType === "admin" ? "0" : "1"; }; if (loading) { return (
); } return (
{/* 메인 컨텐츠 - 2:8 비율 */}
{/* 좌측 사이드바 - 메뉴 타입 선택 (20%) */}

{getMenuTextSync(MENU_MANAGEMENT_KEYS.MENU_TYPE_TITLE)}

handleMenuTypeChange("admin")} >

{getUITextSync(MENU_MANAGEMENT_KEYS.ADMIN_MENU)}

{getUITextSync(MENU_MANAGEMENT_KEYS.ADMIN_DESCRIPTION)}

{adminMenus.length}
handleMenuTypeChange("user")} >

{getUITextSync(MENU_MANAGEMENT_KEYS.USER_MENU)}

{getUITextSync(MENU_MANAGEMENT_KEYS.USER_DESCRIPTION)}

{userMenus.length}
{/* 우측 메인 영역 - 메뉴 목록 (80%) */}

{getMenuTypeString()} {getMenuTextSync(MENU_MANAGEMENT_KEYS.LIST_TITLE)}

{/* 검색 및 필터 영역 */}
{isCompanyDropdownOpen && (
{/* 검색 입력 */}
setCompanySearchText(e.target.value)} className="h-8 text-sm" onClick={(e) => e.stopPropagation()} />
{/* 회사 목록 */}
{ setSelectedCompany("all"); setIsCompanyDropdownOpen(false); setCompanySearchText(""); }} > {getMenuTextSync(MENU_MANAGEMENT_KEYS.FILTER_COMPANY_ALL)}
{ setSelectedCompany("*"); setIsCompanyDropdownOpen(false); setCompanySearchText(""); }} > {getMenuTextSync(MENU_MANAGEMENT_KEYS.FILTER_COMPANY_COMMON)}
{companies .filter((company) => company.code && company.code.trim() !== "") .filter( (company) => company.name.toLowerCase().includes(companySearchText.toLowerCase()) || company.code.toLowerCase().includes(companySearchText.toLowerCase()), ) .map((company, index) => (
{ setSelectedCompany(company.code); setIsCompanyDropdownOpen(false); setCompanySearchText(""); }} > {company.code === "*" ? "공통" : company.name}
))}
)}
setSearchText(e.target.value)} />
{getUITextSync(MENU_MANAGEMENT_KEYS.LIST_SEARCH_RESULT, { count: getCurrentMenus().length })}
{getUITextSync(MENU_MANAGEMENT_KEYS.LIST_TOTAL, { count: getCurrentMenus().length })}
{selectedMenus.size > 0 && ( )}
setFormModalOpen(false)} onSuccess={handleFormSuccess} menuId={formData.menuId} parentId={formData.parentId} menuType={formData.menuType} level={formData.level} parentCompanyCode={formData.parentCompanyCode} /> 메뉴 삭제 해당 메뉴를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다. 취소 삭제
); };