MIGRATION VERS GITEA

This commit is contained in:
mathis committed 2026-08-25 01:23:13 +02:00
commit 5f9d991c15
333 files changed
+108514

No files matched your search

+339
View File
@@ -0,0 +1,339 @@
import React, { useEffect, useState, useCallback } from 'react';
import { getAllHoraires } from '../../api/horaires';
import { getAllPerturbations } from '../../api/perturbations';
import { getCurrentUser, getScopedRegionId } from '../../utils/userUtils';
import './Dashboard.css';
export default function Dashboard() {
// État des statistiques
const [stats, setStats] = useState({
horaires: { total: 0, actifs: 0 },
perturbations: { total: 0, actives: 0, retards: 0, suppressions: 0 },
gares: { total: 0 },
lignes: { total: 0 },
typesTrains: { total: 0 }
});
// État du chargement
const [loading, setLoading] = useState(true);
// Perturbations récentes
const [recentPerturbations, setRecentPerturbations] = useState([]);
// Horaires récents
const [recentHoraires, setRecentHoraires] = useState([]);
const [scopedRegionId, setScopedRegionId] = useState(null);
// Fonction de chargement des données
const loadDashboardData = useCallback(async () => {
setLoading(true);
try {
const user = getCurrentUser();
const regionId = getScopedRegionId(user);
setScopedRegionId(regionId || null);
// Charger les horaires
const { data: horairesData } = await getAllHoraires(regionId);
const horaires = horairesData || [];
// Charger les perturbations
const { data: perturbationsData } = await getAllPerturbations(regionId);
const perturbations = perturbationsData || [];
// Calculer les statistiques des horaires
const horaireStats = {
total: horaires.length,
actifs: horaires.length
};
// Calculer les statistiques des perturbations
const perturbationStats = {
total: perturbations.length,
actives: perturbations.filter(p => p.actif).length,
retards: perturbations.filter(p => p.type_perturbation === 'retard').length,
suppressions: perturbations.filter(p => p.type_perturbation === 'suppression').length
};
// Extraire les gares uniques
const garesSet = new Set();
horaires.forEach(h => {
if (h.gare_depart_nom) garesSet.add(h.gare_depart_nom);
if (h.gare_arrivee_nom) garesSet.add(h.gare_arrivee_nom);
if (h.gares_desservies) {
h.gares_desservies.forEach(g => {
if (g.gare_nom) garesSet.add(g.gare_nom);
});
}
});
// Extraire les lignes uniques
const lignesSet = new Set();
horaires.forEach(h => {
if (h.ligne_nom) lignesSet.add(h.ligne_nom);
});
// Extraire les types de trains uniques
const typesTrainsSet = new Set();
horaires.forEach(h => {
if (h.type_train) typesTrainsSet.add(h.type_train);
});
// Mettre à jour les stats
setStats({
horaires: horaireStats,
perturbations: perturbationStats,
gares: { total: garesSet.size },
lignes: { total: lignesSet.size },
typesTrains: { total: typesTrainsSet.size }
});
// Perturbations récentes (5 dernières)
setRecentPerturbations(perturbations.slice(0, 5));
// Horaires récents (5 derniers)
setRecentHoraires(horaires.slice(0, 5));
} catch (error) {
console.error('Erreur lors du chargement du dashboard:', error);
} finally {
setLoading(false);
}
}, []);
// Charger les données au montage
useEffect(() => {
loadDashboardData();
}, [loadDashboardData]);
// Fonction pour formater les heures
const formatHeure = (heure) => {
if (!heure) return '—';
return heure.substring(0, 5);
};
const navigate = (path) => {
window.location.href = path;
};
// Rendu des cartes de statistiques
const renderStatCard = (title, value, icon, color = 'primary', subtitle = null) => (
<div className={`stat-card stat-card-${color}`}>
<div className="stat-card-header">
<div className="stat-card-icon-wrap">
<wcs-mat-icon icon={icon}></wcs-mat-icon>
</div>
<div className="stat-card-content">
<span className="stat-card-title">{title}</span>
<span className="stat-card-value">{loading ? '...' : value}</span>
{subtitle && <span className="stat-card-subtitle">{subtitle}</span>}
</div>
</div>
</div>
);
// Rendu de la liste des perturbations récentes
const renderRecentPerturbations = () => (
<div className="dashboard-widget widget-panel">
<div className="widget-header widget-header-panel">
<h3>
<span className="widget-title-icon"><wcs-mat-icon icon="warning"></wcs-mat-icon></span>
Perturbations récentes
</h3>
<wcs-button
className="wcs-secondary wcs-small widget-link-btn"
onClick={() => navigate('/perturbations')}
>
Voir tout
</wcs-button>
</div>
<div className="widget-content widget-content-panel">
{loading ? (
<div className="dashboard-state widget-state-panel">
<wcs-spinner mode="border" />
<p>Chargement...</p>
</div>
) : recentPerturbations.length === 0 ? (
<div className="dashboard-state dashboard-state-empty widget-state-panel">
<wcs-mat-icon className="dashboard-state-icon" icon="check_circle"></wcs-mat-icon>
<p>Aucune perturbation</p>
</div>
) : (
<div className="perturbations-list widget-list-panel">
{recentPerturbations.map(p => (
<div key={p.id} className="perturbation-item widget-list-item">
<div className="perturbation-item-header widget-item-main">
<div className="widget-item-text">
<strong>{p.horaire?.numero_train || 'N/A'}</strong>
<span className="perturbation-item-route">
{p.horaire?.gare_depart_nom} → {p.horaire?.gare_arrivee_nom}
</span>
</div>
<wcs-badge className={
p.type_perturbation === 'retard' ? 'wcs-warning' :
p.type_perturbation === 'suppression' ? 'wcs-danger' :
'wcs-info'
}>
{p.type_perturbation === 'retard' ? `Retard +${p.duree_retard_minutes || 0} min` :
p.type_perturbation === 'suppression' ? 'Supprime' :
'Modifié'}
</wcs-badge>
</div>
<div className="perturbation-item-details">
<span>
<wcs-mat-icon icon="info"></wcs-mat-icon>
{p.cause || 'Non spécifiée'}
</span>
<span className={p.actif ? 'status-active' : 'status-inactive'}>
{p.actif ? '● Active' : '○ Inactive'}
</span>
</div>
</div>
))}
</div>
)}
</div>
</div>
);
// Rendu de la liste des horaires récents
const renderRecentHoraires = () => (
<div className="dashboard-widget widget-panel">
<div className="widget-header widget-header-panel">
<h3>
<span className="widget-title-icon"><wcs-mat-icon icon="schedule"></wcs-mat-icon></span>
Horaires récents
</h3>
<wcs-button
className="wcs-secondary wcs-small widget-link-btn"
onClick={() => navigate('/horaires')}
>
Voir tout
</wcs-button>
</div>
<div className="widget-content widget-content-panel">
{loading ? (
<div className="dashboard-state widget-state-panel">
<wcs-spinner mode="border" />
<p>Chargement...</p>
</div>
) : recentHoraires.length === 0 ? (
<div className="dashboard-state dashboard-state-empty widget-state-panel">
<wcs-mat-icon className="dashboard-state-icon" icon="train"></wcs-mat-icon>
<p>Aucun horaire</p>
</div>
) : (
<div className="horaires-list widget-list-panel">
{recentHoraires.map(h => (
<div key={h.id} className="horaire-item widget-list-item">
<div className="horaire-item-header widget-item-main">
<div className="widget-item-text">
<strong>{h.numero_train}</strong>
{h.type_train && (
<wcs-badge className="wcs-info horaire-type-badge">
{h.type_train}
</wcs-badge>
)}
</div>
{h.ligne_nom && (
<wcs-badge className="wcs-secondary">{h.ligne_nom}</wcs-badge>
)}
</div>
<div className="horaire-item-route">
<span>
{h.gare_depart_nom} ({formatHeure(h.heure_depart)})
</span>
<wcs-mat-icon icon="arrow_forward"></wcs-mat-icon>
<span>
{h.gare_arrivee_nom} ({formatHeure(h.heure_arrivee)})
</span>
</div>
</div>
))}
</div>
)}
</div>
</div>
);
// Rendu des actions rapides
const renderQuickActions = () => (
<div className="dashboard-widget widget-panel">
<div className="widget-header widget-header-panel">
<h3>
<span className="widget-title-icon"><wcs-mat-icon icon="bolt"></wcs-mat-icon></span>
Actions rapides
</h3>
</div>
<div className="widget-content widget-content-panel">
<div className="quick-actions">
<a className="quick-action-row" href="/perturbations/creer">
<span className="quick-action-row-left">
<span className="quick-action-icon"><wcs-mat-icon icon="add"></wcs-mat-icon></span>
<span>Créer une perturbation</span>
</span>
<wcs-mat-icon icon="arrow_forward"></wcs-mat-icon>
</a>
<a className="quick-action-row" href="/horaires">
<span className="quick-action-row-left">
<span className="quick-action-icon"><wcs-mat-icon icon="schedule"></wcs-mat-icon></span>
<span>Gérer les horaires</span>
</span>
<wcs-mat-icon icon="arrow_forward"></wcs-mat-icon>
</a>
<a className="quick-action-row" href="/gares">
<span className="quick-action-row-left">
<span className="quick-action-icon"><wcs-mat-icon icon="location_on"></wcs-mat-icon></span>
<span>Gérer les gares</span>
</span>
<wcs-mat-icon icon="arrow_forward"></wcs-mat-icon>
</a>
<button className="quick-action-row quick-action-row-refresh" type="button" onClick={loadDashboardData}>
<span className="quick-action-row-left">
<span className="quick-action-icon"><wcs-mat-icon icon="refresh"></wcs-mat-icon></span>
<span>Actualiser les données</span>
</span>
<wcs-mat-icon icon="refresh"></wcs-mat-icon>
</button>
</div>
</div>
</div>
);
return (
<div className="sncf-groupe dashboard-page panel-layout">
<div className="panel-content">
<header className="dashboard-hero">
<div>
<p className="dashboard-kicker">Panel de gestion</p>
<h1>Tableau de bord</h1>
<p className="dashboard-subtitle">Suivez l'activite des horaires, perturbations et donnees d'exploitation en temps reel.</p>
</div>
<div className="dashboard-hero-side">
<wcs-button className="wcs-primary" onClick={loadDashboardData}>
<wcs-mat-icon icon="refresh"></wcs-mat-icon>
Actualiser
</wcs-button>
{scopedRegionId && <p>Region courante : <strong>{scopedRegionId}</strong></p>}
</div>
</header>
<div className="stats-grid">
{renderStatCard('Horaires', stats.horaires.total, 'schedule', 'primary', `${stats.horaires.actifs} actifs`)}
{renderStatCard('Perturbations', stats.perturbations.total, 'warning', 'warning', `${stats.perturbations.actives} actives`)}
{renderStatCard('Gares', stats.gares.total, 'location_on', 'info', 'Desservies')}
{renderStatCard('Lignes', stats.lignes.total, 'route', 'secondary', 'Actives')}
{renderStatCard('Types de trains', stats.typesTrains.total, 'train', 'success', 'Disponibles')}
{renderStatCard('Retards', stats.perturbations.retards, 'schedule', 'warning', 'En cours')}
</div>
<div className="widgets-grid">
<div className="widgets-column">
{renderRecentPerturbations()}
{renderQuickActions()}
</div>
<div className="widgets-column">{renderRecentHoraires()}</div>
</div>
</div>
</div>
);
}