diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx index ac7e7e1b2..ddb3785c6 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Payment/PaymentClient.tsx @@ -49,7 +49,6 @@ import type { PriceChangeData, } from "@/types/components/hotelReservation/enterDetails/payment" import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" -import { RateTypeEnum } from "@/types/enums/rateType" const maxRetries = 15 const retryInterval = 2000 @@ -287,103 +286,72 @@ export default function PaymentClient({ hotelId, language: lang, payment, - rooms: rooms.map(({ room }, idx) => { - let bookingCode = undefined - if (room.roomRate.rateDefinition) { - switch (room.roomRate.rateDefinition.rateType) { - case RateTypeEnum.Regular: - // do nothing, regular is not bookable with bookingCode - break - case RateTypeEnum.PublicPromotion: - // PublicPromotion WITH CODE - // only way to figure it out since API use the same - // label for both yet only one should have bookingCoke - if ( - booking.bookingCode === room.roomRate.rateDefinition.rateCode - ) { - bookingCode = booking.bookingCode - } - break - case RateTypeEnum.Arb: - case RateTypeEnum.Company: - case RateTypeEnum.CorporateCheque: - case RateTypeEnum.Promotion: - case RateTypeEnum.Redemption: - case RateTypeEnum.TravelAgent: - case RateTypeEnum.Voucher: - default: - bookingCode = booking.bookingCode - break - } - } - - return { - adults: room.adults, - bookingCode, - childrenAges: room.childrenInRoom?.map((child) => ({ - age: child.age, - bedType: bedTypeMap[parseInt(child.bed.toString())], - })), - guest: { - becomeMember: room.guest.join, - countryCode: room.guest.countryCode, - email: room.guest.email, - firstName: room.guest.firstName, - lastName: room.guest.lastName, - membershipNumber: room.guest.membershipNo, - phoneNumber: room.guest.phoneNumber, - // Only allowed for room one - ...(idx === 0 && { - dateOfBirth: - "dateOfBirth" in room.guest && room.guest.dateOfBirth - ? room.guest.dateOfBirth - : undefined, - postalCode: - "zipCode" in room.guest && room.guest.zipCode - ? room.guest.zipCode - : undefined, - }), - }, - packages: { - accessibility: - room.roomFeatures?.some( - (feature) => - feature.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM - ) ?? false, - allergyFriendly: - room.roomFeatures?.some( - (feature) => feature.code === RoomPackageCodeEnum.ALLERGY_ROOM - ) ?? false, - breakfast: !!(room.breakfast && room.breakfast.code), - petFriendly: - room.roomFeatures?.some( - (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM - ) ?? false, - }, - rateCode: - (room.guest.join || room.guest.membershipNo) && - booking.rooms[idx].counterRateCode - ? booking.rooms[idx].counterRateCode - : booking.rooms[idx].rateCode, - roomPrice: { - memberPrice: - "member" in room.roomRate - ? room.roomRate.member?.localPrice.pricePerStay + rooms: rooms.map(({ room }, idx) => ({ + adults: room.adults, + bookingCode: room.roomRate.bookingCode, + childrenAges: room.childrenInRoom?.map((child) => ({ + age: child.age, + bedType: bedTypeMap[parseInt(child.bed.toString())], + })), + guest: { + becomeMember: room.guest.join, + countryCode: room.guest.countryCode, + email: room.guest.email, + firstName: room.guest.firstName, + lastName: room.guest.lastName, + membershipNumber: room.guest.membershipNo, + phoneNumber: room.guest.phoneNumber, + // Only allowed for room one + ...(idx === 0 && { + dateOfBirth: + "dateOfBirth" in room.guest && room.guest.dateOfBirth + ? room.guest.dateOfBirth : undefined, - publicPrice: - "public" in room.roomRate - ? room.roomRate.public?.localPrice.pricePerStay + postalCode: + "zipCode" in room.guest && room.guest.zipCode + ? room.guest.zipCode : undefined, - }, - roomTypeCode: room.bedType!.roomTypeCode, // A selection has been made in order to get to this step. - smsConfirmationRequested: data.smsConfirmation, - specialRequest: { - comment: room.specialRequest.comment - ? room.specialRequest.comment + }), + }, + packages: { + accessibility: + room.roomFeatures?.some( + (feature) => + feature.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM + ) ?? false, + allergyFriendly: + room.roomFeatures?.some( + (feature) => feature.code === RoomPackageCodeEnum.ALLERGY_ROOM + ) ?? false, + breakfast: !!(room.breakfast && room.breakfast.code), + petFriendly: + room.roomFeatures?.some( + (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM + ) ?? false, + }, + rateCode: + (room.guest.join || room.guest.membershipNo) && + booking.rooms[idx].counterRateCode + ? booking.rooms[idx].counterRateCode + : booking.rooms[idx].rateCode, + roomPrice: { + memberPrice: + "member" in room.roomRate + ? room.roomRate.member?.localPrice.pricePerStay : undefined, - }, - } - }), + publicPrice: + "public" in room.roomRate + ? room.roomRate.public?.localPrice.pricePerStay + : undefined, + }, + roomTypeCode: room.bedType!.roomTypeCode, // A selection has been made in order to get to this step. + smsConfirmationRequested: data.smsConfirmation, + specialRequest: { + comment: room.specialRequest.comment + ? room.specialRequest.comment + : undefined, + }, + })), }) }, [ diff --git a/apps/scandic-web/server/routers/hotels/output.ts b/apps/scandic-web/server/routers/hotels/output.ts index 5557cf962..782a98640 100644 --- a/apps/scandic-web/server/routers/hotels/output.ts +++ b/apps/scandic-web/server/routers/hotels/output.ts @@ -267,6 +267,11 @@ export const roomsAvailabilitySchema = z return null } + if (attributes.bookingCode) { + product.bookingCode = attributes.bookingCode + } else { + product.bookingCode = undefined + } product.breakfastIncluded = rateDefinition.breakfastIncluded product.rate = rate product.rateDefinition = rateDefinition diff --git a/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/configuration.ts b/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/configuration.ts index b4d4765eb..b154d89a4 100644 --- a/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/configuration.ts +++ b/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/configuration.ts @@ -8,63 +8,51 @@ import { voucherProduct, } from "./product" -import { - AvailabilityEnum, -} from "@/types/components/hotelReservation/selectHotel/selectHotel" -import { - RoomPackageCodeEnum, -} from "@/types/components/hotelReservation/selectRate/roomFilter" +import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel" +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" -export const roomConfigurationSchema = z - .object({ - breakfastIncludedInAllRatesMember: z.boolean().default(false), - breakfastIncludedInAllRates: z.boolean().default(false), - features: z - .array( - z.object({ - inventory: z.number(), - code: z.enum([ - RoomPackageCodeEnum.PET_ROOM, - RoomPackageCodeEnum.ALLERGY_ROOM, - RoomPackageCodeEnum.ACCESSIBILITY_ROOM, - ]), - }) - ) - .default([]), - products: z.array(productSchema).default([]), - roomsLeft: z.number(), - roomType: z.string(), - roomTypeCode: z.string(), - status: z - .nativeEnum(AvailabilityEnum) - .nullish() - .default(AvailabilityEnum.NotAvailable), +export const roomConfigurationSchema = z.object({ + breakfastIncludedInAllRatesMember: z.boolean().default(false), + breakfastIncludedInAllRates: z.boolean().default(false), + features: z + .array( + z.object({ + inventory: z.number(), + code: z.enum([ + RoomPackageCodeEnum.PET_ROOM, + RoomPackageCodeEnum.ALLERGY_ROOM, + RoomPackageCodeEnum.ACCESSIBILITY_ROOM, + ]), + }) + ) + .default([]), + products: z.array(productSchema).default([]), + roomsLeft: z.number(), + roomType: z.string(), + roomTypeCode: z.string(), + status: z + .nativeEnum(AvailabilityEnum) + .nullish() + .default(AvailabilityEnum.NotAvailable), - // Red - campaign: z - .array(priceProduct) - .nullish() - .transform(val => val ? val.filter(Boolean) : []), - // Blue - code: z - .array( - z - .union([ - corporateChequeProduct, - priceProduct, - voucherProduct, - ]) - ) - .nullish() - .transform(val => val ? val.filter(Boolean) : []), - // Beige - regular: z - .array(priceProduct) - .nullish() - .transform(val => val ? val.filter(Boolean) : []), - // Burgundy - redemptions: z - .array(redemptionProduct) - .nullish() - .transform(val => val ? val.filter(Boolean) : []), - }) + // Red + campaign: z + .array(priceProduct) + .optional() + .transform((val) => (val ? val.filter(Boolean) : [])), + // Blue + code: z + .array(z.union([corporateChequeProduct, priceProduct, voucherProduct])) + .optional() + .transform((val) => (val ? val.filter(Boolean) : [])), + // Beige + regular: z + .array(priceProduct) + .optional() + .transform((val) => (val ? val.filter(Boolean) : [])), + // Burgundy + redemptions: z + .array(redemptionProduct) + .optional() + .transform((val) => (val ? val.filter(Boolean) : [])), +}) diff --git a/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/product.ts b/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/product.ts index 4966edfb7..803fdcf9e 100644 --- a/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/product.ts +++ b/apps/scandic-web/server/routers/hotels/schemas/roomAvailability/product.ts @@ -9,6 +9,11 @@ import { import { rateDefinitionSchema } from "./rateDefinition" const baseProductSchema = z.object({ + // transform empty string to undefined + bookingCode: z + .string() + .optional() + .transform((val) => val), // Is breakfast included on product breakfastIncluded: z.boolean().default(false), // Used to set the rate that we use to chose titles etc. @@ -35,13 +40,14 @@ const baseProductSchema = z.object({ function mapBaseProduct(baseProduct: typeof baseProductSchema._type) { return { + bookingCode: baseProduct.bookingCode, breakfastIncluded: baseProduct.breakfastIncluded, rate: baseProduct.rate, rateDefinition: baseProduct.rateDefinition, } } -const rawCorporateChequeProduct = z +export const corporateChequeProduct = z .object({ productType: z .object({ @@ -52,21 +58,12 @@ const rawCorporateChequeProduct = z })), }) .merge(baseProductSchema) - -function transformCorporateCheque( - data: z.output -) { - return { + .transform((data) => ({ ...data.productType, ...mapBaseProduct(data), - } -} + })) -export const corporateChequeProduct = rawCorporateChequeProduct.transform( - transformCorporateCheque -) - -const rawPriceProduct = z +export const priceProduct = z .object({ productType: z.object({ member: productTypePriceSchema.nullish().default(null), @@ -74,63 +71,58 @@ const rawPriceProduct = z }), }) .merge(baseProductSchema) - -function transformPriceProduct(data: z.output) { - return { + .transform((data) => ({ ...data.productType, ...mapBaseProduct(data), - } -} - -export const priceProduct = rawPriceProduct.transform(transformPriceProduct) + })) export const redemptionProduct = z .object({ redemption: productTypePointsSchema, }) .merge(baseProductSchema) + .transform((data) => ({ + redemption: data.redemption, + ...mapBaseProduct(data), + })) -const rawRedemptionsProduct = z.object({ - type: z.literal("REDEMPTION").optional().default("REDEMPTION"), - productType: z.object({ - redemptions: z - .array(productTypePointsSchema.merge(baseProductSchema)) - .transform((data) => - data.map( - ({ breakfastIncluded, rate, rateDefinition, ...redemption }) => ({ - breakfastIncluded, - rate, - rateDefinition, - redemption, - }) - ) - ), - }), -}) - -export const redemptionsProduct = rawRedemptionsProduct.transform( - (data) => data.productType.redemptions -) - -const rawVoucherProduct = z +export const redemptionsProduct = z + .object({ + productType: z.object({ + redemptions: z + .array(productTypePointsSchema.merge(baseProductSchema)) + .transform((data) => + data.map( + ({ + bookingCode, + breakfastIncluded, + rate, + rateDefinition, + ...redemption + }) => ({ + bookingCode, + breakfastIncluded, + rate, + rateDefinition, + redemption, + }) + ) + ), + }), + }) + .transform((data) => data.productType.redemptions) + +export const voucherProduct = z .object({ - type: z.literal("VOUCHER").optional().default("VOUCHER"), productType: z.object({ voucher: productTypeVoucherSchema, }), }) .merge(baseProductSchema) - -function transformVoucherProduct(data: z.output) { - return { + .transform((data) => ({ ...data.productType, ...mapBaseProduct(data), - } -} - -export const voucherProduct = rawVoucherProduct.transform( - transformVoucherProduct -) + })) export const productSchema = z.union([ corporateChequeProduct, @@ -138,24 +130,3 @@ export const productSchema = z.union([ voucherProduct, priceProduct, ]) -// export const productSchema = z.discriminatedUnion( -// "type", -// [ -// rawCorporateChequeProduct, -// rawPriceProduct, -// rawRedemptionsProduct, -// rawVoucherProduct, -// ] -// ) -// .transform(data => { -// switch (data.type) { -// case "CORPORATECHEQUE": -// return transformCorporateCheque(data) -// case "PRICEPRODUCT": -// return transformPriceProduct(data) -// case "REDEMPTION": -// return data.productType.redemptions -// case "VOUCHER": -// return transformVoucherProduct(data) -// } -// })