"use client"; import { ChevronDown } from "lucide-react"; import { usePathname } from "next/navigation"; import { useTranslations } from "next-intl"; import { useCallback, useEffect, useMemo, useState } from "react"; import { AdminNavLink } from "@/components/admin/admin-nav-link"; import { ADMIN_NAV_GROUPS, type AdminNavItem } from "@/lib/admin-nav"; import { cn } from "@/lib/utils"; const STORAGE_KEY = "admin-nav-collapsed"; function itemIsActive( pathname: string, item: AdminNavItem, ): boolean { if (item.matchExcludePrefixes?.some( (p) => pathname === p || pathname.startsWith(`${p}/`), )) { return false; } if (item.href === "/admin") return pathname === "/admin"; if (item.matchPrefixes?.length) { return item.matchPrefixes.some( (p) => pathname === p || pathname.startsWith(`${p}/`), ); } return pathname === item.href || pathname.startsWith(`${item.href}/`); } function groupHasActive(pathname: string, items: AdminNavItem[]): boolean { return items.some((item) => itemIsActive(pathname, item)); } function readCollapsed(): Record { if (typeof window === "undefined") return {}; try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return {}; const parsed = JSON.parse(raw) as unknown; if (!parsed || typeof parsed !== "object") return {}; return parsed as Record; } catch { return {}; } } export function AdminSidebarNav() { const t = useTranslations("pages.admin.nav"); const pathname = usePathname() ?? ""; const [collapsed, setCollapsed] = useState>({}); const [hydrated, setHydrated] = useState(false); useEffect(() => { setCollapsed(readCollapsed()); setHydrated(true); }, []); // Keep the group that contains the current page open. useEffect(() => { if (!hydrated) return; const activeKeys = ADMIN_NAV_GROUPS.filter((g) => groupHasActive(pathname, g.items), ).map((g) => g.labelKey); if (activeKeys.length === 0) return; setCollapsed((prev) => { let changed = false; const next = { ...prev }; for (const key of activeKeys) { if (next[key]) { next[key] = false; changed = true; } } if (!changed) return prev; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(next)); } catch { /* ignore quota */ } return next; }); }, [pathname, hydrated]); const toggle = useCallback((labelKey: string) => { setCollapsed((prev) => { const next = { ...prev, [labelKey]: !prev[labelKey] }; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(next)); } catch { /* ignore quota */ } return next; }); }, []); const groups = useMemo(() => ADMIN_NAV_GROUPS, []); return ( ); }