Files
web/apps/scandic-web/components/HotelReservation/MyStay/Rooms/MultiRoom/Room.tsx
Hrishikesh Vaipurkar e2c1b066be Merged in feat/SW-2407-mystay-tc-to-modal (pull request #2082)
Feat/SW-2407 mystay tc to modal

* feat: SW-2407 Moved terms in modal view for my stay

* feat: SW-2407 Updated modal to show terms for reward nights and corporate cheque stay

* feat: SW-2407 Optimised code

* feat: SW-2407 Optimised code


Approved-by: Niclas Edenvin
2025-05-27 07:00:02 +00:00

344 lines
10 KiB
TypeScript

"use client"
import { useIntl } from "react-intl"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { CancellationRuleEnum } from "@/constants/booking"
import { dt } from "@/lib/dt"
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
import Image from "@/components/Image"
import Modal from "@/components/Modal"
import Divider from "@/components/TempDesignSystem/Divider"
import IconChip from "@/components/TempDesignSystem/IconChip"
import useRateTitles from "@/hooks/booking/useRateTitles"
import useLang from "@/hooks/useLang"
import { formatPrice } from "@/utils/numberFormatting"
import PriceType from "../../PriceType"
import { hasModifiableRate } from "../../utils"
import RoomDetailsSidePeek from "./RoomDetailsSidePeek"
import styles from "./room.module.css"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import { RateEnum } from "@/types/enums/rate"
import type { Room } from "@/types/stores/my-stay"
import type { SafeUser } from "@/types/user"
interface RoomProps {
booking: Room
roomNr: number
user: SafeUser
}
export default function Room({ booking, roomNr, user }: RoomProps) {
const intl = useIntl()
const lang = useLang()
const {
adults,
breakfast,
cancellationNumber,
checkInDate,
cheques,
childrenAges,
confirmationNumber,
currencyCode,
packages,
rateDefinition,
room,
roomName,
totalPoints,
isCancelled,
priceType,
vouchers,
totalPrice,
} = booking
const fromDate = dt(checkInDate).locale(lang)
const adultsMsg = intl.formatMessage(
{
defaultMessage: "{adults, plural, one {# adult} other {# adults}}",
},
{
adults: adults,
}
)
const childrenMsg = intl.formatMessage(
{
defaultMessage: "{children, plural, one {# child} other {# children}}",
},
{
children: childrenAges.length,
}
)
const adultsOnlyMsg = adultsMsg
const adultsAndChildrenMsg = [adultsMsg, childrenMsg].join(", ")
const formattedTotalPrice = formatPrice(intl, totalPrice, currencyCode)
let breakfastPrice = intl.formatMessage({
defaultMessage: "No breakfast",
})
if (rateDefinition.breakfastIncluded) {
breakfastPrice = intl.formatMessage({
defaultMessage: "Included",
})
} else if (breakfast) {
breakfastPrice = formatPrice(
intl,
breakfast.localPrice.totalPrice,
breakfast.localPrice.currency
)
}
const rateTitles = useRateTitles()
let rateTerm: { paymentTerm: string; title: string }
switch (rateDefinition.cancellationRule) {
case CancellationRuleEnum.CancellableBefore6PM:
rateTerm = rateTitles[RateEnum.flex]
break
case CancellationRuleEnum.Changeable:
rateTerm = rateTitles[RateEnum.change]
break
default:
rateTerm = rateTitles[RateEnum.save]
}
return (
<article className={styles.multiRoom}>
<Typography variant="Title/smRegular">
<h3 className={styles.roomName}>{roomName}</h3>
</Typography>
<div className={styles.roomHeader}>
{isCancelled ? (
<IconChip
color={"red"}
icon={
<MaterialIcon
icon="cancel"
size={20}
color="Icon/Feedback/Error"
/>
}
>
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{intl.formatMessage({
defaultMessage: "Cancelled",
})}
</span>
</Typography>
</IconChip>
) : (
<div className={styles.chip}>
<Typography variant="Tag/sm">
<span>
{intl.formatMessage(
{
defaultMessage: "Room {roomIndex}",
},
{
roomIndex: roomNr,
}
)}
</span>
</Typography>
</div>
)}
<div className={styles.reference}>
<Typography variant="Body/Supporting text (caption)/smBold">
{isCancelled ? (
<span>
{intl.formatMessage({
defaultMessage: "Cancellation no",
})}
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{":"}
</span>
) : (
<span>
{intl.formatMessage({
defaultMessage: "Booking number",
})}
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{":"}
</span>
)}
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
{isCancelled ? (
<span className={styles.cancellationNumber}>
{cancellationNumber}
</span>
) : (
<span>{confirmationNumber}</span>
)}
</Typography>
</div>
<div className={styles.toggleSidePeek}>
<RoomDetailsSidePeek booking={booking} user={user} />
</div>
</div>
<div
className={`${styles.multiRoomCard} ${isCancelled ? styles.cancelled : ""}`}
>
{packages?.some((item) =>
Object.values(RoomPackageCodeEnum).includes(
item.code as RoomPackageCodeEnum
)
) && (
<div className={styles.packages}>
{packages
.filter((item) =>
Object.values(RoomPackageCodeEnum).includes(
item.code as RoomPackageCodeEnum
)
)
.map((item) => {
return (
<span className={styles.package} key={item.code}>
<IconForFeatureCode
featureCode={item.code}
size={16}
color="Icon/Interactive/Default"
/>
</span>
)
})}
</div>
)}
<div className={styles.imageContainer}>
<Image
src={room?.images[0]?.imageSizes.small ?? ""}
alt={roomName}
fill
/>
</div>
<div className={styles.details}>
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage({
defaultMessage: "Guests",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{childrenAges.length > 0 ? adultsAndChildrenMsg : adultsOnlyMsg}
</p>
</Typography>
</div>
{
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage({
defaultMessage: "Terms",
})}
</p>
</Typography>
<div className={styles.termsLabel}>
<Typography variant="Body/Paragraph/mdRegular">
<span>{rateTerm.title}</span>
</Typography>
<Modal
title={rateTerm.title}
subtitle={rateTerm.paymentTerm}
trigger={
<IconButton
theme="Black"
style="Muted"
className={styles.termsInfoIcon}
>
<MaterialIcon
icon="info"
color="Icon/Default"
size={20}
/>
</IconButton>
}
>
<div className={styles.terms}>
{rateDefinition.generalTerms.map((term) => (
<Typography key={term} variant="Body/Paragraph/mdRegular">
<p className={styles.term}>
<MaterialIcon
icon="check"
color="Icon/Feedback/Success"
size={20}
/>
{term}
</p>
</Typography>
))}
</div>
</Modal>
</div>
</div>
}
{hasModifiableRate(rateDefinition.cancellationRule) && (
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage({
defaultMessage: "Modify By",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<p>18:00, {fromDate.format("dddd D MMM")}</p>
</Typography>
</div>
)}
{breakfastPrice !== null && (
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage({
defaultMessage: "Breakfast",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>{breakfastPrice}</p>
</Typography>
</div>
)}
<Divider color="subtle" />
<div className={styles.row}>
<Typography variant="Body/Lead text">
<p>
{intl.formatMessage({
defaultMessage: "Room total",
})}
</p>
</Typography>
<PriceType
cheques={cheques}
formattedTotalPrice={formattedTotalPrice}
isCancelled={isCancelled}
currencyCode={currencyCode}
priceType={priceType}
rateDefinition={rateDefinition}
totalPoints={totalPoints}
totalPrice={totalPrice}
vouchers={vouchers}
/>
</div>
</div>
</div>
</article>
)
}