Merged in feat/SW-1353 (pull request #1513)

feat: add multiroom tracking to booking flow

Approved-by: Linus Flood
This commit is contained in:
Simon.Emanuelsson
2025-03-17 09:35:12 +00:00
72 changed files with 2277 additions and 1308 deletions

View File

@@ -26,21 +26,25 @@ export const getHotelsByHotelIdsAvailabilityInputSchema = z.object({
})
export const roomsCombinedAvailabilityInputSchema = z.object({
hotelId: z.number(),
roomStayStartDate: z.string(),
roomStayEndDate: z.string(),
uniqueAdultsCount: z.array(z.number()),
adultsCount: z.array(z.number()),
bookingCode: z.string().optional(),
childArray: z
.array(
z.object({
bed: z.nativeEnum(ChildBedMapEnum),
age: z.number(),
})
z
.array(
z.object({
age: z.number(),
bed: z.nativeEnum(ChildBedMapEnum),
})
)
.nullable()
)
.optional(),
bookingCode: z.string().optional(),
rateCode: z.string().optional(),
.nullish(),
hotelId: z.number(),
lang: z.nativeEnum(Lang),
rateCode: z.string().optional(),
roomStayEndDate: z.string(),
roomStayStartDate: z.string(),
})
export const selectedRoomAvailabilityInputSchema = z.object({

View File

@@ -22,6 +22,7 @@ import { relationshipsSchema } from "./schemas/relationships"
import { roomConfigurationSchema } from "./schemas/roomAvailability/configuration"
import { rateDefinitionSchema } from "./schemas/roomAvailability/rateDefinition"
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import type {
AdditionalData,
City,
@@ -137,6 +138,13 @@ const cancellationRules = {
NotCancellable: 0,
} as const
// Used to ensure `Available` rooms
// are shown before all `NotAvailable`
const statusLookup = {
[AvailabilityEnum.Available]: 1,
[AvailabilityEnum.NotAvailable]: 2,
}
export const roomsAvailabilitySchema = z
.object({
data: z.object({
@@ -161,8 +169,8 @@ export const roomsAvailabilitySchema = z
return acc
}, {})
attributes.roomConfigurations = attributes.roomConfigurations.map(
(room) => {
const roomConfigurations = attributes.roomConfigurations
.map((room) => {
if (room.products.length) {
room.breakfastIncludedInAllRatesMember = room.products.every(
(product) =>
@@ -222,10 +230,16 @@ export const roomsAvailabilitySchema = z
}
return room
}
)
})
.sort(
// @ts-expect-error - array indexing
(a, b) => statusLookup[a.status] - statusLookup[b.status]
)
return attributes
return {
...attributes,
roomConfigurations,
}
})
export const ratesSchema = z.array(rateSchema)

View File

@@ -499,20 +499,20 @@ export const hotelQueryRouter = router({
const { lang } = input
const apiLang = toApiLang(lang)
const {
hotelId,
roomStayStartDate,
roomStayEndDate,
uniqueAdultsCount,
childArray,
adultsCount,
bookingCode,
childArray,
hotelId,
rateCode,
roomStayEndDate,
roomStayStartDate,
} = input
const metricsData = {
hotelId,
roomStayStartDate,
roomStayEndDate,
uniqueAdultsCount,
adultsCount,
childArray: childArray ? JSON.stringify(childArray) : undefined,
bookingCode,
}
@@ -525,15 +525,15 @@ export const hotelQueryRouter = router({
)
const availabilityResponses = await Promise.allSettled(
uniqueAdultsCount.map(async (adultCount: number) => {
adultsCount.map(async (adultCount: number, idx: number) => {
const kids = childArray?.[idx]
const params: Record<string, string | number | undefined> = {
roomStayStartDate,
roomStayEndDate,
adults: adultCount,
...(childArray &&
childArray.length > 0 && {
children: generateChildrenString(childArray),
}),
...(kids?.length && {
children: generateChildrenString(kids),
}),
...(bookingCode && { bookingCode }),
language: apiLang,
}
@@ -769,9 +769,9 @@ export const hotelQueryRouter = router({
type: matchingRoom.mainBed.type,
extraBed: matchingRoom.fixedExtraBed
? {
type: matchingRoom.fixedExtraBed.type,
description: matchingRoom.fixedExtraBed.description,
}
type: matchingRoom.fixedExtraBed.type,
description: matchingRoom.fixedExtraBed.description,
}
: undefined,
}
}
@@ -794,23 +794,27 @@ export const hotelQueryRouter = router({
)
return {
selectedRoom,
rateDetails: rateDefinition?.generalTerms,
bedTypes,
breakfastIncluded: !!rateDefinition?.breakfastIncluded,
cancellationRule: rateDefinition?.cancellationRule,
cancellationText: rateDefinition?.cancellationText ?? "",
isFlexRate:
rateDefinition?.cancellationRule ===
CancellationRuleEnum.CancellableBefore6PM,
mustBeGuaranteed: !!rateDefinition?.mustBeGuaranteed,
memberMustBeGuaranteed: !!memberRateDefinition?.mustBeGuaranteed,
breakfastIncluded: !!rateDefinition?.breakfastIncluded,
memberRate: rates?.member,
mustBeGuaranteed: !!rateDefinition?.mustBeGuaranteed,
publicRate: rates?.public,
rate: selectedRoom.products[0].rate,
rateDefinitionTitle: rateDefinition?.title ?? "",
rateDetails: rateDefinition?.generalTerms,
// Send rate Title when it is a booking code rate
rateTitle:
rateDefinition?.rateType !== RateTypeEnum.Regular
? rateDefinition?.title
: undefined,
memberRate: rates?.member,
publicRate: rates?.public,
bedTypes,
rateType: rateDefinition?.rateType ?? "",
selectedRoom,
}
}),
hotelsByCityWithBookingCode: serviceProcedure
@@ -1096,9 +1100,9 @@ export const hotelQueryRouter = router({
return hotelData
? {
...hotelData,
url: hotelPage?.url ?? null,
}
...hotelData,
url: hotelPage?.url ?? null,
}
: null
})
)

View File

@@ -38,9 +38,15 @@ export const roomConfigurationSchema = z
(product) => !product.public?.rateCode && !product.member?.rateCode
)
if (allProductsMissBothRateCodes) {
data.status = AvailabilityEnum.NotAvailable
return {
...data,
status: AvailabilityEnum.NotAvailable,
}
}
}
return data
// Creating a new objekt since data is frozen (readony)
// and can cause errors to be thrown if trying to manipulate
// object elsewhere
return { ...data }
})