"use client"; import * as React from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { Activity, Award, BarChart3, Coins, FlaskConical, Gamepad2, Gift, HeartPulse, LayoutDashboard, LogOut, Menu, Settings, ShieldAlert, Target, Users, UsersRound, X } from "lucide-react"; import { SpinzaMark } from "@/components/brand/logo"; import { cn } from "@/lib/utils"; import { useAdmin } from "./store"; import { Pill } from "./primitives"; interface NavItem { href: string; label: string; icon: React.ComponentType<{ className?: string }>; } const SECTIONS: { title: string; items: NavItem[] }[] = [ { title: "Overview", items: [{ href: "/admin", label: "Dashboard", icon: LayoutDashboard }] }, { title: "Operations", items: [ { href: "/admin/users", label: "Users", icon: Users }, { href: "/admin/games", label: "Games", icon: Gamepad2 }, { href: "/admin/simulator", label: "Game Simulator", icon: FlaskConical }, ], }, { title: "Insights", items: [ { href: "/admin/economy", label: "Economy", icon: Coins }, { href: "/admin/analytics/games", label: "Game Analytics", icon: BarChart3 }, { href: "/admin/analytics/players", label: "Player Analytics", icon: UsersRound }, ], }, { title: "Progression", items: [ { href: "/admin/missions", label: "Missions", icon: Target }, { href: "/admin/achievements", label: "Achievements", icon: Award }, { href: "/admin/rewards", label: "Daily Rewards", icon: Gift }, ], }, { title: "Platform", items: [ { href: "/admin/system", label: "System Health", icon: HeartPulse }, { href: "/admin/security", label: "Security", icon: ShieldAlert }, { href: "/admin/settings", label: "Settings", icon: Settings }, ], }, ]; const ALL_ITEMS = SECTIONS.flatMap((s) => s.items); function isActive(path: string, href: string) { return href === "/admin" ? path === "/admin" : path === href || path.startsWith(href + "/"); } function currentTitle(path: string): string { const hit = ALL_ITEMS.filter((i) => isActive(path, i.href)).sort((a, b) => b.href.length - a.href.length)[0]; if (!hit) return "Admin"; if (path.startsWith("/admin/users/") && path !== "/admin/users") return "User detail"; if (path.startsWith("/admin/games/") && path !== "/admin/games") return "Game detail"; return hit.label; } export function AdminShell({ children }: { children: React.ReactNode }) { const path = usePathname() ?? "/admin"; const [open, setOpen] = React.useState(false); const admin = useAdmin((s) => s.admin); const maintenance = useAdmin((s) => s.maintenance); const node = useAdmin((s) => s.node); const version = useAdmin((s) => s.version); const signOut = useAdmin((s) => s.signOut); const loadStatus = useAdmin((s) => s.loadStatus); React.useEffect(() => { const t = setInterval(() => { if (document.visibilityState === "visible") void loadStatus(); }, 60_000); return () => clearInterval(t); }, [loadStatus]); const nav = ( ); return (
{/* Sidebar (desktop) */} {/* Mobile drawer */} {open ? (
setOpen(false)} />
SPINZA Admin
{nav}
) : null}
{currentTitle(path)}
{maintenance ? ( maintenance.enabled ? ( Maintenance ) : ( Live ) ) : ( … )} {node ?? "—"} · v{version ?? "—"} {admin?.username.slice(0, 1).toUpperCase()} {admin?.username} {admin?.role}
{children}
); }