"use client"; import React, { useState, useEffect } from "react"; import { MenuItem, MenuFormData, menuApi, LangKey } from "@/lib/api/menu"; import { companyAPI } from "@/lib/api/company"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { toast } from "sonner"; import { MENU_MANAGEMENT_KEYS } from "@/lib/utils/multilang"; interface Company { company_code: string; company_name: string; status: string; } interface MenuFormModalProps { isOpen: boolean; onClose: () => void; onSuccess: () => void; menuId?: string; parentId?: string; menuType?: string; level?: number; parentCompanyCode?: string; // 다국어 텍스트 props 추가 uiTexts: Record; } export const MenuFormModal: React.FC = ({ isOpen, onClose, onSuccess, menuId, parentId, menuType, level, parentCompanyCode, uiTexts, }) => { console.log("🎯 MenuFormModal 렌더링 - Props:", { isOpen, menuId, parentId, menuType, level, parentCompanyCode, }); // 다국어 텍스트 가져오기 함수 const getText = (key: string, fallback?: string): string => { return uiTexts[key] || fallback || key; }; console.log("🔍 MenuFormModal 컴포넌트 마운트됨"); const [formData, setFormData] = useState({ parentObjId: parentId || "0", menuNameKor: "", menuUrl: "", menuDesc: "", seq: 1, menuType: "1", status: "ACTIVE", companyCode: parentCompanyCode || "none", langKey: "", }); const [loading, setLoading] = useState(false); const [isEdit, setIsEdit] = useState(false); const [companies, setCompanies] = useState([]); const [langKeys, setLangKeys] = useState([]); const [isLangKeyDropdownOpen, setIsLangKeyDropdownOpen] = useState(false); const [langKeySearchText, setLangKeySearchText] = useState(""); // loadMenuData 함수를 먼저 정의 const loadMenuData = async () => { console.log("loadMenuData 호출됨 - menuId:", menuId); if (!menuId) { console.log("menuId가 없어서 loadMenuData 종료"); return; } try { setLoading(true); console.log("API 호출 시작 - menuId:", menuId); console.log("API URL:", `/admin/menus/${menuId}`); const response = await menuApi.getMenuInfo(menuId); console.log("메뉴 정보 조회 응답:", response); console.log("응답 success:", response.success); console.log("응답 data:", response.data); console.log("응답 message:", response.message); console.log("응답 errorCode:", response.errorCode); if (response.success && response.data) { const menu = response.data; console.log("메뉴 데이터:", menu); console.log("메뉴 데이터 키들:", Object.keys(menu)); // 대문자 키와 소문자 키 모두 처리 const menuType = menu.menu_type || menu.MENU_TYPE || "1"; const status = menu.status || menu.STATUS || "active"; const companyCode = menu.company_code || menu.COMPANY_CODE || ""; const langKey = menu.lang_key || menu.LANG_KEY || ""; // 메뉴 타입 변환 (admin/user -> 0/1) let convertedMenuType = menuType; if (menuType === "admin" || menuType === "0") { convertedMenuType = "0"; } else if (menuType === "user" || menuType === "1") { convertedMenuType = "1"; } // 상태 변환 (active/inactive/inActive -> ACTIVE/INACTIVE) let convertedStatus = status; if (status === "active") { convertedStatus = "ACTIVE"; } else if (status === "inactive" || status === "inActive") { convertedStatus = "INACTIVE"; } setFormData({ objid: menu.objid || menu.OBJID, parentObjId: menu.parent_obj_id || menu.PARENT_OBJ_ID || "0", menuNameKor: menu.menu_name_kor || menu.MENU_NAME_KOR || "", menuUrl: menu.menu_url || menu.MENU_URL || "", menuDesc: menu.menu_desc || menu.MENU_DESC || "", seq: menu.seq || menu.SEQ || 1, menuType: convertedMenuType, status: convertedStatus, companyCode: companyCode, langKey: langKey, // 다국어 키 설정 }); console.log("설정된 폼 데이터:", { objid: menu.objid || menu.OBJID, parentObjId: menu.parent_obj_id || menu.PARENT_OBJ_ID || "0", menuNameKor: menu.menu_name_kor || menu.MENU_NAME_KOR || "", menuUrl: menu.menu_url || menu.MENU_URL || "", menuDesc: menu.menu_desc || menu.MENU_DESC || "", seq: menu.seq || menu.SEQ || 1, menuType: convertedMenuType, status: convertedStatus, companyCode: companyCode, langKey: langKey, }); } } catch (error: any) { console.error("메뉴 정보 로딩 오류:", error); console.error("오류 상세 정보:", { message: error?.message, stack: error?.stack, response: error?.response, }); toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_ERROR_LOAD_MENU_INFO)); } finally { setLoading(false); } }; // useEffect를 loadMenuData 함수 정의 후로 이동 useEffect(() => { console.log("🚀 MenuFormModal useEffect 실행됨!"); console.log("📋 useEffect 파라미터:", { menuId, parentId, menuType }); console.log("MenuFormModal useEffect - menuId:", menuId, "parentId:", parentId, "menuType:", menuType); if (menuId) { console.log("메뉴 수정 모드 - menuId:", menuId); setIsEdit(true); loadMenuData(); } else { console.log("메뉴 등록 모드 - parentId:", parentId, "menuType:", menuType); setIsEdit(false); // 메뉴 타입 변환 (0 -> 0, 1 -> 1, admin -> 0, user -> 1) let defaultMenuType = "1"; // 기본값은 사용자 if (menuType === "0" || menuType === "admin") { defaultMenuType = "0"; // 관리자 } else if (menuType === "1" || menuType === "user") { defaultMenuType = "1"; // 사용자 } setFormData({ parentObjId: parentId || "0", menuNameKor: "", menuUrl: "", menuDesc: "", seq: 1, menuType: defaultMenuType, status: "ACTIVE", // 기본값은 활성화 companyCode: parentCompanyCode || "none", // 상위 메뉴의 회사 코드를 기본값으로 설정 langKey: "", // 다국어 키 초기화 }); console.log("메뉴 등록 기본값 설정:", { parentObjId: parentId || "0", menuType: defaultMenuType, status: "ACTIVE", companyCode: "", langKey: "", }); } }, [menuId, parentId, menuType]); // 강제로 useEffect 실행시키기 위한 별도 useEffect useEffect(() => { console.log("🔧 강제 useEffect 실행 - 컴포넌트 마운트됨"); console.log("🔧 현재 props:", { isOpen, menuId, parentId, menuType }); // isOpen이 true일 때만 실행 if (isOpen && menuId) { console.log("🔧 모달이 열렸고 menuId가 있음 - 강제 실행"); // 약간의 지연 후 실행 setTimeout(() => { console.log("🔧 setTimeout으로 loadMenuData 실행"); loadMenuData(); }, 100); } }, [isOpen]); // isOpen만 의존성으로 설정 // 회사 목록 로드 useEffect(() => { if (isOpen) { loadCompanies(); } }, [isOpen]); // 다국어 키 목록 로드 useEffect(() => { if (isOpen && formData.companyCode) { loadLangKeys(); } }, [isOpen, formData.companyCode]); // 드롭다운 외부 클릭 시 닫기 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const target = event.target as Element; if (!target.closest(".langkey-dropdown")) { setIsLangKeyDropdownOpen(false); setLangKeySearchText(""); } }; if (isLangKeyDropdownOpen) { document.addEventListener("mousedown", handleClickOutside); } return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [isLangKeyDropdownOpen]); const loadCompanies = async () => { try { const companyList = await companyAPI.getList({ status: "active" }); setCompanies(companyList); } catch (error) { console.error("회사 목록 로딩 오류:", error); toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_ERROR_LOAD_COMPANY_LIST)); } }; const loadLangKeys = async () => { console.log("🔤 다국어 키 목록 조회 시작 - companyCode:", formData.companyCode); try { const response = await menuApi.getLangKeys({ companyCode: formData.companyCode === "none" ? "*" : formData.companyCode, }); if (response.success && response.data) { // 활성화된 다국어 키만 필터링 const activeKeys = response.data.filter((key) => key.isActive === "Y"); console.log("🔤 다국어 키 목록 조회 성공:", activeKeys.length, "개 (활성화된 키)"); setLangKeys(activeKeys); } } catch (error) { console.error("❌ 다국어 키 목록 로딩 오류:", error); toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_ERROR_LOAD_LANG_KEY_LIST)); setLangKeys([]); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.menuNameKor.trim()) { toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_VALIDATION_MENU_NAME_REQUIRED)); return; } if (!formData.companyCode) { toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_VALIDATION_COMPANY_REQUIRED)); return; } try { setLoading(true); // 백엔드에 전송할 데이터 변환 const submitData = { ...formData, // 상태를 소문자로 변환 (백엔드에서 소문자 기대) status: formData.status.toLowerCase(), }; console.log("저장할 데이터:", submitData); let response; if (isEdit && menuId) { // 수정 모드: updateMenu API 호출 console.log("🔧 메뉴 수정 API 호출:", menuId); response = await menuApi.updateMenu(menuId, submitData); } else { // 추가 모드: saveMenu API 호출 console.log("➕ 메뉴 추가 API 호출"); response = await menuApi.saveMenu(submitData); } if (response.success) { toast.success(response.message); onSuccess(); onClose(); } else { toast.error(response.message); } } catch (error) { console.error("메뉴 저장/수정 실패:", error); toast.error(getText(MENU_MANAGEMENT_KEYS.MESSAGE_MENU_SAVE_FAILED)); } finally { setLoading(false); } }; const handleInputChange = (field: keyof MenuFormData, value: string | number) => { setFormData((prev) => ({ ...prev, [field]: value, })); }; // 선택된 다국어 키 정보 가져오기 const getSelectedLangKeyInfo = () => { if (!formData.langKey) return null; return langKeys.find((key) => key.langKey === formData.langKey); }; const selectedLangKeyInfo = getSelectedLangKeyInfo(); // 전역 사용자 로케일 가져오기 const getCurrentUserLang = () => { return (window as any).__GLOBAL_USER_LANG || localStorage.getItem("userLocale") || "KR"; }; return ( {isEdit ? getText(MENU_MANAGEMENT_KEYS.MODAL_MENU_MODIFY_TITLE) : getText(MENU_MANAGEMENT_KEYS.MODAL_MENU_REGISTER_TITLE)}
{!isEdit && level !== 1 && (

{getText(MENU_MANAGEMENT_KEYS.FORM_COMPANY_SUBMENU_NOTE)}

)}
{isLangKeyDropdownOpen && (
{/* 검색 입력 */}
setLangKeySearchText(e.target.value)} className="h-8 text-sm" onClick={(e) => e.stopPropagation()} />
{/* 다국어 키 목록 */}
{ handleInputChange("langKey", ""); setIsLangKeyDropdownOpen(false); setLangKeySearchText(""); }} > {getText(MENU_MANAGEMENT_KEYS.FORM_LANG_KEY_NONE)}
{langKeys .filter( (key) => key.langKey.toLowerCase().includes(langKeySearchText.toLowerCase()) || key.description.toLowerCase().includes(langKeySearchText.toLowerCase()), ) .map((key) => (
{ handleInputChange("langKey", key.langKey); setIsLangKeyDropdownOpen(false); setLangKeySearchText(""); }} >
{key.langKey}
{key.description &&
{key.description}
}
))}
)}
{selectedLangKeyInfo && (

{getText(MENU_MANAGEMENT_KEYS.FORM_LANG_KEY_SELECTED) .replace("{key}", selectedLangKeyInfo.langKey) .replace("{description}", selectedLangKeyInfo.description)}

)}
handleInputChange("menuNameKor", e.target.value)} placeholder={getText(MENU_MANAGEMENT_KEYS.FORM_MENU_NAME_PLACEHOLDER)} required />
handleInputChange("menuUrl", e.target.value)} placeholder={getText(MENU_MANAGEMENT_KEYS.FORM_MENU_URL_PLACEHOLDER)} />