RELEASE V5.0.0 : Voici les modifications apportées :

-> IMPLÉMENTATION DONNÉES GTFS / GTFS-RT / SIRI LTE SNCF
-> RESTRUCTURATION DE L'APP.

FONCTIONNALITÉS EN COURS DE DÉVELOPPEMENT :

-> REFONTE DU DESIGN DES AFFICHEURS CLASSIQUES
-> AMÉLIORATION DES
This commit is contained in:
mathis committed 2026-08-30 01:58:16 +02:00
1 parent 0e0d8c435f
commit 72de543dc6
18 files changed
+1550 -544

No files matched your search

+74 -11
View File
@@ -5,21 +5,34 @@ import { fetchAllRows } from '../../../lib/fetchAllRows';
import MarqueeText from '../../../components/MarqueeText';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../hooks/useAutoAnnonce';
import { getSourceFromPath } from '../../../services/railwayService';
import { getSncfTimetable } from '../../../services/sncfApi';
// Helper utilitaire : format HH:MM avec deux points (ex: 22:39)
const formatTimeWithColon = (v) => {
if (v == null) return '';
const tryDate = new Date(v);
if (!isNaN(tryDate.getTime())) {
const hh = String(tryDate.getHours()).padStart(2, '0');
const hh = String(tryDate.getHours() % 24).padStart(2, '0');
const mm = String(tryDate.getMinutes()).padStart(2, '0');
return `${hh}:${mm}`;
}
if (typeof v === 'string') {
const m = v.match(/(\d{1,2}):(\d{2})(?::\d{2})?/);
if (m) return `${String(m[1]).padStart(2, '0')}:${m[2]}`;
if (m) {
const h = parseInt(m[1], 10) % 24;
return `${String(h).padStart(2, '0')}:${m[2]}`;
}
const m2 = v.match(/T(\d{2}):(\d{2})/);
if (m2) return `${m2[1]}:${m2[2]}`;
if (m2) {
const h = parseInt(m2[1], 10) % 24;
return `${String(h).padStart(2, '0')}:${m2[2]}`;
}
const m3 = v.match(/(\d{1,2})h(\d{2})/i);
if (m3) {
const h = parseInt(m3[1], 10) % 24;
return `${String(h).padStart(2, '0')}:${m3[2]}`;
}
return v.slice(0, 5).replace('h', ':');
}
return String(v).slice(0, 5).replace('h', ':');
@@ -445,7 +458,15 @@ export default function EVAArrivees() {
// Récupération type de gare
useEffect(() => {
let mounted = true;
const source = getSourceFromPath(window.location.pathname);
const fetchStationType = async () => {
if (source === 'sncf') {
if (mounted) {
setStationType('ville');
setResolvedGareId(null);
}
return;
}
try {
let fetchedType = null;
let fetchedId = gareIdParam || null;
@@ -475,9 +496,7 @@ export default function EVAArrivees() {
}
} catch (e) { /* ignore */ }
};
if (supabase) {
fetchStationType();
}
fetchStationType();
return () => { mounted = false; };
}, [gareIdParam, gareDisplay]);
@@ -831,14 +850,55 @@ export default function EVAArrivees() {
});
}, [buildPerturbMap, computeStatusForHoraireAtStop, gareDisplay, gareIdParam, getStops, normalizeName]);
// Récupération Supabase avec polling
// Récupération des données (SNCF GTFS ou Supabase) avec polling
useEffect(() => {
let mounted = true;
let inFlight = false;
const source = getSourceFromPath(window.location.pathname);
const fetchData = async () => {
if (!mounted || inFlight) return;
inFlight = true;
if (source === 'sncf') {
setLoading(true);
setError(null);
try {
const { data: sncfData, error: sncfErr } = await getSncfTimetable({
gareName: gareDisplay || gareParam,
mode: 'arrivees'
});
if (!mounted) { inFlight = false; return; }
if (sncfErr) {
setError(sncfErr);
} else {
const formatted = (sncfData || []).map(t => {
const timeStr = t.heure_arrivee || t.heure_depart || t.time || '';
return {
...t,
_displayTime: formatTimeWithColon(timeStr),
_displayPlatform: t.quai || t.voie || '',
_arrHM: t._arrHM || 0,
_status: t._status || {
label: t.etat === 'supprime' ? 'supprimé' : (t.retard_minutes > 0 ? `retardé +${t.retard_minutes}min.` : "à l'heure"),
detail: '',
delayMinutes: t.retard_minutes || null,
causeDetails: t.cause_retard || null
}
};
});
setHoraires(formatted.slice(0, 10));
setAllHoraires(formatted);
}
} catch (e) {
if (mounted) setError(e.message || String(e));
} finally {
if (mounted) setLoading(false);
inFlight = false;
}
return;
}
if (!supabase) {
setLoading(false);
inFlight = false;
@@ -936,9 +996,12 @@ export default function EVAArrivees() {
const parseTimeHM = (s) => {
if (!s) return null;
if (typeof s === 'number') return s;
const m = String(s).match(/(\d{1,2}):(\d{2})/);
if (m) return parseInt(m[1], 10) * 60 + parseInt(m[2], 10);
if (typeof s === 'number') return s % 1440;
const m = String(s).match(/(\d{1,2})[:h](\d{2})/i);
if (m) {
const h = parseInt(m[1], 10) % 24;
return h * 60 + parseInt(m[2], 10);
}
const d = new Date(s);
if (!isNaN(d.getTime())) return d.getHours() * 60 + d.getMinutes();
return null;
@@ -1129,7 +1192,7 @@ export default function EVAArrivees() {
fetchData();
const intervalId = setInterval(fetchData, 15000);
return () => { mounted = false; clearInterval(intervalId); };
}, [gareDisplay, gareIdParam, buildPerturbMap, computeStatusForHoraireAtStop, normalizeName, applyPerturbationsToHoraires, getStops, getPerturbationJours]);
}, [gareDisplay, gareParam, gareIdParam, buildPerturbMap, computeStatusForHoraireAtStop, normalizeName, applyPerturbationsToHoraires, getStops, getPerturbationJours]);
// Alternance retard / texte toutes les 2s
const [alternateDelay, setAlternateDelay] = useState(false);