diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/payment-callback/page.tsx new file mode 100644 index 000000000..e0ff199ee --- /dev/null +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/payment-callback/page.tsx @@ -0,0 +1,3 @@ +export default function ConfirmedBookingSlot() { + return null +} diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx index 2eeccb516..d296f5358 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/PriceDetailsModal/index.tsx @@ -75,6 +75,9 @@ export default function PriceDetailsModal() { return null } + const checkInDate = dt(fromDate).format("YYYY-MM-DD") + const checkOutDate = dt(toDate).format("YYYY-MM-DD") + const bookingTotal = rooms.reduce( (acc, room) => { if (room) { @@ -89,7 +92,7 @@ export default function PriceDetailsModal() { { price: 0, priceExVat: 0, vatAmount: 0 } ) - const diff = dt(toDate).diff(fromDate, "days") + const diff = dt(checkOutDate).diff(checkInDate, "days") const nights = intl.formatMessage( { id: "{totalNights, plural, one {# night} other {# nights}}" }, { totalNights: diff } diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx index 607e2a37c..d8f049921 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx @@ -163,21 +163,23 @@ export default function ReceiptRoom({ ) : null} -
- {intl.formatMessage({ id: "Breakfast buffet" })} - {(room.rateDefinition.breakfastIncluded ?? room.breakfastIncluded) ? ( - {intl.formatMessage({ id: "Included" })} - ) : null} - {room.breakfast ? ( - - {formatPrice( - intl, - room.breakfast.totalPrice * room.adults, - room.breakfast.currency - )} - - ) : null} -
+ {room.breakfast || room.breakfastIncluded ? ( +
+ {intl.formatMessage({ id: "Breakfast buffet" })} + {(room.rateDefinition.breakfastIncluded ?? room.breakfastIncluded) ? ( + {intl.formatMessage({ id: "Included" })} + ) : null} + {room.breakfast ? ( + + {formatPrice( + intl, + room.breakfast.totalPrice, + room.breakfast.currency + )} + + ) : null} +
+ ) : null} ) } diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Tracking/tracking.ts b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Tracking/tracking.ts index a1492acf9..7b5277cf4 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Tracking/tracking.ts +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Tracking/tracking.ts @@ -11,6 +11,7 @@ import { type TrackingSDKPaymentInfo, } from "@/types/components/tracking" import { BreakfastPackageEnum } from "@/types/enums/breakfast" +import { RateEnum } from "@/types/enums/rate" import type { Room } from "@/types/stores/booking-confirmation" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { RateDefinition } from "@/types/trpc/routers/hotel/roomAvailability" @@ -19,11 +20,11 @@ import type { Lang } from "@/constants/languages" function getRate(cancellationRule: RateDefinition["cancellationRule"] | null) { switch (cancellationRule) { case "CancellableBefore6PM": - return "flex" + return RateEnum.flex case "Changeable": - return "change" + return RateEnum.change case "NotCancellable": - return "save" + return RateEnum.save default: return "-" } diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Breakfast/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Breakfast/index.tsx index f8425c717..22c3a89f7 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Breakfast/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Breakfast/index.tsx @@ -42,13 +42,11 @@ export default function Breakfast() { : undefined const methods = useForm({ - defaultValues: breakfastSelection - ? { breakfast: breakfastSelection } - : undefined, criteriaMode: "all", mode: "all", resolver: zodResolver(breakfastFormSchema), reValidateMode: "onChange", + values: breakfastSelection ? { breakfast: breakfastSelection } : undefined, }) const onSubmit = useCallback( diff --git a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx index 83828369f..0c23092eb 100644 --- a/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx +++ b/apps/scandic-web/components/HotelReservation/EnterDetails/Summary/UI/index.tsx @@ -28,6 +28,14 @@ import styles from "./ui.module.css" import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums" import type { RoomRate } from "@/types/components/hotelReservation/enterDetails/details" import type { EnterDetailsSummaryProps } from "@/types/components/hotelReservation/summary" +import { CurrencyEnum } from "@/types/enums/currency" + +const notDisplayableCurrencies = [ + CurrencyEnum.CC, + CurrencyEnum.POINTS, + CurrencyEnum.Voucher, + CurrencyEnum.Unknown, +] export default function SummaryUI({ booking, @@ -81,6 +89,10 @@ export default function SummaryUI({ "redemption" in roomOneRoomRate || "voucher" in roomOneRoomRate + const isSameCurrency = totalPrice.requested + ? totalPrice.requested.currency === totalPrice.local.currency + : false + return (
@@ -160,6 +172,10 @@ export default function SummaryUI({ guestsParts.push(childrenMsg) } + const hideBedCurrency = notDisplayableCurrencies.includes( + room.roomPrice.perStay.local.currency + ) + return (
@@ -418,7 +436,7 @@ export default function SummaryUI({ )} ) : null} - {totalPrice.requested && !isSpecialRate && ( + {totalPrice.requested && !isSpecialRate && !isSameCurrency && ( {intl.formatMessage( { id: "Approx. {value}" }, diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx index ff6631e8e..efdd22741 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/index.tsx @@ -31,7 +31,7 @@ import styles from "./rateSummary.module.css" import type { Price } from "@/types/components/hotelReservation/price" import type { RateSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary" import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" -import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate" +import { RateEnum } from "@/types/enums/rate" import { RateTypeEnum } from "@/types/enums/rateType" export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { @@ -111,13 +111,13 @@ export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { const payLater = intl.formatMessage({ id: "Pay later" }) const payNow = intl.formatMessage({ id: "Pay now" }) - function getRateDetails(rate: Rate["rate"]) { + function getRateDetails(rate: RateEnum) { switch (rate) { - case "change": + case RateEnum.change: return `${freeBooking}, ${payNow}` - case "flex": + case RateEnum.flex: return `${freeCancelation}, ${payLater}` - case "save": + case RateEnum.save: default: return `${nonRefundable}, ${payNow}` } @@ -243,19 +243,29 @@ export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { total, { features, packages: roomPackages, product } ) => { - if (!("member" in product) || !product.member) { - return total - } - const memberPrice = - product.member.localPrice.pricePerStay - if (!memberPrice) { + const memberExists = + "member" in product && product.member + const publicExists = + "public" in product && product.public + if (!memberExists) { + if (!publicExists) { + return total + } + } + + const price = + product.member?.localPrice.pricePerStay || + product.public?.localPrice.pricePerStay + + if (!price) { return total } + const hasSelectedPetRoom = roomPackages.includes( RoomPackageCodeEnum.PET_ROOM ) if (!hasSelectedPetRoom) { - return total + memberPrice + return total + price } const isPetRoom = features.find( (feature) => @@ -265,7 +275,7 @@ export default function RateSummary({ isUserLoggedIn }: RateSummaryProps) { isPetRoom && petRoomPackage ? Number(petRoomPackage.localPrice.totalPrice) : 0 - return total + memberPrice + petRoomPrice + return total + price + petRoomPrice }, 0 ), diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts index 439d30a0e..3ae2146ba 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/RateSummary/utils.ts @@ -34,24 +34,32 @@ export function calculateTotalPrice( const isPetRoom = room.features.find( (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM ) - let petRoomPrice = 0 + let petRoomPriceLocal = 0 if ( petRoomPackage && isPetRoom && room.packages.includes(RoomPackageCodeEnum.PET_ROOM) ) { - petRoomPrice = Number(petRoomPackage.localPrice.totalPrice) + petRoomPriceLocal = Number(petRoomPackage.localPrice.totalPrice) + } + let petRoomPriceRequested = 0 + if ( + petRoomPackage && + isPetRoom && + room.packages.includes(RoomPackageCodeEnum.PET_ROOM) + ) { + petRoomPriceRequested = Number(petRoomPackage.requestedPrice.totalPrice) } total.local.currency = rate.localPrice.currency total.local.price = - total.local.price + rate.localPrice.pricePerStay + petRoomPrice + total.local.price + rate.localPrice.pricePerStay + petRoomPriceLocal if (rate.localPrice.regularPricePerStay) { total.local.regularPrice = (total.local.regularPrice || 0) + rate.localPrice.regularPricePerStay + - petRoomPrice + petRoomPriceLocal } if (rate.requestedPrice) { @@ -69,13 +77,13 @@ export function calculateTotalPrice( total.requested.price = total.requested.price + rate.requestedPrice.pricePerStay + - petRoomPrice + petRoomPriceRequested if (rate.requestedPrice.regularPricePerStay) { total.requested.regularPrice = (total.requested.regularPrice || 0) + rate.requestedPrice.regularPricePerStay + - petRoomPrice + petRoomPriceRequested } } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx index ddf6cbe79..4cb01a735 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/MultiRoomWrapper/SelectedRoomPanel/index.tsx @@ -15,8 +15,8 @@ import { useRoomContext } from "@/contexts/SelectRate/Room" import styles from "./selectedRoomPanel.module.css" -import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate" import { CurrencyEnum } from "@/types/enums/currency" +import { RateEnum } from "@/types/enums/rate" export default function SelectedRoomPanel() { const intl = useIntl() @@ -43,13 +43,13 @@ export default function SelectedRoomPanel() { const payLater = intl.formatMessage({ id: "Pay later" }) const payNow = intl.formatMessage({ id: "Pay now" }) - function getRateTitle(rate: Rate["rate"]) { + function getRateTitle(rate: RateEnum) { switch (rate) { - case "change": + case RateEnum.change: return `${freeBooking}, ${payNow}` - case "flex": + case RateEnum.flex: return `${freeCancelation}, ${payLater}` - case "save": + case RateEnum.save: default: return `${nonRefundable}, ${payNow}` } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/BreakfastMessage/getBreakfastMessage.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/BreakfastMessage/getBreakfastMessage.ts index 872f337b0..9ce1ae7d6 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/BreakfastMessage/getBreakfastMessage.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/BreakfastMessage/getBreakfastMessage.ts @@ -27,5 +27,5 @@ export function getBreakfastMessage( return msgs.notIncluded } - return msgs.noSelection + return msgs.notIncluded } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx index 2cda658a2..06fddbd07 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Campaign.tsx @@ -4,8 +4,6 @@ import { useIntl } from "react-intl" import CampaignRateCard from "@scandic-hotels/design-system/CampaignRateCard" import NoRateAvailableCard from "@scandic-hotels/design-system/NoRateAvailableCard" -import { useRatesStore } from "@/stores/select-rate" - import { useRoomContext } from "@/contexts/SelectRate/Room" import useRateTitles from "@/hooks/booking/useRateTitles" @@ -30,7 +28,6 @@ export default function Campaign({ const intl = useIntl() const { roomAvailability, roomNr, selectedFilter, selectedRate } = useRoomContext() - const bookingCode = useRatesStore((state) => state.booking.bookingCode) const rateTitles = useRateTitles() let isCampaignRate = false @@ -85,11 +82,11 @@ export default function Campaign({ ) let bannerText = intl.formatMessage({ id: "Campaign" }) - if (bookingCode) { - bannerText = bookingCode + if (product.bookingCode) { + bannerText = product.bookingCode } - if (product.rateDefinition?.breakfastIncluded) { + if (product.rateDefinition.breakfastIncluded) { bannerText = `${bannerText} ∙ ${intl.formatMessage({ id: "Breakfast included" })}` } else { bannerText = `${bannerText} ∙ ${intl.formatMessage({ id: "Breakfast excluded" })}` diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx index e77c154dd..1ce4e73fa 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Code.tsx @@ -38,7 +38,7 @@ export default function Code({ return code.map((product) => { let bannerText = "" - if (product.breakfastIncluded) { + if (product.rateDefinition.breakfastIncluded) { bannerText = `${bookingCode} ∙ ${intl.formatMessage({ id: "Breakfast included" })}` } else { bannerText = `${bookingCode} ∙ ${intl.formatMessage({ id: "Breakfast excluded" })}` @@ -141,12 +141,13 @@ export default function Code({ petRoomPackage ) - const comparisonRate = regularPricePerNight.totalPrice - ? { - price: regularPricePerNight.totalPrice, - unit: localPrice.currency, - } - : undefined + const comparisonRate = + +regularPricePerNight.totalPrice > +pricePerNight.totalPrice + ? { + price: regularPricePerNight.totalPrice, + unit: localPrice.currency, + } + : undefined const isSelected = isSelectedPriceProduct( product, diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx index 3b1ae8c0a..88f7944c9 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Redemptions.tsx @@ -72,7 +72,7 @@ export default function Redemptions({ const notEnoughPoints = rates.every((rate) => rate.isDisabled) const firstRedemption = redemptions[0] - const bannerText = firstRedemption.breakfastIncluded + const bannerText = firstRedemption.rateDefinition.breakfastIncluded ? `${rewardNight} ∙ ${breakfastIncluded}` : `${rewardNight} ∙ ${breakfastExcluded}` diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx index 3092ed393..d0ff275a9 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/Regular.tsx @@ -114,7 +114,7 @@ export default function Regular({ unit: `${standard!.localPrice.currency}/${night}`, } - if (standardPricePerNight.totalRequestedPrice) { + if (standardPricePerNight.totalRequestedPrice && !isUserLoggedIn) { approximateStandardRatePrice = standardPricePerNight.totalRequestedPrice } } diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts index f4f3b01ef..f1930b45f 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts @@ -10,34 +10,29 @@ export function isSelectedPriceProduct( selectedRate: SelectedRate | null, roomTypeCode: string ) { - if (!selectedRate) { + if (!selectedRate || roomTypeCode !== selectedRate.roomTypeCode) { return false } const { member, public: standard } = product - let selectedRateMember: PriceProduct["member"] = null - if ("member" in selectedRate.product) { - selectedRateMember = selectedRate.product.member + let isSelected = false + if ( + "member" in selectedRate.product && + selectedRate.product.member && + member + ) { + isSelected = selectedRate.product.member.rateCode === member.rateCode } - let selectedRatePublic: PriceProduct["public"] = null - if ("public" in selectedRate.product) { - selectedRatePublic = selectedRate.product.public + if ( + "public" in selectedRate.product && + selectedRate.product.public && + standard + ) { + isSelected = selectedRate.product.public.rateCode === standard.rateCode } - const selectedRateIsMember = - member && - selectedRateMember && - member.rateCode === selectedRateMember.rateCode - - const selectedRateIsPublic = - standard && - selectedRatePublic && - standard.rateCode === selectedRatePublic.rateCode - return !!( - (selectedRateIsMember || selectedRateIsPublic) && - selectedRate.roomTypeCode === roomTypeCode - ) + return isSelected } export function isSelectedCorporateCheque( diff --git a/apps/scandic-web/providers/SelectRate/RoomProvider.tsx b/apps/scandic-web/providers/SelectRate/RoomProvider.tsx index 20e7ec44e..7660df079 100644 --- a/apps/scandic-web/providers/SelectRate/RoomProvider.tsx +++ b/apps/scandic-web/providers/SelectRate/RoomProvider.tsx @@ -42,6 +42,15 @@ export default function RoomProvider({ const dontShowRegularRates = hasRedemptionRates || hasCorporateChequeOrVoucherRates + // Since input would be the same on single room as already + // done in useRoomsAvailability hook, data is already present + // and thus runs the appendRegularRates updater resulting in + // duplicate data + const enabled = !!( + booking.bookingCode && + selectedFilter === BookingCodeFilterEnum.All && + !dontShowRegularRates + ) // Extra query needed to fetch regular rates upon user // selecting to view all rates. // TODO: Setup route to handle singular availability call @@ -58,22 +67,18 @@ export default function RoomProvider({ roomStayStartDate: booking.fromDate, }, { - enabled: !!( - booking.bookingCode && - selectedFilter === BookingCodeFilterEnum.All && - !dontShowRegularRates - ), + enabled, } ) useEffect(() => { - if (isFetched && !isFetching && data?.length) { + if (isFetched && !isFetching && data?.length && enabled) { const regularRates = data[0] if ("roomConfigurations" in regularRates) { appendRegularRates(regularRates.roomConfigurations) } } - }, [appendRegularRates, data, isFetched, isFetching]) + }, [appendRegularRates, data, enabled, isFetched, isFetching]) return ( val), - // 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"), + rate: z.nativeEnum(RateEnum).default(RateEnum.save), rateDefinition: rateDefinitionSchema.optional().transform((val) => val ? val @@ -42,7 +42,6 @@ const baseProductSchema = z.object({ function mapBaseProduct(baseProduct: typeof baseProductSchema._type) { return { bookingCode: baseProduct.bookingCode, - breakfastIncluded: baseProduct.breakfastIncluded, rate: baseProduct.rate, rateDefinition: baseProduct.rateDefinition, rateDefinitionMember: baseProduct.rateDefinitionMember, @@ -97,14 +96,12 @@ export const redemptionsProduct = z data.map( ({ bookingCode, - breakfastIncluded, rate, rateDefinition, rateDefinitionMember, ...redemption }) => ({ bookingCode, - breakfastIncluded, rate, rateDefinition, rateDefinitionMember, diff --git a/apps/scandic-web/stores/enter-details/helpers.ts b/apps/scandic-web/stores/enter-details/helpers.ts index 5abd92ce1..a1ca92599 100644 --- a/apps/scandic-web/stores/enter-details/helpers.ts +++ b/apps/scandic-web/stores/enter-details/helpers.ts @@ -430,7 +430,7 @@ export function calcTotalPrice( ? (room.breakfast.localPrice?.price ?? 0) : 0 - const roomFeaturesTotal = room.roomFeatures?.reduce( + const roomFeaturesTotal = (room.roomFeatures || []).reduce( (total, pkg) => { if (pkg.requestedPrice.totalPrice) { total.requestedPrice = add( @@ -445,45 +445,72 @@ export function calcTotalPrice( { local: 0, requestedPrice: 0 } ) - const result: Price = { - requested: roomPrice.perStay.requested - ? { - currency: roomPrice.perStay.requested.currency, - price: add( - acc.requested?.price ?? 0, - roomPrice.perStay.requested.price, - breakfastRequestedPrice * room.adults * nights - ), - } - : undefined, - local: { - currency: roomPrice.perStay.local.currency, - price: add( - acc.local.price, - roomPrice.perStay.local.price, - breakfastLocalPrice * room.adults * nights, - roomFeaturesTotal?.local ?? 0 - ), - regularPrice: add( - acc.local.regularPrice, - roomPrice.perStay.local.regularPrice, - breakfastLocalPrice * room.adults * nights, - roomFeaturesTotal?.requestedPrice ?? 0 - ), - additionalPrice: add( - acc.local.additionalPrice, - roomPrice.perStay.local.additionalPrice, - breakfastLocalPrice * room.adults * nights, - roomFeaturesTotal?.local ?? 0 - ), - additionalPriceCurrency: roomPrice.perStay.local - .additionalPriceCurrency - ? roomPrice.perStay.local.additionalPriceCurrency - : undefined, - }, + if (roomPrice.perStay.requested) { + if (!acc.requested) { + acc.requested = { + currency: roomPrice.perStay.requested.currency, + price: 0, + } + } + + acc.requested.price = add( + acc.requested.price, + roomPrice.perStay.requested.price, + breakfastRequestedPrice * room.adults * nights + ) + + // TODO: Come back and verify on CC, PTS, Voucher + if (roomPrice.perStay.requested.additionalPrice) { + acc.requested.additionalPrice = add( + acc.requested.additionalPrice, + roomPrice.perStay.requested.additionalPrice + ) + } + + if ( + roomPrice.perStay.requested.additionalPriceCurrency && + !acc.requested.additionalPriceCurrency + ) { + acc.requested.additionalPriceCurrency = + roomPrice.perStay.requested.additionalPriceCurrency + } } - return result + const breakfastLocalTotalPrice = + breakfastLocalPrice * room.adults * nights + + acc.local.price = add( + acc.local.price, + roomPrice.perStay.local.price, + breakfastLocalTotalPrice, + roomFeaturesTotal.local + ) + + if (roomPrice.perStay.local.regularPrice) { + acc.local.regularPrice = add( + acc.local.regularPrice, + roomPrice.perStay.local.regularPrice, + breakfastLocalTotalPrice, + roomFeaturesTotal.local + ) + } + + if (roomPrice.perStay.local.additionalPrice) { + acc.local.additionalPrice = add( + acc.local.additionalPrice, + roomPrice.perStay.local.additionalPrice + ) + } + + if ( + roomPrice.perStay.local.additionalPriceCurrency && + !acc.local.additionalPriceCurrency + ) { + acc.local.additionalPriceCurrency = + roomPrice.perStay.local.additionalPriceCurrency + } + + return acc }, { requested: undefined, diff --git a/apps/scandic-web/stores/enter-details/index.ts b/apps/scandic-web/stores/enter-details/index.ts index 4f7e4ee27..fab511c26 100644 --- a/apps/scandic-web/stores/enter-details/index.ts +++ b/apps/scandic-web/stores/enter-details/index.ts @@ -168,100 +168,19 @@ export function createDetailsStore( currentRoom.steps[StepEnum.breakfast].isValid = true } - const currentTotalPriceRequested = state.totalPrice.requested - let stateTotalRequestedPrice = 0 - if (currentTotalPriceRequested) { - stateTotalRequestedPrice = - currentTotalPriceRequested.price ?? 0 - } - - const stateTotalLocalPrice = state.totalPrice.local.price - const stateTotalLocalRegularPrice = - state.totalPrice.local.regularPrice - - const addToTotalPrice = - (currentRoom.room.breakfast === undefined || - currentRoom.room.breakfast === false) && - !!breakfast - - const subtractFromTotalPrice = - currentRoom.room.breakfast && breakfast === false + currentRoom.room.breakfast = breakfast const nights = dt(state.booking.toDate).diff( state.booking.fromDate, "days" ) - if (addToTotalPrice) { - const breakfastTotalRequestedPrice = - breakfast.requestedPrice.price * - currentRoom.room.adults * - nights - const breakfastTotalPrice = - breakfast.localPrice.price * - currentRoom.room.adults * - nights - state.totalPrice = { - requested: state.totalPrice.requested && { - currency: state.totalPrice.requested.currency, - price: - stateTotalRequestedPrice + breakfastTotalRequestedPrice, - }, - local: { - currency: breakfast.localPrice.currency, - price: stateTotalLocalPrice ?? 0 + breakfastTotalPrice, - regularPrice: stateTotalLocalRegularPrice - ? stateTotalLocalRegularPrice + breakfastTotalPrice - : undefined, - }, - } - } - - if (subtractFromTotalPrice) { - let currency = state.totalPrice.local.currency - let currentBreakfastTotalPrice = 0 - let currentBreakfastTotalRequestedPrice = 0 - if (currentRoom.room.breakfast) { - currentBreakfastTotalPrice = - currentRoom.room.breakfast.localPrice.price * - currentRoom.room.adults * - nights - currentBreakfastTotalRequestedPrice = - currentRoom.room.breakfast.requestedPrice.totalPrice * - currentRoom.room.adults * - nights - currency = currentRoom.room.breakfast.localPrice.currency - } - - let requestedPrice = - stateTotalRequestedPrice - - currentBreakfastTotalRequestedPrice - if (requestedPrice < 0) { - requestedPrice = 0 - } - let localPrice = - stateTotalLocalPrice - currentBreakfastTotalPrice - if (localPrice < 0) { - localPrice = 0 - } - let regularPrice = stateTotalLocalRegularPrice - ? stateTotalLocalRegularPrice - currentBreakfastTotalPrice - : undefined - - state.totalPrice = { - requested: state.totalPrice.requested && { - currency: state.totalPrice.requested.currency, - price: requestedPrice, - }, - local: { - currency, - price: localPrice, - regularPrice, - }, - } - } - - currentRoom.room.breakfast = breakfast + state.totalPrice = calcTotalPrice( + state.rooms, + currentRoom.room.roomPrice.perStay.local.currency, + isMember, + nights + ) const isAllStepsCompleted = checkRoomProgress( state.rooms[idx].steps diff --git a/apps/scandic-web/stores/select-rate/helpers.ts b/apps/scandic-web/stores/select-rate/helpers.ts index ab8d69218..c416c5af2 100644 --- a/apps/scandic-web/stores/select-rate/helpers.ts +++ b/apps/scandic-web/stores/select-rate/helpers.ts @@ -5,7 +5,11 @@ import type { RoomConfiguration, } from "@/types/trpc/routers/hotel/roomAvailability" -export function findProduct(rateCode: string, product: Product) { +export function findProduct( + rateCode: string, + product: Product, + counterRateCode = "" +) { if ("corporateCheque" in product) { return product.corporateCheque.rateCode === rateCode } @@ -18,21 +22,35 @@ export function findProduct(rateCode: string, product: Product) { return product.voucher.rateCode === rateCode } - if ("public" in product && product.public) { - return product.public.rateCode === rateCode - } - - if ("member" in product && product.member) { - return product.member.rateCode === rateCode + const memberExists = "member" in product + const publicExists = "public" in product + const isRegularRate = memberExists && publicExists + if (isRegularRate) { + let isProduct = false + if (product.member) { + isProduct = + product.member.rateCode === rateCode || + product.member.rateCode === counterRateCode + } + if (product.public) { + isProduct = + product.public.rateCode === rateCode || + product.public.rateCode === counterRateCode + } + return isProduct } return null } -export function findProductInRoom(rateCode: string, room: RoomConfiguration) { +export function findProductInRoom( + rateCode: string, + room: RoomConfiguration, + counterRateCode = "" +) { if (room.campaign.length) { const campaignProduct = room.campaign.find((product) => - findProduct(rateCode, product) + findProduct(rateCode, product, counterRateCode) ) if (campaignProduct) { return campaignProduct @@ -40,7 +58,7 @@ export function findProductInRoom(rateCode: string, room: RoomConfiguration) { } if (room.code.length) { const codeProduct = room.code.find((product) => - findProduct(rateCode, product) + findProduct(rateCode, product, counterRateCode) ) if (codeProduct) { return codeProduct @@ -56,7 +74,7 @@ export function findProductInRoom(rateCode: string, room: RoomConfiguration) { } if (room.regular.length) { const regularProduct = room.regular.find((product) => - findProduct(rateCode, product) + findProduct(rateCode, product, counterRateCode) ) if (regularProduct) { return regularProduct @@ -66,6 +84,7 @@ export function findProductInRoom(rateCode: string, room: RoomConfiguration) { export function findSelectedRate( rateCode: string, + counterRateCode: string, roomTypeCode: string, rooms: RoomConfiguration[] | AvailabilityError ) { @@ -76,7 +95,7 @@ export function findSelectedRate( if (room.roomTypeCode !== roomTypeCode) { return false } - return findProductInRoom(rateCode, room) + return findProductInRoom(rateCode, room, counterRateCode) }) } diff --git a/apps/scandic-web/stores/select-rate/index.ts b/apps/scandic-web/stores/select-rate/index.ts index 17f275909..4b0587d73 100644 --- a/apps/scandic-web/stores/select-rate/index.ts +++ b/apps/scandic-web/stores/select-rate/index.ts @@ -71,6 +71,7 @@ export function createRatesStore({ const roomConfiguration = roomConfigurations?.[idx] const selectedRoom = findSelectedRate( room.rateCode, + room.counterRateCode, room.roomTypeCode, roomConfiguration ) @@ -79,7 +80,11 @@ export function createRatesStore({ continue } - const product = findProductInRoom(room.rateCode, selectedRoom) + const product = findProductInRoom( + room.rateCode, + selectedRoom, + room.counterRateCode + ) if (product) { rateSummary[idx] = { features: selectedRoom.features, @@ -121,13 +126,18 @@ export function createRatesStore({ const selectedRate = findSelectedRate( room.rateCode, + room.counterRateCode, room.roomTypeCode, roomConfiguration ) ?? null let product = null if (selectedRate) { - product = findProductInRoom(room.rateCode, selectedRate) + product = findProductInRoom( + room.rateCode, + selectedRate, + room.counterRateCode + ) } // Since features are fetched async based on query string, we need to read from query string to apply correct filtering diff --git a/apps/scandic-web/types/components/hotelReservation/selectRate/selectRate.ts b/apps/scandic-web/types/components/hotelReservation/selectRate/selectRate.ts index 3dba3bd1f..7b88e9fa8 100644 --- a/apps/scandic-web/types/components/hotelReservation/selectRate/selectRate.ts +++ b/apps/scandic-web/types/components/hotelReservation/selectRate/selectRate.ts @@ -1,3 +1,4 @@ +import type { RateEnum } from "@/types/enums/rate" import type { Product, RoomConfiguration, @@ -35,7 +36,7 @@ export type Rate = { priceName?: string priceTerm?: string product: Product - rate: "change" | "flex" | "save" + rate: RateEnum roomRates?: { rate: Rate roomIndex: number diff --git a/apps/scandic-web/types/components/tracking.ts b/apps/scandic-web/types/components/tracking.ts index 65f615508..10a97a766 100644 --- a/apps/scandic-web/types/components/tracking.ts +++ b/apps/scandic-web/types/components/tracking.ts @@ -1,5 +1,6 @@ import type { Lang } from "@/constants/languages" import type { MembershipLevel } from "@/constants/membershipLevels" +import type { RateEnum } from "../enums/rate" export enum TrackingChannelEnum { "scandic-friends" = "scandic-friends", @@ -54,7 +55,7 @@ export type TrackingSDKUserData = export type TrackingSDKHotelInfo = { ageOfChildren?: string // "10", "2,5,10" ancillaries?: Ancillary[] - analyticsRateCode?: "flex" | "change" | "save" | string + analyticsRateCode?: RateEnum | string arrivalDate?: string availableResults?: number // Number of hotels to choose from after a city search bedType?: string diff --git a/apps/scandic-web/types/enums/rate.ts b/apps/scandic-web/types/enums/rate.ts new file mode 100644 index 000000000..e14de2ee4 --- /dev/null +++ b/apps/scandic-web/types/enums/rate.ts @@ -0,0 +1,5 @@ +export enum RateEnum { + change = "change", + flex = "flex", + save = "save", +} diff --git a/apps/scandic-web/types/providers/details/room.ts b/apps/scandic-web/types/providers/details/room.ts index 713d80ce0..4eb28dcd4 100644 --- a/apps/scandic-web/types/providers/details/room.ts +++ b/apps/scandic-web/types/providers/details/room.ts @@ -1,5 +1,6 @@ import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType" import type { RoomRate } from "@/types/components/hotelReservation/enterDetails/details" +import type { RateEnum } from "@/types/enums/rate" import type { Packages } from "@/types/requests/packages" export interface Room { @@ -10,7 +11,7 @@ export interface Room { mustBeGuaranteed: boolean memberMustBeGuaranteed?: boolean packages: Packages | null - rate: "change" | "flex" | "save" + rate: RateEnum rateDefinitionTitle: string rateDetails: string[] rateTitle?: string diff --git a/packages/design-system/lib/components/RateCard/Code/index.tsx b/packages/design-system/lib/components/RateCard/Code/index.tsx index 8b4212806..48d2bca72 100644 --- a/packages/design-system/lib/components/RateCard/Code/index.tsx +++ b/packages/design-system/lib/components/RateCard/Code/index.tsx @@ -120,7 +120,9 @@ export default function CodeRateCard({

- {rate.price}{' '} + + {comparisonRate.price} + {' '} {comparisonRate.unit}