265 lines
9.3 KiB
TypeScript
265 lines
9.3 KiB
TypeScript
"use client"
|
|
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking"
|
|
import {
|
|
changeOrCancelDateFormat,
|
|
longDateFormat,
|
|
} from "@scandic-hotels/common/constants/dateFormats"
|
|
import { dt } from "@scandic-hotels/common/dt"
|
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
import Image from "@scandic-hotels/design-system/Image"
|
|
import ImageFallback from "@scandic-hotels/design-system/ImageFallback"
|
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
import { getHotelRoom } from "@scandic-hotels/trpc/routers/booking/helpers"
|
|
|
|
import { RoomDetailsSidePeek } from "../../../../components/RoomDetailsSidePeek"
|
|
import useLang from "../../../../hooks/useLang"
|
|
import { useBookingConfirmationStore } from "../../../../stores/booking-confirmation"
|
|
|
|
import styles from "./room.module.css"
|
|
|
|
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
|
|
|
|
interface RoomProps {
|
|
booking: BookingConfirmation["booking"]
|
|
checkInTime: string
|
|
checkOutTime: string
|
|
img?: NonNullable<BookingConfirmation["room"]>["images"][number]
|
|
roomName: NonNullable<BookingConfirmation["room"]>["name"]
|
|
}
|
|
|
|
export function Room({
|
|
booking,
|
|
checkInTime,
|
|
checkOutTime,
|
|
img,
|
|
roomName,
|
|
}: RoomProps) {
|
|
const intl = useIntl()
|
|
const lang = useLang()
|
|
const { roomCategories } = useBookingConfirmationStore((state) => ({
|
|
roomCategories: state.roomCategories,
|
|
}))
|
|
const room = getHotelRoom(roomCategories, booking.roomTypeCode)
|
|
|
|
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`
|
|
const fromDate = dt(booking.checkInDate).locale(lang)
|
|
const toDate = dt(booking.checkOutDate).locale(lang)
|
|
|
|
const isFlexBooking =
|
|
booking.rateDefinition.cancellationRule ===
|
|
CancellationRuleEnum.CancellableBefore6PM
|
|
const isChangeBooking =
|
|
booking.rateDefinition.cancellationRule === CancellationRuleEnum.Changeable
|
|
return (
|
|
<article className={styles.room}>
|
|
<header className={styles.header}>
|
|
<Typography variant="Title/Subtitle/md">
|
|
<h2>
|
|
{intl.formatMessage(
|
|
{
|
|
id: "bookingConfirmation.rooms.bookingNumber",
|
|
defaultMessage: "Booking number {value}",
|
|
},
|
|
{ value: booking.confirmationNumber }
|
|
)}
|
|
</h2>
|
|
</Typography>
|
|
{booking.rateDefinition.isMemberRate ? (
|
|
<div className={styles.benefits}>
|
|
<>
|
|
<MaterialIcon
|
|
color="Icon/Feedback/Success"
|
|
icon="check_circle"
|
|
size={20}
|
|
/>
|
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
|
<p>
|
|
{intl.formatMessage({
|
|
id: "bookingConfirmation.rooms.benefitsApplied",
|
|
defaultMessage: "Membership benefits applied",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
</>
|
|
</div>
|
|
) : null}
|
|
{booking.guaranteeInfo && (
|
|
<div className={styles.benefits}>
|
|
<MaterialIcon
|
|
icon="check_circle"
|
|
color="Icon/Feedback/Success"
|
|
size={20}
|
|
/>
|
|
<Typography
|
|
variant="Body/Supporting text (caption)/smBold"
|
|
className={styles.guaranteeText}
|
|
>
|
|
<p>
|
|
{intl.formatMessage({
|
|
id: "bookingConfirmation.rooms.guaranteeTitle",
|
|
defaultMessage: "Booking guaranteed.",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
{/* eslint-disable formatjs/no-literal-string-in-jsx */}{" "}
|
|
{/* eslint-enable formatjs/no-literal-string-in-jsx */}
|
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
|
<p>
|
|
{intl.formatMessage({
|
|
id: "bookingConfirmation.rooms.guaranteeDetails",
|
|
defaultMessage:
|
|
"Your room will remain available for check-in even after 18:00.",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
</div>
|
|
)}
|
|
</header>
|
|
<div className={styles.booking}>
|
|
{img?.src ? (
|
|
<Image
|
|
alt={img.altText || img.altText_En || ""}
|
|
className={styles.img}
|
|
focalPoint={{ x: 50, y: 50 }}
|
|
height={204}
|
|
src={img.src}
|
|
style={{ borderRadius: "var(--Corner-Radius-md)" }}
|
|
title={img.title || img.title_En || ""}
|
|
width={204}
|
|
/>
|
|
) : (
|
|
<ImageFallback height="204px" />
|
|
)}
|
|
<div className={styles.roomDetails}>
|
|
<div className={styles.roomName}>
|
|
<Typography variant="Title/Subtitle/md">
|
|
<h2>{roomName}</h2>
|
|
</Typography>
|
|
{room && (
|
|
<RoomDetailsSidePeek
|
|
hotelId={booking.hotelId}
|
|
room={room}
|
|
roomTypeCode={booking.roomTypeCode}
|
|
buttonVariant="primary"
|
|
triggerLabel={intl.formatMessage({
|
|
id: "hotel.seeRoomDetails",
|
|
defaultMessage: "See room details",
|
|
})}
|
|
wrapping={false}
|
|
/>
|
|
)}
|
|
</div>
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<ul className={styles.details}>
|
|
<li className={styles.listItem}>
|
|
<p className={styles.label}>
|
|
{intl.formatMessage({
|
|
id: "common.checkIn",
|
|
defaultMessage: "Check-in",
|
|
})}
|
|
</p>
|
|
<p>
|
|
{intl.formatMessage(
|
|
{
|
|
id: "bookingConfirmation.rooms.checkInDetails",
|
|
defaultMessage: "{checkInDate} from {checkInTime}",
|
|
},
|
|
{
|
|
checkInDate: fromDate.format(longDateFormat[lang]),
|
|
checkInTime: checkInTime,
|
|
}
|
|
)}
|
|
</p>
|
|
</li>
|
|
<li className={styles.listItem}>
|
|
<p className={styles.label}>
|
|
{intl.formatMessage({
|
|
id: "common.checkOut",
|
|
defaultMessage: "Check-out",
|
|
})}
|
|
</p>
|
|
<p>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
{`${toDate.format(longDateFormat[lang])}, ${checkOutTime}`}
|
|
</p>
|
|
</li>
|
|
<li className={styles.listItem}>
|
|
<p className={styles.label}>
|
|
{intl.formatMessage({
|
|
id: "bookingConfirmation.rooms.cancellationPolicy",
|
|
defaultMessage: "Cancellation policy",
|
|
})}
|
|
</p>
|
|
<p>{booking.rateDefinition.cancellationText}</p>
|
|
</li>
|
|
{isFlexBooking || isChangeBooking ? (
|
|
<li className={styles.listItem}>
|
|
<p className={styles.label}>
|
|
{intl.formatMessage({
|
|
id: "booking.changeOrCancel",
|
|
defaultMessage: "Change or cancel",
|
|
})}
|
|
</p>
|
|
<p>
|
|
{intl.formatMessage(
|
|
{
|
|
id: "common.untilWithTimeAndDate",
|
|
defaultMessage: "Until {time}, {date}",
|
|
},
|
|
{
|
|
time: "18:00",
|
|
date: fromDate.format(changeOrCancelDateFormat[lang]),
|
|
}
|
|
)}
|
|
</p>
|
|
</li>
|
|
) : null}
|
|
</ul>
|
|
</Typography>
|
|
<div className={styles.guest}>
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p className={styles.label}>
|
|
{intl.formatMessage({
|
|
id: "bookingConfirmation.rooms.guestLabel",
|
|
defaultMessage: "Guest",
|
|
})}
|
|
</p>
|
|
</Typography>
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p data-hj-suppress>{guestName}</p>
|
|
</Typography>
|
|
{booking.guest.membershipNumber ? (
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p data-hj-suppress>
|
|
{intl.formatMessage(
|
|
{
|
|
id: "bookingConfirmation.rooms.friendNumber",
|
|
defaultMessage: "Friend no. {value}",
|
|
},
|
|
{
|
|
value: booking.guest.membershipNumber,
|
|
}
|
|
)}
|
|
</p>
|
|
</Typography>
|
|
) : null}
|
|
{booking.guest.phoneNumber ? (
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p data-hj-suppress>{booking.guest.phoneNumber}</p>
|
|
</Typography>
|
|
) : null}
|
|
{booking.guest.email ? (
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p data-hj-suppress>{booking.guest.email}</p>
|
|
</Typography>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
)
|
|
}
|