feat(SW-1717): rewrite select-rate to show all variants of rate-cards

This commit is contained in:
Simon Emanuelsson
2025-03-25 11:25:44 +01:00
committed by Michael Zetterberg
parent adde77eaa9
commit ebaea78fb3
118 changed files with 4601 additions and 4374 deletions

View File

@@ -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,
}
}