"use client"; import { useState, useEffect, useRef, useCallback, KeyboardEvent } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useRouter } from "next/navigation"; import { authClient } from "@/lib/auth-client"; // Elegant warm sidebar design // Colors: parchment 100 bg, soft linen text, powder petal accent type NavItem = { href?: string; label: string; icon?: string; divider?: boolean; }; const NAV_ITEMS: NavItem[] = [ // Main { href: "/admin", label: "Dashboard", icon: "grid" }, { href: "/admin/orders", label: "Orders", icon: "shopping-cart" }, { href: "/admin/stops", label: "Stops & Routes", icon: "map-pin" }, { href: "/admin/products", label: "Products", icon: "package" }, { href: "/admin/communications", label: "Communications", icon: "mail" }, // Settings section { divider: true, label: "Settings" }, { href: "/admin/settings", label: "General", icon: "settings" }, { href: "/admin/time-tracking", label: "Workers & PINs", icon: "users" }, { href: "/admin/time-tracking?tab=tasks", label: "Tasks", icon: "clipboard" }, { href: "/admin/users", label: "Users & Permissions", icon: "shield" }, { href: "/admin/settings/integrations", label: "Integrations", icon: "plug" }, { href: "/admin/settings/billing", label: "Billing", icon: "billing" }, ]; // Icon components function GridIcon({ className }: { className?: string }) { return ( ); } function CartIcon({ className }: { className?: string }) { return ( ); } function MapPinIcon({ className }: { className?: string }) { return ( ); } function PackageIcon({ className }: { className?: string }) { return ( ); } function ClipboardIcon({ className }: { className?: string }) { return ( ); } function ClockIcon({ className }: { className?: string }) { return ( ); } function MailIcon({ className }: { className?: string }) { return ( ); } function SparkleIcon({ className }: { className?: string }) { return ( ); } function SettingsCogIcon({ open }: { open: boolean }) { return ( ); } function ChevronIcon({ open }: { open: boolean }) { return ( ); } function HamburgerIcon() { return ( ); } function CloseIcon() { return ( ); } function BillingIcon({ className }: { className?: string }) { return ( ); } function PuzzleIcon({ className }: { className?: string }) { return ( ); } function PlugIcon({ className }: { className?: string }) { return ( ); } function TruckIcon({ className }: { className?: string }) { return ( ); } function SquareIcon({ className }: { className?: string }) { return ( ); } function LogoutIcon({ className }: { className?: string }) { return ( ); } function UsersIcon({ className }: { className?: string }) { return ( ); } function ShieldIcon({ className }: { className?: string }) { return ( ); } const ICON_MAP: Record = { grid: , "shopping-cart": , "map-pin": , package: , clipboard: , clock: , mail: , settings: , advanced: , billing: , puzzle: , plug: , sparkles: , truck: , square: , users: , shield: , }; type SidebarProps = { userRole?: string | null; }; export default function AdminSidebar({ userRole }: SidebarProps) { const pathname = usePathname(); const router = useRouter(); const [mobileOpen, setMobileOpen] = useState(false); const [isClosing, setIsClosing] = useState(false); const sidebarRef = useRef(null); const mobileMenuRef = useRef(null); const closeButtonRef = useRef(null); const roleLabel = userRole === "platform_admin" ? "Platform Admin" : userRole === "brand_admin" ? "Brand Admin" : userRole === "store_employee" ? "Store Employee" : null; const isActive = useCallback((href: string) => { if (href === "/admin") return pathname === "/admin"; return pathname.startsWith(href); }, [pathname]); // Close mobile menu with animation const closeMobileMenu = useCallback(() => { setIsClosing(true); setTimeout(() => { setMobileOpen(false); setIsClosing(false); }, 200); }, []); // Handle escape key useEffect(() => { const handleEscape = (e: globalThis.KeyboardEvent) => { if (e.key === "Escape" && mobileOpen) { closeMobileMenu(); } }; document.addEventListener("keydown", handleEscape); return () => document.removeEventListener("keydown", handleEscape); }, [mobileOpen, closeMobileMenu]); // Focus trap and body scroll lock useEffect(() => { if (mobileOpen) { document.body.style.overflow = "hidden"; // Focus close button after animation setTimeout(() => { closeButtonRef.current?.focus(); }, 100); } else { document.body.style.overflow = ""; } return () => { document.body.style.overflow = ""; }; }, [mobileOpen]); // Keyboard navigation for nav items const handleNavKeyDown = useCallback((e: KeyboardEvent, href: string, index: number) => { const navLinks = NAV_ITEMS.filter(item => !item.divider); if (e.key === "ArrowDown") { e.preventDefault(); const nextIndex = (index + 1) % navLinks.length; const nextLink = document.querySelector(`[data-nav-index="${nextIndex}"]`) as HTMLAnchorElement; nextLink?.focus(); } else if (e.key === "ArrowUp") { e.preventDefault(); const prevIndex = index === 0 ? navLinks.length - 1 : index - 1; const prevLink = document.querySelector(`[data-nav-index="${prevIndex}"]`) as HTMLAnchorElement; prevLink?.focus(); } else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); router.push(href); if (mobileOpen) closeMobileMenu(); } }, [router, mobileOpen, closeMobileMenu]); async function handleLogout() { document.cookie = "dev_session=;path=/;max-age=0"; await authClient.signOut(); router.push("/login"); router.refresh(); } return ( <> {/* Mobile hamburger button - accessible */} {/* Mobile overlay backdrop with blur */} {mobileOpen && (