"use client"; import React, { useEffect, useRef, useState,useCallback } from "react"; import Link from "next/link"; import Image from "next/image"; import { useTranslations } from "next-intl"; import { usePathname } from "next/navigation"; import { useSidebar } from "../context/SidebarContext"; import useSWR from "swr"; import axios from "@/lib/axios"; import { LayoutGrid, Calendar, Users, ShieldCheck, LifeBuoy, FileText, Send, Mail, Server, Layers, UserCircle, Settings, KeyRound, ChevronDown, Ellipsis, } from "lucide-react"; type NavItem = { name: string; icon: string; route?: string; subItems?: { name: string; route: string; pro?: boolean; new?: boolean }[]; }; type MenuGroup = { title: string; items: NavItem[]; }; const iconMap: Record = { dashboard: , calendar: , users: , certificate: , "support-ticket": , pages: , email: , inbox: , smtp: , "server-settings": , layers: , "user-profile": , settings: , "api-key": , }; const getIcon = (iconName: string) => iconMap[iconName] || ; // Static items removed in favor of dynamic API data const AppSidebar: React.FC = () => { const { isExpanded, isMobileOpen, isHovered, setIsHovered } = useSidebar(); const pathname = usePathname(); const t = useTranslations("Navigation"); const renderMenuItems = ( navItems: NavItem[], menuType: string ) => (
    {navItems.map((nav, index) => (
  • {nav.subItems ? ( ) : ( nav.route && ( {getIcon(nav.icon)} {(isExpanded || isHovered || isMobileOpen) && ( {(() => { const key = nav.name.toLowerCase().replace(/\s+/g, '_'); const translated = t(key); return translated === `Navigation.${key}` ? nav.name : translated; })()} )} ) )} {nav.subItems && (isExpanded || isHovered || isMobileOpen) && (
    { subMenuRefs.current[`${menuType}-${index}`] = el; }} className="overflow-hidden transition-all duration-300" style={{ height: openSubmenu?.type === menuType && openSubmenu?.index === index ? `${subMenuHeight[`${menuType}-${index}`]}px` : "0px", }} >
      {nav.subItems.map((subItem) => (
    • {(() => { const key = subItem.name.toLowerCase().replace(/\s+/g, '_'); const translated = t(key); return translated === `Navigation.${key}` ? subItem.name : translated; })()} {subItem.new && ( new )} {subItem.pro && ( pro )}
    • ))}
    )}
  • ))}
); const { data: menuGroups, error } = useSWR('/api/navigation', () => axios.get('/api/navigation').then(res => res.data) ); const [openSubmenu, setOpenSubmenu] = useState<{ type: string; index: number; } | null>(null); const [subMenuHeight, setSubMenuHeight] = useState>( {} ); const subMenuRefs = useRef>({}); // const isActive = (path: string) => path === pathname; const isActive = useCallback((path: string) => path === pathname, [pathname]); useEffect(() => { if (!menuGroups) return; // Check if the current path matches any submenu item let targetSubmenu: { type: string; index: number } | null = null; // Use some/find to break early if possible, or just foreach for (const group of menuGroups) { for (let index = 0; index < group.items.length; index++) { const nav = group.items[index]; if (nav.subItems) { const hasActiveSubItem = nav.subItems.some(subItem => isActive(subItem.route)); if (hasActiveSubItem) { targetSubmenu = { type: group.title, index }; break; } } } if (targetSubmenu) break; } // Only update state if it has changed to avoid loops and unnecessary re-renders const isMismatch = (openSubmenu === null && targetSubmenu !== null) || (openSubmenu !== null && targetSubmenu === null) || (openSubmenu && targetSubmenu && (openSubmenu.type !== targetSubmenu.type || openSubmenu.index !== targetSubmenu.index)); if (isMismatch) { setOpenSubmenu(targetSubmenu); } }, [pathname, isActive, menuGroups, openSubmenu]); useEffect(() => { // Set the height of the submenu items when the submenu is opened if (openSubmenu !== null) { const key = `${openSubmenu.type}-${openSubmenu.index}`; if (subMenuRefs.current[key]) { setSubMenuHeight((prevHeights) => ({ ...prevHeights, [key]: subMenuRefs.current[key]?.scrollHeight || 0, })); } } }, [openSubmenu]); const handleSubmenuToggle = (index: number, menuType: string) => { setOpenSubmenu((prevOpenSubmenu) => { if ( prevOpenSubmenu && prevOpenSubmenu.type === menuType && prevOpenSubmenu.index === index ) { return null; } return { type: menuType, index }; }); }; return ( ); }; export default AppSidebar;