import { useCallback, useEffect, useRef, useState } from "react"; import { Link, useLocation } from "react-router"; // Assume these icons are imported from an icon library import { BoxCubeIcon, CalenderIcon, ChevronDownIcon, GridIcon, HorizontaLDots, ListIcon, PageIcon, PieChartIcon, PlugInIcon, TableIcon, UserCircleIcon, } from "../icons"; import { useSidebar } from "../context/SidebarContext"; import SidebarWidget from "./SidebarWidget"; type NavItem = { name: string; icon: React.ReactNode; path?: string; subItems?: { name: string; path: string; pro?: boolean; new?: boolean }[]; }; const navItems: NavItem[] = [ { icon: , name: "Dashboard", subItems: [{ name: "Ecommerce", path: "/", pro: false }], }, { icon: , name: "Calendar", path: "/calendar", }, { icon: , name: "User Profile", path: "/profile", }, { name: "Forms", icon: , subItems: [{ name: "Form Elements", path: "/form-elements", pro: false }], }, { name: "Tables", icon: , subItems: [{ name: "Basic Tables", path: "/basic-tables", pro: false }], }, { name: "Pages", icon: , subItems: [ { name: "Blank Page", path: "/blank", pro: false }, { name: "404 Error", path: "/error-404", pro: false }, ], }, ]; const othersItems: NavItem[] = [ { icon: , name: "Charts", subItems: [ { name: "Line Chart", path: "/line-chart", pro: false }, { name: "Bar Chart", path: "/bar-chart", pro: false }, ], }, { icon: , name: "UI Elements", subItems: [ { name: "Alerts", path: "/alerts", pro: false }, { name: "Avatar", path: "/avatars", pro: false }, { name: "Badge", path: "/badge", pro: false }, { name: "Buttons", path: "/buttons", pro: false }, { name: "Images", path: "/images", pro: false }, { name: "Videos", path: "/videos", pro: false }, ], }, { icon: , name: "Authentication", subItems: [ { name: "Sign In", path: "/signin", pro: false }, { name: "Sign Up", path: "/signup", pro: false }, ], }, ]; const AppSidebar: React.FC = () => { const { isExpanded, isMobileOpen, isHovered, setIsHovered } = useSidebar(); const location = useLocation(); const [openSubmenu, setOpenSubmenu] = useState<{ type: "main" | "others"; index: number; } | null>(null); const [subMenuHeight, setSubMenuHeight] = useState>( {} ); const subMenuRefs = useRef>({}); // const isActive = (path: string) => location.pathname === path; const isActive = useCallback( (path: string) => location.pathname === path, [location.pathname] ); useEffect(() => { let submenuMatched = false; ["main", "others"].forEach((menuType) => { const items = menuType === "main" ? navItems : othersItems; items.forEach((nav, index) => { if (nav.subItems) { nav.subItems.forEach((subItem) => { if (isActive(subItem.path)) { setOpenSubmenu({ type: menuType as "main" | "others", index, }); submenuMatched = true; } }); } }); }); if (!submenuMatched) { setOpenSubmenu(null); } }, [location, isActive]); useEffect(() => { 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: "main" | "others") => { setOpenSubmenu((prevOpenSubmenu) => { if ( prevOpenSubmenu && prevOpenSubmenu.type === menuType && prevOpenSubmenu.index === index ) { return null; } return { type: menuType, index }; }); }; const renderMenuItems = (items: NavItem[], menuType: "main" | "others") => ( {items.map((nav, index) => ( {nav.subItems ? ( handleSubmenuToggle(index, menuType)} className={`menu-item group ${ openSubmenu?.type === menuType && openSubmenu?.index === index ? "menu-item-active" : "menu-item-inactive" } cursor-pointer ${ !isExpanded && !isHovered ? "lg:justify-center" : "lg:justify-start" }`} > {nav.icon} {(isExpanded || isHovered || isMobileOpen) && ( {nav.name} )} {(isExpanded || isHovered || isMobileOpen) && ( )} ) : ( nav.path && ( {nav.icon} {(isExpanded || isHovered || isMobileOpen) && ( {nav.name} )} ) )} {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) => ( {subItem.name} {subItem.new && ( new )} {subItem.pro && ( pro )} ))} )} ))} ); return ( ); }; export default AppSidebar;