V2.0.1 : VOICI LES MODIFICATIONS MAJEURS APPRTÉES DANS CETTE VERSION :

-> REFONTE DU DESIGN DES AFFICHEURS CLASSIQUES (GÉNÉRAL + QUAIS)
-> IMPLÉMENTATION DU DESIGN AFL : GÉNÉRAL ET QUAIS

-> CHOIX DE LA SÉLECTION DES TYPES D'AFFICHEURS (GÉNÉRAL / QUAIS) UNE FOIS LE TYPE D'AFFICHEUR SÉLECTIONNÉS
This commit is contained in:
Ferrovia committed 2026-07-10 17:55:13 +02:00
1 parent 71822823f2
commit 19868a451f
16 files changed
+156 -48

No files matched your search

+5 -5
View File
@@ -27,7 +27,7 @@ export default function SelectAfficheur({ onBack, navigate }) {
}
try {
setLoading(true);
const { data, error } = await supabase.from('horaires').select('stops, quai_reel, voie, quai, gare_depart_nom, gare_arrivee_nom');
const { data, error } = await supabase.from('horaires').select('quai_reel, voie, quai, gare_depart_nom, gare_arrivee_nom, gares_desservies');
if (error) throw error;
if (!mounted) return;
@@ -36,10 +36,10 @@ export default function SelectAfficheur({ onBack, navigate }) {
(data || []).forEach(h => {
let stopsList = [];
if (Array.isArray(h.stops)) {
stopsList = h.stops;
} else if (typeof h.stops === 'string') {
try { stopsList = JSON.parse(h.stops); } catch (e) {}
if (Array.isArray(h.gares_desservies)) {
stopsList = h.gares_desservies;
} else if (typeof h.gares_desservies === 'string') {
try { stopsList = JSON.parse(h.gares_desservies); } catch (e) {}
}
if (!Array.isArray(stopsList)) stopsList = [];
+7 -6
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import './AFLArrivees.css';
import supabase from '../../../lib/supabase';
import { fetchAllRows } from '../../../lib/fetchAllRows';
import MarqueeText from '../../../components/MarqueeText';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../hooks/useAutoAnnonce';
@@ -586,7 +587,7 @@ export default function AFLArrivees(){
setError(null);
try {
const [{ data: horairesData, error: hError }, { data: perturbData, error: pError }, { data: travauxData, error: tError }, { data: travauxSubstData }] = await Promise.all([
supabase.from('horaires').select('id, *'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*'),
supabase.from('travaux_substitutions').select('*')
@@ -609,14 +610,14 @@ export default function AFLArrivees(){
// conserver la liste complète telle que renvoyée par la BDD (avant filtrage par gare)
let parsedHoraires = (horairesData || []).map(h => h || {});
// Certains champs (comme stops) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que stops est un tableau utilisable.
// Certains champs (comme gares_desservies) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que gares_desservies est un tableau utilisable.
parsedHoraires = parsedHoraires.map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) {
return { ...h, stops: parsed };
return { ...h, gares_desservies: parsed };
}
}
} catch (e) {
+5 -4
View File
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import supabase from '../../../lib/supabase';
import { fetchAllRows } from '../../../lib/fetchAllRows';
import './AFLArriveesQuais.css';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
@@ -419,7 +420,7 @@ const AFLArriveesQuais = () => {
const fetchData = useCallback(async () => {
try {
const [{ data: horairesData }, { data: subData }, { data: perturbData }, { data: travauxData }] = await Promise.all([
supabase.from('horaires').select('*'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('travaux_substitutions').select('*'),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*')
@@ -427,9 +428,9 @@ const AFLArriveesQuais = () => {
let parsedHoraires = (horairesData || []).map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (Array.isArray(parsed)) return { ...h, stops: parsed };
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) return { ...h, gares_desservies: parsed };
}
} catch (e) {}
return h || {};
+7 -6
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import './AFLDeparts.css';
import supabase from '../../../lib/supabase';
import { fetchAllRows } from '../../../lib/fetchAllRows';
import MarqueeText from '../../../components/MarqueeText';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../hooks/useAutoAnnonce';
@@ -586,7 +587,7 @@ export default function AFLDeparts(){
setError(null);
try {
const [{ data: horairesData, error: hError }, { data: perturbData, error: pError }, { data: travauxData, error: tError }, { data: travauxSubstData }] = await Promise.all([
supabase.from('horaires').select('id, *'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*'),
supabase.from('travaux_substitutions').select('*')
@@ -609,14 +610,14 @@ export default function AFLDeparts(){
// conserver la liste complète telle que renvoyée par la BDD (avant filtrage par gare)
let parsedHoraires = (horairesData || []).map(h => h || {});
// Certains champs (comme stops) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que stops est un tableau utilisable.
// Certains champs (comme gares_desservies) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que gares_desservies est un tableau utilisable.
parsedHoraires = parsedHoraires.map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) {
return { ...h, stops: parsed };
return { ...h, gares_desservies: parsed };
}
}
} catch (e) {
+5 -4
View File
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import supabase from '../../../lib/supabase';
import { fetchAllRows } from '../../../lib/fetchAllRows';
import './AFLDepartsQuais.css';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
@@ -420,7 +421,7 @@ const AFLDepartsQuais = () => {
const fetchData = useCallback(async () => {
try {
const [{ data: horairesData }, { data: subData }, { data: perturbData }, { data: travauxData }] = await Promise.all([
supabase.from('horaires').select('*'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('travaux_substitutions').select('*'),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*')
@@ -428,9 +429,9 @@ const AFLDepartsQuais = () => {
let parsedHoraires = (horairesData || []).map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (Array.isArray(parsed)) return { ...h, stops: parsed };
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) return { ...h, gares_desservies: parsed };
}
} catch (e) {}
return h || {};
@@ -5,6 +5,7 @@ import Logo from '../../../components/Logo';
import MarqueeText from '../../../components/MarqueeText';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../hooks/useAutoAnnonce';
import { fetchAllRows } from '../../../lib/fetchAllRows';
// Helper utilitaire : format HHhMM sans secondes (ex: 06h44)
const formatTimeNoSeconds = (v) => {
@@ -625,9 +626,7 @@ export default function ClassiquesArrivees(){
setError(null);
try {
const [{ data: horairesData, error: hError }, { data: perturbData, error: pError }, { data: travauxData, error: tError }] = await Promise.all([
// DEBUG: récupérer explicitement l'id et toutes les colonnes pour s'assurer que l'identifiant
// `id` est bien présent et peut être mis en correspondance avec `horaire_id` dans perturbations
supabase.from('horaires').select('id, *'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*')
]);
@@ -649,14 +648,13 @@ export default function ClassiquesArrivees(){
// conserver la liste complète telle que renvoyée par la BDD (avant filtrage par gare)
let parsedHoraires = (horairesData || []).map(h => h || {});
// Certains champs (comme stops) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que stops est un tableau utilisable.
// Parser gares_desservies si c'est une chaîne JSON
parsedHoraires = parsedHoraires.map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) {
return { ...h, stops: parsed };
return { ...h, gares_desservies: parsed };
}
}
} catch (e) {
@@ -5,6 +5,7 @@ import Logo from '../../../components/Logo';
import MarqueeText from '../../../components/MarqueeText';
import useAnnonceSonoreRealtime from '../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../hooks/useAutoAnnonce';
import { fetchAllRows } from '../../../lib/fetchAllRows';
// Helper utilitaire : format HHhMM sans secondes (ex: 06h44)
const formatTimeNoSeconds = (v) => {
@@ -625,9 +626,7 @@ export default function ClassiquesDeparts(){
setError(null);
try {
const [{ data: horairesData, error: hError }, { data: perturbData, error: pError }, { data: travauxData, error: tError }] = await Promise.all([
// DEBUG: récupérer explicitement l'id et toutes les colonnes pour s'assurer que l'identifiant
// `id` est bien présent et peut être mis en correspondance avec `horaire_id` dans perturbations
supabase.from('horaires').select('id, *'),
fetchAllRows(supabase.from('horaires').select('*')),
supabase.from('perturbations').select('*'),
supabase.from('travaux').select('*')
]);
@@ -649,14 +648,13 @@ export default function ClassiquesDeparts(){
// conserver la liste complète telle que renvoyée par la BDD (avant filtrage par gare)
let parsedHoraires = (horairesData || []).map(h => h || {});
// Certains champs (comme stops) peuvent arriver en tant que chaîne JSON depuis la BDD;
// essayer de parser pour garantir que stops est un tableau utilisable.
// Parser gares_desservies si c'est une chaîne JSON
parsedHoraires = parsedHoraires.map(h => {
try {
if (h && typeof h.stops === 'string') {
const parsed = JSON.parse(h.stops);
if (h && typeof h.gares_desservies === 'string') {
const parsed = JSON.parse(h.gares_desservies);
if (Array.isArray(parsed)) {
return { ...h, stops: parsed };
return { ...h, gares_desservies: parsed };
}
}
} catch (e) {
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import './ClassiquesArriveesQuais.css';
import supabase from '../../../../lib/supabase';
import { fetchAllRows } from '../../../../lib/fetchAllRows';
import useAnnonceSonoreRealtime from '../../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../../hooks/useAutoAnnonce';
function Clock() {
@@ -490,7 +491,7 @@ export default function ClassiquesArriveesQuais() {
}
} catch (e) {}
const { data: all, error } = await supabase.from('horaires').select('id, *');
const { data: all, error } = await fetchAllRows(supabase.from('horaires').select('*'));
if (error) {
if (mounted) setHoraireError(error.message || String(error));
setLoadingHoraire(false);
@@ -784,8 +785,8 @@ export default function ClassiquesArriveesQuais() {
const horaire = selectedHoraire && selectedHoraire.horaire ? selectedHoraire.horaire : null;
let stops = horaire ? getStops(horaire) : [];
if (!Array.isArray(stops) || stops.length === 0) {
if (horaire && typeof horaire.stops === 'string') {
try { const p = JSON.parse(horaire.stops); if (Array.isArray(p)) stops = p; } catch (e) { /* ignore */ }
if (horaire && typeof horaire.gares_desservies === 'string') {
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 || [];
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import './ClassiquesDepartsQuais.css';
import supabase from '../../../../lib/supabase';
import { fetchAllRows } from '../../../../lib/fetchAllRows';
import useAnnonceSonoreRealtime from '../../../../hooks/useAnnonceSonoreRealtime';
import useAutoAnnonce from '../../../../hooks/useAutoAnnonce';
function Clock() {
@@ -490,7 +491,7 @@ export default function ClassiquesDepartsQuais() {
}
} catch (e) {}
const { data: all, error } = await supabase.from('horaires').select('id, *');
const { data: all, error } = await fetchAllRows(supabase.from('horaires').select('*'));
if (error) {
if (mounted) setHoraireError(error.message || String(error));
setLoadingHoraire(false);
@@ -781,8 +782,8 @@ export default function ClassiquesDepartsQuais() {
const horaire = selectedHoraire && selectedHoraire.horaire ? selectedHoraire.horaire : null;
let stops = horaire ? getStops(horaire) : [];
if (!Array.isArray(stops) || stops.length === 0) {
if (horaire && typeof horaire.stops === 'string') {
try { const p = JSON.parse(horaire.stops); if (Array.isArray(p)) stops = p; } catch (e) { /* ignore */ }
if (horaire && typeof horaire.gares_desservies === 'string') {
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 || [];