146 lines
4.2 KiB
TypeScript
146 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import type React from "react";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { usePathname, useRouter } from "next/navigation";
|
|
import AdminLeftNavigation, {
|
|
type AdminNavGroup,
|
|
} from "@/components/AdminLeftNavigation";
|
|
import { useAuth } from "@/context/AuthContext";
|
|
import {
|
|
LayoutDashboard,
|
|
Download,
|
|
Layers,
|
|
Boxes,
|
|
Store,
|
|
Users,
|
|
Settings,
|
|
Mail,
|
|
Wand2,
|
|
FolderKanban,
|
|
Shield,
|
|
} from "lucide-react";
|
|
|
|
const navGroups: AdminNavGroup[] = [
|
|
{
|
|
label: "Overview",
|
|
icon: <LayoutDashboard className="h-4 w-4" />,
|
|
items: [{ label: "Dashboard", href: "/admin", icon: <LayoutDashboard className="h-4 w-4" /> }],
|
|
},
|
|
{
|
|
label: "Catalog",
|
|
icon: <FolderKanban className="h-4 w-4" />,
|
|
items: [
|
|
{ label: "Products", href: "/admin/products", icon: <Boxes className="h-4 w-4" /> },
|
|
{ label: "Platforms", href: "/admin/platforms", icon: <Layers className="h-4 w-4" /> },
|
|
],
|
|
},
|
|
{
|
|
label: "Data Ops",
|
|
icon: <Download className="h-4 w-4" />,
|
|
items: [
|
|
{ label: "Imports", href: "/admin/import-status", icon: <Download className="h-4 w-4" /> },
|
|
{ label: "Mappings", href: "/admin/mapping", icon: <Layers className="h-4 w-4" /> },
|
|
{ label: "Enrichment", href: "/admin/enrichment", icon: <Wand2 className="h-4 w-4" /> },
|
|
],
|
|
},
|
|
{
|
|
label: "Growth & Comms",
|
|
icon: <Mail className="h-4 w-4" />,
|
|
items: [
|
|
{ label: "Beta Invites", href: "/admin/beta-invites", icon: <Mail className="h-4 w-4" /> },
|
|
{ label: "List Emails", href: "/admin/email", icon: <Mail className="h-4 w-4" /> },
|
|
{ label: "Send an Email", href: "/admin/email/send", icon: <Mail className="h-4 w-4" /> },
|
|
],
|
|
},
|
|
{
|
|
label: "Access & Config",
|
|
icon: <Shield className="h-4 w-4" />,
|
|
items: [
|
|
{ label: "Users", href: "/admin/users", icon: <Users className="h-4 w-4" /> },
|
|
{ label: "Merchants", href: "/admin/merchants", icon: <Store className="h-4 w-4" /> },
|
|
{ label: "Settings", href: "/admin/settings", icon: <Settings className="h-4 w-4" /> },
|
|
],
|
|
},
|
|
];
|
|
|
|
export default function AdminLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
const { user, loading } = useAuth();
|
|
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
|
|
// Where to send people back after login
|
|
const next = useMemo(
|
|
() => encodeURIComponent(pathname || "/admin"),
|
|
[pathname]
|
|
);
|
|
|
|
/**
|
|
* ✅ AUTH GUARD
|
|
* Redirects happen in useEffect (NOT during render)
|
|
*/
|
|
useEffect(() => {
|
|
if (loading) return;
|
|
|
|
// Not logged in
|
|
if (!user) {
|
|
router.replace(`/login?next=${next}`);
|
|
return;
|
|
}
|
|
|
|
// Logged in but not admin
|
|
if (user.role !== "ADMIN") {
|
|
router.replace("/");
|
|
}
|
|
}, [loading, user, router, next]);
|
|
|
|
// While loading OR redirecting, render nothing
|
|
if (loading) return null;
|
|
if (!user) return null;
|
|
if (user.role !== "ADMIN") return null;
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-black text-zinc-50">
|
|
<AdminLeftNavigation
|
|
collapsed={collapsed}
|
|
onToggleCollapsed={() => setCollapsed((v) => !v)}
|
|
groups={navGroups}
|
|
/>
|
|
|
|
{/* Main column */}
|
|
<div className="flex min-h-screen flex-1 flex-col">
|
|
{/* Top bar */}
|
|
<header className="flex items-center justify-between border-b border-zinc-900 bg-zinc-950/70 px-4 py-3">
|
|
<div>
|
|
<p className="text-xs uppercase tracking-[0.18em] text-zinc-500">
|
|
Admin
|
|
</p>
|
|
<p className="text-sm text-zinc-200">
|
|
Battl Builders Control Panel
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3">
|
|
<span className="rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] font-medium text-amber-300">
|
|
Internal • v0.1
|
|
</span>
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-zinc-900 text-[11px] text-zinc-300">
|
|
ADMIN
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Content */}
|
|
<main className="mx-auto flex w-full max-w-6xl flex-1 flex-col px-4 py-6">
|
|
{children}
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |