diff --git a/client/src/pages/Admin.tsx b/client/src/pages/Admin.tsx index 614a545..15becd1 100644 --- a/client/src/pages/Admin.tsx +++ b/client/src/pages/Admin.tsx @@ -1,7 +1,7 @@ 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 } from "lucide-react"; +import { GraduationCap, Calendar, Users, CheckCircle, PieChart as PieChartIcon, Building2 } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from "recharts"; import { useMemo } from "react"; @@ -26,6 +26,28 @@ export default function Admin() { ].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 = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899", "#06b6d4", "#84cc16", "#f97316", "#6366f1"]; + + 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", @@ -83,34 +105,36 @@ export default function Admin() { ))} - {/* 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} + {/* Graphiques de répartition */} +
+ {/* 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" > @@ -128,6 +152,52 @@ export default function Admin() { )} + {/* 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" + > + {statsEtablissement.map((entry, index) => ( + + ))} + + + + + +
+ )} +
+
+ )} +
+ Bienvenue dans l'espace d'administration diff --git a/todo.md b/todo.md index 1c605e8..ff94bf1 100644 --- a/todo.md +++ b/todo.md @@ -535,3 +535,8 @@ - [x] Identifier la source de l'incohérence entre tableau de bord principal et analytique - [x] Uniformiser les calculs de répartition par fonction - [x] Vérifier la cohérence des données affichées + +## Ajout graphique répartition par établissement + +- [x] Ajouter le graphique de répartition par établissement sur le tableau de bord principal +- [x] Placer le graphique à côté du graphique par fonction