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:
1 parent
0e0d8c435f
commit
72de543dc6
18 files changed
+1550
-544
No files matched your search
@@ -4,6 +4,8 @@ import supabase from '../../../../lib/supabase';
|
||||
import { fetchAllRows } from '../../../../lib/fetchAllRows';
|
||||
import useAnnonceSonoreRealtime from '../../../../hooks/useAnnonceSonoreRealtime';
|
||||
import useAutoAnnonce from '../../../../hooks/useAutoAnnonce';
|
||||
import { getSourceFromPath } from '../../../../services/railwayService';
|
||||
import { getSncfTimetable } from '../../../../services/sncfApi';
|
||||
function Clock() {
|
||||
const [now, setNow] = useState(new Date());
|
||||
useEffect(() => {
|
||||
@@ -46,7 +48,7 @@ export default function ClassiquesDepartsQuais() {
|
||||
const [loadingHoraire, setLoadingHoraire] = useState(false);
|
||||
const [, setHoraireError] = useState(null);
|
||||
const [, setCandidatesCount] = useState(0);
|
||||
const [stationType, setStationType] = useState(null);
|
||||
const [, setStationType] = useState(null);
|
||||
const [currentTime, setCurrentTime] = useState(new Date());
|
||||
|
||||
const [resolvedGareId, setResolvedGareId] = useState(gareIdParam || null);
|
||||
@@ -111,11 +113,14 @@ export default function ClassiquesDepartsQuais() {
|
||||
|
||||
const parseTimeHM = useCallback((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();
|
||||
if (!isNaN(d.getTime())) return d.getHours() * 60 + d.getMinutes();
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
@@ -123,15 +128,26 @@ export default function ClassiquesDepartsQuais() {
|
||||
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}h${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')}h${m[2]}`;
|
||||
if (m) {
|
||||
const h = parseInt(m[1], 10) % 24;
|
||||
return `${String(h).padStart(2,'0')}h${m[2]}`;
|
||||
}
|
||||
const m2 = v.match(/T(\d{2}):(\d{2})/);
|
||||
if (m2) return `${m2[1]}h${m2[2]}`;
|
||||
if (m2) {
|
||||
const h = parseInt(m2[1], 10) % 24;
|
||||
return `${String(h).padStart(2,'0')}h${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')}h${m3[2]}`;
|
||||
}
|
||||
return v.slice(0,5).replace(':','h');
|
||||
}
|
||||
return String(v).slice(0,5).replace(':','h');
|
||||
@@ -145,13 +161,7 @@ export default function ClassiquesDepartsQuais() {
|
||||
return `${hh}h${mm}`;
|
||||
}, []);
|
||||
|
||||
const thresholdForStationType = useCallback((type) => {
|
||||
if (!type) return 0;
|
||||
const t = String(type).trim().toLowerCase();
|
||||
if (t === 'interurbaine' || t.includes('interurb')) return 360;
|
||||
if (t === 'ville' || t.includes('ville')) return 30;
|
||||
return 0;
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -457,6 +467,58 @@ export default function ClassiquesDepartsQuais() {
|
||||
setLoadingHoraire(true);
|
||||
setHoraireError(null);
|
||||
setSelectedHoraire(null);
|
||||
|
||||
const source = getSourceFromPath(window.location.pathname);
|
||||
if (source === 'sncf') {
|
||||
try {
|
||||
const { data: sncfData, error: sncfErr } = await getSncfTimetable({
|
||||
gareName: gareDisplayParam || gareParam,
|
||||
mode: 'departs',
|
||||
quai: quaiParam
|
||||
});
|
||||
if (!mounted) return;
|
||||
if (sncfErr) {
|
||||
setHoraireError(sncfErr);
|
||||
} else if (sncfData && sncfData.length > 0) {
|
||||
const train = sncfData[0];
|
||||
const now = new Date();
|
||||
const nowHM = now.getHours() * 60 + now.getMinutes();
|
||||
const depHM = parseTimeHM(train.heure_depart);
|
||||
|
||||
const chosen = {
|
||||
horaire: {
|
||||
...train,
|
||||
_status: train._status || {
|
||||
label: train.etat === 'supprime' ? 'supprimé' : (train.retard_minutes > 0 ? `retardé +${train.retard_minutes}min.` : "à l'heure"),
|
||||
detail: '',
|
||||
delayMinutes: train.retard_minutes || null,
|
||||
causeDetails: train.cause_retard || null
|
||||
}
|
||||
},
|
||||
stop: {
|
||||
gare_nom: train.gare_depart_nom || gareDisplayParam || gareParam,
|
||||
heure_depart: train.heure_depart,
|
||||
quai: train.quai || quaiParam,
|
||||
quai_reel: train.quai || quaiParam
|
||||
},
|
||||
depHM: depHM != null ? depHM : nowHM,
|
||||
rawTime: train.heure_depart,
|
||||
circulatesToday: true,
|
||||
circulatesTomorrow: false,
|
||||
isTomorrow: false
|
||||
};
|
||||
setSelectedHoraire(chosen);
|
||||
setCandidatesCount(sncfData.length);
|
||||
setStationType('interurbaine');
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setHoraireError(e.message || String(e));
|
||||
} finally {
|
||||
if (mounted) setLoadingHoraire(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!supabase) {
|
||||
setHoraireError('Supabase non initialisé');
|
||||
setLoadingHoraire(false);
|
||||
@@ -648,16 +710,10 @@ export default function ClassiquesDepartsQuais() {
|
||||
|
||||
loadNextForQuai();
|
||||
return () => { mounted = false; };
|
||||
}, [gareDisplayParam, gareIdParam, quaiParam, parseTimeHM, normalizeName, circulatesOn]);
|
||||
}, [gareDisplayParam, gareParam, gareIdParam, quaiParam, parseTimeHM, normalizeName, circulatesOn]);
|
||||
|
||||
// Rail is handled purely in CSS for better performance and alignment
|
||||
const showPlatform = (() => {
|
||||
const sched = selectedHoraire ? selectedHoraire.depHM : null;
|
||||
if (sched === null || !stationType) return true;
|
||||
const nowHM = currentTime.getHours() * 60 + currentTime.getMinutes();
|
||||
const threshold = thresholdForStationType(stationType);
|
||||
return nowHM >= (sched - threshold);
|
||||
})();
|
||||
const showPlatform = true;
|
||||
|
||||
if (!loadingHoraire && !selectedHoraire) {
|
||||
return (
|
||||
@@ -786,7 +842,7 @@ export default function ClassiquesDepartsQuais() {
|
||||
try { const p = JSON.parse(horaire.gares_desservies); if (Array.isArray(p)) stops = p; } catch (e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(stops) || stops.length === 0) stops = mock.stops || [];
|
||||
if (!Array.isArray(stops) || stops.length === 0) stops = [];
|
||||
|
||||
const labeled = stops.map((stop, idx) => {
|
||||
let label = '';
|
||||
@@ -868,7 +924,7 @@ export default function ClassiquesDepartsQuais() {
|
||||
{/* BOTTOM FOOTER: Full Width */}
|
||||
<div className="aff-quais-departs-redesign__footer">
|
||||
<div className="aff-quais-departs-redesign__footer-left">
|
||||
ain.
|
||||
{quaiParam ? `Voie ${quaiParam}` : (selectedHoraire?.horaire?.quai ? `Voie ${selectedHoraire.horaire.quai}` : (selectedHoraire?.stop?.quai ? `Voie ${selectedHoraire.stop.quai}` : ''))}
|
||||
</div>
|
||||
<div className="aff-quais-departs-redesign__footer-right">
|
||||
<Clock />
|
||||
|
||||
Reference in new issue
Block a user