updated search suggestions functionality

This commit is contained in:
sriram
2026-08-20 12:59:32 +05:30
parent c84f0a9529
commit f5d3d80f42
5 changed files with 281 additions and 10 deletions

View File

@@ -0,0 +1,74 @@
import { useEffect, useRef, useState } from 'react';
import { api } from '../api/client';
/**
* Debounce a fast-changing value (here, whatever is typed in the search box).
* 180ms is roughly two requests per word at 60wpm - responsive without firing
* on every keystroke.
*/
export function useDebouncedValue(value, delay = 180) {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
/**
* Brand/category suggestions for a partial query.
*
* Responses can arrive out of order, so a monotonic request id decides which
* one is allowed to land - the same guard HomePage uses for search results.
* Errors resolve to an empty list rather than propagating: a failing suggest
* endpoint must never stop someone typing or submitting a search.
*/
export function useSuggestions(query, { enabled = true, minLength = 2, limit = 8 } = {}) {
const debounced = useDebouncedValue(query);
const [suggestions, setSuggestions] = useState([]);
const [loading, setLoading] = useState(false);
const requestIdRef = useRef(0);
const cacheRef = useRef(new Map());
useEffect(() => {
const trimmed = (debounced || '').trim();
if (!enabled || trimmed.length < minLength) {
requestIdRef.current += 1; // invalidate anything still in flight
setSuggestions([]);
setLoading(false);
return;
}
const cacheKey = `${limit}|${trimmed.toLowerCase()}`;
const cached = cacheRef.current.get(cacheKey);
if (cached) {
// Backspacing back through text already typed shouldn't refetch.
requestIdRef.current += 1;
setSuggestions(cached);
setLoading(false);
return;
}
const id = ++requestIdRef.current;
setLoading(true);
api.suggest(trimmed, { limit })
.then((res) => {
const results = res.suggestions || [];
cacheRef.current.set(cacheKey, results);
if (id === requestIdRef.current) setSuggestions(results);
})
.catch(() => {
if (id === requestIdRef.current) setSuggestions([]);
})
.finally(() => {
if (id === requestIdRef.current) setLoading(false);
});
}, [debounced, enabled, minLength, limit]);
return { suggestions, loading };
}