From 7f9af6c12e88a088d0293e23501c0c58650f4e3f Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Mon, 4 Nov 2024 14:20:46 +0100 Subject: [PATCH] feat(SW-697): Update package structure on price from API --- .../EnterDetails/Breakfast/index.tsx | 28 +++++------ .../EnterDetails/Summary/index.tsx | 4 +- .../FlexibilityOption/PriceList/index.tsx | 44 ++++++++++++++++-- .../FlexibilityOption/PriceList/utils.ts | 46 +++++++++++++++++++ .../RoomSelection/FlexibilityOption/index.tsx | 7 ++- .../RoomSelection/RateSummary/index.tsx | 4 +- .../RoomSelection/RoomCard/index.tsx | 7 +++ .../SelectRate/RoomSelection/index.tsx | 1 + server/routers/hotels/output.ts | 14 ++++-- server/routers/hotels/query.ts | 4 +- server/routers/hotels/schemas/packages.ts | 42 ++++++++--------- .../selectRate/flexibilityOption.ts | 5 ++ .../hotelReservation/selectRate/roomCard.ts | 19 +++++++- .../hotelReservation/selectRate/roomFilter.ts | 7 ++- 14 files changed, 178 insertions(+), 54 deletions(-) create mode 100644 components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/utils.ts diff --git a/components/HotelReservation/EnterDetails/Breakfast/index.tsx b/components/HotelReservation/EnterDetails/Breakfast/index.tsx index e8868edf7..00d5ab4cc 100644 --- a/components/HotelReservation/EnterDetails/Breakfast/index.tsx +++ b/components/HotelReservation/EnterDetails/Breakfast/index.tsx @@ -76,21 +76,21 @@ export default function Breakfast({ packages }: BreakfastProps) { subtitle={ pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST ? intl.formatMessage( - { id: "breakfast.price.free" }, - { - amount: pkg.originalPrice, - currency: pkg.currency, - free: (str) => {str}, - strikethrough: (str) => {str}, - } - ) + { id: "breakfast.price.free" }, + { + amount: pkg.localPrice.price, + currency: pkg.localPrice.currency, + free: (str) => {str}, + strikethrough: (str) => {str}, + } + ) : intl.formatMessage( - { id: "breakfast.price" }, - { - amount: pkg.packagePrice, - currency: pkg.currency, - } - ) + { id: "breakfast.price" }, + { + amount: pkg.localPrice.price, + currency: pkg.localPrice.currency, + } + ) } text={intl.formatMessage({ id: "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.", diff --git a/components/HotelReservation/EnterDetails/Summary/index.tsx b/components/HotelReservation/EnterDetails/Summary/index.tsx index 84c6280af..ca2891912 100644 --- a/components/HotelReservation/EnterDetails/Summary/index.tsx +++ b/components/HotelReservation/EnterDetails/Summary/index.tsx @@ -150,8 +150,8 @@ export default function Summary({ {intl.formatMessage( { id: "{amount} {currency}" }, { - amount: chosenBreakfast.totalPrice, - currency: chosenBreakfast.currency, + amount: chosenBreakfast.localPrice.price, + currency: chosenBreakfast.localPrice.currency, } )} diff --git a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/index.tsx index dc7ca20fc..6ec68426f 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/index.tsx @@ -1,9 +1,12 @@ +import { differenceInCalendarDays } from "date-fns" import { useIntl } from "react-intl" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" +import { calculatePricesPerNight } from "./utils" + import styles from "./priceList.module.css" import { PriceListProps } from "@/types/components/hotelReservation/selectRate/flexibilityOption" @@ -11,6 +14,7 @@ import { PriceListProps } from "@/types/components/hotelReservation/selectRate/f export default function PriceList({ publicPrice = {}, memberPrice = {}, + petRoomPackage, }: PriceListProps) { const intl = useIntl() @@ -19,15 +23,45 @@ export default function PriceList({ const { localPrice: memberLocalPrice, requestedPrice: memberRequestedPrice } = memberPrice + const petRoomLocalPrice = petRoomPackage?.localPrice + const petRoomRequestedPrice = petRoomPackage?.requestedPrice + const showRequestedPrice = publicRequestedPrice && memberRequestedPrice + const searchParams = new URLSearchParams(window.location.search) + const fromDate = searchParams.get("fromDate") + const toDate = searchParams.get("toDate") + + let nights = 1 + + if (fromDate && toDate) { + nights = differenceInCalendarDays(new Date(fromDate), new Date(toDate)) + } + + const { + totalPublicLocalPricePerNight, + totalMemberLocalPricePerNight, + totalPublicRequestedPricePerNight, + totalMemberRequestedPricePerNight, + } = calculatePricesPerNight({ + publicLocalPrice, + memberLocalPrice, + publicRequestedPrice, + memberRequestedPrice, + petRoomLocalPrice, + petRoomRequestedPrice, + nights, + }) + return (
{intl.formatMessage({ id: "Standard price" })} @@ -36,7 +70,7 @@ export default function PriceList({ {publicLocalPrice ? (
- {publicLocalPrice.pricePerNight} + {totalPublicLocalPricePerNight} {publicLocalPrice.currency} @@ -63,7 +97,7 @@ export default function PriceList({ {memberLocalPrice ? (
- {memberLocalPrice.pricePerNight} + {totalMemberLocalPricePerNight} {memberLocalPrice.currency} @@ -91,8 +125,8 @@ export default function PriceList({
{showRequestedPrice ? ( - {publicRequestedPrice.pricePerNight}/ - {memberRequestedPrice.pricePerNight}{" "} + {totalPublicRequestedPricePerNight}/ + {totalMemberRequestedPricePerNight}{" "} {publicRequestedPrice.currency} ) : ( diff --git a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/utils.ts b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/utils.ts new file mode 100644 index 000000000..4043aa652 --- /dev/null +++ b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/PriceList/utils.ts @@ -0,0 +1,46 @@ +import type { CalculatePricesPerNightProps } from "@/types/components/hotelReservation/selectRate/roomCard" + +export function calculatePricesPerNight({ + publicLocalPrice, + memberLocalPrice, + publicRequestedPrice, + memberRequestedPrice, + petRoomLocalPrice, + petRoomRequestedPrice, + nights, +}: CalculatePricesPerNightProps) { + const totalPublicLocalPricePerNight = publicLocalPrice + ? petRoomLocalPrice + ? Number(publicLocalPrice.pricePerNight) + + Number(petRoomLocalPrice.price) / nights + : Number(publicLocalPrice.pricePerNight) + : undefined + + const totalMemberLocalPricePerNight = memberLocalPrice + ? petRoomLocalPrice + ? Number(memberLocalPrice.pricePerNight) + + Number(petRoomLocalPrice.price) / nights + : Number(memberLocalPrice.pricePerNight) + : undefined + + const totalPublicRequestedPricePerNight = publicRequestedPrice + ? petRoomRequestedPrice + ? Number(publicRequestedPrice.pricePerNight) + + Number(petRoomRequestedPrice.price) / nights + : Number(publicRequestedPrice.pricePerNight) + : undefined + + const totalMemberRequestedPricePerNight = memberRequestedPrice + ? petRoomRequestedPrice + ? Number(memberRequestedPrice.pricePerNight) + + Number(petRoomRequestedPrice.price) / nights + : Number(memberRequestedPrice.pricePerNight) + : undefined + + return { + totalPublicLocalPricePerNight, + totalMemberLocalPricePerNight, + totalPublicRequestedPricePerNight, + totalMemberRequestedPricePerNight, + } +} diff --git a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx index a0a92bb66..f1781d978 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx @@ -20,6 +20,7 @@ export default function FlexibilityOption({ roomType, roomTypeCode, features, + petRoomPackage, handleSelectRate, }: FlexibilityOptionProps) { const [rootDiv, setRootDiv] = useState(undefined) @@ -113,7 +114,11 @@ export default function FlexibilityOption({ {name} ({paymentTerm})
- + pkg.code === RoomPackageCodeEnum.PET_ROOM ) - const petRoomPrice = petRoomPackage?.calculatedPrice ?? null - const petRoomCurrency = petRoomPackage?.currency ?? null + const petRoomPrice = petRoomPackage?.localPrice.totalPrice ?? null + const petRoomCurrency = petRoomPackage?.localPrice.currency ?? null const checkInDate = new Date(roomsAvailability.checkInDate) const checkOutDate = new Date(roomsAvailability.checkOutDate) diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index 4eae4293c..530af45da 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -18,12 +18,14 @@ import { getIconForFeatureCode } from "../../utils" import styles from "./roomCard.module.css" import type { RoomCardProps } from "@/types/components/hotelReservation/selectRate/roomCard" +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" export default function RoomCard({ rateDefinitions, roomConfiguration, roomCategories, selectedPackages, + packages, handleSelectRate, }: RoomCardProps) { const intl = useIntl() @@ -55,6 +57,10 @@ export default function RoomCard({ ?.generalTerms } + const petRoomPackage = packages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM + ) + const selectedRoom = roomCategories.find( (room) => room.name === roomConfiguration.roomType ) @@ -118,6 +124,7 @@ export default function RoomCard({ roomType={roomConfiguration.roomType} roomTypeCode={roomConfiguration.roomTypeCode} features={roomConfiguration.features} + petRoomPackage={petRoomPackage} /> ))} diff --git a/components/HotelReservation/SelectRate/RoomSelection/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/index.tsx index 38745e241..112f69f76 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/index.tsx @@ -72,6 +72,7 @@ export default function RoomSelection({ roomCategories={roomCategories} handleSelectRate={setRateSummary} selectedPackages={selectedPackages} + packages={packages} /> ))} diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 1b49b5fbf..dad7abe49 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -488,7 +488,7 @@ export type HotelsAvailability = z.infer export type HotelsAvailabilityPrices = HotelsAvailability["data"][number]["attributes"]["bestPricePerNight"] -const priceSchema = z.object({ +export const priceSchema = z.object({ pricePerNight: z.string(), pricePerStay: z.string(), currency: z.string(), @@ -774,17 +774,21 @@ export const apiLocationsSchema = z.object({ ), }) +const breakfastPackagePriceSchema = z.object({ + currency: z.nativeEnum(CurrencyEnum), + price: z.string(), + totalPrice: z.string(), +}) + export const breakfastPackageSchema = z.object({ code: z.string(), - currency: z.nativeEnum(CurrencyEnum), description: z.string(), - originalPrice: z.number().default(0), - packagePrice: z.number(), + localPrice: breakfastPackagePriceSchema, + requestedPrice: breakfastPackagePriceSchema, packageType: z.enum([ PackageTypeEnum.BreakfastAdult, PackageTypeEnum.BreakfastChildren, ]), - totalPrice: z.number(), }) export const breakfastPackagesSchema = z diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 627ad1f8d..416b22d49 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -1086,8 +1086,8 @@ export const hotelQueryRouter = router({ ) if (freeBreakfastPackage) { if (originalBreakfastPackage) { - freeBreakfastPackage.originalPrice = - originalBreakfastPackage.packagePrice + freeBreakfastPackage.localPrice.price = + originalBreakfastPackage.localPrice.price } return [freeBreakfastPackage] } diff --git a/server/routers/hotels/schemas/packages.ts b/server/routers/hotels/schemas/packages.ts index 2f12f7255..9de3c0574 100644 --- a/server/routers/hotels/schemas/packages.ts +++ b/server/routers/hotels/schemas/packages.ts @@ -11,33 +11,33 @@ export const getRoomPackagesInputSchema = z.object({ packageCodes: z.array(z.string()).optional().default([]), }) -const packagesSchema = z.array( - z.object({ - code: z.enum([ - RoomPackageCodeEnum.PET_ROOM, - RoomPackageCodeEnum.ALLERGY_ROOM, - RoomPackageCodeEnum.ACCESSIBILITY_ROOM, - ]), - itemCode: z.string(), - description: z.string(), - currency: z.string(), - calculatedPrice: z.number(), - inventories: z.array( - z.object({ - date: z.string(), - total: z.number(), - available: z.number(), - }) - ), - }) -) +export const packagePriceSchema = z.object({ + currency: z.string(), + price: z.string(), + totalPrice: z.string(), +}) + +export const packagesSchema = z.object({ + code: z.nativeEnum(RoomPackageCodeEnum), + itemCode: z.string(), + description: z.string(), + localPrice: packagePriceSchema, + requestedPrice: packagePriceSchema, + inventories: z.array( + z.object({ + date: z.string(), + total: z.number(), + available: z.number(), + }) + ), +}) export const getRoomPackagesSchema = z .object({ data: z.object({ attributes: z.object({ hotelId: z.number(), - packages: packagesSchema, + packages: z.array(packagesSchema), }), relationships: z .object({ diff --git a/types/components/hotelReservation/selectRate/flexibilityOption.ts b/types/components/hotelReservation/selectRate/flexibilityOption.ts index 1a432dc32..811afc139 100644 --- a/types/components/hotelReservation/selectRate/flexibilityOption.ts +++ b/types/components/hotelReservation/selectRate/flexibilityOption.ts @@ -1,14 +1,17 @@ import { z } from "zod" import { + priceSchema, Product, productTypePriceSchema, RoomConfiguration, } from "@/server/routers/hotels/output" +import { RoomPackage } from "./roomFilter" import { Rate } from "./selectRate" type ProductPrice = z.output +export type RoomPriceSchema = z.output export type FlexibilityOptionProps = { product: Product | undefined @@ -19,10 +22,12 @@ export type FlexibilityOptionProps = { roomType: RoomConfiguration["roomType"] roomTypeCode: RoomConfiguration["roomTypeCode"] features: RoomConfiguration["features"] + petRoomPackage: RoomPackage | undefined handleSelectRate: (rate: Rate) => void } export interface PriceListProps { publicPrice?: ProductPrice | Record memberPrice?: ProductPrice | Record + petRoomPackage?: RoomPackage | undefined } diff --git a/types/components/hotelReservation/selectRate/roomCard.ts b/types/components/hotelReservation/selectRate/roomCard.ts index 5af0c4bb1..b47a8c5bb 100644 --- a/types/components/hotelReservation/selectRate/roomCard.ts +++ b/types/components/hotelReservation/selectRate/roomCard.ts @@ -1,17 +1,34 @@ +import { z } from "zod" + import { RateDefinition, RoomConfiguration, } from "@/server/routers/hotels/output" +import { packagePriceSchema } from "@/server/routers/hotels/schemas/packages" +import { RoomPriceSchema } from "./flexibilityOption" import { Rate } from "./selectRate" import type { RoomData } from "@/types/hotel" -import type { RoomPackageCodes } from "./roomFilter" +import type { RoomPackageCodes, RoomPackageData } from "./roomFilter" export type RoomCardProps = { roomConfiguration: RoomConfiguration rateDefinitions: RateDefinition[] roomCategories: RoomData[] selectedPackages: RoomPackageCodes[] + packages: RoomPackageData handleSelectRate: (rate: Rate) => void } + +type RoomPackagePriceSchema = z.output + +export type CalculatePricesPerNightProps = { + publicLocalPrice: RoomPriceSchema + memberLocalPrice: RoomPriceSchema + publicRequestedPrice?: RoomPriceSchema + memberRequestedPrice?: RoomPriceSchema + petRoomLocalPrice?: RoomPackagePriceSchema + petRoomRequestedPrice?: RoomPackagePriceSchema + nights: number +} diff --git a/types/components/hotelReservation/selectRate/roomFilter.ts b/types/components/hotelReservation/selectRate/roomFilter.ts index d42669295..8250e7f32 100644 --- a/types/components/hotelReservation/selectRate/roomFilter.ts +++ b/types/components/hotelReservation/selectRate/roomFilter.ts @@ -1,6 +1,9 @@ import { z } from "zod" -import { getRoomPackagesSchema } from "@/server/routers/hotels/schemas/packages" +import { + getRoomPackagesSchema, + packagesSchema, +} from "@/server/routers/hotels/schemas/packages" export enum RoomPackageCodeEnum { PET_ROOM = "PETR", @@ -17,3 +20,5 @@ export interface RoomPackageData extends z.output {} export type RoomPackageCodes = RoomPackageData[number]["code"] + +export type RoomPackage = z.output