Compare commits

...

1 Commits

Author SHA1 Message Date
Marshall Polaris
783a2cfa8c Clean up search result objects before rendering them 2022-08-14 22:43:14 -07:00

View File

@ -1,6 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import algoliasearch, { SearchIndex } from 'algoliasearch/lite' import algoliasearch, { SearchIndex } from 'algoliasearch/lite'
import { SearchOptions } from '@algolia/client-search' import { Hit, SearchOptions } from '@algolia/client-search'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { User } from 'common/user' import { User } from 'common/user'
@ -75,6 +75,28 @@ type AdditionalFilter = {
groupSlug?: string groupSlug?: string
} }
// get rid of algolia-specific properties on the search results. if we match
// the contract object in the DB, then we save re-renders later when the
// contract cards fetch the latest contract and feed it into `useStateCheckEquality`.
//
// unfortunately, we rarely succeed, because:
// - algolia deletes `null` properties
// - floating-point error is frequently introduced
// but sometimes we do, so it's worth trying
//
function hitToDatabaseDocument<T>(hit: Hit<T>) {
// the properties of the `Hit` type
delete (hit as any).objectID
delete (hit as any)._highlightResult
delete (hit as any)._snippetResult
delete (hit as any)._rankingInfo
delete (hit as any)._distinctSeqId
// algolia doesn't document these but they are things
delete (hit as any).lastmodified
delete (hit as any).path
return hit as T
}
export function ContractSearch(props: { export function ContractSearch(props: {
user?: User | null user?: User | null
defaultSort?: Sort defaultSort?: Sort
@ -122,7 +144,7 @@ export function ContractSearch(props: {
const id = ++requestId.current const id = ++requestId.current
const requestedPage = freshQuery ? 0 : pages.length const requestedPage = freshQuery ? 0 : pages.length
if (freshQuery || requestedPage < numPages) { if (freshQuery || requestedPage < numPages) {
const results = await params.index.search(params.query, { const results = await params.index.search<Contract>(params.query, {
facetFilters: params.facetFilters, facetFilters: params.facetFilters,
numericFilters: params.numericFilters, numericFilters: params.numericFilters,
page: requestedPage, page: requestedPage,
@ -130,7 +152,9 @@ export function ContractSearch(props: {
}) })
// if there's a more recent request, forget about this one // if there's a more recent request, forget about this one
if (id === requestId.current) { if (id === requestId.current) {
const newPage = results.hits as any as Contract[] const newPage = results.hits
.filter((c) => !additionalFilter?.excludeContractIds?.includes(c.id))
.map(hitToDatabaseDocument)
// this spooky looking function is the easiest way to get react to // this spooky looking function is the easiest way to get react to
// batch this and not do multiple renders. we can throw it out in react 18. // batch this and not do multiple renders. we can throw it out in react 18.
// see https://github.com/reactwg/react-18/discussions/21 // see https://github.com/reactwg/react-18/discussions/21
@ -154,10 +178,6 @@ export function ContractSearch(props: {
}, 100) }, 100)
).current ).current
const contracts = pages
.flat()
.filter((c) => !additionalFilter?.excludeContractIds?.includes(c.id))
if (IS_PRIVATE_MANIFOLD || process.env.NEXT_PUBLIC_FIREBASE_EMULATE) { if (IS_PRIVATE_MANIFOLD || process.env.NEXT_PUBLIC_FIREBASE_EMULATE) {
return <ContractSearchFirestore additionalFilter={additionalFilter} /> return <ContractSearchFirestore additionalFilter={additionalFilter} />
} }
@ -176,7 +196,7 @@ export function ContractSearch(props: {
onSearchParametersChanged={onSearchParametersChanged} onSearchParametersChanged={onSearchParametersChanged}
/> />
<ContractsGrid <ContractsGrid
contracts={pages.length === 0 ? undefined : contracts} contracts={pages.length === 0 ? undefined : pages.flat()}
loadMore={performQuery} loadMore={performQuery}
showTime={showTime} showTime={showTime}
onContractClick={onContractClick} onContractClick={onContractClick}