diff --git a/web/components/contract-search.tsx b/web/components/contract-search.tsx index 7c34e252..b6339156 100644 --- a/web/components/contract-search.tsx +++ b/web/components/contract-search.tsx @@ -4,7 +4,7 @@ import algoliasearch from 'algoliasearch/lite' import { Contract } from 'common/contract' import { Sort, - useInitialQueryAndSort, + useQueryAndSortParams, } from '../hooks/use-sort-and-query-params' import { ContractsGrid } from './contract/contracts-list' import { Row } from './layout/row' @@ -91,14 +91,12 @@ export function ContractSearch(props: { memberPillGroups.length > 0 ? memberPillGroups : defaultPillGroups const follows = useFollows(user?.id) - const { initialSort: savedSort } = useInitialQueryAndSort(querySortOptions) - const initialSort = - savedSort && sortOptions.map(({ value }) => value).includes(savedSort) - ? savedSort - : querySortOptions?.defaultSort ?? DEFAULT_SORT - - const [sort, setSort] = useState(initialSort) + const { shouldLoadFromStorage, defaultSort } = querySortOptions ?? {} + const { query, setQuery, sort, setSort } = useQueryAndSortParams({ + defaultSort, + shouldLoadFromStorage, + }) const [filter, setFilter] = useState( querySortOptions?.defaultFilter ?? 'open' @@ -156,7 +154,6 @@ export function ContractSearch(props: { const indexName = `${indexPrefix}contracts-${sort}` const index = useMemo(() => searchClient.initIndex(indexName), [indexName]) - const [query, setQuery] = useState('') const [page, setPage] = useState(0) const [numPages, setNumPages] = useState(1) const [hitsByPage, setHitsByPage] = useState<{ [page: string]: Contract[] }>( @@ -172,6 +169,7 @@ export function ContractSearch(props: { facetFilters, numericFilters, }) + let wasMostRecentQuery = true index .search(query, { facetFilters, @@ -180,6 +178,8 @@ export function ContractSearch(props: { hitsPerPage: 20, }) .then((results) => { + if (!wasMostRecentQuery) return + if (page === 0) { setHitsByPage({ [0]: results.hits as any as Contract[], @@ -191,8 +191,11 @@ export function ContractSearch(props: { })) } setNumPages(results.nbPages) - console.log(results.page, '/', results.nbPages, results.hits) + console.log(results.page + 1, '/', results.nbPages, results.hits) }) + return () => { + wasMostRecentQuery = false + } // Note numeric filters are unique based on current time, so can't compare // them by value. }, [query, page, index, JSON.stringify(facetFilters), filter]) @@ -215,9 +218,16 @@ export function ContractSearch(props: { const showTime = sort === 'close-date' || sort === 'resolve-date' ? sort : undefined - const selectFilter = (filter: filter) => { - setFilter(filter) - trackCallback('select search filter', { filter }) + const updateQuery = (newQuery: string) => { + setQuery(newQuery) + setPage(0) + } + + const selectFilter = (newFilter: filter) => { + if (newFilter === filter) return + setFilter(newFilter) + setPage(0) + trackCallback('select search filter', { filter: newFilter }) } const selectSort = (newSort: Sort) => { @@ -243,7 +253,7 @@ export function ContractSearch(props: { setQuery(e.target.value)} + onChange={(e) => updateQuery(e.target.value)} placeholder={showPlaceHolder ? `Search ${filter} markets` : ''} className="input input-bordered w-full" /> diff --git a/web/hooks/use-sort-and-query-params.tsx b/web/hooks/use-sort-and-query-params.tsx index 9023dc1a..0184570d 100644 --- a/web/hooks/use-sort-and-query-params.tsx +++ b/web/hooks/use-sort-and-query-params.tsx @@ -1,8 +1,6 @@ import { defaults, debounce } from 'lodash' import { useRouter } from 'next/router' import { useEffect, useMemo, useState } from 'react' -import { useSearchBox } from 'react-instantsearch-hooks-web' -import { track } from 'web/lib/service/analytics' import { DEFAULT_SORT } from 'web/components/contract-search' const MARKETS_SORT = 'markets_sort' @@ -74,25 +72,32 @@ export function useInitialQueryAndSort(options?: { } } -export function useUpdateQueryAndSort(props: { - shouldLoadFromStorage: boolean +export function useQueryAndSortParams(options?: { + defaultSort?: Sort + shouldLoadFromStorage?: boolean }) { - const { shouldLoadFromStorage } = props + const { defaultSort = DEFAULT_SORT, shouldLoadFromStorage = true } = + options ?? {} const router = useRouter() + const { s: sort, q: query } = router.query as { + q?: string + s?: Sort + } + const setSort = (sort: Sort | undefined) => { - if (sort !== router.query.s) { - router.query.s = sort - router.replace({ query: { ...router.query, s: sort } }, undefined, { - shallow: true, - }) - if (shouldLoadFromStorage) { - localStorage.setItem(MARKETS_SORT, sort || '') - } + router.query.s = sort + router.push(router, undefined, { shallow: true }) + if (shouldLoadFromStorage) { + localStorage.setItem(MARKETS_SORT, sort || '') } } - const { query, refine } = useSearchBox() + const [queryState, setQueryState] = useState(query) + + useEffect(() => { + setQueryState(query) + }, [query]) // Debounce router query update. const pushQuery = useMemo( @@ -103,22 +108,32 @@ export function useUpdateQueryAndSort(props: { } else { delete router.query.q } - router.replace({ query: router.query }, undefined, { - shallow: true, - }) - track('search', { query }) - }, 500), + router.replace(router, undefined, { shallow: true }) + }, 100), [router] ) const setQuery = (query: string | undefined) => { - refine(query ?? '') + setQueryState(query) pushQuery(query) } + useEffect(() => { + // If there's no sort option, then set the one from localstorage + if (router.isReady && !sort && shouldLoadFromStorage) { + const localSort = localStorage.getItem(MARKETS_SORT) as Sort + if (localSort) { + router.query.s = localSort + // Use replace to not break navigating back. + router.replace(router, undefined, { shallow: true }) + } + } + }) + return { + sort: sort ?? defaultSort, + query: queryState ?? '', setSort, setQuery, - query, } }