Merged in fix/SW-2457-destination-page-search-for-countries (pull request #1873)
* fix: able to search for countries on destinationpage * fix: filter out only desired types when using autocomplete Approved-by: Linus Flood
This commit is contained in:
@@ -8,6 +8,7 @@ import { getCacheClient } from "@/services/dataCache"
|
||||
import { safeTry } from "@/utils/safeTry"
|
||||
|
||||
import { getCityPageUrls } from "../contentstack/destinationCityPage/utils"
|
||||
import { getCountryPageUrls } from "../contentstack/destinationCountryPage/utils"
|
||||
import { getHotelPageUrls } from "../contentstack/hotelPage/utils"
|
||||
import { getCitiesByCountry, getCountries, getLocations } from "../hotels/utils"
|
||||
import { filterAndCategorizeAutoComplete } from "./util/filterAndCategorizeAutoComplete"
|
||||
@@ -20,12 +21,14 @@ const destinationsAutoCompleteInputSchema = z.object({
|
||||
selectedHotelId: z.string().optional(),
|
||||
selectedCity: z.string().optional(),
|
||||
lang: z.nativeEnum(Lang),
|
||||
includeTypes: z.array(z.enum(["hotels", "cities", "countries"])),
|
||||
})
|
||||
|
||||
type DestinationsAutoCompleteOutput = {
|
||||
hits: {
|
||||
hotels: AutoCompleteLocation[]
|
||||
cities: AutoCompleteLocation[]
|
||||
countries: AutoCompleteLocation[]
|
||||
}
|
||||
currentSelection: {
|
||||
hotel: (AutoCompleteLocation & { type: "hotels" }) | null
|
||||
@@ -39,12 +42,13 @@ export const getDestinationsAutoCompleteRoute = safeProtectedServiceProcedure
|
||||
const cacheClient = await getCacheClient()
|
||||
|
||||
const lang = input.lang || ctx.lang
|
||||
|
||||
const locations: AutoCompleteLocation[] = await cacheClient.cacheOrGet(
|
||||
`autocomplete:destinations:locations:${lang}`,
|
||||
async () => {
|
||||
const hotelUrlsPromise = safeTry(getHotelPageUrls(lang))
|
||||
const cityUrlsPromise = safeTry(getCityPageUrls(lang))
|
||||
|
||||
const countryUrlsPromise = safeTry(getCountryPageUrls(lang))
|
||||
const countries = await getCountries({
|
||||
lang: lang,
|
||||
serviceToken: ctx.serviceToken,
|
||||
@@ -53,6 +57,7 @@ export const getDestinationsAutoCompleteRoute = safeProtectedServiceProcedure
|
||||
if (!countries) {
|
||||
throw new Error("Unable to fetch countries")
|
||||
}
|
||||
|
||||
const countryNames = countries.data.map((country) => country.name)
|
||||
const citiesByCountry = await getCitiesByCountry({
|
||||
countries: countryNames,
|
||||
@@ -68,12 +73,20 @@ export const getDestinationsAutoCompleteRoute = safeProtectedServiceProcedure
|
||||
|
||||
const [hotelUrls, hotelUrlsError] = await hotelUrlsPromise
|
||||
const [cityUrls, cityUrlsError] = await cityUrlsPromise
|
||||
const [countryUrls, countryUrlsError] = await countryUrlsPromise
|
||||
|
||||
if (hotelUrlsError || cityUrlsError || !hotelUrls || !cityUrls) {
|
||||
if (
|
||||
hotelUrlsError ||
|
||||
cityUrlsError ||
|
||||
countryUrlsError ||
|
||||
!hotelUrls ||
|
||||
!cityUrls ||
|
||||
!countryUrls
|
||||
) {
|
||||
throw new Error("Unable to fetch location URLs")
|
||||
}
|
||||
|
||||
return locations
|
||||
const hotelsAndCities = locations
|
||||
.map((location) => {
|
||||
let url: string | undefined
|
||||
|
||||
@@ -96,13 +109,31 @@ export const getDestinationsAutoCompleteRoute = safeProtectedServiceProcedure
|
||||
})
|
||||
.map(mapLocationToAutoCompleteLocation)
|
||||
.filter(isDefined)
|
||||
|
||||
const countryAutoCompleteLocations = countries.data.map((country) => {
|
||||
const url = countryUrls.find(
|
||||
(c) => c.country && c.country === country.name
|
||||
)?.url
|
||||
|
||||
return {
|
||||
id: country.id,
|
||||
name: country.name,
|
||||
type: "countries",
|
||||
searchTokens: [country.name],
|
||||
destination: "",
|
||||
url,
|
||||
} satisfies AutoCompleteLocation
|
||||
})
|
||||
|
||||
return [...hotelsAndCities, ...countryAutoCompleteLocations]
|
||||
},
|
||||
"1d"
|
||||
)
|
||||
|
||||
const hits = filterAndCategorizeAutoComplete({
|
||||
locations,
|
||||
locations: locations,
|
||||
query: input.query,
|
||||
includeTypes: input.includeTypes,
|
||||
})
|
||||
|
||||
const selectedHotel = locations.find(
|
||||
|
||||
@@ -3,7 +3,7 @@ import { z } from "zod"
|
||||
export const autoCompleteLocationSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
type: z.enum(["cities", "hotels"]),
|
||||
type: z.enum(["cities", "hotels", "countries"]),
|
||||
searchTokens: z.array(z.string()),
|
||||
destination: z.string(),
|
||||
url: z.string().optional(),
|
||||
|
||||
@@ -6,6 +6,7 @@ export type DestinationsAutoCompleteOutput = {
|
||||
hits: {
|
||||
hotels: AutoCompleteLocation[]
|
||||
cities: AutoCompleteLocation[]
|
||||
countries: AutoCompleteLocation[]
|
||||
}
|
||||
currentSelection: {
|
||||
hotel: (AutoCompleteLocation & { type: "hotels" }) | null
|
||||
@@ -16,27 +17,50 @@ export type DestinationsAutoCompleteOutput = {
|
||||
export function filterAndCategorizeAutoComplete({
|
||||
locations,
|
||||
query,
|
||||
includeTypes,
|
||||
}: {
|
||||
locations: AutoCompleteLocation[]
|
||||
query: string
|
||||
includeTypes: ("cities" | "hotels" | "countries")[]
|
||||
}) {
|
||||
const rankedLocations = filterAutoCompleteLocations(locations, query)
|
||||
|
||||
const sortedCities = rankedLocations.filter(isCity)
|
||||
const sortedHotels = rankedLocations.filter(isHotel)
|
||||
const sortedCities = rankedLocations.filter(
|
||||
(loc) => shouldIncludeType(includeTypes, loc) && isCity(loc)
|
||||
)
|
||||
const sortedHotels = rankedLocations.filter(
|
||||
(loc) => shouldIncludeType(includeTypes, loc) && isHotel(loc)
|
||||
)
|
||||
const sortedCountries = rankedLocations.filter(
|
||||
(loc) => shouldIncludeType(includeTypes, loc) && isCountry(loc)
|
||||
)
|
||||
|
||||
return {
|
||||
cities: sortedCities,
|
||||
hotels: sortedHotels,
|
||||
countries: sortedCountries,
|
||||
}
|
||||
}
|
||||
|
||||
function shouldIncludeType(
|
||||
includedTypes: ("cities" | "hotels" | "countries")[],
|
||||
location: AutoCompleteLocation
|
||||
) {
|
||||
return includedTypes.includes(location.type)
|
||||
}
|
||||
|
||||
function isHotel(
|
||||
location: AutoCompleteLocation | null | undefined
|
||||
): location is AutoCompleteLocation & { type: "hotels" } {
|
||||
return !!location && location.type === "hotels"
|
||||
}
|
||||
|
||||
function isCountry(
|
||||
location: AutoCompleteLocation | null | undefined
|
||||
): location is AutoCompleteLocation & { type: "countries" } {
|
||||
return !!location && location.type === "countries"
|
||||
}
|
||||
|
||||
function isCity(
|
||||
location: AutoCompleteLocation | null | undefined
|
||||
): location is AutoCompleteLocation & { type: "cities" } {
|
||||
|
||||
Reference in New Issue
Block a user