import { useEffect, useRef, useState } from 'react' import { MapPin, X } from 'lucide-react' import { mapsApi } from '../../api/client' import { useTranslation } from '../../i18n' export interface LocationPoint { name: string lat: number lng: number address?: string | null } interface Props { value: LocationPoint | null onChange: (loc: LocationPoint | null) => void placeholder?: string style?: React.CSSProperties } export default function LocationSelect({ value, onChange, placeholder, style }: Props) { const { t, locale } = useTranslation() const [query, setQuery] = useState(value?.name || '') const [open, setOpen] = useState(false) const [results, setResults] = useState([]) const [highlight, setHighlight] = useState(-1) const [loading, setLoading] = useState(false) const wrapRef = useRef(null) const debounceRef = useRef | null>(null) useEffect(() => { setQuery(value?.name || '') }, [value]) useEffect(() => { const handler = (e: MouseEvent) => { if (!wrapRef.current?.contains(e.target as Node)) setOpen(false) } if (open) document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) }, [open]) useEffect(() => { if (debounceRef.current) clearTimeout(debounceRef.current) const trimmed = query.trim() if (trimmed.length < 3 || (value && trimmed === value.name)) { setResults([]) return } debounceRef.current = setTimeout(async () => { setLoading(true) try { const data = await mapsApi.search(trimmed, locale) setResults(data.places || []) setHighlight(-1) } catch { setResults([]) } finally { setLoading(false) } }, 320) return () => { if (debounceRef.current) clearTimeout(debounceRef.current) } }, [query, value, locale]) const pick = (r: any) => { const lat = Number(r.lat) const lng = Number(r.lng) if (!Number.isFinite(lat) || !Number.isFinite(lng)) return const loc: LocationPoint = { name: r.name || r.address || 'Location', lat, lng, address: r.address || null } onChange(loc) setQuery(loc.name) setOpen(false) setResults([]) } const clear = () => { onChange(null) setQuery('') setResults([]) } const onKey = (e: React.KeyboardEvent) => { if (!open || results.length === 0) return if (e.key === 'ArrowDown') { e.preventDefault(); setHighlight(h => Math.min(h + 1, results.length - 1)) } else if (e.key === 'ArrowUp') { e.preventDefault(); setHighlight(h => Math.max(h - 1, 0)) } else if (e.key === 'Enter' && highlight >= 0) { e.preventDefault(); pick(results[highlight]) } else if (e.key === 'Escape') setOpen(false) } return (
{ setQuery(e.target.value); setOpen(true); if (value) onChange(null) }} onFocus={() => setOpen(true)} onKeyDown={onKey} style={{ flex: 1, minWidth: 0, background: 'transparent', border: 'none', outline: 'none', color: 'var(--text-primary)', fontSize: 13 }} /> {value && ( )}
{open && (loading || results.length > 0) && (
{loading && results.length === 0 && (
{t('common.loading')}
)} {results.map((r, i) => ( ))}
)}
) }