"use client"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useAuth } from "./auth-provider"; import { useTheme } from "next-themes"; import type { LucideIcon } from "lucide-react"; import { LayoutDashboard, Users, Building2, Truck, FileText, ShoppingCart, LogOut, Sun, Moon, Menu, CheckCircle, Archive, Package, ClipboardList, Wrench, MapPinned, MapPin, Plus, Settings as SettingsIcon, Tag, Zap, ChevronDown, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Separator } from "@/components/ui/separator"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Sheet, SheetContent, SheetTrigger, SheetTitle } from "@/components/ui/sheet"; import { useEffect, useState } from "react"; import { cn } from "@/lib/utils"; /* ============================================================================ * Sidebar nav structure * * Six flat sections. The active state is the theme's single accent. * No per-category brand colours — every section reads the same so the eye * scans label + icon, not colour. * ========================================================================== */ type NavEntry = { href: string; label: string; icon: LucideIcon; }; const dashboardItems: NavEntry[] = [ { href: "/dashboard", label: "Dashboard", icon: LayoutDashboard }, ]; const managementItems: NavEntry[] = [ { href: "/companies", label: "Companies", icon: Building2 }, { href: "/customers", label: "Customers", icon: Users }, { href: "/suppliers", label: "Suppliers", icon: Truck }, { href: "/supplier-map", label: "Supplier Map", icon: MapPinned }, { href: "/pricelist", label: "Pricelist", icon: Tag }, ]; const quoteItems: NavEntry[] = [ { href: "/quotes", label: "Quote List", icon: FileText }, { href: "/sprint", label: "Sprint", icon: Zap }, { href: "/quotes/approvals", label: "Pending Approvals", icon: CheckCircle }, { href: "/quotes/archived", label: "Archived", icon: Archive }, ]; const orderItems: NavEntry[] = [ { href: "/orders/new", label: "New Order", icon: Plus }, { href: "/orders", label: "Order List", icon: ShoppingCart }, { href: "/orders/assign", label: "Assign Drivers", icon: Truck }, ]; const operationsItems: NavEntry[] = [ { href: "/collection-pool", label: "Collection Pool", icon: Package }, { href: "/collection-map", label: "Collection Map", icon: MapPin }, { href: "/delivery-notes", label: "Delivery Notes", icon: ClipboardList }, { href: "/repairs", label: "Repairs", icon: Wrench }, ]; /* ============================================================================ * Active-route resolution * The naïve "exact OR starts-with-prefix" rule double-highlights * `/orders/new` and `/orders`. We fix it by demanding the item is the * most-specific match within its group. * ========================================================================== */ function isActive(itemHref: string, siblings: NavEntry[], pathname: string): boolean { if (pathname === itemHref) return true; if (!pathname.startsWith(itemHref + "/")) return false; return !siblings.some( (other) => other.href !== itemHref && other.href.length > itemHref.length && (pathname === other.href || pathname.startsWith(other.href + "/")) ); } /* ============================================================================ * NavSection — collapsible group with a small uppercase label * ========================================================================== */ function NavSection({ label, items, pathname, defaultOpen = false, onLinkClick, }: { label: string; items: NavEntry[]; pathname: string; defaultOpen?: boolean; onLinkClick?: () => void; }) { const sectionActive = items.some( (i) => pathname === i.href || pathname.startsWith(i.href + "/") ); const [open, setOpen] = useState(defaultOpen || sectionActive); useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect if (sectionActive) setOpen(true); }, [sectionActive]); return (
{open && (
{items.map((item) => ( ))}
)}
); } /* ============================================================================ * NavLink — single nav row, theme-driven active state * ========================================================================== */ function NavLink({ item, active, onClick, }: { item: NavEntry; active: boolean; onClick?: () => void; }) { return ( {item.label} {active && ( )} ); } /* ============================================================================ * NavContent — the actual sidebar body * ========================================================================== */ function NavContent({ onLinkClick }: { onLinkClick?: () => void }) { const pathname = usePathname(); const { user, logout } = useAuth(); const { theme, setTheme } = useTheme(); return (
{/* Brand block */}
WFDASH
Westcott Fasteners
{/* Nav */} {/* Bottom block */}
Settings
{user?.name?.charAt(0)?.toUpperCase() || user?.email?.charAt(0)?.toUpperCase() || "U"}

{user?.name || "User"}

{user?.email}

); } /* ============================================================================ * Sidebar — desktop + mobile (Sheet) wrappers * ========================================================================== */ export function Sidebar() { const [open, setOpen] = useState(false); return ( <>
} > Navigation setOpen(false)} />
WFDASH
); }