import { redirect } from "next/navigation"; import Link from "next/link"; import { headers } from "next/headers"; import { currentUser } from "@/lib/auth/session"; import { pgAvailable } from "@/db/client"; import { Empty } from "@/components/ui"; import { isFreshMfa } from "@/lib/admin/mfa"; export const dynamic = "force-dynamic"; /** Console d'administration applicative : rôle ADMIN/MODERATOR + TOTP récent. Non indexée ; à exposer de préférence via VPN/Tailscale. */ export default async function AdminLayout({ children }: { children: React.ReactNode }) { if (!pgAvailable()) return
; const u = await currentUser(); const path = (await headers()).get("x-pathname") ?? "/admin"; if (!u) redirect(`/connexion?next=${encodeURIComponent(path)}`); if (!u.roles.includes("ADMIN") && !u.roles.includes("MODERATOR")) redirect("/membre"); const fresh = isFreshMfa(u.mfaAt); if (!fresh && !path.startsWith("/admin/mfa")) redirect(`/admin/mfa?next=${encodeURIComponent(path)}`); const nav = [["/admin", "Tableau de bord"], ["/admin/annonces", "Annonces à vérifier"], ["/admin/signalements", "Signalements"], ...(u.roles.includes("ADMIN") ? [["/admin/utilisateurs", "Utilisateurs"]] : []), ["/admin/journal", "Journal d'audit"]]; return (
Administration{u.email} · {u.roles.join(", ")}{fresh ? " · TOTP ✓" : ""}
{children}
); }