feat(SW-1717): rewrite select-rate to show all variants of rate-cards
This commit is contained in:
committed by
Michael Zetterberg
parent
adde77eaa9
commit
ebaea78fb3
@@ -3,6 +3,7 @@ import deepmerge from "deepmerge"
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { env } from "@/env/server"
|
||||
import * as api from "@/lib/api"
|
||||
import { badRequestError } from "@/server/errors/trpc"
|
||||
import { toApiLang } from "@/server/utils"
|
||||
|
||||
import { getCacheClient } from "@/services/dataCache"
|
||||
@@ -16,16 +17,26 @@ import {
|
||||
countriesSchema,
|
||||
getHotelIdsSchema,
|
||||
locationsSchema,
|
||||
roomsAvailabilitySchema,
|
||||
} from "./output"
|
||||
import { getHotel } from "./query"
|
||||
|
||||
import type { z } from "zod"
|
||||
|
||||
import { PointOfInterestGroupEnum } from "@/types/enums/pointOfInterest"
|
||||
import type { HotelDataWithUrl } from "@/types/hotel"
|
||||
import type {
|
||||
CitiesGroupedByCountry,
|
||||
CityLocation,
|
||||
} from "@/types/trpc/routers/hotel/locations"
|
||||
import type {
|
||||
Product,
|
||||
Products,
|
||||
RateDefinition,
|
||||
RedemptionsProduct,
|
||||
} from "@/types/trpc/routers/hotel/roomAvailability"
|
||||
import type { Endpoint } from "@/lib/api/endpoints"
|
||||
import type { selectedRoomAvailabilityInputSchema } from "./input"
|
||||
|
||||
export function getPoiGroupByCategoryName(category: string | undefined) {
|
||||
if (!category) return PointOfInterestGroupEnum.LOCATION
|
||||
@@ -532,3 +543,173 @@ export async function getHotelsByHotelIds({
|
||||
|
||||
return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel)
|
||||
}
|
||||
|
||||
function findProduct(product: Products, rateDefinition: RateDefinition) {
|
||||
if ("corporateCheque" in product) {
|
||||
return product.corporateCheque.rateCode === rateDefinition.rateCode
|
||||
}
|
||||
|
||||
if (("member" in product && product.member) || "public" in product) {
|
||||
let isMemberRate = false
|
||||
if (product.member) {
|
||||
isMemberRate = product.member.rateCode === rateDefinition.rateCode
|
||||
}
|
||||
let isPublicRate = false
|
||||
if (product.public) {
|
||||
isPublicRate = product.public.rateCode === rateDefinition.rateCode
|
||||
}
|
||||
return isMemberRate || isPublicRate
|
||||
}
|
||||
|
||||
if ("voucher" in product) {
|
||||
return product.voucher.rateCode === rateDefinition.rateCode
|
||||
}
|
||||
|
||||
if (Array.isArray(product)) {
|
||||
return product.find(
|
||||
(r) => r.redemption.rateCode === rateDefinition.rateCode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSelectedRoomAvailability(
|
||||
input: z.input<typeof selectedRoomAvailabilityInputSchema>,
|
||||
lang: string,
|
||||
serviceToken: string
|
||||
) {
|
||||
const {
|
||||
adults,
|
||||
bookingCode,
|
||||
children,
|
||||
hotelId,
|
||||
inputLang,
|
||||
roomStayEndDate,
|
||||
roomStayStartDate,
|
||||
redemption,
|
||||
} = input
|
||||
|
||||
const params: Record<string, string | number | undefined> = {
|
||||
roomStayStartDate,
|
||||
roomStayEndDate,
|
||||
adults,
|
||||
...(children && { children }),
|
||||
...(bookingCode && { bookingCode }),
|
||||
...(redemption && { isRedemption: "true" }),
|
||||
language: inputLang ?? lang,
|
||||
}
|
||||
|
||||
metrics.selectedRoomAvailability.counter.add(1, input)
|
||||
console.info(
|
||||
"api.hotels.selectedRoomAvailability start",
|
||||
JSON.stringify({ query: { hotelId: input.hotelId, params } })
|
||||
)
|
||||
const apiResponseAvailability = await api.get(
|
||||
api.endpoints.v1.Availability.hotel(hotelId.toString()),
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${serviceToken}`,
|
||||
},
|
||||
},
|
||||
params
|
||||
)
|
||||
|
||||
if (!apiResponseAvailability.ok) {
|
||||
const text = await apiResponseAvailability.text()
|
||||
metrics.selectedRoomAvailability.fail.add(1, {
|
||||
hotelId,
|
||||
roomStayStartDate,
|
||||
roomStayEndDate,
|
||||
adults,
|
||||
children,
|
||||
bookingCode,
|
||||
error_type: "http_error",
|
||||
error: JSON.stringify({
|
||||
status: apiResponseAvailability.status,
|
||||
statusText: apiResponseAvailability.statusText,
|
||||
text,
|
||||
}),
|
||||
})
|
||||
console.error(
|
||||
"api.hotels.selectedRoomAvailability error",
|
||||
JSON.stringify({
|
||||
query: { hotelId, params },
|
||||
error: {
|
||||
status: apiResponseAvailability.status,
|
||||
statusText: apiResponseAvailability.statusText,
|
||||
text,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
throw new Error("Failed to fetch selected room availability")
|
||||
}
|
||||
const apiJsonAvailability = await apiResponseAvailability.json()
|
||||
const validateAvailabilityData =
|
||||
roomsAvailabilitySchema.safeParse(apiJsonAvailability)
|
||||
if (!validateAvailabilityData.success) {
|
||||
metrics.selectedRoomAvailability.fail.add(1, {
|
||||
hotelId,
|
||||
roomStayStartDate,
|
||||
roomStayEndDate,
|
||||
adults,
|
||||
children,
|
||||
bookingCode,
|
||||
error_type: "validation_error",
|
||||
error: JSON.stringify(validateAvailabilityData.error),
|
||||
})
|
||||
console.error(
|
||||
"api.hotels.selectedRoomAvailability validation error",
|
||||
JSON.stringify({
|
||||
query: { hotelId, params },
|
||||
error: validateAvailabilityData.error,
|
||||
})
|
||||
)
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
const { rateDefinitions, roomConfigurations } = validateAvailabilityData.data
|
||||
|
||||
const rateDefinition = rateDefinitions.find(
|
||||
(rd) => rd.rateCode === input.rateCode
|
||||
)
|
||||
if (!rateDefinition) {
|
||||
return null
|
||||
}
|
||||
|
||||
const selectedRoom = roomConfigurations.find(
|
||||
(room) =>
|
||||
room.roomTypeCode === input.roomTypeCode &&
|
||||
room.products.find((product) => findProduct(product, rateDefinition))
|
||||
)
|
||||
|
||||
if (!selectedRoom) {
|
||||
return null
|
||||
}
|
||||
|
||||
let product: Product | RedemptionsProduct | undefined =
|
||||
selectedRoom.products.find((product) =>
|
||||
findProduct(product, rateDefinition)
|
||||
)
|
||||
|
||||
if (!product) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (Array.isArray(product)) {
|
||||
const redemptionProduct = product.find(
|
||||
(r) => r.redemption.rateCode === rateDefinition.rateCode
|
||||
)
|
||||
if (!redemptionProduct) {
|
||||
return null
|
||||
}
|
||||
product = redemptionProduct
|
||||
}
|
||||
|
||||
return {
|
||||
rateDefinition,
|
||||
rateDefinitions,
|
||||
rooms: roomConfigurations,
|
||||
product,
|
||||
selectedRoom,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user