V1.1.0 //

-> Refonte du design de sélection d'afficheurs
-> Ajout du Mode PiP
-> Patch du bug du logo de l'horaire pas affiché. Corrigé pour les Horaires TER à 6 numéros.
This commit is contained in:
AdminGit committed 2026-10-07 15:32:21 +02:00
1 parent c30a0e9002
commit 6cc1e1820d
14 files changed
+1143 -849

No files matched your search

+98 -125
View File
@@ -1,5 +1,5 @@
import React, { useEffect, useState, useMemo } from 'react';
import WcsButton from '../components/WcsButton';
import { WcsCard, WcsCardBody, WcsButton, WcsInput, WcsBadge, WcsHorizontalStepper } from 'wcs-react';
import sessionMemory from '../lib/sessionMemory';
import { getSourceFromPath, searchGares } from '../services/railwayService';
@@ -90,139 +90,112 @@ export default function Departs({ onBack, navigate }) {
}
};
const steps = [
{ text: 'Choix de la gare', button: { kind: 'Text', text: '1' }, complete: false },
{ text: "Type d'afficheur", button: { kind: 'Text', text: '2' }, disable: true },
{ text: 'Options & Affichage', button: { kind: 'Text', text: '3' }, disable: true }
];
return (
<div className="launcher-container">
{/* Stepper */}
<div className="launcher-stepper">
<div className="launcher-step launcher-step--active">
<span className="launcher-step-num">1</span>
<span>Choix de la gare</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step">
<span className="launcher-step-num">2</span>
<span>Type d'afficheur</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step">
<span className="launcher-step-num">3</span>
<span>Options & Affichage</span>
</div>
</div>
<div style={{ maxWidth: '900px', margin: '0 auto', padding: '24px', overflowY: 'auto', maxHeight: 'calc(100vh - 120px)' }}>
<WcsHorizontalStepper steps={steps} currentStep={0} style={{ marginBottom: '24px' }} />
<div className="launcher-card">
{/* Header */}
<div className="launcher-header">
<div>
<h1 className="launcher-title">🚆 Prochains Départs</h1>
<p className="launcher-subtitle">Recherchez une gare pour afficher le tableau des départs en temps réel.</p>
<WcsCard mode="raised">
<WcsCardBody>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '24px' }}>
<div>
<h1 style={{ margin: '0 0 8px 0', fontSize: '24px', color: 'var(--wcs-primary)' }}>🚆 Prochains Départs</h1>
<p style={{ margin: 0, color: 'var(--wcs-text-light)' }}>Recherchez une gare pour afficher le tableau des départs en temps réel.</p>
</div>
<WcsBadge className={source === 'supabase' ? 'wcs-secondary' : 'wcs-primary'} shape="rounded">
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF GTFS Live'}
</WcsBadge>
</div>
<span className={`launcher-badge ${source === 'supabase' ? 'launcher-badge--supabase' : ''}`}>
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF GTFS Live'}
</span>
</div>
{/* Barre de recherche */}
<div className="launcher-search-box">
<input
type="search"
placeholder="Rechercher une gare (ex: Dijon, Paris, Lyon, Besançon...)"
value={search}
onChange={(e) => setSearch(e.target.value)}
className="launcher-search-input"
aria-label="Rechercher une gare"
autoFocus
/>
{search && (
<button
type="button"
className="launcher-search-clear"
onClick={() => setSearch('')}
aria-label="Effacer la recherche"
>
✕
</button>
)}
</div>
{/* Suggestions rapides / Gares populaires */}
<div className="launcher-chips-container">
<span className="launcher-chips-label">Gares fréquentes :</span>
<div className="launcher-chips-list">
{POPULAR_GARES.map((gName) => (
<button
key={gName}
type="button"
className="launcher-chip"
onClick={() => handleSelectGare(gName)}
>
{gName.replace(/-/g, ' ')}
</button>
))}
<div style={{ marginBottom: '24px' }}>
<WcsInput
type="text"
icon="search"
placeholder="Rechercher une gare (ex: Dijon, Paris, Lyon, Besançon...)"
value={search}
onWcsInput={(e) => setSearch(e.target.value)}
style={{ width: '100%' }}
clearable={true}
/>
</div>
</div>
{loading && <p style={{ color: '#00439e', fontWeight: 600 }}>⏳ Chargement des gares...</p>}
{error && <p style={{ color: '#d70022', fontWeight: 600 }}>⚠️ Erreur : {error}</p>}
{/* Invitation à la recherche en mode SNCF */}
{source === 'sncf' && search.trim().length < 2 && (
<div style={{ textAlign: 'center', padding: '24px 16px', color: '#666', background: '#f8fafc', borderRadius: '8px', border: '1px dashed #d0d7de' }}>
<p style={{ margin: 0, fontSize: '14px' }}>
💡 Saisissez au moins <strong>2 lettres</strong> pour chercher parmi plus de 3 500 gares du réseau français.
</p>
</div>
)}
{/* Aucun résultat */}
{source === 'sncf' && search.trim().length >= 2 && displayedGares.length === 0 && (
<div style={{ textAlign: 'center', padding: '24px', color: '#777', background: '#fff', borderRadius: '8px' }}>
Aucune gare trouvée pour « <strong>{search}</strong> ».
</div>
)}
{/* Liste des résultats */}
{displayedGares.length > 0 && (
<div className="launcher-results-list" role="list">
{displayedGares.map((g) => {
const nom = g.nom;
return (
<div
key={g.uic || nom}
className="launcher-result-item"
onClick={() => handleSelectGare(nom)}
onKeyDown={(e) => (e.key === 'Enter' ? handleSelectGare(nom) : null)}
tabIndex={0}
role="listitem"
<div style={{ marginBottom: '24px' }}>
<p style={{ fontWeight: 'bold', marginBottom: '12px' }}>Gares fréquentes :</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
{POPULAR_GARES.map((gName) => (
<WcsButton
key={gName}
mode="stroked"
shape="round"
size="s"
onClick={() => handleSelectGare(gName)}
>
<div>
<div className="launcher-result-name">{nom}</div>
{g.commune && (
<div className="launcher-result-sub">
{g.commune} {g.departement ? `(${g.departement})` : ''}
</div>
)}
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
{g.uic && <span className="launcher-result-tag">UIC {g.uic}</span>}
<span style={{ color: '#00439e', fontSize: '18px', fontWeight: 'bold' }}>›</span>
</div>
</div>
);
})}
{gName.replace(/-/g, ' ')}
</WcsButton>
))}
</div>
</div>
)}
{/* Navigation retour */}
<div className="launcher-footer-nav">
<WcsButton
mode="plain"
onClick={onBack}
label="← Retour à l'accueil"
/>
</div>
</div>
{loading && <p style={{ color: 'var(--wcs-primary)', fontWeight: 600 }}>⏳ Chargement des gares...</p>}
{error && <p style={{ color: 'var(--wcs-danger)', fontWeight: 600 }}>⚠️ Erreur : {error}</p>}
{source === 'sncf' && search.trim().length < 2 && (
<div style={{ textAlign: 'center', padding: '24px 16px', color: 'var(--wcs-text-light)', background: 'var(--wcs-light)', borderRadius: '8px', border: '1px dashed var(--wcs-gray)' }}>
<p style={{ margin: 0, fontSize: '14px' }}>
💡 Saisissez au moins <strong>2 lettres</strong> pour chercher parmi plus de 3 500 gares du réseau français.
</p>
</div>
)}
{source === 'sncf' && search.trim().length >= 2 && displayedGares.length === 0 && (
<div style={{ textAlign: 'center', padding: '24px', color: 'var(--wcs-text-light)', background: 'var(--wcs-white)', borderRadius: '8px' }}>
Aucune gare trouvée pour « <strong>{search}</strong> ».
</div>
)}
{displayedGares.length > 0 && (
<div role="list" style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '24px' }}>
{displayedGares.map((g) => {
const nom = g.nom;
return (
<WcsCard
key={g.uic || nom}
mode="flat"
style={{ cursor: 'pointer', border: '1px solid var(--wcs-light)' }}
onClick={() => handleSelectGare(nom)}
>
<WcsCardBody style={{ padding: '12px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div style={{ fontWeight: 'bold', fontSize: '16px', color: 'var(--wcs-primary)' }}>{nom}</div>
{g.commune && (
<div style={{ fontSize: '13px', color: 'var(--wcs-text-light)' }}>
{g.commune} {g.departement ? `(${g.departement})` : ''}
</div>
)}
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
{g.uic && <WcsBadge>{g.uic}</WcsBadge>}
<span style={{ color: 'var(--wcs-primary)', fontSize: '20px', fontWeight: 'bold' }}>›</span>
</div>
</WcsCardBody>
</WcsCard>
);
})}
</div>
)}
<div style={{ borderTop: '1px solid var(--wcs-light)', paddingTop: '16px' }}>
<WcsButton mode="clear" onClick={onBack}>
← Retour à l'accueil
</WcsButton>
</div>
</WcsCardBody>
</WcsCard>
</div>
);
}