-> Refonte du système de GESTION DES ROULEMENTS de matériels roulants -> Optimisation rendue BDD
614 lines
28 KiB
JavaScript
614 lines
28 KiB
JavaScript
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 (
|
|
<div className="sncf-groupe travaux-page-root">
|
|
<div className="panel-layout">
|
|
<div className="panel-nav">
|
|
<NavPanel />
|
|
</div>
|
|
|
|
<div className="panel-content travaux-form-page-content">
|
|
{/* Header Banner SNCF avec composants WCS */}
|
|
<header className="travaux-form-header-modern">
|
|
<div className="form-header-main">
|
|
<wcs-button
|
|
mode="stroked"
|
|
size="s"
|
|
className="wcs-secondary mb-2"
|
|
onClick={() => navigate('/travaux')}
|
|
>
|
|
<wcs-mat-icon icon="arrow_back" size="s" class="mr-1"></wcs-mat-icon>
|
|
<span>Retour aux travaux</span>
|
|
</wcs-button>
|
|
|
|
<div className="form-title-group">
|
|
<div className="d-flex align-items-center gap-2 mb-1">
|
|
<wcs-badge shape="pill" className="wcs-info">
|
|
<wcs-mat-icon icon="add_circle" size="s" class="mr-1"></wcs-mat-icon>
|
|
Nouveau Chantier
|
|
</wcs-badge>
|
|
{scopedRegionId && (
|
|
<wcs-badge shape="pill" className="wcs-secondary">
|
|
Région : {scopedRegionId}
|
|
</wcs-badge>
|
|
)}
|
|
</div>
|
|
<h1>Déclarer des travaux sur le réseau</h1>
|
|
<p>Planifiez une coupure, des restrictions de circulation et les substitutions associées.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-header-actions">
|
|
<wcs-button className="wcs-secondary" mode="stroked" onClick={() => navigate('/travaux')}>
|
|
<span>Annuler</span>
|
|
</wcs-button>
|
|
<wcs-button
|
|
className="wcs-primary"
|
|
onClick={handleCreate}
|
|
disabled={saving || !canCreateTravaux}
|
|
loading={saving}
|
|
>
|
|
<wcs-mat-icon icon="save" size="s" class="mr-1"></wcs-mat-icon>
|
|
<span>Créer le chantier</span>
|
|
</wcs-button>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Navigation par Onglets WCS */}
|
|
<div className="mb-4">
|
|
<wcs-tabs ref={tabsRef} selected-key={activeTabKey}>
|
|
<wcs-tab header="1. Général & Ligne" item-key="general"></wcs-tab>
|
|
<wcs-tab header="2. Calendrier & Période" item-key="calendrier"></wcs-tab>
|
|
<wcs-tab header={`3. Substitutions (${horairesSelectionnes.length})`} item-key="substitutions"></wcs-tab>
|
|
</wcs-tabs>
|
|
</div>
|
|
|
|
<div className="travaux-form-grid">
|
|
{/* Onglet 1 : Informations Générales */}
|
|
{(activeTabKey === 'general' || activeTabKey === 'all') && (
|
|
<wcs-card className="wcs-card-form mb-4">
|
|
<wcs-card-body>
|
|
<div className="section-title-wrap mb-3">
|
|
<div className="section-icon-box">
|
|
<wcs-mat-icon icon="info" size="m"></wcs-mat-icon>
|
|
</div>
|
|
<div>
|
|
<h2 className="travaux-section-title">Informations Générales</h2>
|
|
<p className="travaux-section-subtitle">Définissez l'intitulé, la ligne concernée et les consignes d'exploitation.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<wcs-form-field class="mb-3">
|
|
<label htmlFor="titre-travaux">Titre des travaux *</label>
|
|
<input
|
|
id="titre-travaux"
|
|
type="text"
|
|
className="form-control"
|
|
placeholder="Ex: Rénovation caténaire et voies Paris vers Lyon"
|
|
value={titre}
|
|
onChange={(e) => setTitre(e.target.value)}
|
|
/>
|
|
</wcs-form-field>
|
|
|
|
<wcs-form-field class="mb-3">
|
|
<label htmlFor="ligne-select">Ligne ferroviaire associée</label>
|
|
<select
|
|
id="ligne-select"
|
|
className="form-control"
|
|
value={selectedLigneId}
|
|
onChange={(e) => setSelectedLigneId(e.target.value)}
|
|
disabled={loadingLignes}
|
|
>
|
|
<option value="">Sélectionner une ligne (optionnel)</option>
|
|
{lignes.map(l => (
|
|
<option key={l.id} value={l.id}>{l.nom || l.numero || `Ligne ${l.id}`}</option>
|
|
))}
|
|
</select>
|
|
</wcs-form-field>
|
|
|
|
<div className="mb-3">
|
|
<label className="form-label font-weight-bold d-block mb-2">Description détaillée & Informations voyageurs</label>
|
|
<RichTextEditor
|
|
value={description}
|
|
onChange={setDescription}
|
|
placeholder="Détaillez les impacts prévus, motifs techniques, gares concernées..."
|
|
/>
|
|
</div>
|
|
</wcs-card-body>
|
|
</wcs-card>
|
|
)}
|
|
|
|
{/* Onglet 2 : Planification & Calendrier */}
|
|
{(activeTabKey === 'calendrier' || activeTabKey === 'all') && (
|
|
<wcs-card className="wcs-card-form mb-4">
|
|
<wcs-card-body>
|
|
<div className="section-title-wrap mb-3">
|
|
<div className="section-icon-box">
|
|
<wcs-mat-icon icon="calendar_month" size="m"></wcs-mat-icon>
|
|
</div>
|
|
<div>
|
|
<h2 className="travaux-section-title">Planification & Horaires</h2>
|
|
<p className="travaux-section-subtitle">Période de validité du chantier, jours impactés et créneaux journaliers.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="form-columns-2 mb-3">
|
|
<wcs-form-field>
|
|
<label htmlFor="date-debut">Date de début *</label>
|
|
<input
|
|
id="date-debut"
|
|
type="date"
|
|
className="form-control"
|
|
value={dateDebut}
|
|
onChange={(e) => setDateDebut(e.target.value)}
|
|
/>
|
|
</wcs-form-field>
|
|
|
|
<wcs-form-field>
|
|
<label htmlFor="date-fin">Date de fin *</label>
|
|
<input
|
|
id="date-fin"
|
|
type="date"
|
|
className="form-control"
|
|
value={dateFin}
|
|
onChange={(e) => setDateFin(e.target.value)}
|
|
/>
|
|
</wcs-form-field>
|
|
</div>
|
|
|
|
<div className="form-columns-2 mb-3">
|
|
<wcs-form-field>
|
|
<label htmlFor="heure-debut">Heure de début journalière *</label>
|
|
<input
|
|
id="heure-debut"
|
|
type="time"
|
|
className="form-control"
|
|
value={heureDebut}
|
|
onChange={(e) => setHeureDebut(e.target.value)}
|
|
/>
|
|
</wcs-form-field>
|
|
|
|
<wcs-form-field>
|
|
<label htmlFor="heure-fin">Heure de fin journalière *</label>
|
|
<input
|
|
id="heure-fin"
|
|
type="time"
|
|
className="form-control"
|
|
value={heureFin}
|
|
onChange={(e) => setHeureFin(e.target.value)}
|
|
/>
|
|
</wcs-form-field>
|
|
</div>
|
|
|
|
<div className="mt-4">
|
|
<div className="days-header-row d-flex justify-content-between align-items-center mb-2">
|
|
<label className="font-weight-bold mb-0">Jours impactés dans la semaine *</label>
|
|
<div className="d-flex gap-2">
|
|
<wcs-button mode="stroked" size="s" onClick={selectAllDays}>Tous les jours</wcs-button>
|
|
<wcs-button mode="stroked" size="s" onClick={selectWeekdays}>Semaine</wcs-button>
|
|
<wcs-button mode="stroked" size="s" onClick={selectWeekend}>Week-end</wcs-button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="d-flex flex-wrap gap-2 mt-2">
|
|
{JOURS_SEMAINE.map((jour) => {
|
|
const isSelected = joursTravaux.includes(jour.value);
|
|
return (
|
|
<button
|
|
key={jour.value}
|
|
type="button"
|
|
className={`btn-day-pill ${isSelected ? 'is-selected' : ''}`}
|
|
onClick={() => toggleJour(jour.value)}
|
|
>
|
|
<wcs-mat-icon icon={isSelected ? 'check_circle' : 'circle_outline'} size="s" class="mr-1"></wcs-mat-icon>
|
|
<span>{jour.label}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</wcs-card-body>
|
|
</wcs-card>
|
|
)}
|
|
|
|
{/* Onglet 3 : Plan de Substitution */}
|
|
{(activeTabKey === 'substitutions' || activeTabKey === 'all') && (
|
|
<wcs-card className="wcs-card-form mb-4">
|
|
<wcs-card-body>
|
|
<div className="section-title-wrap mb-3">
|
|
<div className="section-icon-box">
|
|
<wcs-mat-icon icon="swap_horiz" size="m"></wcs-mat-icon>
|
|
</div>
|
|
<div>
|
|
<h2 className="travaux-section-title">Plan de Transport de Substitution</h2>
|
|
<p className="travaux-section-subtitle">Associez des cars ou trains spéciaux pour remplacer les circulations supprimées.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Interrupteur WCS Switch pour substitutions */}
|
|
<div className="d-flex align-items-center justify-content-between p-3 mb-4 rounded border bg-light">
|
|
<div>
|
|
<strong className="d-block text-dark">Activer le plan de substitution pour ce chantier</strong>
|
|
<small className="text-muted">Permet de relier des horaires de cars ou trains de substitution actifs</small>
|
|
</div>
|
|
<label className="switch-container">
|
|
<input
|
|
type="checkbox"
|
|
checked={substitutionsActive}
|
|
onChange={(e) => setSubstitutionsActive(e.target.checked)}
|
|
/>
|
|
<span className="switch-slider"></span>
|
|
</label>
|
|
</div>
|
|
|
|
{substitutionsActive && (
|
|
<div className="substitutions-module-body">
|
|
<div className="substitutions-search-bar d-flex gap-2 mb-3">
|
|
<div className="flex-grow-1 position-relative">
|
|
<input
|
|
type="text"
|
|
className="form-control"
|
|
placeholder="Rechercher par numéro de train, gare de départ ou terminus..."
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
onKeyDown={(e) => { if (e.key === 'Enter') handleSearchHoraires(); }}
|
|
/>
|
|
</div>
|
|
<wcs-button
|
|
className="wcs-primary"
|
|
onClick={handleSearchHoraires}
|
|
disabled={loadingHoraires}
|
|
loading={loadingHoraires}
|
|
>
|
|
<wcs-mat-icon icon="search" size="s" class="mr-1"></wcs-mat-icon>
|
|
<span>Rechercher</span>
|
|
</wcs-button>
|
|
</div>
|
|
|
|
{/* Horaires sélectionnés */}
|
|
{horairesSelectionnes.length > 0 && (
|
|
<div className="selected-subs-container mb-4">
|
|
<div className="selected-subs-header mb-2 d-flex align-items-center justify-content-between">
|
|
<h4 className="m-0 text-primary">
|
|
<wcs-mat-icon icon="check_circle" size="s" class="text-success mr-1"></wcs-mat-icon>
|
|
{horairesSelectionnes.length} circulation{horairesSelectionnes.length > 1 ? 's' : ''} de substitution sélectionnée{horairesSelectionnes.length > 1 ? 's' : ''}
|
|
</h4>
|
|
</div>
|
|
<div className="selected-subs-list d-flex flex-column gap-2">
|
|
{horairesSelectionnes.map(h => (
|
|
<div key={h.id} className="selected-sub-card d-flex align-items-center justify-content-between p-2 rounded border bg-white">
|
|
<div className="d-flex align-items-center gap-3">
|
|
<div className="d-flex align-items-center gap-2">
|
|
<wcs-mat-icon icon="directions_bus" size="s"></wcs-mat-icon>
|
|
<strong>{h.numero_train || 'Train'}</strong>
|
|
{h.type_train && <wcs-badge className="wcs-info" shape="pill">{h.type_train}</wcs-badge>}
|
|
</div>
|
|
<div className="sub-route d-flex align-items-center gap-1 text-muted">
|
|
<span>{h.gare_depart_nom} ({formatHeure(h.heure_depart)})</span>
|
|
<wcs-mat-icon icon="arrow_forward" size="s"></wcs-mat-icon>
|
|
<span>{h.gare_arrivee_nom} ({formatHeure(h.heure_arrivee)})</span>
|
|
</div>
|
|
</div>
|
|
<wcs-button
|
|
mode="clear"
|
|
className="wcs-danger"
|
|
size="s"
|
|
onClick={() => toggleHoraireSelection(h)}
|
|
title="Retirer cette substitution"
|
|
>
|
|
<wcs-mat-icon icon="close" size="s"></wcs-mat-icon>
|
|
</wcs-button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Résultats de recherche */}
|
|
{showResults && (
|
|
<div className="search-results-section">
|
|
<div className="search-results-header mb-2 d-flex align-items-center justify-content-between">
|
|
<h4 className="m-0">Résultats disponibles ({horairesDisponibles.length})</h4>
|
|
<span className="text-muted small">Cliquez sur une circulation pour l'ajouter ou la retirer</span>
|
|
</div>
|
|
|
|
{loadingHoraires ? (
|
|
<div className="text-center p-4">
|
|
<wcs-spinner mode="border"></wcs-spinner>
|
|
<p className="mt-2 text-muted">Recherche des circulations en cours...</p>
|
|
</div>
|
|
) : horairesDisponibles.length === 0 ? (
|
|
<div className="text-center p-4 bg-light rounded text-muted">
|
|
<p className="m-0">Aucun horaire de substitution trouvé pour « {searchQuery} ».</p>
|
|
</div>
|
|
) : (
|
|
<div className="subs-results-list d-flex flex-column gap-2">
|
|
{horairesDisponibles.map(h => {
|
|
const isSelected = horairesSelectionnes.some(hs => hs.id === h.id);
|
|
return (
|
|
<div
|
|
key={h.id}
|
|
className={`sub-result-card d-flex align-items-center justify-content-between p-2 rounded border cursor-pointer ${isSelected ? 'border-primary bg-primary-soft' : 'bg-white'}`}
|
|
onClick={() => toggleHoraireSelection(h)}
|
|
style={{ cursor: 'pointer' }}
|
|
>
|
|
<div className="result-info">
|
|
<div className="d-flex align-items-center gap-2 mb-1">
|
|
<strong>{h.numero_train}</strong>
|
|
{h.type_train && <wcs-badge className="wcs-info" shape="pill">{h.type_train}</wcs-badge>}
|
|
{h.ligne_nom && <wcs-badge className="wcs-secondary" shape="pill">{h.ligne_nom}</wcs-badge>}
|
|
</div>
|
|
<div className="d-flex align-items-center gap-1 text-muted small">
|
|
<span>{h.gare_depart_nom} ({formatHeure(h.heure_depart)})</span>
|
|
<wcs-mat-icon icon="arrow_forward" size="s"></wcs-mat-icon>
|
|
<span>{h.gare_arrivee_nom} ({formatHeure(h.heure_arrivee)})</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<wcs-badge className={isSelected ? 'wcs-success' : 'wcs-secondary'} shape="pill">
|
|
<wcs-mat-icon icon={isSelected ? 'check' : 'add'} size="s"></wcs-mat-icon>
|
|
<span>{isSelected ? 'Sélectionné' : 'Ajouter'}</span>
|
|
</wcs-badge>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</wcs-card-body>
|
|
</wcs-card>
|
|
)}
|
|
</div>
|
|
|
|
{/* Barre d'action inférieure sticky avec Switch d'activation et WCS buttons */}
|
|
<div className="form-sticky-bottom-bar d-flex justify-content-between align-items-center p-3 rounded shadow-sm bg-white border mt-4">
|
|
<div className="d-flex align-items-center gap-3">
|
|
<label className="switch-container">
|
|
<input
|
|
type="checkbox"
|
|
checked={actif}
|
|
onChange={(e) => setActif(e.target.checked)}
|
|
/>
|
|
<span className="switch-slider"></span>
|
|
</label>
|
|
<div>
|
|
<strong className="d-block">{actif ? 'Chantier Actif et visible' : 'Chantier Inactif / Masqué'}</strong>
|
|
<small className="text-muted">{actif ? 'Ce chantier sera diffusé aux usagers et aux agents' : 'Ce chantier restera en brouillon non diffusé'}</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="d-flex gap-2">
|
|
<wcs-button className="wcs-secondary" mode="stroked" onClick={() => navigate('/travaux')}>
|
|
<span>Annuler</span>
|
|
</wcs-button>
|
|
<wcs-button
|
|
className="wcs-primary"
|
|
onClick={handleCreate}
|
|
disabled={saving || !canCreateTravaux}
|
|
loading={saving}
|
|
>
|
|
<wcs-mat-icon icon="check" size="s" class="mr-1"></wcs-mat-icon>
|
|
<span>Enregistrer le chantier</span>
|
|
</wcs-button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* WCS Footer Corporate SNCF */}
|
|
<wcs-footer className="sncf-page-footer mt-5">
|
|
<div className="d-flex align-items-center gap-3">
|
|
<div className="footer-sncf-badge">
|
|
<wcs-mat-icon icon="construction" style={{ fontSize: '20px', color: '#ffffff' }}></wcs-mat-icon>
|
|
</div>
|
|
<div>
|
|
<strong style={{ color: '#ffffff', fontSize: '14px', display: 'block' }}>
|
|
FERROVIA PANEL · DIRECTION TECHNIQUE & INFRASTRUCTURE SNCF
|
|
</strong>
|
|
<span style={{ color: 'rgba(255, 255, 255, 0.75)', fontSize: '12px' }}>
|
|
Module Officiel de Planification des Travaux & Substitutions Routières
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div slot="end-left">
|
|
<span style={{ fontSize: '12px', color: 'rgba(255, 255, 255, 0.65)' }}>
|
|
© {new Date().getFullYear()} SNCF · Réseau Ferroviaire National
|
|
</span>
|
|
</div>
|
|
|
|
<div slot="end-right">
|
|
<div className="d-flex align-items-center gap-2">
|
|
<wcs-badge className="wcs-success" shape="rounded">
|
|
<wcs-mat-icon icon="cloud_done" class="mr-1"></wcs-mat-icon>
|
|
Supabase Connecté
|
|
</wcs-badge>
|
|
<span style={{ fontSize: '12px', color: 'rgba(255, 255, 255, 0.7)' }}>
|
|
v2.6.0-WCS
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</wcs-footer>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|