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

@@ -1,14 +1,24 @@
import { z } from "zod"
import { productSchema } from "./product"
import {
corporateChequeProduct,
priceProduct,
productSchema,
redemptionProduct,
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),
breakfastIncludedInAllRatesPublic: z.boolean().default(false),
breakfastIncludedInAllRates: z.boolean().default(false),
features: z
.array(
z.object({
@@ -25,36 +35,36 @@ export const roomConfigurationSchema = z
roomsLeft: z.number(),
roomType: z.string(),
roomTypeCode: z.string(),
status: z.string(),
})
.transform((data) => {
if (data.products.length) {
if (data.products[0].redemptions) {
// No need of rate check in reward night scenario
return { ...data }
} else {
const isVoucher = data.products.some((product) => product.voucher)
const isCorpChq = data.products.some((product) => product.bonusCheque)
if (isVoucher || isCorpChq) {
return {
...data,
}
}
/**
* Just guaranteeing that if all products all miss
* both public and member rateCode that status is
* set to `NotAvailable`
*/
const allProductsMissBothRateCodes = data.products.every(
(product) => !product.public?.rateCode && !product.member?.rateCode
)
if (allProductsMissBothRateCodes) {
return {
...data,
status: AvailabilityEnum.NotAvailable,
}
}
}
}
return data
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) : []),
})

View File

@@ -1,28 +1,161 @@
import { z } from "zod"
import {
productTypeCorporateChequeSchema,
productTypePointsSchema,
productTypeChequeSchema,
productTypePriceSchema,
productTypeVoucherSchema,
} from "../productTypePrice"
import { rateDefinitionSchema } from "./rateDefinition"
export const productSchema = z
const baseProductSchema = z.object({
// Is breakfast included on product
breakfastIncluded: z.boolean().default(false),
// Used to set the rate that we use to chose titles etc.
rate: z.enum(["change", "flex", "save"]).default("save"),
rateDefinition: rateDefinitionSchema.nullish().transform((val) =>
val
? val
: {
breakfastIncluded: false,
cancellationRule: "",
cancellationText: "",
displayPriceRed: false,
isCampaignRate: false,
isMemberRate: false,
isPackageRate: false,
generalTerms: [],
mustBeGuaranteed: false,
rateCode: "",
rateType: "",
title: "",
}
),
})
function mapBaseProduct(baseProduct: typeof baseProductSchema._type) {
return {
breakfastIncluded: baseProduct.breakfastIncluded,
rate: baseProduct.rate,
rateDefinition: baseProduct.rateDefinition,
}
}
const rawCorporateChequeProduct = z
.object({
// Is product flex rate
isFlex: z.boolean().default(false),
productType: z.object({
bonusCheque: productTypeChequeSchema.optional(),
member: productTypePriceSchema.optional(),
public: productTypePriceSchema.optional(),
redemptions: z.array(productTypePointsSchema).optional(),
voucher: productTypeVoucherSchema.optional(),
}),
// Used to set the rate that we use to chose titles etc.
rate: z.enum(["change", "flex", "save"]).default("save"),
productType: z
.object({
bonusCheque: productTypeCorporateChequeSchema,
})
.transform((data) => ({
corporateCheque: data.bonusCheque,
})),
})
.transform((data) => ({
.merge(baseProductSchema)
function transformCorporateCheque(
data: z.output<typeof rawCorporateChequeProduct>
) {
return {
...data.productType,
isFlex: data.isFlex,
rate: data.rate,
}))
...mapBaseProduct(data),
}
}
export const corporateChequeProduct = rawCorporateChequeProduct.transform(
transformCorporateCheque
)
const rawPriceProduct = z
.object({
productType: z.object({
member: productTypePriceSchema.nullish().default(null),
public: productTypePriceSchema.nullish().default(null),
}),
})
.merge(baseProductSchema)
function transformPriceProduct(data: z.output<typeof rawPriceProduct>) {
return {
...data.productType,
...mapBaseProduct(data),
}
}
export const priceProduct = rawPriceProduct.transform(transformPriceProduct)
export const redemptionProduct = z
.object({
redemption: productTypePointsSchema,
})
.merge(baseProductSchema)
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
.object({
type: z.literal("VOUCHER").optional().default("VOUCHER"),
productType: z.object({
voucher: productTypeVoucherSchema,
}),
})
.merge(baseProductSchema)
function transformVoucherProduct(data: z.output<typeof rawVoucherProduct>) {
return {
...data.productType,
...mapBaseProduct(data),
}
}
export const voucherProduct = rawVoucherProduct.transform(
transformVoucherProduct
)
export const productSchema = z.union([
corporateChequeProduct,
redemptionsProduct,
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)
// }
// })

View File

@@ -1,12 +1,17 @@
import { nullableStringValidator } from "@/utils/zod/stringValidator"
import { z } from "zod"
export const rateDefinitionSchema = z.object({
breakfastIncluded: z.boolean(),
cancellationRule: z.string(),
cancellationText: z.string().optional(),
cancellationText: nullableStringValidator,
displayPriceRed: z.boolean().default(false),
generalTerms: z.array(z.string()),
isCampaignRate: z.boolean().default(false),
isMemberRate: z.boolean().default(false),
isPackageRate: z.boolean().default(false),
mustBeGuaranteed: z.boolean(),
rateCode: z.string(),
rateType: z.string().optional(),
rateType: nullableStringValidator,
title: z.string(),
})