Checkpoint: Implémentation des trois améliorations demandées : ajout de filtres par fonction sur les pages apprenants et inscrits, création d'un graphique circulaire de répartition par fonction sur le tableau de bord avec recharts, et personnalisation des templates d'emails (confirmation, teaser, rappel J-7) incluant la fonction de l'apprenant dans la salutation.
This commit is contained in:
@@ -1,14 +1,31 @@
|
||||
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 } from "lucide-react";
|
||||
import { GraduationCap, Calendar, Users, CheckCircle, PieChart as PieChartIcon } 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: sessions, isLoading: loadingSessions } = trpc.sessions.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: "#3b82f6" },
|
||||
{ name: "Chefs de service", value: chefsService, color: "#10b981" },
|
||||
{ name: "Autres", value: autres, color: "#f59e0b" },
|
||||
].filter(item => item.value > 0);
|
||||
}, [apprenants]);
|
||||
|
||||
const stats = [
|
||||
{
|
||||
title: "Formations actives",
|
||||
@@ -66,6 +83,51 @@ export default function Admin() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Graphique de répartition par fonction */}
|
||||
{statsFonction.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<PieChartIcon className="w-5 h-5" />
|
||||
Répartition des apprenants par fonction
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Distribution des {apprenants?.length || 0} apprenants selon leur fonction
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loadingApprenants ? (
|
||||
<div className="h-80 flex items-center justify-center">
|
||||
<Skeleton className="h-64 w-64 rounded-full" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-80">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<PieChart>
|
||||
<Pie
|
||||
data={statsFonction}
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
labelLine={false}
|
||||
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
|
||||
outerRadius={100}
|
||||
fill="#8884d8"
|
||||
dataKey="value"
|
||||
>
|
||||
{statsFonction.map((entry, index) => (
|
||||
<Cell key={`cell-${index}`} fill={entry.color} />
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Bienvenue dans l'espace d'administration</CardTitle>
|
||||
|
||||
Reference in New Issue
Block a user