diff --git a/fems-app/src/components/layout/SideNav.tsx b/fems-app/src/components/layout/SideNav.tsx deleted file mode 100644 index 33cb7a3..0000000 --- a/fems-app/src/components/layout/SideNav.tsx +++ /dev/null @@ -1,297 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { cn } from "@/lib/utils"; -import { usePermissions } from "@/hooks/usePermissions"; -import { useAuth } from "@/hooks/useAuth"; -import { useQuery } from "@tanstack/react-query"; -import { useAuthStore } from "@/stores/auth"; -import { api } from "@/lib/api"; -import { - Building2, - Box, - ChevronDown, - ChevronRight, - Calendar, - Gauge -} from "lucide-react"; -import { useState } from "react"; - -interface DBMenuItem { - id: string; - menu_type: string; - parent_id: string | null; - menu_name_kor: string; - menu_name_eng: string; - seq: string; - menu_url: string; - menu_desc?: string; - isActive: boolean; - children?: DBMenuItem[]; -} - -interface DBApiResponse { - success: boolean; - data: { - success: boolean; - data: DBMenuItem[]; - } -} - -interface ProcessedMenuItem { - id: string; - title: string; - href?: string; - icon: React.ComponentType<{ className?: string }>; - items?: ProcessedMenuItem[]; -} - -interface MenuItemProps { - item: ProcessedMenuItem; - depth: number; - openSections: { [key: string]: boolean }; - onToggle: (id: string) => void; - pathname: string; -} - -const MenuItemComponent: React.FC = ({ - item, - depth, - openSections, - onToggle, - pathname, - }) => { - const hasChildren = item.items && item.items.length > 0; - const isOpen = openSections[item.id]; - const IconComponent = item.icon || Box; - - // 들여쓰기 계산 - const getIndentClass = (depth: number) => { - if (depth === 0) return "px-3"; - if (depth === 1) return "px-3 pl-7"; - return "px-3 pl-11"; - }; - - const itemContent = ( - <> - - {item.title} - {hasChildren && ( -
- {isOpen - ? - : - } -
- )} - - ); - - return ( -
- {item.href ? ( - 0 && "bg-gray-50/50" - ) - )} - > - {itemContent} - - ) : ( - - )} - - {hasChildren && isOpen && ( -
- {item.items?.map((subItem) => ( - - ))} -
- )} -
- ); - }; - -function processMenuItems(responseData: DBApiResponse, role: string): ProcessedMenuItem[] { - if (!responseData?.data?.data) { - return []; - } - - const menuData = responseData.data.data; - - const buildMenuItem = (menu: DBMenuItem): ProcessedMenuItem => { - // 자식 메뉴들을 seq 기준으로 정렬 - const sortedChildren = menu.children - ? [...menu.children].sort((a, b) => { - const seqA = parseInt(a.seq) || 0; - const seqB = parseInt(b.seq) || 0; - return seqA - seqB; - }) - : []; - - // 재귀적으로 자식 메뉴들을 처리 - const processedChildren = sortedChildren.map(buildMenuItem); - - return { - id: menu.id, - title: menu.menu_name_kor, - href: menu.menu_url || undefined, - icon: Box, - ...(processedChildren.length > 0 && { items: processedChildren }), - }; - }; - - // 최상위 메뉴들을 찾고 권한 체크 후 seq로 정렬 - return menuData - .filter(menu => - (menu.menu_type !== "0" || ["super_admin", "company_admin"].includes(role)) && - !menu.parent_id - ) - .sort((a, b) => { - const seqA = parseInt(a.seq) || 0; - const seqB = parseInt(b.seq) || 0; - return seqA - seqB; - }) - .map(buildMenuItem); -} - -export function SideNav() { - const pathname = usePathname(); - const { user } = useAuth(); - const { hasPermission } = usePermissions(); - const { token } = useAuthStore(); - - const { data: dbMenuData } = useQuery({ - queryKey: ["menus"], - queryFn: async () => { - const response = await api.get("/api/v1/app/common/menu"); - return response.data; - }, - enabled: !!token, - }); - - const menuItems = dbMenuData ? processMenuItems(dbMenuData, user?.role || "") : []; - - const [openSections, setOpenSections] = useState<{ [key: string]: boolean }>( - () => { - const findOpenSections = (items: ProcessedMenuItem[], path: string): string[] => { - const openSections: string[] = []; - - const findPath = (items: ProcessedMenuItem[]): boolean => { - for (const item of items) { - if (item.href === path) { - return true; - } - if (item.items) { - if (findPath(item.items)) { - openSections.push(item.id); - return true; - } - } - } - return false; - }; - - findPath(items); - return openSections; - }; - - const openIds = findOpenSections(menuItems, pathname); - return openIds.reduce((acc, id) => ({ ...acc, [id]: true }), {}); - } - ); - - const toggleSection = (id: string) => { - setOpenSections((prev) => ({ - ...prev, - [id]: !prev[id], - })); - }; - - return ( - - ); -} - -export default SideNav; \ No newline at end of file