"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { Flag, FolderClosed, LayoutGrid, LogOut, MessageSquare, Users, } from "lucide-react"; import { api, type Me } from "@/lib/api"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { ConfirmProvider } from "@/components/confirm"; const NAV = [ { href: "/users", label: "Users", icon: Users }, { href: "/posts", label: "Posts", icon: LayoutGrid }, { href: "/collections", label: "Collections", icon: FolderClosed }, { href: "/feedback", label: "Feedback", icon: MessageSquare }, { href: "/reports", label: "Reports", icon: Flag }, ]; export default function DashboardLayout({ children, }: { children: React.ReactNode; }) { const router = useRouter(); const pathname = usePathname(); const [me, setMe] = useState(null); const [checked, setChecked] = useState(false); // Admin gate: only an authenticated admin may see the dashboard. Anyone // else is bounced to /login. The BFF independently enforces this on every // /admin/* call, so this is UX, not the security boundary. useEffect(() => { let cancelled = false; api .me() .then((u) => { if (cancelled) return; if (!u || u.role !== "admin") { router.replace("/login"); return; } setMe(u); setChecked(true); }) .catch(() => { if (!cancelled) router.replace("/login"); }); return () => { cancelled = true; }; }, [router]); async function signOut() { await api.logout().catch(() => {}); router.replace("/login"); } if (!checked || !me) { return (
Loading…
); } return (
{children}
); }