karbe/src/components/admin/StatusBadge.tsx
Claude Integration 9aa0771001 feat(admin): CRUD complet carbets + gestion médias (Sprint 2)
Server actions (src/app/admin/carbets/actions.ts) avec validation Zod :
- createCarbetAction → INSERT + audit + redirect /admin/carbets/[id]
- updateCarbetAction → UPDATE + revalidate page publique
- updateCarbetStatusAction → DRAFT/PUBLISHED/ARCHIVED
- deleteCarbetAction → soft archive (bookings/reviews FK Restrict)
- addMediaAction(carbetId, fd) → INSERT Media + sortOrder
- removeMediaAction, reorderMediaAction (transactionnel up/down)

Helpers (src/lib/admin/carbets.ts) :
- listCarbetsAdmin avec filtres (q/river/status/accessType)
- listDistinctRivers, listOwners, listPirogueProviders
- getCarbetForEdit (include owner, provider, media, _count bookings/reviews)
- Options enum pour les selects (ACCESS_TYPE, TRANSPORT_MODE, STATUS)

Pages :
- /admin/carbets : liste tableau dense avec recherche/filtres GET, status badge,
  liens vers édition, count médias/résas
- /admin/carbets/new : page création avec CarbetForm
- /admin/carbets/[id] : header titre+badge+actions, MediaManager, CarbetForm
  d'édition. Lien public si PUBLISHED.

Composants admin réutilisables :
- StatusBadge (DRAFT/PUBLISHED/ARCHIVED + statuts Booking)
- FormField + inputCls/selectCls/textareaCls
- CarbetForm (client, 5 sections : identité, localisation, accès, séjour,
  publication) avec useTransition + erreur + succès inline
- MediaManager (client, liste + reorder ↑↓ + suppression + ajout par URL)
- StatusActions (client, publier/dépublier/archiver/réactiver avec confirm)

API :
- GET /api/admin/carbets/[id]/media pour refresh client après mutation

Audit léger en log console (JSON structuré) — Sprint 5 ajoutera la table.
2026-05-31 19:51:33 +00:00

31 lines
1 KiB
TypeScript

const TONES = {
draft: "bg-zinc-100 text-zinc-700 ring-zinc-300",
published: "bg-emerald-100 text-emerald-800 ring-emerald-300",
archived: "bg-amber-100 text-amber-800 ring-amber-300",
pending: "bg-sky-100 text-sky-800 ring-sky-300",
confirmed: "bg-emerald-100 text-emerald-800 ring-emerald-300",
cancelled: "bg-rose-100 text-rose-700 ring-rose-300",
completed: "bg-zinc-100 text-zinc-700 ring-zinc-300",
} as const;
const LABELS: Record<string, string> = {
DRAFT: "Brouillon",
PUBLISHED: "Publié",
ARCHIVED: "Archivé",
PENDING: "En attente",
CONFIRMED: "Confirmé",
CANCELLED: "Annulé",
COMPLETED: "Terminé",
};
export function StatusBadge({ status }: { status: string }) {
const key = status.toLowerCase() as keyof typeof TONES;
const tone = TONES[key] ?? TONES.draft;
return (
<span
className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wider ring-1 ring-inset ${tone}`}
>
{LABELS[status] ?? status}
</span>
);
}