karbe/src/app/admin/layout.tsx
Claude Integration bcb93c6b29 feat(admin): shell admin + dashboard KPI + recherche ⌘K (Sprint 1)
Layout admin :
- src/app/admin/layout.tsx : route protégée requireRole(ADMIN), sidebar + topbar + breadcrumbs, data-admin sur racine pour theme sobre indépendant du theme public
- Sidebar : 12 sections groupées (Vue d'ensemble, Catalogue, Activité, Membres, Contenu, Système), highlight de la route courante
- TopBar : prompt ⌘K, lien vers site public, email admin
- Breadcrumbs : auto depuis pathname
- CommandPalette : ⌘K / Ctrl K, navigation ↑↓ + Entrée, recherche live debounced 150ms

Dashboard :
- 7 KPI cards avec tone neutral/ok/warn/info (réservations semaine, confirmées 30j, revenus reversés, occupation, nouveaux users, carbets publiés, avis à modérer)
- Section raccourcis fréquents

Theme admin :
- globals.css : [data-admin] override le background+font, neutralise les borders sépia/papier teinté du theme aquarelle, garantit lisibilité permanente

Recherche globale :
- lib/admin/search.ts : query parallèle sur Carbet, User, Booking, ContentPage, PirogueProvider (5 résultats par catégorie, LIKE insensitive)
- api/admin/search?q=… route handler avec requireRole

KPI :
- lib/admin/kpis.ts : 7 métriques live (cache 0), Promise.all, helper formatEur

Pas de dépendance externe ajoutée (cmdk, shadcn) — composants custom Tailwind pour rester léger.
2026-05-31 18:21:50 +00:00

24 lines
942 B
TypeScript

import type { ReactNode } from "react";
import { requireRole } from "@/lib/authorization";
import { UserRole } from "@/generated/prisma/enums";
import { Sidebar } from "@/components/admin/Sidebar";
import { TopBar } from "@/components/admin/TopBar";
import { Breadcrumbs } from "@/components/admin/Breadcrumbs";
import { CommandPalette } from "@/components/admin/CommandPalette";
export const dynamic = "force-dynamic";
export default async function AdminLayout({ children }: { children: ReactNode }) {
const session = await requireRole([UserRole.ADMIN]);
return (
<div data-admin className="flex h-screen w-full overflow-hidden bg-zinc-50">
<Sidebar />
<div className="flex min-w-0 flex-1 flex-col">
<TopBar userEmail={session.user.email ?? ""} />
<Breadcrumbs />
<main className="flex-1 overflow-y-auto px-4 pb-12 pt-3">{children}</main>
</div>
<CommandPalette />
</div>
);
}