diff --git a/apps/web/src/app/(app)/wasteland/by-id/[wastelandId]/wanted/WantedBoardClient.tsx b/apps/web/src/app/(app)/wasteland/by-id/[wastelandId]/wanted/WantedBoardClient.tsx index 89a827e50..866589ca6 100644 --- a/apps/web/src/app/(app)/wasteland/by-id/[wastelandId]/wanted/WantedBoardClient.tsx +++ b/apps/web/src/app/(app)/wasteland/by-id/[wastelandId]/wanted/WantedBoardClient.tsx @@ -155,6 +155,21 @@ export function WantedBoardClient({ const search = searchParams?.get('q') ?? ''; const sortField = parseSortField(searchParams?.get('sort')); + const [localSearch, setLocalSearch] = useState(search); + const debounceTimeoutRef = useRef | null>(null); + + useEffect(() => { + setLocalSearch(search); + }, [search]); + + useEffect(() => { + return () => { + if (debounceTimeoutRef.current) { + clearTimeout(debounceTimeoutRef.current); + } + }; + }, []); + const updateFilterParams = useCallback( (updates: { status?: StatusFilter | 'all'; q?: string; sort?: SortField }) => { const next = new URLSearchParams(searchParams?.toString()); @@ -178,6 +193,25 @@ export function WantedBoardClient({ [pathname, router, searchParams] ); + const handleSearchChange = useCallback( + (val: string) => { + setLocalSearch(val); + + if (debounceTimeoutRef.current) { + clearTimeout(debounceTimeoutRef.current); + } + + if (val === '') { + updateFilterParams({ q: '' }); + } else { + debounceTimeoutRef.current = setTimeout(() => { + updateFilterParams({ q: val }); + }, 250); + } + }, + [updateFilterParams] + ); + // Dialog state const [doneItem, setDoneItem] = useState(null); const [acceptItem, setAcceptItem] = useState(null); @@ -410,8 +444,8 @@ export function WantedBoardClient({ updateFilterParams({ q: e.target.value })} + value={localSearch} + onChange={e => handleSearchChange(e.target.value)} className="w-48 bg-transparent text-xs text-white/80 outline-none placeholder:text-white/25" />