import React, { useState, useEffect, useCallback, useRef } from 'react'; import NavPanel from '../../components/nav-panel/NavPanel'; import { createTravaux, getHorairesSubstitution } from '../../api/travaux'; import { getAllLignes } from '../../api/lignes'; import { canPerform, getCurrentUser, getScopedRegionId } from '../../utils/userUtils'; import './Travaux.css'; import RichTextEditor from '../gares/RichTextEditor'; const JOURS_SEMAINE = [ { value: 'lundi', label: 'Lundi', short: 'Lun' }, { value: 'mardi', label: 'Mardi', short: 'Mar' }, { value: 'mercredi', label: 'Mercredi', short: 'Mer' }, { value: 'jeudi', label: 'Jeudi', short: 'Jeu' }, { value: 'vendredi', label: 'Vendredi', short: 'Ven' }, { value: 'samedi', label: 'Samedi', short: 'Sam' }, { value: 'dimanche', label: 'Dimanche', short: 'Dim' } ]; export default function CreerTravaux() { const currentUser = getCurrentUser(); const canCreateTravaux = canPerform(currentUser, 'travaux', 'create'); const [activeTabKey, setActiveTabKey] = useState('general'); const tabsRef = useRef(null); const [titre, setTitre] = useState(''); const [description, setDescription] = useState(''); const [dateDebut, setDateDebut] = useState(''); const [dateFin, setDateFin] = useState(''); const [joursTravaux, setJoursTravaux] = useState(['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']); const [heureDebut, setHeureDebut] = useState('22:00'); const [heureFin, setHeureFin] = useState('06:00'); const [actif, setActif] = useState(true); // Substitutions const [substitutionsActive, setSubstitutionsActive] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [horairesDisponibles, setHorairesDisponibles] = useState([]); const [horairesSelectionnes, setHorairesSelectionnes] = useState([]); const [loadingHoraires, setLoadingHoraires] = useState(false); const [showResults, setShowResults] = useState(false); const [saving, setSaving] = useState(false); const scopedRegionId = getScopedRegionId(getCurrentUser()); const [lignes, setLignes] = useState([]); const [selectedLigneId, setSelectedLigneId] = useState(''); const [loadingLignes, setLoadingLignes] = useState(false); useEffect(() => { const fetchLignes = async () => { setLoadingLignes(true); try { const { data, error } = await getAllLignes(scopedRegionId); if (!error && data) { setLignes(data); } } catch (err) { console.error('Erreur lors du chargement des lignes:', err); } finally { setLoadingLignes(false); } }; fetchLignes(); }, [scopedRegionId]); // Synchronisation des wcs-tabs useEffect(() => { const el = tabsRef.current; if (!el) return; const handleTabChange = (e) => { if (e.detail?.selectedKey) { setActiveTabKey(e.detail.selectedKey); } }; el.addEventListener('wcsChange', handleTabChange); return () => { el.removeEventListener('wcsChange', handleTabChange); }; }, []); const handleSearchHoraires = useCallback(async () => { setLoadingHoraires(true); setShowResults(true); try { const { data, error } = await getHorairesSubstitution(searchQuery, scopedRegionId); if (!error && data) { setHorairesDisponibles(data); } else { setHorairesDisponibles([]); } } catch (err) { setHorairesDisponibles([]); } finally { setLoadingHoraires(false); } }, [searchQuery, scopedRegionId]); const toggleHoraireSelection = (horaire) => { const existe = horairesSelectionnes.find(h => h.id === horaire.id); if (existe) { setHorairesSelectionnes(horairesSelectionnes.filter(h => h.id !== horaire.id)); } else { setHorairesSelectionnes([...horairesSelectionnes, horaire]); } }; const toggleJour = (jour) => { if (joursTravaux.includes(jour)) { setJoursTravaux(joursTravaux.filter(j => j !== jour)); } else { setJoursTravaux([...joursTravaux, jour]); } }; const selectAllDays = () => { setJoursTravaux(JOURS_SEMAINE.map(j => j.value)); }; const selectWeekdays = () => { setJoursTravaux(['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']); }; const selectWeekend = () => { setJoursTravaux(['samedi', 'dimanche']); }; const formatHeure = (heure) => (heure ? heure.substring(0, 5) : '—'); const navigate = (path) => { window.location.href = path; }; const handleCreate = async () => { if (!canCreateTravaux) { alert("Vous n'avez pas les droits pour créer des travaux."); return; } if (!titre.trim() || !dateDebut || !dateFin || joursTravaux.length === 0 || !heureDebut || !heureFin) { alert('Veuillez remplir tous les champs obligatoires (*)'); return; } if (new Date(dateFin) < new Date(dateDebut)) { alert('La date de fin doit être postérieure ou égale à la date de début.'); return; } setSaving(true); try { const payload = { titre, description: description || null, date_debut: dateDebut, date_fin: dateFin, jours_travaux: joursTravaux, heure_debut: heureDebut, heure_fin: heureFin, actif, region_id: scopedRegionId || null, ligne_id: selectedLigneId || null, ligne_nom: selectedLigneId ? (lignes.find(l => l.id === selectedLigneId)?.nom || null) : null }; const substitutionsIds = substitutionsActive ? horairesSelectionnes.map(h => h.id) : []; const { error } = await createTravaux(payload, substitutionsIds); if (error) { alert('Erreur lors de la création des travaux : ' + (error.message || 'Erreur')); } else { navigate('/travaux'); } } catch (err) { alert("Une erreur inattendue s'est produite"); } finally { setSaving(false); } }; return (
{/* Header Banner SNCF avec composants WCS */}
navigate('/travaux')} > Retour aux travaux
Nouveau Chantier {scopedRegionId && ( Région : {scopedRegionId} )}

Déclarer des travaux sur le réseau

Planifiez une coupure, des restrictions de circulation et les substitutions associées.

navigate('/travaux')}> Annuler Créer le chantier
{/* Navigation par Onglets WCS */}
{/* Onglet 1 : Informations Générales */} {(activeTabKey === 'general' || activeTabKey === 'all') && (

Informations Générales

Définissez l'intitulé, la ligne concernée et les consignes d'exploitation.

setTitre(e.target.value)} />
)} {/* Onglet 2 : Planification & Calendrier */} {(activeTabKey === 'calendrier' || activeTabKey === 'all') && (

Planification & Horaires

Période de validité du chantier, jours impactés et créneaux journaliers.

setDateDebut(e.target.value)} /> setDateFin(e.target.value)} />
setHeureDebut(e.target.value)} /> setHeureFin(e.target.value)} />
Tous les jours Semaine Week-end
{JOURS_SEMAINE.map((jour) => { const isSelected = joursTravaux.includes(jour.value); return ( ); })}
)} {/* Onglet 3 : Plan de Substitution */} {(activeTabKey === 'substitutions' || activeTabKey === 'all') && (

Plan de Transport de Substitution

Associez des cars ou trains spéciaux pour remplacer les circulations supprimées.

{/* Interrupteur WCS Switch pour substitutions */}
Activer le plan de substitution pour ce chantier Permet de relier des horaires de cars ou trains de substitution actifs
{substitutionsActive && (
setSearchQuery(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleSearchHoraires(); }} />
Rechercher
{/* Horaires sélectionnés */} {horairesSelectionnes.length > 0 && (

{horairesSelectionnes.length} circulation{horairesSelectionnes.length > 1 ? 's' : ''} de substitution sélectionnée{horairesSelectionnes.length > 1 ? 's' : ''}

{horairesSelectionnes.map(h => (
{h.numero_train || 'Train'} {h.type_train && {h.type_train}}
{h.gare_depart_nom} ({formatHeure(h.heure_depart)}) {h.gare_arrivee_nom} ({formatHeure(h.heure_arrivee)})
toggleHoraireSelection(h)} title="Retirer cette substitution" >
))}
)} {/* Résultats de recherche */} {showResults && (

Résultats disponibles ({horairesDisponibles.length})

Cliquez sur une circulation pour l'ajouter ou la retirer
{loadingHoraires ? (

Recherche des circulations en cours...

) : horairesDisponibles.length === 0 ? (

Aucun horaire de substitution trouvé pour « {searchQuery} ».

) : (
{horairesDisponibles.map(h => { const isSelected = horairesSelectionnes.some(hs => hs.id === h.id); return (
toggleHoraireSelection(h)} style={{ cursor: 'pointer' }} >
{h.numero_train} {h.type_train && {h.type_train}} {h.ligne_nom && {h.ligne_nom}}
{h.gare_depart_nom} ({formatHeure(h.heure_depart)}) {h.gare_arrivee_nom} ({formatHeure(h.heure_arrivee)})
{isSelected ? 'Sélectionné' : 'Ajouter'}
); })}
)}
)}
)}
)}
{/* Barre d'action inférieure sticky avec Switch d'activation et WCS buttons */}
{actif ? 'Chantier Actif et visible' : 'Chantier Inactif / Masqué'} {actif ? 'Ce chantier sera diffusé aux usagers et aux agents' : 'Ce chantier restera en brouillon non diffusé'}
navigate('/travaux')}> Annuler Enregistrer le chantier
{/* WCS Footer Corporate SNCF */}
FERROVIA PANEL · DIRECTION TECHNIQUE & INFRASTRUCTURE SNCF Module Officiel de Planification des Travaux & Substitutions Routières
© {new Date().getFullYear()} SNCF · Réseau Ferroviaire National
Supabase Connecté v2.6.0-WCS
); }