Update station type handling and current time logic for quai display

This commit is contained in:
Ferrovia committed 2026-05-01 21:47:27 +02:00
1 parent e42f6c01ec
commit 503a70bd49
5 files changed
+368 -40

No files matched your search

@@ -106,11 +106,82 @@ export default function ClassiquesDepartsQuais(){
const [loadingHoraire, setLoadingHoraire] = useState(false);
const [horaireError, setHoraireError] = useState(null);
const [candidatesCount, setCandidatesCount] = useState(0);
// type de la gare (récupéré depuis la table gares)
const [stationType, setStationType] = useState(null);
// Heure actuelle mise à jour chaque seconde pour la logique de seuil
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const id = setInterval(() => setCurrentTime(new Date()), 1000);
return () => clearInterval(id);
}, []);
// perturbations/travaux (récupérées depuis Supabase)
const [perturbations, setPerturbations] = useState([]);
const [, setTravaux] = useState([]);
// helpers locaux (simples) — similaires à ceux du composant principal
const weekdayNameForColumn = useCallback((d) => {
const i = d.getDay();
switch(i) {
case 1: return 'circule_lundi';
case 2: return 'circule_mardi';
case 3: return 'circule_mercredi';
case 4: return 'circule_jeudi';
case 5: return 'circule_vendredi';
case 6: return 'circule_samedi';
case 0: return 'circule_dimanche';
default: return null;
}
}, []);
const isPublicHoliday = useCallback((d) => {
const y = d.getFullYear();
const m = d.getMonth() + 1;
const day = d.getDate();
const s = `${y}-${String(m).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
const holidays = [
`${y}-01-01`, // Jour de l'an
`${y}-05-01`, // Fête du Travail
`${y}-05-08`, // Victoire 1945
`${y}-07-14`, // Fête nationale
`${y}-08-15`, // Assomption
`${y}-11-01`, // Toussaint
`${y}-11-11`, // Armistice 1918
`${y}-12-25`, // Noël
];
// Dates variables pour 2026
if (y === 2026) {
holidays.push('2026-04-06'); // Lundi de Pâques
holidays.push('2026-05-14'); // Ascension
holidays.push('2026-05-25'); // Lundi de Pentecôte
}
return holidays.includes(s);
}, []);
const circulatesOn = useCallback((h, d) => {
if (isPublicHoliday(d)) {
const v = h['circule_jours_feries'];
if (typeof v === 'boolean') return v;
if (typeof v === 'number') return v === 1;
if (typeof v === 'string') {
const s = v.trim().toLowerCase();
return s === 'true' || s === '1' || s === 't' || s === 'y' || s === 'yes';
}
return (typeof v === 'undefined' || v === null) ? false : Boolean(v);
}
const col = weekdayNameForColumn(d);
if (!col) return true;
const v = h[col];
if (typeof v === 'boolean') return v;
if (typeof v === 'number') return v === 1;
if (typeof v === 'string') {
const s = v.trim().toLowerCase();
return s === 'true' || s === '1' || s === 't' || s === 'y' || s === 'yes';
}
return (typeof v === 'undefined' || v === null) ? true : Boolean(v);
}, [isPublicHoliday, weekdayNameForColumn]);
const normalizeName = useCallback((s) => {
if (!s) return '';
try { return String(s).normalize('NFD').replace(/\p{M}/gu,'').toLowerCase().trim().replace(/[-_]+/g,' ').replace(/\s+/g,' '); } catch (e) { return String(s).toLowerCase().trim(); }
@@ -154,6 +225,15 @@ export default function ClassiquesDepartsQuais(){
return `${hh}h${mm}`;
}, []);
// retourne le threshold (en minutes) pour afficher le quai selon le type de gare
const thresholdForStationType = useCallback((type) => {
if (!type) return 0;
const t = String(type).trim().toLowerCase();
if (t === 'interurbaine' || t.includes('interurb')) return 360; // 6 heures
if (t === 'ville' || t.includes('ville')) return 30; // 30 minutes
return 0;
}, []);
// lecture des query params pour gare & quai
const paramsForThis = new URLSearchParams(window.location.search || '');
const gareParam = paramsForThis.get('gare');
@@ -437,6 +517,19 @@ export default function ClassiquesDepartsQuais(){
return;
}
try {
// Récupérer le type de la gare
let fetchedType = null;
try {
if (gareIdParam) {
const { data: g } = await supabase.from('gares').select('type').eq('gare_id', gareIdParam).single();
if (g) fetchedType = g.type;
} else if (gareDisplayParam) {
const { data: g } = await supabase.from('gares').select('type').ilike('nom', `%${gareDisplayParam}%`).limit(1).single();
if (g) fetchedType = g.type;
}
} catch (e) { /* ignore */ }
if (mounted) setStationType(fetchedType);
const { data: all, error } = await supabase.from('horaires').select('id, *');
if (error) {
if (mounted) setHoraireError(error.message || String(error));
@@ -453,12 +546,20 @@ export default function ClassiquesDepartsQuais(){
const targetQuai = quaiParam ? String(quaiParam).toLowerCase().replace(/\s+/g,'') : null;
const now = new Date();
const tomorrow = new Date(now);
tomorrow.setDate(now.getDate() + 1);
const nowHM = now.getHours()*60 + now.getMinutes();
const candidates = [];
for (const h of all) {
if (!h) continue;
// Filtrage par jour de circulation
const circulatesToday = circulatesOn(h, now);
const circulatesTomorrow = circulatesOn(h, tomorrow);
if (!circulatesToday && !circulatesTomorrow) continue;
// build stops list (support multiple field names)
const stops = getStops(h);
@@ -577,7 +678,7 @@ export default function ClassiquesDepartsQuais(){
let minutesUntil = depHM - nowHM;
if (minutesUntil < 0) minutesUntil = depHM + 24*60 - nowHM;
candidates.push({ horaire: h, stop: stopMatch, depHM, minutesUntil, rawTime });
candidates.push({ horaire: h, stop: stopMatch, depHM, minutesUntil, rawTime, circulatesToday, circulatesTomorrow });
}
if (!candidates.length) {
@@ -587,9 +688,9 @@ export default function ClassiquesDepartsQuais(){
return;
}
// split into today (depHM > nowHM) and tomorrow (depHM <= nowHM)
const todayCandidates = candidates.filter(c => c.depHM > nowHM).sort((a,b) => a.depHM - b.depHM);
const tomorrowCandidates = candidates.filter(c => c.depHM <= nowHM).sort((a,b) => a.depHM - b.depHM);
// split into today (circulatesToday AND depHM > nowHM) and tomorrow (circulatesTomorrow AND (depHM <= nowHM OR not circulatesToday))
const todayCandidates = candidates.filter(c => c.circulatesToday && c.depHM > nowHM).sort((a,b) => a.depHM - b.depHM);
const tomorrowCandidates = candidates.filter(c => c.circulatesTomorrow && (c.depHM <= nowHM || !c.circulatesToday)).sort((a,b) => a.depHM - b.depHM);
let chosen = null;
if (todayCandidates.length > 0) chosen = todayCandidates[0];
@@ -609,7 +710,7 @@ export default function ClassiquesDepartsQuais(){
loadNextForQuai();
return () => { mounted = false; };
}, [gareDisplayParam, gareIdParam, quaiParam, parseTimeHM, normalizeName]);
}, [gareDisplayParam, gareIdParam, quaiParam, parseTimeHM, normalizeName, circulatesOn]);
// toggle flag to alternate time/status when needed (observe selectedHoraire.status when present)
const [showTime, setShowTime] = useState(true);
@@ -730,6 +831,21 @@ export default function ClassiquesDepartsQuais(){
const s = (canonicalStatus || statusStrFromField || '').toLowerCase();
const isAlert = s.includes('retard') || s.includes('supprim');
const label = canonicalStatus || statusStrFromField || '';
// Logique de seuil d'affichage du quai
const nowHM = currentTime.getHours() * 60 + currentTime.getMinutes();
const sched = selectedHoraire && selectedHoraire.depHM ? selectedHoraire.depHM : null;
const threshold = thresholdForStationType(stationType);
const showPlatform = (sched !== null) ? (nowHM >= (sched - threshold)) : true;
if (!showPlatform) {
return (
<span className="aff-quais__time-status-wrapper" aria-live="polite">
<span className="aff-quais__time aff-quais__time--strict visible">--h--</span>
</span>
);
}
// Always render both time and status inside a fixed-size wrapper to avoid layout shift
return (
<span className="aff-quais__time-status-wrapper" aria-live="polite">