docs: improve search to show results for all filters (#9208)

* docs: improve search to show results for all filters

* fix index ordering
This commit is contained in:
Shahed Nasser
2024-09-22 14:49:16 +02:00
committed by GitHub
parent 138523a629
commit c790af7834
4 changed files with 102 additions and 7 deletions
@@ -97,7 +97,7 @@ export const SearchHits = ({
setNoResults,
checkInternalPattern,
}: SearchHitsProps) => {
const { hits } = useHits<HitType>()
const { items: hits } = useHits<HitType>()
const { status } = useInstantSearch()
const { setIsOpen } = useSearch()
@@ -13,6 +13,9 @@ import { checkArraySameElms } from "../../utils"
import {
liteClient as algoliasearch,
LiteClient as SearchClient,
type SearchResponses,
type SearchHits,
SearchResponse,
} from "algoliasearch/lite"
import clsx from "clsx"
import { CSSTransition, SwitchTransition } from "react-transition-group"
@@ -78,11 +81,37 @@ export const SearchProvider = ({
async search(searchParams) {
const requests =
"requests" in searchParams ? searchParams.requests : searchParams
const noQueries = requests.every(
// always send this request, which is the main request with no filters
const mainRequest = requests[0]
// retrieve only requests that have filters
// this is to ensure that we show no result if no filter is selected
const requestsWithFilters = requests.filter((item) => {
if (
!item.params ||
typeof item.params !== "object" ||
!("tagFilters" in item.params)
) {
return false
}
const tagFilters = item.params.tagFilters as string[]
// if no tag filters are specified, there's still one item,
// which is an empty array
return tagFilters.length >= 1 && tagFilters[0].length > 0
})
// check whether a query is entered in the search box
const noQueries = requestsWithFilters.every(
(item) =>
("facetQuery" in item && !item.facetQuery) ||
("query" in item && !item.query)
!item.facetQuery &&
(!item.params ||
typeof item.params !== "object" ||
!("query" in item.params) ||
!item.params.query)
)
if (noQueries) {
return Promise.resolve({
results: requests.map(() => ({
@@ -99,7 +128,73 @@ export const SearchProvider = ({
})
}
return algoliaClient.search(searchParams)
// split requests per tags
const newRequests: typeof requestsWithFilters = [mainRequest]
for (const request of requestsWithFilters) {
const params = request.params as Record<string, unknown>
const tagFilters = (params.tagFilters as string[][])[0]
// if only one tag is selected, keep the request as-is
if (tagFilters.length === 1) {
newRequests.push(request)
continue
}
// if multiple tags are selected, split the tags
// to retrieve a small subset of results per each tag.
newRequests.push(
...tagFilters.map((tag) => ({
...request,
params: {
...params,
tagFilters: [tag],
},
hitsPerPage: 4,
}))
)
}
return algoliaClient
.search<SearchHits>(newRequests)
.then((response) => {
// combine results of the same index and return the results
const resultsByIndex: {
[indexName: string]: SearchResponse<SearchHits>
} = {}
// extract the response of the main request
const mainResult = response.results[0]
response.results.forEach((result, indexNum) => {
if (indexNum === 0) {
// ignore the main request's result
return
}
const resultIndex = "index" in result ? result.index : undefined
const resultHits = "hits" in result ? result.hits : []
if (!resultIndex) {
return
}
resultsByIndex[resultIndex] = {
...result,
...(resultsByIndex[resultIndex] || {}),
hits: [
...(resultsByIndex[resultIndex]?.hits || []),
...resultHits,
],
nbHits:
(resultsByIndex[resultIndex]?.nbHits || 0) +
resultHits.length,
}
})
return {
// append the results with the main request's results
results: [mainResult, ...Object.values(resultsByIndex)],
} as SearchResponses<any>
})
},
}
}, [algolia.appId, algolia.apiKey])