init projet

This commit is contained in:
2026-05-20 10:43:18 +02:00
parent 51f27903bb
commit 9a402b0b34
57 changed files with 5622 additions and 0 deletions
@@ -0,0 +1,147 @@
/* Page principale du dashboard : KPI cards + grille de monitorings */
import { useState, useEffect, useCallback } from 'react';
import { RefreshCw } from 'lucide-react';
import { getDashboard, getDashboardSummary, getServices, getCategories } from '../../services/api';
import MonitoringCard from '../../components/common/MonitoringCard';
import LoadingSpinner from '../../components/common/LoadingSpinner';
import ErrorMessage from '../../components/common/ErrorMessage';
import styles from './Dashboard.module.css';
/* Carte KPI affichant un indicateur clé */
function KpiCard({ label, value, color }) {
return (
<div className={styles.kpiCard}>
<span className={styles.kpiValue} style={{ color }}>{value}</span>
<span className={styles.kpiLabel}>{label}</span>
</div>
);
}
export default function Dashboard() {
const [summary, setSummary] = useState(null);
const [monitorings, setMonitorings] = useState([]);
const [services, setServices] = useState([]);
const [categories, setCategories] = useState([]);
const [filtreService, setFiltreService] = useState('');
const [filtreCategorie, setFiltreCategorie] = useState('');
const [loading, setLoading] = useState(true);
const [erreur, setErreur] = useState('');
/* Chargement initial des filtres */
useEffect(() => {
async function loadFiltres() {
try {
const [svcs, cats] = await Promise.all([getServices(), getCategories()]);
setServices(svcs);
setCategories(cats);
} catch {
/* Non bloquant, les filtres restent vides */
}
}
loadFiltres();
}, []);
/* Chargement des données dashboard */
const loadData = useCallback(async () => {
setLoading(true);
setErreur('');
try {
const [sum, data] = await Promise.all([
getDashboardSummary(),
getDashboard(filtreService, filtreCategorie),
]);
setSummary(sum);
setMonitorings(Array.isArray(data) ? data : []);
} catch (e) {
setErreur(e.message || 'Erreur lors du chargement du dashboard.');
} finally {
setLoading(false);
}
}, [filtreService, filtreCategorie]);
useEffect(() => {
loadData();
}, [loadData]);
return (
<div className={styles.page}>
<div className={styles.pageHeader}>
<h1 className={styles.title}>Dashboard</h1>
<button className={styles.refreshBtn} onClick={loadData} disabled={loading}>
<RefreshCw size={14} className={loading ? styles.spinning : ''} />
Actualiser
</button>
</div>
{/* KPI Cards */}
{summary && (
<div className={styles.kpiGrid}>
<KpiCard
label="Total monitorings"
value={summary.total ?? 0}
color="var(--color-text)"
/>
<KpiCard
label="Sans erreur"
value={summary.ok ?? 0}
color="var(--color-ok)"
/>
<KpiCard
label="En erreur"
value={summary.critical ?? 0}
color="var(--color-primary)"
/>
<KpiCard
label="Total erreurs"
value={summary.total_erreurs ?? 0}
color="var(--color-warning)"
/>
</div>
)}
{/* Filtres */}
<div className={styles.filtres}>
<select
className={styles.select}
value={filtreService}
onChange={e => setFiltreService(e.target.value)}
>
<option value="">Tous les services</option>
{services.map(s => (
<option key={s.id_service} value={s.nom_service}>{s.nom_service}</option>
))}
</select>
<select
className={styles.select}
value={filtreCategorie}
onChange={e => setFiltreCategorie(e.target.value)}
>
<option value="">Toutes les catégories</option>
{categories.map(c => (
<option key={c.id_categorie} value={c.intitule_categorie}>{c.intitule_categorie}</option>
))}
</select>
</div>
{/* Contenu principal */}
{loading ? (
<LoadingSpinner message="Chargement du dashboard..." />
) : erreur ? (
<ErrorMessage message={erreur} onRetry={loadData} />
) : (
<>
{monitorings.length === 0 ? (
<p className={styles.empty}>Aucun monitoring trouvé pour ces filtres.</p>
) : (
<div className={styles.grid}>
{monitorings.map(m => (
<MonitoringCard key={m.id} monitoring={m} />
))}
</div>
)}
</>
)}
</div>
);
}