import { useIntl } from "react-intl" import { RateEnum } from "@scandic-hotels/common/constants/rate" import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting" import Body from "@scandic-hotels/design-system/Body" import Caption from "@scandic-hotels/design-system/Caption" import Footnote from "@scandic-hotels/design-system/Footnote" import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton" import Subtitle from "@scandic-hotels/design-system/Subtitle" import { useIsLoggedIn } from "../../../../hooks/useIsLoggedIn" import SignupPromoDesktop from "../../../SignupPromo/Desktop" import { isBookingCodeRate } from "./utils" import styles from "./rateSummary.module.css" import type { useSelectRateContext } from "../../../../contexts/SelectRate/SelectRateContext" import type { SelectedRate } from "../../../../contexts/SelectRate/types" export function DesktopSummary({ input, selectedRates, isSubmitting, bookingCode, }: { selectedRates: ReturnType["selectedRates"] isSubmitting: boolean input: ReturnType["input"] bookingCode: string }) { const intl = useIntl() const isUserLoggedIn = useIsLoggedIn() if (!selectedRates.totalPrice) { return null } const hasMemberRates = selectedRates.rates.some( (rate) => rate && "member" in rate && rate.member ) const showMemberDiscountBanner = hasMemberRates && !isUserLoggedIn const totalNights = intl.formatMessage( { defaultMessage: "{totalNights, plural, one {# night} other {# nights}}", }, { totalNights: input.nights } ) const totalAdults = intl.formatMessage( { defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}", }, { totalAdults: input.data?.booking.rooms.reduce((acc, room) => acc + room.adults, 0) ?? 0, } ) const childrenInOneOrMoreRooms = input.data?.booking.rooms.some( (room) => room.childrenInRoom?.length ) const childrenInroom = intl.formatMessage( { defaultMessage: "{totalChildren, plural, one {# child} other {# children}}", }, { totalChildren: input.data?.booking.rooms.reduce( (acc, room) => acc + (room.childrenInRoom?.length ?? 0), 0 ), } ) const totalChildren = childrenInOneOrMoreRooms ? `, ${childrenInroom}` : "" const totalRooms = intl.formatMessage( { defaultMessage: "{totalRooms, plural, one {# room} other {# rooms}}", }, { totalRooms: input.roomCount } ) const summaryPriceText = `${totalNights}, ${totalAdults}${totalChildren}, ${totalRooms}` const isAllRoomsSelected = selectedRates.state === "ALL_SELECTED" const showDiscounted = isUserLoggedIn || selectedRates.rates.some(isBookingCodeRate) const mainRoomRate = selectedRates.rates.at(0) let mainRoomCurrency = getRoomCurrency(mainRoomRate) const totalRegularPrice = selectedRates.totalPrice.local?.regularPrice ? selectedRates.totalPrice.local.regularPrice : 0 const isTotalRegularPriceGreaterThanPrice = totalRegularPrice > selectedRates.totalPrice.local.price const showStrikedThroughPrice = (!!bookingCode || isUserLoggedIn) && isTotalRegularPriceGreaterThanPrice return ( <>
{selectedRates.rates.map((room, index) => { return ( 1} /> ) })}
{showMemberDiscountBanner && (
{ if (!rate) { return total } const memberExists = "member" in rate && rate.member const publicExists = "public" in rate && rate.public if (!memberExists && !publicExists) { return total } const price = rate.member?.localPrice.pricePerStay || rate.public?.localPrice.pricePerStay if (!price) { return total } const selectedPackagesPrice = rate.roomInfo.selectedPackages.reduce( (acc, pkg) => acc + pkg.localPrice.totalPrice, 0 ) return total + price + selectedPackagesPrice }, 0), currency: mainRoomCurrency ?? "", }} />
)}
{intl.formatMessage( { defaultMessage: "Total price (incl VAT)", }, { b: (str) => {str} } )} {summaryPriceText}
{formatPrice( intl, selectedRates.totalPrice.local.price, selectedRates.totalPrice.local.currency, selectedRates.totalPrice.local.additionalPrice, selectedRates.totalPrice.local.additionalPriceCurrency )} {showStrikedThroughPrice && selectedRates.totalPrice.local.regularPrice && ( {formatPrice( intl, selectedRates.totalPrice.local.regularPrice, selectedRates.totalPrice.local.currency )} )} {selectedRates.totalPrice.requested ? ( {intl.formatMessage( { defaultMessage: "Approx. {value}", }, { value: formatPrice( intl, selectedRates.totalPrice.requested.price, selectedRates.totalPrice.requested.currency, selectedRates.totalPrice.requested.additionalPrice, selectedRates.totalPrice.requested.additionalPriceCurrency ), } )} ) : null}
{intl.formatMessage({ defaultMessage: "Total price", })} {formatPrice( intl, selectedRates.totalPrice.local.price, selectedRates.totalPrice.local.currency, selectedRates.totalPrice.local.additionalPrice, selectedRates.totalPrice.local.additionalPriceCurrency )} {summaryPriceText}
) } function RateSummary({ roomIndex, room, isMultiRoom, }: { room: SelectedRate | undefined roomIndex: number isMultiRoom: boolean }) { const intl = useIntl() const getRateDetails = useRateDetails() if (!room || !room.isSelected) { return (
{intl.formatMessage( { defaultMessage: "Room {roomIndex}", }, { roomIndex: roomIndex + 1 } )} {intl.formatMessage({ defaultMessage: "Select room", })}
) } return (
{isMultiRoom ? ( <> {intl.formatMessage( { defaultMessage: "Room {roomIndex}", }, { roomIndex: roomIndex + 1 } )} {room.roomInfo.roomType} {getRateDetails(room.rate)} ) : ( <> {room.roomInfo.roomType} {getRateDetails(room.rate)} )}
) } function useRateDetails() { const intl = useIntl() const freeCancelation = intl.formatMessage({ defaultMessage: "Free cancellation", }) const nonRefundable = intl.formatMessage({ defaultMessage: "Non-refundable", }) const freeBooking = intl.formatMessage({ defaultMessage: "Free rebooking", }) const payLater = intl.formatMessage({ defaultMessage: "Pay later", }) const payNow = intl.formatMessage({ defaultMessage: "Pay now", }) return (rate: RateEnum) => { switch (rate) { case RateEnum.change: return `${freeBooking}, ${payNow}` case RateEnum.flex: return `${freeCancelation}, ${payLater}` case RateEnum.save: default: return `${nonRefundable}, ${payNow}` } } } function getRoomCurrency(rate: SelectedRate | undefined) { if (!rate) { return null } if ("member" in rate && rate.member?.localPrice) { return rate.member.localPrice.currency } if ("public" in rate && rate.public?.localPrice) { return rate.public.localPrice.currency } }