//============================================= // File: Statistiche.tsx // Componente per la gestione delle statistiche // da parte dei Referenti Academy // @author: "villari.andrea@libero.it" // @version: "1.0.0 2026-07-14" //============================================= import { useCallback, useEffect, useMemo, useState } from "react"; import { AlertCircle, BarChart3, Filter } from "lucide-react"; import { getCorsi, getStatisticheAcademy, getUtenti } from "@/api/client"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Skeleton } from "@/components/ui/skeleton"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import type { StatisticaAcademy, Utente } from "@/types"; const ALL_VALUE = "__all__"; function currentMonth(): string { return new Date().toISOString().slice(0, 7); } function formatMeseIt(mese: string): string { const [year, month] = mese.split("-"); if (!year || !month) return mese; const date = new Date(Number(year), Number(month) - 1, 1); return date.toLocaleDateString("it-IT", { month: "long", year: "numeric" }); } function dipendenteLabel(utente: Pick) { return `${utente.cognome} ${utente.nome}`; } function TableSkeleton() { return (
{Array.from({ length: 5 }).map((_, index) => ( ))}
); } function SummaryCard({ title, value, description, }: { title: string; value: string | number; description: string; }) { return ( {title}

{value}

{description}

); } export default function Statistiche() { const [statistiche, setStatistiche] = useState([]); const [categorie, setCategorie] = useState([]); const [dipendenti, setDipendenti] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [meseFilter, setMeseFilter] = useState(currentMonth()); const [categoriaFilter, setCategoriaFilter] = useState(ALL_VALUE); const [dipendenteFilter, setDipendenteFilter] = useState(ALL_VALUE); useEffect(() => { Promise.all([getCorsi(), getUtenti({ ruolo: "Dipendente" })]) .then(([corsi, dipendentiData]) => { const values = new Set(corsi.map((c) => c.categoria)); setCategorie(Array.from(values).sort()); setDipendenti(dipendentiData); }) .catch(() => { /* i filtri possono restare vuoti */ }); }, []); const loadStatistiche = useCallback(async () => { setLoading(true); setError(null); try { const data = await getStatisticheAcademy({ mese: meseFilter || undefined, categoria: categoriaFilter === ALL_VALUE ? undefined : categoriaFilter, dipendenteId: dipendenteFilter === ALL_VALUE ? undefined : Number(dipendenteFilter), }); setStatistiche(data); } catch (err) { setError(err instanceof Error ? err.message : "Errore nel caricamento"); } finally { setLoading(false); } }, [meseFilter, categoriaFilter, dipendenteFilter]); useEffect(() => { loadStatistiche(); }, [loadStatistiche]); const totali = useMemo(() => { const assegnazioni = statistiche.reduce( (sum, row) => sum + row.numeroAssegnazioni, 0 ); const completamenti = statistiche.reduce( (sum, row) => sum + row.numeroCompletamenti, 0 ); const percentuale = assegnazioni === 0 ? 0 : Math.round((completamenti / assegnazioni) * 10000) / 100; return { assegnazioni, completamenti, percentuale }; }, [statistiche]); const dipendenteSelezionato = dipendenti.find( (d) => String(d.id) === dipendenteFilter ); return (

Statistiche

Riepiloghi formativi aggregati per mese e categoria. Le assegnazioni annullate sono escluse dal conteggio.

{error && ( {error} )} Filtri Filtra per mese di assegnazione, categoria o dipendente.
setMeseFilter(e.target.value)} className="w-44" />
{!loading && statistiche.length > 0 && (
)} {loading ? "Caricamento..." : `${statistiche.length} righe di riepilogo`} {meseFilter && ( Dati per {formatMeseIt(meseFilter)} {categoriaFilter !== ALL_VALUE && ` · ${categoriaFilter}`} {dipendenteSelezionato && ` · ${dipendenteLabel(dipendenteSelezionato)}`} )} {loading ? ( ) : statistiche.length === 0 ? (

Nessun dato disponibile per i filtri selezionati.

) : ( Mese Categoria Assegnazioni Completamenti Completamento {statistiche.map((row) => ( {formatMeseIt(row.mese)} {row.categoria} {row.numeroAssegnazioni} {row.numeroCompletamenti} {row.percentualeCompletamento}% ))}
)}
); }