/* Voyage Assistant — SearchBar éditable avec autocomplete lieux. Chaque champ est cliquable individuellement et ouvre son éditeur inline. Le bouton Rechercher déclenche onSearch(values). */ const Autocomplete = ({ value, onChange, onPick, placeholder, type }) => { const [items, setItems] = React.useState([]); const [open, setOpen] = React.useState(false); const [loading, setLoading] = React.useState(false); const inputRef = React.useRef(null); const timerRef = React.useRef(null); React.useEffect(() => { if (timerRef.current) clearTimeout(timerRef.current); timerRef.current = setTimeout(async () => { setLoading(true); try { const qs = new URLSearchParams({ q: value || '', limit: 8 }); if (type) qs.set('type', type); const res = await fetch(`${window.VA_CONFIG.API_BASE}/lieux?${qs.toString()}`); const data = await res.json(); setItems(Array.isArray(data) ? data : []); } catch { setItems([]); } finally { setLoading(false); } }, 150); return () => clearTimeout(timerRef.current); }, [value, type]); React.useEffect(() => { if (inputRef.current) inputRef.current.focus(); }, []); return (
onChange(e.target.value)} onFocus={() => setOpen(true)} onBlur={() => setTimeout(() => setOpen(false), 180)} placeholder={placeholder} style={{ width: '100%', height: 38, padding: '0 12px', border: '1px solid var(--va-border)', borderRadius: 8, fontSize: 14, fontFamily: 'inherit', color: 'var(--va-text)', background: 'var(--va-bg)', }} /> {open && (items.length > 0 || loading) && (
{loading &&
{t('Recherche…')}
} {!loading && items.map((it, i) => ( ))}
)}
); }; const SearchBarEditable = ({ values, onChange, onSearch, type }) => { const [editing, setEditing] = React.useState(null); // 'depart' | 'arrivee' | 'date' | 'passagers' | null React.useEffect(() => { const onClick = (e) => { // Close when clicking outside the search bar if (!e.target.closest('.va-search')) setEditing(null); }; document.addEventListener('mousedown', onClick); return () => document.removeEventListener('mousedown', onClick); }, []); const set = (k, v) => onChange({ ...values, [k]: v }); const dateLabel = (() => { if (!values.date) return t('Choisir une date'); const d = new Date(values.date); if (isNaN(d)) return t('Choisir une date'); return d.toLocaleDateString(window.VA_I18N.locale(), { weekday: 'short', day: 'numeric', month: 'short' }); })(); const tripType = values.tripType || 'aller'; const roundTrip = window.isRoundTrip(tripType); const retourLabel = (() => { if (!values.dateRetour) return t('Choisir une date'); const d = new Date(values.dateRetour); if (isNaN(d)) return t('Choisir une date'); return d.toLocaleDateString(window.VA_I18N.locale(), { weekday: 'short', day: 'numeric', month: 'short' }); })(); return (
onChange({ ...values, tripType: t })} />
{/* Départ */}
{ e.stopPropagation(); setEditing('depart'); }}> {t('Départ')} {editing === 'depart' ? ( set('depart', v)} onPick={(it) => { set('depart', it.nom); setEditing(null); }} /> ) : ( <> {values.depart || t("D'où partez-vous ?")} {t('Cliquer pour modifier')} )}
{/* Arrivée */}
{ e.stopPropagation(); setEditing('arrivee'); }}> {t('Arrivée')} {editing === 'arrivee' ? ( set('arrivee', v)} onPick={(it) => { set('arrivee', it.nom); setEditing(null); }} /> ) : ( <> {values.arrivee || t('Où allez-vous ?')} {t('Cliquer pour modifier')} )}
{/* Date aller */}
{ e.stopPropagation(); setEditing('date'); }}> {tripType === 'retour' ? t('Date retour') : roundTrip ? t('Date aller') : t('Date')} {editing === 'date' ? ( set('date', e.target.value)} onBlur={() => setEditing(null)} style={{ width: '100%', height: 38, padding: '0 12px', border: '1px solid var(--va-border)', borderRadius: 8, fontSize: 14, fontFamily: 'inherit', color: 'var(--va-text)', background: 'var(--va-bg)', }} /> ) : ( <> {dateLabel} {t('Cliquer pour modifier')} )}
{roundTrip && (
{ e.stopPropagation(); setEditing('dateRetour'); }}> {t('Date retour')} {editing === 'dateRetour' ? ( set('dateRetour', e.target.value)} onBlur={() => setEditing(null)} style={{ width: '100%', height: 38, padding: '0 12px', border: '1px solid var(--va-border)', borderRadius: 8, fontSize: 14, fontFamily: 'inherit', color: 'var(--va-text)', background: 'var(--va-bg)', }} /> ) : ( <> {retourLabel} {t('Cliquer pour modifier')} )}
)} {/* Voyageurs — popover adulte/enfant/bébé */}
{ e.stopPropagation(); setEditing(editing === 'passagers' ? null : 'passagers'); }} > {t('Voyageurs')} {window.paxLabel(window.normalizePax(values))} {window.paxBreakdown(window.normalizePax(values)) || t('Cliquer pour modifier')} {editing === 'passagers' && (
e.stopPropagation()} > onChange({ ...values, pax, passagers: window.paxCount(pax) })} onValidate={() => setEditing(null)} />
)}
); }; Object.assign(window, { Autocomplete, SearchBarEditable });