"use client"; import React, { useState, useEffect } from "react"; import Link from "next/link"; import { useParams, usePathname } from "next/navigation"; import { cn } from "@app/lib/cn"; import { ChevronDown, ChevronRight } from "lucide-react"; import { useUserContext } from "@app/hooks/useUserContext"; export interface SidebarNavItem { href: string; title: string; icon?: React.ReactNode; children?: SidebarNavItem[]; autoExpand?: boolean; } export interface SidebarNavProps extends React.HTMLAttributes { items: SidebarNavItem[]; disabled?: boolean; onItemClick?: () => void; } export function SidebarNav({ className, items, disabled = false, onItemClick, ...props }: SidebarNavProps) { const pathname = usePathname(); const params = useParams(); const orgId = params.orgId as string; const niceId = params.niceId as string; const resourceId = params.resourceId as string; const userId = params.userId as string; const [expandedItems, setExpandedItems] = useState>(new Set()); const { user } = useUserContext(); function hydrateHref(val: string): string { return val .replace("{orgId}", orgId) .replace("{niceId}", niceId) .replace("{resourceId}", resourceId) .replace("{userId}", userId); } // Initialize expanded items based on autoExpand property and current path useEffect(() => { const autoExpanded = new Set(); function findAutoExpandedAndActivePath( items: SidebarNavItem[], parentHrefs: string[] = [] ) { items.forEach((item) => { const hydratedHref = hydrateHref(item.href); // Add current item's href to the path const currentPath = [...parentHrefs, hydratedHref]; // Auto expand if specified or if this item or any child is active if (item.autoExpand || pathname.startsWith(hydratedHref)) { // Expand all parent sections when a child is active currentPath.forEach((href) => autoExpanded.add(href)); } // Recursively check children if (item.children) { findAutoExpandedAndActivePath(item.children, currentPath); } }); } findAutoExpandedAndActivePath(items); setExpandedItems(autoExpanded); }, [items, pathname]); function toggleItem(href: string) { setExpandedItems((prev) => { const newSet = new Set(prev); if (newSet.has(href)) { newSet.delete(href); } else { newSet.add(href); } return newSet; }); } function renderItems(items: SidebarNavItem[], level = 0) { return items.map((item) => { const hydratedHref = hydrateHref(item.href); const isActive = pathname.startsWith(hydratedHref); const hasChildren = item.children && item.children.length > 0; const isExpanded = expandedItems.has(hydratedHref); const indent = level * 16; // Base indent for each level return (
{ if (disabled) { e.preventDefault(); } else if (onItemClick) { onItemClick(); } }} tabIndex={disabled ? -1 : undefined} aria-disabled={disabled} > {item.icon && ( {item.icon} )} {item.title} {hasChildren && ( )}
{hasChildren && isExpanded && (
{renderItems(item.children || [], level + 1)}
)}
); }); } return ( ); }