"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"; 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()); // Initialize expanded items based on autoExpand property useEffect(() => { const autoExpanded = new Set(); function findAutoExpanded(items: SidebarNavItem[]) { items.forEach(item => { const hydratedHref = hydrateHref(item.href); if (item.autoExpand) { autoExpanded.add(hydratedHref); } if (item.children) { findAutoExpanded(item.children); } }); } findAutoExpanded(items); setExpandedItems(autoExpanded); }, [items]); function hydrateHref(val: string): string { return val .replace("{orgId}", orgId) .replace("{niceId}", niceId) .replace("{resourceId}", resourceId) .replace("{userId}", userId); } 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 ( ); }