- Enhanced the menu management functionality by adding a new `menu_icon` field in the database schema, allowing for the storage of menu icons. - Updated the `saveMenu` and `updateMenu` functions in the admin controller to handle the new `menu_icon` field during menu creation and updates. - Modified the `AdminService` to include `MENU_ICON` in various queries, ensuring that the icon data is retrieved and processed correctly. - Integrated the `MenuIconPicker` component in the frontend to allow users to select and display menu icons in the `MenuFormModal`. - Updated the sidebar and layout components to utilize the new icon data, enhancing the visual representation of menus across the application.
120 lines
4.2 KiB
TypeScript
120 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import React, { createContext, useContext, useState, useEffect, ReactNode } from "react";
|
|
import type { MenuItem } from "@/lib/api/menu";
|
|
import { menuApi } from "@/lib/api/menu"; // API 호출 활성화
|
|
import { toast } from "sonner";
|
|
import { useAuth } from "@/hooks/useAuth"; // user 정보 가져오기
|
|
|
|
interface MenuContextType {
|
|
adminMenus: MenuItem[];
|
|
userMenus: MenuItem[];
|
|
loading: boolean;
|
|
refreshMenus: () => Promise<void>;
|
|
}
|
|
|
|
const MenuContext = createContext<MenuContextType | undefined>(undefined);
|
|
|
|
export function MenuProvider({ children }: { children: ReactNode }) {
|
|
const [adminMenus, setAdminMenus] = useState<MenuItem[]>([]);
|
|
const [userMenus, setUserMenus] = useState<MenuItem[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const { user } = useAuth(); // user 정보 가져오기
|
|
|
|
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,
|
|
// 아이콘 필드
|
|
menu_icon: item.MENU_ICON || item.menu_icon,
|
|
// 다국어 관련 필드
|
|
lang_key: item.LANG_KEY || item.lang_key,
|
|
lang_key_desc: item.LANG_KEY_DESC || item.lang_key_desc,
|
|
translated_name: item.TRANSLATED_NAME || item.translated_name,
|
|
translated_desc: item.TRANSLATED_DESC || item.translated_desc,
|
|
}));
|
|
};
|
|
|
|
const loadMenus = async () => {
|
|
try {
|
|
setLoading(true);
|
|
|
|
// 사용자 로케일이 로드될 때까지 잠시 대기
|
|
let retryCount = 0;
|
|
const maxRetries = 20; // 최대 2초 대기 (100ms * 20)
|
|
|
|
while (retryCount < maxRetries) {
|
|
if (typeof window !== "undefined") {
|
|
const hasGlobalLang = !!(window as any).__GLOBAL_USER_LANG;
|
|
const hasStoredLang = !!localStorage.getItem("userLocale");
|
|
|
|
if (hasGlobalLang || hasStoredLang) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
retryCount++;
|
|
}
|
|
|
|
if (retryCount >= maxRetries) {
|
|
console.warn("⚠️ 사용자 로케일 로드 타임아웃, 기본값으로 진행");
|
|
}
|
|
|
|
// 관리자 메뉴와 사용자 메뉴를 병렬로 로드
|
|
// 좌측 사이드바용: active만 표시
|
|
const [adminResponse, userResponse] = await Promise.all([menuApi.getAdminMenus(), menuApi.getUserMenus()]);
|
|
|
|
if (adminResponse.success && adminResponse.data) {
|
|
const convertedAdminMenus = convertMenuData(adminResponse.data);
|
|
setAdminMenus(convertedAdminMenus);
|
|
}
|
|
|
|
if (userResponse.success && userResponse.data) {
|
|
const convertedUserMenus = convertMenuData(userResponse.data);
|
|
setUserMenus(convertedUserMenus);
|
|
}
|
|
} catch (error) {
|
|
console.error("메뉴 로드 오류:", error);
|
|
toast.error("메뉴 목록을 불러오는데 실패했습니다.");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const refreshMenus = async () => {
|
|
await loadMenus();
|
|
};
|
|
|
|
useEffect(() => {
|
|
// user.companyCode가 변경되면 메뉴 다시 로드
|
|
// console.log("🔄 MenuContext: user.companyCode 변경 감지, 메뉴 재로드", user?.companyCode);
|
|
loadMenus();
|
|
}, [user?.companyCode]); // companyCode 변경 시 재로드
|
|
|
|
return (
|
|
<MenuContext.Provider value={{ adminMenus, userMenus, loading, refreshMenus }}>{children}</MenuContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useMenu() {
|
|
const context = useContext(MenuContext);
|
|
if (context === undefined) {
|
|
throw new Error("useMenu must be used within a MenuProvider");
|
|
}
|
|
return context;
|
|
}
|