use-search-query-sync.ts1.7 KBView on GitHub import { useEffect } from 'react';
import { useQueryState } from 'nuqs';
import { buildSearchQuery } from '@/modules/search/build-search-query';
import { useCedarStore } from '@/modules/store';
import { getMainSearchTerm } from '@/lib/utils';
/**
* Mirror the `?search=` URL param into the search slice — the store value `useThreads` filters
* the list by.
*
* This lives with the LIST rather than with the search input, and that placement is the whole
* point. It used to be an effect inside `SearchInput`, which mail.tsx mounts only while
* `isSearchOpen || !!searchQuery`. `isSearchOpen` is component state that resets to false on
* remount and `?search=` is dropped by any navigation that rewrites the URL, so the input could
* unmount with a compiled query still in the store — and `useCedarStore` is a module singleton
* that outlives it. Nothing was then left to clear the filter: the list stayed narrowed to a
* search whose box was no longer on screen (<email>, staging, 2026-09-08 —
* `mail.listThreads` re-ran her `thiago` search every five minutes for three hours while she
* looked at what she thought was her inbox).
*
* Call it unconditionally, next to the list it filters.
*/
export function useSearchQuerySync(): void {
const [searchQuery] = useQueryState('search');
const setSearchState = useCedarStore((state) => state.setSearchState);
useEffect(() => {
if (searchQuery) {
setSearchState({
value: buildSearchQuery(searchQuery, 'google'),
highlight: getMainSearchTerm(searchQuery),
});
} else {
setSearchState({ value: '', highlight: '' });
}
}, [searchQuery, setSearchState]);
}