import DashboardLayout from "@/components/DashboardLayout"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { trpc } from "@/lib/trpc"; import { GraduationCap, Calendar, Users, CheckCircle, PieChart as PieChartIcon, Building2, TrendingUp } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from "recharts"; import { useMemo } from "react"; export default function Admin() { const { data: formations, isLoading: loadingFormations } = trpc.formations.list.useQuery(); const { data: sequences, isLoading: loadingSessions } = trpc.sequences.list.useQuery(); const { data: apprenants, isLoading: loadingApprenants } = trpc.apprenants.list.useQuery(); // Statistiques par fonction const statsFonction = useMemo(() => { if (!apprenants) return []; const directeurs = apprenants.filter(a => a.fonction === "directeur").length; const chefsService = apprenants.filter(a => a.fonction === "chef_service").length; const autres = apprenants.filter(a => a.fonction === "autre").length; return [ { name: "Directeurs", value: directeurs, color: "#93c5fd" }, { name: "Chefs de service", value: chefsService, color: "#6ee7b7" }, { name: "Autres", value: autres, color: "#fcd34d" }, ].filter(item => item.value > 0); }, [apprenants]); // Statistiques par établissement const statsEtablissement = useMemo(() => { if (!apprenants) return []; const etablissementCounts: Record = {}; apprenants.forEach(a => { const code = a.codeEtablissement || "Non renseigné"; etablissementCounts[code] = (etablissementCounts[code] || 0) + 1; }); const colors = ["#93c5fd", "#6ee7b7", "#fcd34d", "#fca5a5", "#c4b5fd", "#f9a8d4", "#67e8f9", "#bef264", "#fdba74", "#a5b4fc"]; return Object.entries(etablissementCounts) .map(([name, value], index) => ({ name, value, color: colors[index % colors.length], })) .sort((a, b) => b.value - a.value) .slice(0, 10); // Top 10 établissements }, [apprenants]); const stats = [ { title: "Formations actives", value: formations?.filter(f => f.actif).length || 0, icon: GraduationCap, gradient: "from-blue-300 to-blue-400", borderColor: "border-l-blue-400", bgColor: "bg-blue-50/80", iconBg: "bg-gradient-to-br from-blue-300 to-blue-400", loading: loadingFormations, }, { title: "Séquences ouvertes", value: sequences?.filter(s => s.statut === "ouverte").length || 0, icon: Calendar, gradient: "from-green-300 to-emerald-400", borderColor: "border-l-green-400", bgColor: "bg-green-50/80", iconBg: "bg-gradient-to-br from-green-300 to-emerald-400", loading: loadingSessions, }, { title: "Apprenants inscrits", value: apprenants?.length || 0, icon: Users, gradient: "from-purple-300 to-purple-400", borderColor: "border-l-purple-400", bgColor: "bg-purple-50/80", iconBg: "bg-gradient-to-br from-purple-300 to-purple-400", loading: loadingApprenants, }, { title: "Séquences terminées", value: sequences?.filter(s => s.statut === "terminee").length || 0, icon: CheckCircle, gradient: "from-orange-300 to-orange-400", borderColor: "border-l-orange-400", bgColor: "bg-orange-50/80", iconBg: "bg-gradient-to-br from-orange-300 to-orange-400", loading: loadingSessions, }, ]; return (

Tableau de bord

Gestion des formations Manager Itinova

Données en temps réel
{/* Cartes de statistiques avec animations */}
{stats.map((stat, index) => { const Icon = stat.icon; return ( {stat.title}
{stat.loading ? ( ) : (
{stat.value}
Actif
)}
{/* Effet de brillance au survol */}
); })}
{/* Graphiques de répartition avec animations */}
{/* Graphique de répartition par fonction */} {statsFonction.length > 0 && (
Répartition des apprenants par fonction
Distribution des {apprenants?.length || 0} apprenants selon leur fonction
{loadingApprenants ? (
) : (
`${name}: ${(percent * 100).toFixed(0)}%`} outerRadius={100} fill="#8884d8" dataKey="value" animationBegin={0} animationDuration={800} > {statsFonction.map((entry, index) => ( ))}
)}
)} {/* Graphique de répartition par établissement */} {statsEtablissement.length > 0 && (
Répartition des apprenants par établissement
Top 10 des établissements avec le plus d'apprenants
{loadingApprenants ? (
) : (
`${name}: ${(percent * 100).toFixed(0)}%`} outerRadius={100} fill="#8884d8" dataKey="value" animationBegin={0} animationDuration={800} > {statsEtablissement.map((entry, index) => ( ))}
)}
)}
); }