"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 { supabase } from "@/lib/supabase";
// 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 supabase.auth.signOut();
router.push("/login");
router.refresh();
}
return (
<>
{/* Mobile hamburger button - accessible */}
{/* Mobile overlay backdrop with blur */}
{mobileOpen && (
)}
{/* Sidebar panel - Elegant warm dark with smooth transitions */}
>
);
}