diff --git a/native/src/routes/SearchModal.tsx b/native/src/routes/SearchModal.tsx index 9e7da908ea..c723e609a9 100644 --- a/native/src/routes/SearchModal.tsx +++ b/native/src/routes/SearchModal.tsx @@ -29,6 +29,7 @@ const SearchCounter = styled.Text` export type SearchModalProps = { allPossibleResults: SearchResult[] + allPossibleFallbackResults: SearchResult[] languageCode: string cityCode: string closeModal: (query: string) => void @@ -37,6 +38,7 @@ export type SearchModalProps = { const SearchModal = ({ allPossibleResults, + allPossibleFallbackResults, languageCode, cityCode, closeModal, @@ -46,7 +48,10 @@ const SearchModal = ({ const resourceCache = useResourceCache({ cityCode, languageCode }) const { t } = useTranslation('search') - const searchResults = useSearch(allPossibleResults, query) + const mainResults = useSearch(allPossibleResults, query) + const fallbackResults = useSearch(allPossibleFallbackResults, query) + + const searchResults = mainResults?.length === 0 ? fallbackResults : mainResults if (!searchResults) { return null diff --git a/native/src/routes/SearchModalContainer.tsx b/native/src/routes/SearchModalContainer.tsx index abd6f9b950..7f1425aa73 100644 --- a/native/src/routes/SearchModalContainer.tsx +++ b/native/src/routes/SearchModalContainer.tsx @@ -1,6 +1,9 @@ import React, { ReactElement, useMemo } from 'react' import { SearchRouteType } from 'shared' +import { CategoriesMapModel, EventModel, PoiModel } from 'shared/api' +import { formatPossibleSearchResults } from 'shared/hooks/useSearch' +import { config } from 'translations' import { NavigationProps, RouteProps } from '../constants/NavigationTypes' import useCityAppContext from '../hooks/useCityAppContext' @@ -13,18 +16,24 @@ export type SearchModalContainerProps = { route: RouteProps } +const useMemoizeResults = ( + categories?: CategoriesMapModel | null, + events?: EventModel[] | null, + pois?: PoiModel[] | null, +) => useMemo(() => formatPossibleSearchResults(categories, events, pois), [categories, events, pois]) + const SearchModalContainer = ({ navigation, route }: SearchModalContainerProps): ReactElement | null => { const { cityCode, languageCode } = useCityAppContext() const initialSearchText = route.params.searchText ?? '' const { data, ...response } = useLoadCityContent({ cityCode, languageCode }) + const { data: fallbackData } = useLoadCityContent({ cityCode, languageCode: config.sourceLanguage }) + + const allPossibleResults = useMemoizeResults(data?.categories, data?.events, data?.pois) - const allPossibleResults = useMemo( - () => [ - ...(data?.categories.toArray().filter(category => !category.isRoot()) || []), - ...(data?.events || []), - ...(data?.pois || []), - ], - [data?.categories, data?.events, data?.pois], + const allPossibleFallbackResults = useMemoizeResults( + fallbackData?.categories, + fallbackData?.events, + fallbackData?.pois, ) return ( @@ -34,6 +43,7 @@ const SearchModalContainer = ({ navigation, route }: SearchModalContainerProps): cityCode={cityCode} closeModal={navigation.goBack} allPossibleResults={allPossibleResults} + allPossibleFallbackResults={allPossibleFallbackResults} languageCode={languageCode} initialSearchText={initialSearchText} /> diff --git a/native/src/routes/__tests__/SearchModal.spec.tsx b/native/src/routes/__tests__/SearchModal.spec.tsx index 50385309ee..d8023d8f99 100644 --- a/native/src/routes/__tests__/SearchModal.spec.tsx +++ b/native/src/routes/__tests__/SearchModal.spec.tsx @@ -55,6 +55,7 @@ describe('SearchModal', () => { const props: SearchModalProps = { allPossibleResults, + allPossibleFallbackResults: [], languageCode, cityCode, closeModal: dummy, diff --git a/shared/hooks/useSearch.ts b/shared/hooks/useSearch.ts index 9299c5231c..f0c487508f 100644 --- a/shared/hooks/useSearch.ts +++ b/shared/hooks/useSearch.ts @@ -2,10 +2,23 @@ import MiniSearch from 'minisearch' import { useCallback } from 'react' import useLoadAsync from '../api/endpoints/hooks/useLoadAsync' +import CategoriesMapModel from '../api/models/CategoriesMapModel' +import EventModel from '../api/models/EventModel' import ExtendedPageModel from '../api/models/ExtendedPageModel' +import PoiModel from '../api/models/PoiModel' export type SearchResult = ExtendedPageModel +export const formatPossibleSearchResults = ( + categories?: CategoriesMapModel | null, + events?: EventModel[] | null, + pois?: PoiModel[] | null, +): SearchResult[] => [ + ...(categories?.toArray().filter(category => !category.isRoot()) || []), + ...(events || []), + ...(pois || []), +] + const useSearch = (allPossibleResults: SearchResult[], query: string): SearchResult[] | null => { const initializeMiniSearch = useCallback(async () => { const search = new MiniSearch({ diff --git a/web/src/hooks/__tests__/useAllPossibleSearchResults.spec.ts b/web/src/hooks/__tests__/useAllPossibleSearchResults.spec.ts index cfd38b34c1..e6a0af5333 100644 --- a/web/src/hooks/__tests__/useAllPossibleSearchResults.spec.ts +++ b/web/src/hooks/__tests__/useAllPossibleSearchResults.spec.ts @@ -27,11 +27,8 @@ describe('useAllPossibleSearchResults', () => { const city = new CityModelBuilder(1).build()[0]!.code const language = new LanguageModelBuilder(1).build()[0]!.code - const categories = new CategoriesMapModelBuilder(city, language).build() - const events = new EventModelBuilder('seed', 2, city, language).build() - const locations = new PoiModelBuilder(3).build() it('should return the correct results', () => { diff --git a/web/src/hooks/useAllPossibleSearchResults.ts b/web/src/hooks/useAllPossibleSearchResults.ts index be5a70dbe3..d08759802b 100644 --- a/web/src/hooks/useAllPossibleSearchResults.ts +++ b/web/src/hooks/useAllPossibleSearchResults.ts @@ -7,6 +7,7 @@ import { ExtendedPageModel, useLoadFromEndpoint, } from 'shared/api' +import { formatPossibleSearchResults } from 'shared/hooks/useSearch' type UseAllPossibleSearchResultsProps = { city: string @@ -27,19 +28,19 @@ const useAllPossibleSearchResults = ({ }: UseAllPossibleSearchResultsProps): UseAllPossibleSearchResultsReturn => { const params = { city, language } - const { data: categories, ...categoriesReturn } = useLoadFromEndpoint(createCategoriesEndpoint, cmsApiBaseUrl, params) - const { data: events, ...eventsReturn } = useLoadFromEndpoint(createEventsEndpoint, cmsApiBaseUrl, params) - const { data: pois, ...poisReturn } = useLoadFromEndpoint(createPOIsEndpoint, cmsApiBaseUrl, params) + const categories = useLoadFromEndpoint(createCategoriesEndpoint, cmsApiBaseUrl, params) + const events = useLoadFromEndpoint(createEventsEndpoint, cmsApiBaseUrl, params) + const pois = useLoadFromEndpoint(createPOIsEndpoint, cmsApiBaseUrl, params) const allPossibleResults = useMemo( - () => [...(categories?.toArray().filter(category => !category.isRoot()) || []), ...(events || []), ...(pois || [])], - [categories, events, pois], + () => formatPossibleSearchResults(categories.data, events.data, pois.data), + [categories.data, events.data, pois.data], ) return { data: allPossibleResults, - loading: categoriesReturn.loading || eventsReturn.loading || poisReturn.loading, - error: categoriesReturn.error || eventsReturn.error || poisReturn.error, + loading: categories.loading || events.loading || pois.loading, + error: categories.error || events.error || pois.error, } } diff --git a/web/src/routes/SearchPage.tsx b/web/src/routes/SearchPage.tsx index e145501fd0..0e69357c1f 100644 --- a/web/src/routes/SearchPage.tsx +++ b/web/src/routes/SearchPage.tsx @@ -4,6 +4,7 @@ import { useLocation, useNavigate } from 'react-router-dom' import styled from 'styled-components' import { parseHTML, pathnameFromRouteInformation, SEARCH_ROUTE, useSearch } from 'shared' +import { config } from 'translations' import { CityRouteProps } from '../CityContentSwitcher' import CityContentLayout, { CityContentLayoutProps } from '../components/CityContentLayout' @@ -45,8 +46,16 @@ const SearchPage = ({ city, cityCode, languageCode, pathname }: CityRouteProps): language: languageCode, cmsApiBaseUrl, }) + const mainResults = useSearch(allPossibleResults, query) - const results = useSearch(allPossibleResults, query) + const { data: allPossibleFallbackResults } = useAllPossibleSearchResults({ + city: cityCode, + language: config.sourceLanguage, + cmsApiBaseUrl, + }) + const fallbackResults = useSearch(allPossibleFallbackResults, query) + + const results = mainResults?.length === 0 ? fallbackResults : mainResults if (!city) { return null