Files
web/packages/booking-flow/lib/components/RoomDetailsSidePeek/RoomSidePeekContent/index.tsx
Anton Gunnarsson f7ef58eafa Merged in feat/sw-2874-move-select-rate (pull request #2750)
Approved-by: Joakim Jäderberg
2025-09-03 08:30:05 +00:00

175 lines
5.7 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.
import { useIntl } from "react-intl"
import { FacilityIcon } from "@scandic-hotels/design-system/Icons/FacilityIcon"
import ImageGallery from "@scandic-hotels/design-system/ImageGallery"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { BED_TYPE_ICONS, type BedTypes } from "../../../misc/bedTypeIcons"
import styles from "./roomSidePeekContent.module.css"
import type { ApiImage, Room } from "@scandic-hotels/trpc/types/hotel"
interface RoomSidePeekContentProps {
room: Room
}
export function RoomSidePeekContent({ room }: RoomSidePeekContentProps) {
const intl = useIntl()
const roomSize = room.roomSize
const totalOccupancy = room.totalOccupancy
const roomDescription = room.descriptions.medium
const galleryImages = mapApiImagesToGalleryImages(room.images)
return (
<div className={styles.wrapper}>
<div className={styles.mainContent}>
{totalOccupancy && (
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage(
{
defaultMessage:
"Max. {max, plural, one {{range} guest} other {{range} guests}}",
},
{
max: totalOccupancy.max,
range: totalOccupancy.range,
}
)}
</p>
</Typography>
)}
{roomSize && (
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{roomSize.min === roomSize.max
? intl.formatMessage(
{
defaultMessage: "{roomSize} m²",
},
{
roomSize: roomSize.min,
}
)
: intl.formatMessage(
{
defaultMessage: "{roomSizeMin}{roomSizeMax} m²",
},
{
roomSizeMin: roomSize.min,
roomSizeMax: roomSize.max,
}
)}
</p>
</Typography>
)}
<div className={styles.imageContainer}>
<ImageGallery images={galleryImages} title={room.name} height={280} />
</div>
</div>
<div className={styles.listContainer}>
<Typography variant="Title/Subtitle/md">
<p>
{intl.formatMessage({
defaultMessage: "Room amenities",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<ul className={styles.facilityList}>
{[...room.roomFacilities]
.sort((a, b) => a.sortOrder - b.sortOrder)
.map((facility) => {
return (
<li key={facility.name}>
<FacilityIcon
name={facility.icon}
size={24}
color="Icon/Default"
/>
<span>
{facility.availableInAllRooms
? facility.name
: intl.formatMessage(
{
defaultMessage:
"{facility} (available in some rooms)",
},
{
facility: facility.name,
}
)}
</span>
</li>
)
})}
</ul>
</Typography>
</div>
<div className={styles.listContainer}>
<Typography variant="Title/Subtitle/md">
<p>
{intl.formatMessage({
defaultMessage: "Bed options",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage({
defaultMessage: "Subject to availability",
})}
</p>
</Typography>
<ul className={styles.bedOptions}>
{room.roomTypes.map((roomType) => {
const description =
roomType.description || roomType.mainBed.description
const MainBedIcon =
BED_TYPE_ICONS[roomType.mainBed.type as BedTypes]
const ExtraBedIcon = roomType.fixedExtraBed
? BED_TYPE_ICONS[roomType.fixedExtraBed.type as BedTypes]
: null
return (
<li key={roomType.code}>
{MainBedIcon ? <MainBedIcon height={24} width={24} /> : null}
{ExtraBedIcon ? <ExtraBedIcon height={24} width={30} /> : null}
<Typography variant="Body/Paragraph/mdRegular">
<span>{description}</span>
</Typography>
</li>
)
})}
</ul>
</div>
<div className={styles.listContainer}>
<Typography variant="Title/Subtitle/md">
<p>
{intl.formatMessage({
defaultMessage: "About the hotel",
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>{roomDescription}</p>
</Typography>
</div>
</div>
)
}
function mapApiImagesToGalleryImages(apiImages: ApiImage[]) {
return apiImages.map((apiImage) => ({
src: apiImage.imageSizes.medium,
alt:
apiImage.metaData.altText ||
apiImage.metaData.altText_En ||
apiImage.metaData.title ||
apiImage.metaData.title_En,
caption: apiImage.metaData.title || apiImage.metaData.title_En,
smallSrc: apiImage.imageSizes.small,
}))
}