"use client" import { Fragment } from "react" import { useIntl } from "react-intl" import { useMediaQuery } from "usehooks-ts" import { Button } from "@scandic-hotels/design-system/Button" import { Divider } from "@scandic-hotels/design-system/Divider" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { dt } from "@/lib/dt" import BookingCodeChip from "@/components/BookingCodeChip" import PriceDetailsModal from "@/components/HotelReservation/PriceDetailsModal" import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop" import Modal from "@/components/Modal" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import useLang from "@/hooks/useLang" import { formatPrice } from "@/utils/numberFormatting" import Breakfast from "./Breakfast" import { mapToPrice } from "./mapToPrice" 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" export default function SummaryUI({ booking, rooms, totalPrice, isMember, vat, toggleSummaryOpen, defaultCurrency, }: EnterDetailsSummaryProps) { const intl = useIntl() const lang = useLang() const isDesktop = useMediaQuery("(min-width: 1367px)") const nights = dt(booking.toDate).diff(booking.fromDate, "days") const nightsMsg = intl.formatMessage( { defaultMessage: "{totalNights, plural, one {# night} other {# nights}}", }, { totalNights: nights } ) function handleToggleSummary() { if (toggleSummaryOpen) { toggleSummaryOpen() } } function getMemberPrice(roomRate: RoomRate) { if ("member" in roomRate && roomRate.member) { return { amount: roomRate.member.localPrice.pricePerStay, currency: roomRate.member.localPrice.currency, pricePerNight: roomRate.member.localPrice.pricePerNight, } } return null } const roomOneGuest = rooms[0].room.guest const showSignupPromo = rooms.length === 1 && !isMember && !roomOneGuest.membershipNo && !roomOneGuest.join const roomOneMemberPrice = getMemberPrice(rooms[0].room.roomRate) const roomOneRoomRate = rooms[0].room.roomRate // In case of Redemption, voucher and Corporate cheque do not show approx price const isSpecialRate = "corporateCheque" in roomOneRoomRate || "redemption" in roomOneRoomRate || "voucher" in roomOneRoomRate const isSameCurrency = totalPrice.requested ? totalPrice.requested.currency === totalPrice.local.currency : false const priceDetailsRooms = mapToPrice(rooms, isMember) const isAllCampaignRate = rooms.every( (room) => room.room.roomRate.rateDefinition.isCampaignRate ) const isAllBreakfastIncluded = rooms.every( (room) => room.room.roomRate.rateDefinition.breakfastIncluded ) return (
{intl.formatMessage({ defaultMessage: "Booking summary", })} {dt(booking.fromDate).locale(lang).format("ddd, D MMM")} {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} {dt(booking.toDate).locale(lang).format("ddd, D MMM")} ({nightsMsg})
{rooms.map(({ room }, idx) => { const roomNumber = idx + 1 const adults = room.adults const childrenInRoom = room.childrenInRoom const childrenBeds = childrenInRoom?.reduce( (acc, value) => { const bedType = Number(value.bed) if (bedType === ChildBedMapEnum.IN_ADULTS_BED) { return acc } const count = acc.get(bedType) ?? 0 acc.set(bedType, count + 1) return acc }, new Map([ [ChildBedMapEnum.IN_CRIB, 0], [ChildBedMapEnum.IN_EXTRA_BED, 0], ]) ) const childBedCrib = childrenBeds?.get(ChildBedMapEnum.IN_CRIB) const childBedExtraBed = childrenBeds?.get(ChildBedMapEnum.IN_EXTRA_BED) const memberPrice = getMemberPrice(room.roomRate) const isFirstRoomMember = roomNumber === 1 && isMember const isOrWillBecomeMember = !!( room.guest.join || room.guest.membershipNo || isFirstRoomMember ) const showMemberPrice = !!(isOrWillBecomeMember && memberPrice) const adultsMsg = intl.formatMessage( { defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}", }, { totalAdults: adults } ) const guestsParts = [adultsMsg] if (childrenInRoom?.length) { const childrenMsg = intl.formatMessage( { defaultMessage: "{totalChildren, plural, one {# child} other {# children}}", }, { totalChildren: childrenInRoom.length } ) guestsParts.push(childrenMsg) } const guests = guestsParts.join(", ") let rateDetails = room.rateDetails if (room.memberRateDetails) { if (isMember || room.guest.join) { rateDetails = room.memberRateDetails } } const zeroPrice = formatPrice(intl, 0, defaultCurrency) return (
{rooms.length > 1 ? ( {intl.formatMessage( { defaultMessage: "Room {roomIndex}", }, { roomIndex: roomNumber, } )} ) : null}
{room.roomType} {showMemberPrice ? formatPrice( intl, memberPrice.amount, memberPrice.currency ) : formatPrice( intl, room.roomPrice.perStay.local.price, room.roomPrice.perStay.local.currency, room.roomPrice.perStay.local.additionalPrice, room.roomPrice.perStay.local.additionalPriceCurrency )}
{guests} {room.cancellationText} {rateDetails ? ( {intl.formatMessage({ defaultMessage: "Rate details", })} } title={ room.rateTitle ? room.rateTitle : room.cancellationText } subtitle={ room.rateTitle ? room.cancellationText : undefined } >
{rateDetails.map((info) => { return ( {info} ) })}
) : null}
{room.roomFeatures ? room.roomFeatures.map((feature) => (
{feature.description}
{formatPrice( intl, feature.localPrice.price, feature.localPrice.currency )}
)) : null} {room.bedType ? (
{room.bedType.description} {zeroPrice}
) : null} {childBedCrib ? (
{intl.formatMessage( { defaultMessage: "Crib (child) × {count}", }, { count: childBedCrib } )} {intl.formatMessage({ defaultMessage: "Based on availability", })}
{zeroPrice}
) : null} {childBedExtraBed ? (
{intl.formatMessage( { defaultMessage: "Extra bed (child) × {count}", }, { count: childBedExtraBed, } )}
{zeroPrice}
) : null}
) })}
{intl.formatMessage( { defaultMessage: "Total price (incl VAT)", }, { b: (str) => {str} } )}
{formatPrice( intl, totalPrice.local.price, totalPrice.local.currency, totalPrice.local.additionalPrice, totalPrice.local.additionalPriceCurrency )} {totalPrice.local.regularPrice ? ( {formatPrice( intl, totalPrice.local.regularPrice, totalPrice.local.currency )} ) : null} {totalPrice.requested && !isSpecialRate && !isSameCurrency && ( {intl.formatMessage( { defaultMessage: "Approx. {value}", }, { value: formatPrice( intl, totalPrice.requested.price, totalPrice.requested.currency ), } )} )}
{showSignupPromo && roomOneMemberPrice && !isMember ? ( ) : null}
) }