Désactivation des annonces sonores et refonte responsive mobile/tablette des pages de guidage WCS

This commit is contained in:
mathis committed 2026-08-30 22:07:34 +02:00
1 parent 4f3a34b101
commit 983f4f0160
9 files changed
+1315 -842

No files matched your search

+245 -321
View File
@@ -108,344 +108,268 @@ export default function SelectAfficheur({ onBack, navigate }) {
};
return (
<div style={{
maxWidth: '780px',
margin: '40px auto',
padding: '32px',
backgroundColor: '#ffffff',
borderRadius: '12px',
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.08)',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
}}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
<h2 style={{
margin: 0,
color: '#002257',
fontSize: '28px',
fontWeight: 700
}}>
Sélection de l'Afficheur
</h2>
<span style={{
fontSize: '12px',
fontWeight: '600',
padding: '4px 10px',
borderRadius: '12px',
background: source === 'supabase' ? '#e6f4ea' : '#e8f0fe',
color: source === 'supabase' ? '#137333' : '#1a73e8'
}}>
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF (GTFS)'}
</span>
<div className="launcher-container">
{/* Stepper */}
<div className="launcher-stepper">
<div className="launcher-step launcher-step--completed">
<span className="launcher-step-num">✓</span>
<span>{decodedGare || 'Gare'}</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step launcher-step--completed">
<span className="launcher-step-num">✓</span>
<span>{typeParam.toUpperCase()}</span>
</div>
<span className="launcher-step-separator">›</span>
<div className="launcher-step launcher-step--active">
<span className="launcher-step-num">3</span>
<span>Options & Affichage</span>
</div>
</div>
<p style={{
margin: '0 0 24px 0',
color: '#555555',
fontSize: '16px',
lineHeight: 1.5
}}>
Pour la gare de <strong>{decodedGare}</strong> en mode <strong>{modeParam === 'arrivees' ? 'Arrivées' : 'Départs'}</strong> (Style : <strong>{typeParam.toUpperCase()}</strong>).
</p>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginBottom: '32px' }}>
{/* General Afficheur Option */}
<div style={{
border: '2px solid #e2ebf6',
borderRadius: '8px',
padding: '24px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'flex-start',
background: '#fafbfc'
}}>
<div style={{ width: '100%' }}>
<h3 style={{ margin: '0 0 12px 0', color: '#00439e', fontSize: '20px' }}>Afficheur Général</h3>
<p style={{ margin: '0 0 16px 0', color: '#666', fontSize: '14px', lineHeight: 1.4 }}>
Affiche la liste des trains programmés avec possibilité d'inclure les pages d'informations et services.
<div className="launcher-card">
{/* Header */}
<div className="launcher-header">
<div>
<h1 className="launcher-title">Configuration de l'afficheur</h1>
<p className="launcher-subtitle">
Gare : <strong style={{ color: '#002257' }}>{decodedGare}</strong> • Mode : <strong style={{ color: '#00439e' }}>{modeParam === 'arrivees' ? '🏁 Arrivées' : '🚆 Départs'}</strong> • Style : <strong style={{ color: '#008b47' }}>{typeParam.toUpperCase()}</strong>
</p>
{typeParam === 'afl' && (
<div style={{
background: '#ffffff',
border: '1px solid #d0e1fd',
borderRadius: '8px',
padding: '14px',
marginBottom: '20px'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
<span style={{ fontSize: '13px', fontWeight: 700, color: '#002257' }}>
Pages à inclure dans la rotation :
</span>
<div style={{ display: 'flex', gap: '6px' }}>
<button
type="button"
onClick={() => selectAllAflPages(true)}
style={{
background: 'none',
border: 'none',
color: '#00439e',
fontSize: '11px',
fontWeight: 600,
cursor: 'pointer',
textDecoration: 'underline'
}}
>
Tout cocher
</button>
<span style={{ color: '#ccc', fontSize: '11px' }}>|</span>
<button
type="button"
onClick={() => selectAllAflPages(false)}
style={{
background: 'none',
border: 'none',
color: '#666',
fontSize: '11px',
fontWeight: 600,
cursor: 'pointer',
textDecoration: 'underline'
}}
>
Horaires seuls
</button>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px', color: '#222', cursor: 'pointer' }}>
<input
type="checkbox"
checked={aflPages.horaires}
onChange={() => toggleAflPage('horaires')}
style={{ width: '16px', height: '16px', accentColor: '#00439e' }}
/>
<span><strong>Page 1 & 2</strong> (Horaires des trains)</span>
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px', color: '#222', cursor: 'pointer' }}>
<input
type="checkbox"
checked={aflPages.infos}
onChange={() => toggleAflPage('infos')}
style={{ width: '16px', height: '16px', accentColor: '#00439e' }}
/>
<span><strong>Informations</strong> (Trafic & Travaux)</span>
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px', color: '#222', cursor: 'pointer' }}>
<input
type="checkbox"
checked={aflPages.securite1}
onChange={() => toggleAflPage('securite1')}
style={{ width: '16px', height: '16px', accentColor: '#00439e' }}
/>
<span><strong>Sécurité 1</strong> (Bagages / Objets délaissés)</span>
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px', color: '#222', cursor: 'pointer' }}>
<input
type="checkbox"
checked={aflPages.securite2}
onChange={() => toggleAflPage('securite2')}
style={{ width: '16px', height: '16px', accentColor: '#00439e' }}
/>
<span><strong>Sécurité 2</strong> (Vigipirate / Alerte 3117)</span>
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '13px', color: '#222', cursor: 'pointer' }}>
<input
type="checkbox"
checked={aflPages.corresp}
onChange={() => toggleAflPage('corresp')}
style={{ width: '16px', height: '16px', accentColor: '#00439e' }}
/>
<span><strong>Correspondances</strong> (Transports urbains & bus)</span>
</label>
</div>
</div>
)}
</div>
<button
onClick={handleGeneral}
style={{
backgroundColor: '#00439e',
color: '#ffffff',
border: 'none',
borderRadius: '6px',
padding: '12px 20px',
fontSize: '15px',
fontWeight: '600',
cursor: 'pointer',
width: '100%',
transition: 'background-color 0.2s'
}}
>
Accéder à l'Afficheur
</button>
<span className={`launcher-badge ${source === 'supabase' ? 'launcher-badge--supabase' : ''}`}>
{source === 'supabase' ? '🗄️ BDD Ferrovia' : '🌐 SNCF GTFS'}
</span>
</div>
{/* Platform-specific Afficheur Option */}
<div style={{
border: '2px solid #e2ebf6',
borderRadius: '8px',
padding: '24px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
background: '#fafbfc'
}}>
<div>
<h3 style={{ margin: '0 0 12px 0', color: '#00439e', fontSize: '20px' }}>Afficheur par Quai</h3>
<p style={{ margin: '0 0 16px 0', color: '#666', fontSize: '14px', lineHeight: 1.4 }}>
Affiche le prochain train et sa desserte spécifiquement pour une voie/quai.
</p>
{/* Grille responsive 2 colonnes (1 col sur mobile) */}
<div className="launcher-grid launcher-grid--2col">
{/* Option 1 : Afficheur Général */}
<div className="launcher-select-card" style={{ cursor: 'default' }}>
<div>
<span className="launcher-card-icon">🖥️</span>
<span className="launcher-card-tag launcher-card-tag--modern">Écran Général</span>
<h2 className="launcher-card-title">Afficheur Général (Hall)</h2>
<p className="launcher-card-desc">
Affiche la liste complète des circulations avec basculement automatique des pages.
</p>
{loading ? (
<div style={{ fontSize: '14px', color: '#888', marginBottom: '16px' }}>Chargement des voies...</div>
) : (
<div style={{ marginBottom: '16px' }}>
{platforms.length > 0 ? (
<div style={{ marginBottom: '12px' }}>
<label style={{ display: 'block', fontSize: '13px', fontWeight: 600, color: '#333', marginBottom: '4px' }}>
Sélectionner une voie existante :
</label>
<select
value={selectedPlatform}
onChange={(e) => {
setSelectedPlatform(e.target.value);
setManualPlatform('');
}}
style={{
width: '100%',
padding: '8px 12px',
borderRadius: '6px',
border: '1px solid #ccc',
fontSize: '14px'
}}
>
{platforms.map(p => (
<option key={p} value={p}>Voie {p}</option>
))}
</select>
{typeParam === 'afl' && (
<div className="launcher-checklist-box">
<div className="launcher-checklist-header">
<span className="launcher-checklist-title">
Pages incluses dans la boucle :
</span>
<div className="launcher-checklist-actions">
<button
type="button"
onClick={() => selectAllAflPages(true)}
className="launcher-link-btn"
>
Tout cocher
</button>
<span style={{ color: '#ccc' }}>|</span>
<button
type="button"
onClick={() => selectAllAflPages(false)}
className="launcher-link-btn"
style={{ color: '#666' }}
>
Horaires seuls
</button>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
<label className="launcher-checkbox-label">
<input
type="checkbox"
checked={aflPages.horaires}
onChange={() => toggleAflPage('horaires')}
className="launcher-checkbox"
/>
<span><strong>Page 1 & 2</strong> (Horaires des trains)</span>
</label>
<label className="launcher-checkbox-label">
<input
type="checkbox"
checked={aflPages.infos}
onChange={() => toggleAflPage('infos')}
className="launcher-checkbox"
/>
<span><strong>Informations</strong> (Trafic & Travaux)</span>
</label>
<label className="launcher-checkbox-label">
<input
type="checkbox"
checked={aflPages.securite1}
onChange={() => toggleAflPage('securite1')}
className="launcher-checkbox"
/>
<span><strong>Sécurité 1</strong> (Bagages délaissés)</span>
</label>
<label className="launcher-checkbox-label">
<input
type="checkbox"
checked={aflPages.securite2}
onChange={() => toggleAflPage('securite2')}
className="launcher-checkbox"
/>
<span><strong>Sécurité 2</strong> (Vigipirate / 3117)</span>
</label>
<label className="launcher-checkbox-label">
<input
type="checkbox"
checked={aflPages.corresp}
onChange={() => toggleAflPage('corresp')}
className="launcher-checkbox"
/>
<span><strong>Correspondances</strong> (Bus & Tram)</span>
</label>
</div>
</div>
)}
</div>
<button
type="button"
onClick={handleGeneral}
className="launcher-btn launcher-btn--primary"
>
🖥️ Lancer l'Afficheur Général
</button>
</div>
{/* Option 2 : Afficheur par Quai */}
<div className="launcher-select-card" style={{ cursor: 'default' }}>
<div>
<span className="launcher-card-icon">🚉</span>
<span className="launcher-card-tag launcher-card-tag--retro">Écran de Voie</span>
<h2 className="launcher-card-title">Afficheur par Quai</h2>
<p className="launcher-card-desc">
Affiche le prochain train au départ/arrivée avec la liste déroulante des gares desservies sur la voie.
</p>
<div style={{ background: '#f8fafc', border: '1px solid #e2ebf6', borderRadius: '10px', padding: '16px', marginBottom: '20px' }}>
{loading ? (
<div style={{ fontSize: '14px', color: '#00439e', fontWeight: 600 }}>⏳ Détection des voies réelles...</div>
) : (
<div style={{ fontSize: '13px', color: '#ff6b6b', marginBottom: '12px' }}>
Aucune voie détectée automatiquement pour cette gare.
<div>
{platforms.length > 0 ? (
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', fontSize: '13px', fontWeight: 700, color: '#002257', marginBottom: '6px' }}>
Voies actives détectées :
</label>
<select
value={selectedPlatform}
onChange={(e) => {
setSelectedPlatform(e.target.value);
setManualPlatform('');
}}
style={{
width: '100%',
padding: '12px',
borderRadius: '8px',
border: '2px solid #c2dbfe',
fontSize: '15px',
fontWeight: 600,
background: '#ffffff',
color: '#002257'
}}
>
{platforms.map(p => (
<option key={p} value={p}>Voie {p}</option>
))}
</select>
</div>
) : (
<div style={{ fontSize: '13px', color: '#666', marginBottom: '16px', background: '#fff', padding: '8px 12px', borderRadius: '6px' }}>
ℹ️ Saisie manuelle de la voie ci-dessous.
</div>
)}
<div>
<label style={{ display: 'block', fontSize: '13px', fontWeight: 700, color: '#002257', marginBottom: '6px' }}>
Ou saisie libre d'une voie :
</label>
<input
type="text"
placeholder="Ex: A, B, 1, 2 bis..."
value={manualPlatform}
onChange={(e) => setManualPlatform(e.target.value)}
style={{
width: '100%',
padding: '12px',
borderRadius: '8px',
border: '2px solid #e2ebf6',
fontSize: '15px',
boxSizing: 'border-box',
background: '#ffffff'
}}
/>
</div>
</div>
)}
<div>
<label style={{ display: 'block', fontSize: '13px', fontWeight: 600, color: '#333', marginBottom: '4px' }}>
Saisie libre d'une voie :
</label>
<input
type="text"
placeholder="Ex: A, 2 bis, 4..."
value={manualPlatform}
onChange={(e) => setManualPlatform(e.target.value)}
style={{
width: '100%',
padding: '8px 12px',
borderRadius: '6px',
border: '1px solid #ccc',
fontSize: '14px',
boxSizing: 'border-box'
}}
/>
</div>
</div>
)}
</div>
<button
type="button"
onClick={handlePlatform}
className="launcher-btn launcher-btn--success"
>
🚉 Lancer l'Afficheur de Quai
</button>
</div>
<button
onClick={handlePlatform}
style={{
backgroundColor: '#008b47',
color: '#ffffff',
border: 'none',
borderRadius: '6px',
padding: '12px 20px',
fontSize: '15px',
fontWeight: '600',
cursor: 'pointer',
width: '100%',
transition: 'background-color 0.2s'
</div>
{/* Accès direct aux pages fixes AFL */}
{typeParam === 'afl' && (
<div style={{ borderTop: '1px solid #e2ebf6', paddingTop: '20px', marginBottom: '20px' }}>
<span className="launcher-chips-label">Accès direct à une page fixe AFL :</span>
<div className="launcher-chips-list">
<button type="button" onClick={() => handleSinglePage('1')} className="launcher-chip">
Page 1 (Horaires)
</button>
<button type="button" onClick={() => handleSinglePage('2')} className="launcher-chip">
Page 2 (Horaires)
</button>
<button type="button" onClick={() => handleSinglePage('infos')} className="launcher-chip">
Informations Trafic
</button>
<button type="button" onClick={() => handleSinglePage('securite1')} className="launcher-chip">
Sécurité (Bagages)
</button>
<button type="button" onClick={() => handleSinglePage('securite2')} className="launcher-chip">
Sécurité (Vigipirate / 3117)
</button>
<button type="button" onClick={() => handleSinglePage('corresp')} className="launcher-chip">
Correspondances
</button>
</div>
</div>
)}
{/* Navigation retour */}
<div className="launcher-footer-nav">
<WcsButton
mode="plain"
onClick={() => {
if (typeof onBack === 'function') {
onBack();
} else if (typeof navigate === 'function') {
navigate(`${prefix}/afficheurs?gare=${encodeURIComponent(gareParam)}&mode=${modeParam}`);
}
}}
>
Accéder au Quai
</button>
label="← Retour au choix du style"
/>
</div>
</div>
{typeParam === 'afl' && (
<div style={{
borderTop: '1px solid #eef2f8',
paddingTop: '20px',
marginBottom: '20px'
}}>
<h4 style={{ margin: '0 0 10px 0', fontSize: '14px', color: '#555', fontWeight: 600 }}>
Accès direct à une page AFL spécifique (fixe) :
</h4>
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
<button
onClick={() => handleSinglePage('1')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Horaires (Page 1)
</button>
<button
onClick={() => handleSinglePage('2')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Horaires (Page 2)
</button>
<button
onClick={() => handleSinglePage('infos')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Informations
</button>
<button
onClick={() => handleSinglePage('securite1')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Sécurité 1
</button>
<button
onClick={() => handleSinglePage('securite2')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Sécurité 2
</button>
<button
onClick={() => handleSinglePage('corresp')}
style={{ padding: '6px 12px', fontSize: '12px', borderRadius: '4px', border: '1px solid #ccc', background: '#fff', cursor: 'pointer' }}
>
Correspondances
</button>
</div>
</div>
)}
<div style={{
borderTop: '1px solid #eeeeee',
paddingTop: '20px',
display: 'flex',
justifyContent: 'flex-start'
}}>
<WcsButton
mode="plain"
onClick={() => {
if (typeof onBack === 'function') {
onBack();
} else if (typeof navigate === 'function') {
navigate(`${prefix}/afficheurs?gare=${encodeURIComponent(gareParam)}&mode=${modeParam}`);
}
}}
label="Retour aux types d'afficheurs"
/>
</div>
</div>
);
}