Files
web/apps/scandic-web/components/HotelReservation/BookingConfirmation/Receipt/Room/index.tsx
Bianca Widstam c39baabb03 Merged in fix/SW-2573-children-count-booking-confirmation (pull request #1939)
fix(SW-2573): add children count to summary

* fix(SW-2573): add children count to summary


Approved-by: Michael Zetterberg
2025-05-05 08:13:52 +00:00

263 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { CancellationRuleEnum, ChildBedTypeEnum } from "@/constants/booking"
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
import Modal from "@/components/Modal"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import { formatPrice } from "@/utils/numberFormatting"
import RoomSkeletonLoader from "./RoomSkeletonLoader"
import styles from "./room.module.css"
import type { BookingConfirmationReceiptRoomProps } from "@/types/components/hotelReservation/bookingConfirmation/receipt"
export default function ReceiptRoom({
roomIndex,
}: BookingConfirmationReceiptRoomProps) {
const intl = useIntl()
const { room, currencyCode, isVatCurrency } = useBookingConfirmationStore(
(state) => ({
room: state.rooms[roomIndex],
currencyCode: state.currencyCode,
isVatCurrency: state.isVatCurrency,
})
)
if (!room) {
return <RoomSkeletonLoader />
}
const breakfastIncluded =
room.breakfastIncluded || room.rateDefinition.breakfastIncluded
const childBedCrib = room.childBedPreferences.find(
(c) => c.bedType === ChildBedTypeEnum.Crib
)
const childBedExtraBed = room.childBedPreferences.find(
(c) => c.bedType === ChildBedTypeEnum.ExtraBed
)
const adultsMsg = intl.formatMessage(
{
defaultMessage: "{totalAdults, plural, one {# adult} other {# adults}}",
},
{ totalAdults: room.adults }
)
const guestsParts = [adultsMsg]
if (room.childrenAges?.length) {
const childrenMsg = intl.formatMessage(
{
defaultMessage:
"{totalChildren, plural, one {# child} other {# children}}",
},
{ totalChildren: room.childrenAges.length }
)
guestsParts.push(childrenMsg)
}
return (
<article className={styles.room}>
<header className={styles.roomHeader}>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>{room.name}</p>
</Typography>
{room.rateDefinition.isMemberRate ? (
<div className={styles.memberPrice}>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.red}>{room.formattedRoomCost}</p>
</Typography>
</div>
) : (
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{room.formattedRoomCost}
</p>
</Typography>
)}
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextMediumContrast}>
{guestsParts.join(", ")}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextMediumContrast}>
{room.rateDefinition.cancellationText}
</p>
</Typography>
<Modal
trigger={
<Button intent="text" className={styles.termsLink}>
<Link
color="peach80"
href=""
size="small"
textDecoration="underline"
variant="icon"
>
{intl.formatMessage({
defaultMessage: "Reservation policy",
})}
<MaterialIcon icon="info" color="CurrentColor" />
</Link>
</Button>
}
title={
(isVatCurrency
? room.rateDefinition.cancellationText
: room.rateDefinition.title) || ""
}
subtitle={
room.rateDefinition.cancellationRule ===
CancellationRuleEnum.CancellableBefore6PM
? intl.formatMessage({
defaultMessage: "Pay later",
})
: intl.formatMessage({
defaultMessage: "Pay now",
})
}
>
<div className={styles.terms}>
{room.rateDefinition.generalTerms?.map((info) => (
<Typography
key={info}
className={styles.termsText}
variant="Body/Paragraph/mdRegular"
>
<span>
<MaterialIcon
icon="check"
color="Icon/Feedback/Success"
size={20}
className={styles.termsIcon}
/>
{info}
</span>
</Typography>
))}
</div>
</Modal>
</header>
{room.roomFeatures
? room.roomFeatures.map((feature) => (
<div className={styles.entry} key={feature.code}>
<div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{feature.description}
</p>
</Typography>
</div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{formatPrice(intl, feature.totalPrice, feature.currency)}
</p>
</Typography>
</div>
))
: null}
<div className={styles.entry}>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>{room.bedDescription}</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{formatPrice(intl, 0, currencyCode)}
</p>
</Typography>
</div>
{childBedCrib ? (
<div className={styles.entry}>
<div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{intl.formatMessage(
{
defaultMessage: "Crib (child) × {count}",
},
{ count: childBedCrib.quantity }
)}
</p>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p className={styles.uiTextHighContrast}>
{intl.formatMessage({
defaultMessage: "Based on availability",
})}
</p>
</Typography>
</div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{formatPrice(intl, 0, currencyCode)}
</p>
</Typography>
</div>
) : null}
{childBedExtraBed ? (
<div className={styles.entry}>
<div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{intl.formatMessage(
{
defaultMessage: "Extra bed (child) × {count}",
},
{
count: childBedExtraBed.quantity,
}
)}
</p>
</Typography>
</div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{formatPrice(intl, 0, currencyCode)}
</p>
</Typography>
</div>
) : null}
{room.breakfast || breakfastIncluded ? (
<div className={styles.entry}>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
defaultMessage: "Breakfast buffet",
})}
</p>
</Typography>
{breakfastIncluded ? (
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.red}>
{intl.formatMessage({
defaultMessage: "Included",
})}
</p>
</Typography>
) : null}
{room.breakfast && !breakfastIncluded ? (
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{formatPrice(
intl,
room.breakfast.totalPrice,
room.breakfast.currency
)}
</p>
</Typography>
) : null}
</div>
) : null}
</article>
)
}