Merged in feat/SW-1456-country-dynamic-map (pull request #1310)
feat(SW-1456): Added map and fetching hotels by country * feat(SW-1456): Added map and fetching hotels by country Approved-by: Fredrik Thorsson Approved-by: Matilda Landström
This commit is contained in:
@@ -244,7 +244,6 @@ export const destinationOverviewPageQueryRouter = router({
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
city: city.id,
|
||||
onlyBasicInfo: "true",
|
||||
})
|
||||
|
||||
const hotels = await getHotelIdsByCityId(
|
||||
|
||||
@@ -63,7 +63,7 @@ export const hotelInputSchema = z.object({
|
||||
language: z.nativeEnum(Lang),
|
||||
})
|
||||
|
||||
export const getHotelsInput = z.object({
|
||||
export const getHotelsByCSFilterInput = z.object({
|
||||
locationFilter: z
|
||||
.object({
|
||||
city: z.string().nullable(),
|
||||
@@ -73,7 +73,8 @@ export const getHotelsInput = z.object({
|
||||
.nullable(),
|
||||
hotelsToInclude: z.array(z.string()),
|
||||
})
|
||||
export interface GetHotelsInput extends z.infer<typeof getHotelsInput> {}
|
||||
export interface GetHotelsByCSFilterInput
|
||||
extends z.infer<typeof getHotelsByCSFilterInput> {}
|
||||
|
||||
export const nearbyHotelIdsInput = z.object({
|
||||
hotelId: z.string(),
|
||||
@@ -116,3 +117,7 @@ export const getAdditionalDataInputSchema = z.object({
|
||||
hotelId: z.string(),
|
||||
language: z.string(),
|
||||
})
|
||||
|
||||
export const getHotelsByCountryInput = z.object({
|
||||
country: z.nativeEnum(Country),
|
||||
})
|
||||
|
||||
@@ -24,8 +24,9 @@ import {
|
||||
breakfastPackageInputSchema,
|
||||
cityCoordinatesInputSchema,
|
||||
getAdditionalDataInputSchema,
|
||||
getHotelsByCountryInput,
|
||||
getHotelsByCSFilterInput,
|
||||
getHotelsByHotelIdsAvailabilityInputSchema,
|
||||
getHotelsInput,
|
||||
getMeetingRoomsInputSchema,
|
||||
hotelInputSchema,
|
||||
hotelsAvailabilityInputSchema,
|
||||
@@ -59,8 +60,7 @@ import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHote
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
import { HotelTypeEnum } from "@/types/enums/hotelType"
|
||||
import type { RequestOptionsWithOutBody } from "@/types/fetch"
|
||||
import type { HotelData } from "@/types/hotel"
|
||||
import type { HotelPageUrl } from "@/types/trpc/routers/contentstack/hotelPage"
|
||||
import type { HotelDataWithUrl } from "@/types/hotel"
|
||||
import type { HotelInput } from "@/types/trpc/routers/hotel/hotel"
|
||||
import type { CityLocation } from "@/types/trpc/routers/hotel/locations"
|
||||
|
||||
@@ -833,207 +833,251 @@ export const hotelQueryRouter = router({
|
||||
return getHotel(input, ctx.serviceToken)
|
||||
}),
|
||||
hotels: router({
|
||||
get: contentStackBaseWithServiceProcedure
|
||||
.input(getHotelsInput)
|
||||
.query(async function ({ ctx, input }) {
|
||||
const { locationFilter, hotelsToInclude } = input
|
||||
byCountry: router({
|
||||
get: contentStackBaseWithServiceProcedure
|
||||
.input(getHotelsByCountryInput)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const { lang, serviceToken } = ctx
|
||||
const { country } = input
|
||||
|
||||
const language = ctx.lang
|
||||
const apiLang = toApiLang(language)
|
||||
const options: RequestOptionsWithOutBody = {
|
||||
// needs to clear default option as only
|
||||
// cache or next.revalidate is permitted
|
||||
cache: undefined,
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.serviceToken}`,
|
||||
},
|
||||
next: {
|
||||
revalidate: env.CACHE_TIME_HOTELS,
|
||||
},
|
||||
}
|
||||
|
||||
let hotelsToFetch: string[] = []
|
||||
|
||||
metrics.hotels.counter.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
})
|
||||
console.info(
|
||||
"api.hotel.hotels start",
|
||||
JSON.stringify({
|
||||
query: {
|
||||
...input,
|
||||
language,
|
||||
const options: RequestOptionsWithOutBody = {
|
||||
// needs to clear default option as only
|
||||
// cache or next.revalidate is permitted
|
||||
cache: undefined,
|
||||
headers: {
|
||||
Authorization: `Bearer ${serviceToken}`,
|
||||
},
|
||||
next: {
|
||||
revalidate: env.CACHE_TIME_HOTELS,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
if (hotelsToInclude.length) {
|
||||
hotelsToFetch = hotelsToInclude
|
||||
} else if (locationFilter?.city) {
|
||||
const locationsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
})
|
||||
const locations = await getLocations(
|
||||
language,
|
||||
options,
|
||||
locationsParams,
|
||||
null
|
||||
)
|
||||
if (!locations || "error" in locations) {
|
||||
return []
|
||||
}
|
||||
|
||||
const cityId = locations
|
||||
.filter(
|
||||
(loc): loc is CityLocation =>
|
||||
"type" in loc && loc.type === "cities"
|
||||
)
|
||||
.find((loc) => loc.cityIdentifier === locationFilter.city)?.id
|
||||
|
||||
if (!cityId) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `CityId not found for cityIdentifier: ${locationFilter.city}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { ...input, language },
|
||||
error: `CityId not found for cityIdentifier: ${locationFilter.city}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
city: cityId,
|
||||
onlyBasicInfo: "true",
|
||||
})
|
||||
const hotelIds = await getHotelIdsByCityId(
|
||||
cityId,
|
||||
options,
|
||||
hotelIdsParams
|
||||
)
|
||||
|
||||
if (!hotelIds?.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
cityId,
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `No hotelIds found for cityId: ${cityId}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { cityId, language },
|
||||
error: `No hotelIds found for cityId: ${cityId}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
const filteredHotelIds = hotelIds.filter(
|
||||
(id) => !locationFilter.excluded.includes(id)
|
||||
)
|
||||
|
||||
hotelsToFetch = filteredHotelIds
|
||||
} else if (locationFilter?.country) {
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: ApiLang.En,
|
||||
country: locationFilter.country,
|
||||
onlyBasicInfo: "true",
|
||||
country,
|
||||
})
|
||||
const hotelIds = await getHotelIdsByCountry(
|
||||
locationFilter.country,
|
||||
country,
|
||||
options,
|
||||
hotelIdsParams
|
||||
)
|
||||
|
||||
if (!hotelIds?.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
const hotels = await Promise.all(
|
||||
hotelIds.map(async (hotelId) => {
|
||||
const [hotelData, url] = await Promise.all([
|
||||
getHotel(
|
||||
{ hotelId, isCardOnlyPayment: false, language: lang },
|
||||
ctx.serviceToken
|
||||
),
|
||||
getHotelPageUrl(lang, hotelId),
|
||||
])
|
||||
|
||||
return hotelData ? { ...hotelData, url } : null
|
||||
})
|
||||
)
|
||||
|
||||
return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel)
|
||||
}),
|
||||
}),
|
||||
byCSFilter: router({
|
||||
get: contentStackBaseWithServiceProcedure
|
||||
.input(getHotelsByCSFilterInput)
|
||||
.query(async function ({ ctx, input }) {
|
||||
const { locationFilter, hotelsToInclude } = input
|
||||
|
||||
const language = ctx.lang
|
||||
const apiLang = toApiLang(language)
|
||||
const options: RequestOptionsWithOutBody = {
|
||||
// needs to clear default option as only
|
||||
// cache or next.revalidate is permitted
|
||||
cache: undefined,
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.serviceToken}`,
|
||||
},
|
||||
next: {
|
||||
revalidate: env.CACHE_TIME_HOTELS,
|
||||
},
|
||||
}
|
||||
|
||||
let hotelsToFetch: string[] = []
|
||||
|
||||
metrics.hotels.counter.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
})
|
||||
console.info(
|
||||
"api.hotel.hotels start",
|
||||
JSON.stringify({
|
||||
query: {
|
||||
...input,
|
||||
language,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
if (hotelsToInclude.length) {
|
||||
hotelsToFetch = hotelsToInclude
|
||||
} else if (locationFilter?.city) {
|
||||
const locationsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
})
|
||||
const locations = await getLocations(
|
||||
language,
|
||||
options,
|
||||
locationsParams,
|
||||
null
|
||||
)
|
||||
if (!locations || "error" in locations) {
|
||||
return []
|
||||
}
|
||||
|
||||
const cityId = locations
|
||||
.filter(
|
||||
(loc): loc is CityLocation =>
|
||||
"type" in loc && loc.type === "cities"
|
||||
)
|
||||
.find((loc) => loc.cityIdentifier === locationFilter.city)?.id
|
||||
|
||||
if (!cityId) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `CityId not found for cityIdentifier: ${locationFilter.city}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { ...input, language },
|
||||
error: `CityId not found for cityIdentifier: ${locationFilter.city}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
city: cityId,
|
||||
})
|
||||
const hotelIds = await getHotelIdsByCityId(
|
||||
cityId,
|
||||
options,
|
||||
hotelIdsParams
|
||||
)
|
||||
|
||||
if (!hotelIds?.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
cityId,
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `No hotelIds found for cityId: ${cityId}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { cityId, language },
|
||||
error: `No hotelIds found for cityId: ${cityId}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
const filteredHotelIds = hotelIds.filter(
|
||||
(id) => !locationFilter.excluded.includes(id)
|
||||
)
|
||||
|
||||
hotelsToFetch = filteredHotelIds
|
||||
} else if (locationFilter?.country) {
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: ApiLang.En,
|
||||
country: locationFilter.country,
|
||||
})
|
||||
const hotelIds = await getHotelIdsByCountry(
|
||||
locationFilter.country,
|
||||
options,
|
||||
hotelIdsParams
|
||||
)
|
||||
|
||||
if (!hotelIds?.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
country: locationFilter.country,
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `No hotelIds found for country: ${locationFilter.country}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { country: locationFilter.country, language },
|
||||
error: `No hotelIds found for cityId: ${locationFilter.country}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
const filteredHotelIds = hotelIds.filter(
|
||||
(id) => !locationFilter.excluded.includes(id)
|
||||
)
|
||||
|
||||
hotelsToFetch = filteredHotelIds
|
||||
}
|
||||
|
||||
if (!hotelsToFetch.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `No hotelIds found for country: ${locationFilter.country}`,
|
||||
error: `Couldn't find any hotels for given input: ${JSON.stringify(input)}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: { country: locationFilter.country, language },
|
||||
error: `No hotelIds found for cityId: ${locationFilter.country}`,
|
||||
query: JSON.stringify(input),
|
||||
error: `Couldn't find any hotels for given input: ${JSON.stringify(input)}`,
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
const filteredHotelIds = hotelIds.filter(
|
||||
(id) => !locationFilter.excluded.includes(id)
|
||||
)
|
||||
const hotels = await Promise.all(
|
||||
hotelsToFetch.map(async (hotelId) => {
|
||||
const [hotelData, url] = await Promise.all([
|
||||
getHotel(
|
||||
{ hotelId, isCardOnlyPayment: false, language },
|
||||
ctx.serviceToken
|
||||
),
|
||||
getHotelPageUrl(language, hotelId),
|
||||
])
|
||||
|
||||
hotelsToFetch = filteredHotelIds
|
||||
}
|
||||
|
||||
if (!hotelsToFetch.length) {
|
||||
metrics.hotels.fail.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
error_type: "not_found",
|
||||
error: `Couldn't find any hotels for given input: ${JSON.stringify(input)}`,
|
||||
})
|
||||
|
||||
console.error(
|
||||
"api.hotel.hotels not found error",
|
||||
JSON.stringify({
|
||||
query: JSON.stringify(input),
|
||||
error: `Couldn't find any hotels for given input: ${JSON.stringify(input)}`,
|
||||
return hotelData
|
||||
? {
|
||||
...hotelData,
|
||||
url,
|
||||
}
|
||||
: null
|
||||
})
|
||||
)
|
||||
return []
|
||||
}
|
||||
|
||||
const hotels = await Promise.all(
|
||||
hotelsToFetch.map(async (hotelId) => {
|
||||
const [hotelData, url] = await Promise.all([
|
||||
getHotel(
|
||||
{ hotelId, isCardOnlyPayment: false, language },
|
||||
ctx.serviceToken
|
||||
),
|
||||
getHotelPageUrl(language, hotelId),
|
||||
])
|
||||
|
||||
return {
|
||||
data: hotelData,
|
||||
url,
|
||||
}
|
||||
metrics.hotels.success.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
})
|
||||
)
|
||||
|
||||
metrics.hotels.success.add(1, {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
})
|
||||
console.info(
|
||||
"api.hotels success",
|
||||
JSON.stringify({
|
||||
query: {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
console.info(
|
||||
"api.hotels success",
|
||||
JSON.stringify({
|
||||
query: {
|
||||
input: JSON.stringify(input),
|
||||
language,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
return hotels.filter(
|
||||
(hotel): hotel is { data: HotelData; url: HotelPageUrl } =>
|
||||
!!hotel.data
|
||||
)
|
||||
}),
|
||||
return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel)
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
nearbyHotelIds: serviceProcedure
|
||||
.input(nearbyHotelIdsInput)
|
||||
|
||||
@@ -432,7 +432,6 @@ export async function getHotelIdsByCityIdentifier(
|
||||
const hotelIdsParams = new URLSearchParams({
|
||||
language: apiLang,
|
||||
city: cityId,
|
||||
onlyBasicInfo: "true",
|
||||
})
|
||||
const options: RequestOptionsWithOutBody = {
|
||||
// needs to clear default option as only
|
||||
|
||||
Reference in New Issue
Block a user