- Replace ADMIN_SECRET query param with proper Supabase auth + is_admin flag - Add admin layout with auth check (redirects non-admin to /) - Add AdminShell component with sidebar navigation (Dashboard, Candidatures, Cours) - Add admin dashboard with stats (candidatures, users, modules) - Add admin candidatures page with filters and approve/reject - Add admin course management page (create, edit, delete, publish/unpublish) - Add API routes: GET/POST /api/admin/modules, GET/PUT/DELETE /api/admin/modules/[id] - Add verifyAdmin() helper for API route protection - Update database types with is_admin on profiles https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
47 lines
1.1 KiB
TypeScript
47 lines
1.1 KiB
TypeScript
import { redirect } from "next/navigation";
|
|
import { createClient, createAdminClient } from "@/lib/supabase/server";
|
|
import AdminShell from "@/components/admin/AdminShell";
|
|
import type { Profile } from "@/types/database.types";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
export default async function AdminLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const supabase = await createClient();
|
|
|
|
// Vérifier l'authentification
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser();
|
|
|
|
if (!user) {
|
|
redirect("/login?redirect=/admin");
|
|
}
|
|
|
|
// Vérifier le statut admin via service role (pas de RLS)
|
|
const adminClient = createAdminClient();
|
|
const { data: profile } = await adminClient
|
|
.from("profiles")
|
|
.select("*")
|
|
.eq("id", user.id)
|
|
.single();
|
|
|
|
const typedProfile = profile as Profile | null;
|
|
|
|
if (!typedProfile || !typedProfile.is_admin) {
|
|
redirect("/");
|
|
}
|
|
|
|
return (
|
|
<AdminShell
|
|
adminName={typedProfile.full_name || "Admin"}
|
|
adminEmail={typedProfile.email}
|
|
>
|
|
{children}
|
|
</AdminShell>
|
|
);
|
|
}
|