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:
1 parent
c30a0e9002
commit
6cc1e1820d
14 files changed
+1143
-849
No files matched your search
+98
-125
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user