import { useEffect, useRef, useState } from 'react'; import { LoaderCircleIcon, MapPinIcon, SearchIcon } from 'lucide-react'; import type { ISeoAddress } from '../../service/seo/seo.interface'; import { searchSeoAddress } from '../../service/seo/seo.service'; import { Input } from '../ui/input'; /** How long the box waits after the last keystroke before it asks. The map * services forbid a request per key, and the answer is cached on the site, * so this is politeness rather than latency. */ const DEBOUNCE_MS = 700; /** Below this many characters nothing is worth searching for. */ const MIN_QUERY = 4; /** * One box that fills the address under it. The merchant writes the address * the way they would say it, picks their own from what comes back, and the * street, city, region, postal code, country and coordinates are filled * together - so they cannot disagree with each other or with the map. * * @param props - Component props. * @param props.onPick - What to do with the address chosen. * @return The box and its suggestions. */ export const AddressSearch = ({ onPick, }: { onPick: (address: ISeoAddress) => void; }): JSX.Element => { const [query, setQuery] = useState(''); const [items, setItems] = useState([]); const [busy, setBusy] = useState(false); const [note, setNote] = useState(''); // What the last pick wrote, so choosing a suggestion does not immediately // search for the text it put in the box. const pickedRef = useRef(''); useEffect(() => { const asked: string = query.trim(); if (asked.length < MIN_QUERY || asked === pickedRef.current) { setItems([]); return undefined; } const handle: number = window.setTimeout(() => { setBusy(true); setNote(''); void searchSeoAddress(asked) .then(result => { setItems(result.items); if (result.items.length === 0) { setNote( 'No match; try the street and the city, or type it by hand below.' ); } }) .catch(() => setNote('The lookup failed; try again in a moment.')) .finally(() => setBusy(false)); }, DEBOUNCE_MS); return () => window.clearTimeout(handle); }, [query]); return (
{busy ? ( ) : ( )} setQuery(event.target.value)} placeholder="Street and number, city" className="pl-9" />
{items.length > 0 && (
    {items.map((item: ISeoAddress, index: number) => (
  • ))}
)} {note &&

{note}

}
); };