import type { ReactNode } from "react"; import { AlertTriangle, Inbox, type LucideIcon } from "lucide-react"; import { cn } from "@/lib/utils"; interface EmptyStateProps { title: ReactNode; description?: ReactNode; icon?: LucideIcon; action?: ReactNode; className?: string; } /** Rien à afficher : dire pourquoi, et quoi faire. */ export function EmptyState({ title, description, icon: Icon = Inbox, action, className }: EmptyStateProps) { return (

{title}

{description &&

{description}

} {action &&
{action}
}
); } interface ErrorStateProps { title?: ReactNode; /** Explication pour l'utilisateur ; le détail technique va dans `detail`. */ description?: ReactNode; /** Message technique, replié par défaut. */ detail?: string; action?: ReactNode; className?: string; } /** Un chargement a échoué : message clair, détail technique replié, action de reprise. */ export function ErrorState({ title = "Les données n'ont pas pu être chargées", description = "Réessayez dans un instant. Si le problème persiste, prévenez un administrateur.", detail, action, className, }: ErrorStateProps) { return (

{title}

{description}

{detail && (
Détail technique
{detail}
)} {action &&
{action}
}
); } export function Skeleton({ className }: { className?: string }) { return
; } /** * Silhouette d'une page pendant son chargement : la mise en page reste visible * et rien ne bloque l'écran (contrairement à l'ancienne fenêtre plein écran). */ export function PageSkeleton({ cards = 0, rows = 8 }: { cards?: number; rows?: number }) { return (
{cards > 0 && (
{Array.from({ length: cards }, (_, i) => )}
)}
{Array.from({ length: rows }, (_, i) => )}
); }