This commit is contained in:
Andras Schmelczer 2026-05-31 20:20:41 +01:00
parent 8688b7475e
commit e8345cbdc1
40 changed files with 1980 additions and 904 deletions

View file

@ -160,6 +160,7 @@ export function useLocationSearch(mode?: string) {
const [recentSearches, setRecentSearches] = useState<SearchResult[]>(readRecentSearches);
const [activeIndex, setActiveIndex] = useState(-1);
const [open, setOpen] = useState(false);
const [searching, setSearching] = useState(false);
const abortRef = useRef<AbortController | null>(null);
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const latestQueryRef = useRef('');
@ -176,6 +177,7 @@ export function useLocationSearch(mode?: string) {
const trimmed = value.trim();
if (!trimmed) {
setSearching(false);
setResults(recentSearches);
lastResultsRef.current = [];
setOpen(recentSearches.length > 0);
@ -183,6 +185,7 @@ export function useLocationSearch(mode?: string) {
}
if (!mode && looksLikePostcode(trimmed)) {
setSearching(false);
const postcodeResults: SearchResult[] = [
{ type: 'postcode', label: normalizePostcode(trimmed) },
];
@ -192,6 +195,7 @@ export function useLocationSearch(mode?: string) {
}
if (trimmed.length < 2) {
setSearching(false);
setResults([]);
setOpen(false);
return;
@ -200,6 +204,7 @@ export function useLocationSearch(mode?: string) {
const locallyFilteredResults = filterResultsForQuery(lastResultsRef.current, trimmed);
setResults(locallyFilteredResults);
setOpen(locallyFilteredResults.length > 0);
setSearching(true);
debounceRef.current = setTimeout(async () => {
const controller = new AbortController();
@ -211,7 +216,13 @@ export function useLocationSearch(mode?: string) {
`/api/places?${params}`,
authHeaders({ signal: controller.signal })
);
if (!res.ok) return;
if (!res.ok) {
if (!controller.signal.aborted && latestQueryRef.current.trim() === trimmed) {
setResults([]);
setOpen(true);
}
return;
}
const json: {
places: PlaceResult[];
postcodes?: string[];
@ -253,9 +264,17 @@ export function useLocationSearch(mode?: string) {
lastResultsRef.current = combinedResults;
const matchingResults = filterResultsForQuery(combinedResults, trimmed);
setResults(matchingResults);
setOpen(matchingResults.length > 0);
setOpen(true);
} catch (err) {
logNonAbortError('places search', err);
if (!controller.signal.aborted && latestQueryRef.current.trim() === trimmed) {
setResults([]);
setOpen(true);
}
} finally {
if (!controller.signal.aborted && latestQueryRef.current.trim() === trimmed) {
setSearching(false);
}
}
}, 200);
},
@ -264,7 +283,7 @@ export function useLocationSearch(mode?: string) {
const showEmptySearches = useCallback(() => {
if (latestQueryRef.current.trim()) {
setOpen(results.length > 0);
setOpen(results.length > 0 || latestQueryRef.current.trim().length >= 2);
return;
}
@ -278,6 +297,7 @@ export function useLocationSearch(mode?: string) {
const clear = useCallback(() => {
setQuery('');
latestQueryRef.current = '';
setSearching(false);
setResults([]);
lastResultsRef.current = [];
setOpen(false);
@ -308,6 +328,8 @@ export function useLocationSearch(mode?: string) {
e.preventDefault();
if (activeIndex >= 0 && activeIndex < results.length) {
onSelect(results[activeIndex]);
} else if (results.length > 0) {
onSelect(results[0]);
} else if (looksLikePostcode(query)) {
onSelect({ type: 'postcode', label: normalizePostcode(query) });
}
@ -332,6 +354,7 @@ export function useLocationSearch(mode?: string) {
activeIndex,
setActiveIndex,
open,
searching,
setOpen,
handleInputChange,
handleKeyDown,