"use client"; import { ChevronRight, type LucideIcon } from "lucide-react"; import { useTranslations } from "next-intl"; import { useCallback, useMemo, useState } from "react"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, } from "@/components/ui/sidebar"; interface NavItem { title: string; url: string; icon: LucideIcon; isActive?: boolean; items?: { title: string; url: string; }[]; } interface NavMainProps { items: NavItem[]; onSourcesExpandedChange?: (expanded: boolean) => void; } export function NavMain({ items, onSourcesExpandedChange }: NavMainProps) { const t = useTranslations("nav_menu"); // Translation function that handles both exact matches and fallback to original const translateTitle = (title: string): string => { const titleMap: Record = { Researcher: "researcher", "Manage LLMs": "manage_llms", Sources: "sources", "Add Sources": "add_sources", "Manage Documents": "manage_documents", "Manage Connectors": "manage_connectors", Podcasts: "podcasts", Logs: "logs", Platform: "platform", Team: "team", }; const key = titleMap[title]; return key ? t(key) : title; }; // Memoize items to prevent unnecessary re-renders const memoizedItems = useMemo(() => items, [items]); // Track expanded state for items with sub-menus (like Sources) const [expandedItems, setExpandedItems] = useState>(() => { const initial: Record = {}; items.forEach((item) => { if (item.items?.length) { initial[item.title] = item.isActive ?? false; } }); return initial; }); // Handle collapsible state change const handleOpenChange = useCallback( (title: string, isOpen: boolean) => { setExpandedItems((prev) => ({ ...prev, [title]: isOpen })); // Notify parent when Sources is expanded/collapsed if (title === "Sources" && onSourcesExpandedChange) { onSourcesExpandedChange(isOpen); } }, [onSourcesExpandedChange] ); return ( {translateTitle("Platform")} {memoizedItems.map((item, index) => { const translatedTitle = translateTitle(item.title); const hasSub = !!item.items?.length; const isItemOpen = expandedItems[item.title] ?? item.isActive ?? false; return ( handleOpenChange(item.title, open) : undefined} defaultOpen={!hasSub ? item.isActive : undefined} > {hasSub ? ( // When the item has children, make the whole row a collapsible trigger <> Toggle submenu {item.items?.map((subItem, subIndex) => { const translatedSubTitle = translateTitle(subItem.title); return ( {translatedSubTitle} ); })} ) : ( // Leaf item: treat as a normal link {translatedTitle} )} ); })} ); }