Refactor TripadvisorChip * feat: create new StaticChip componeny * refactor tripadvisor chip to use ChipStatic * refactor: use TripadvisorChip everywhere * fix: use withChipStatic Approved-by: Erik Tiekstra
192 lines
6.0 KiB
TypeScript
192 lines
6.0 KiB
TypeScript
"use client"
|
|
|
|
import { getSingleDecimal } from "@scandic-hotels/common/utils/numberFormatting"
|
|
import { Alert } from "../Alert"
|
|
import { Divider } from "../Divider"
|
|
import { FacilityToIcon } from "../FacilityToIcon"
|
|
import ImageGallery, { GalleryImage } from "../ImageGallery"
|
|
import SkeletonShimmer from "../SkeletonShimmer"
|
|
import { TripAdvisorChip } from "../TripAdvisorChip"
|
|
import { Typography } from "../Typography"
|
|
|
|
import HotelDescription from "./HotelDescription"
|
|
|
|
import styles from "./hotelInfoCard.module.css"
|
|
import { useIntl } from "react-intl"
|
|
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
|
import { FacilityEnum } from "@scandic-hotels/common/constants/facilities"
|
|
|
|
export type HotelInfoCardProps = {
|
|
hotel: {
|
|
id: string
|
|
name: string
|
|
url: string | null
|
|
ratings?: {
|
|
tripAdvisor?: { rating: number }
|
|
}
|
|
}
|
|
description: string
|
|
address: {
|
|
streetAddress: string
|
|
city: string
|
|
kilometersToCentre: number
|
|
}
|
|
galleryImages: GalleryImage[]
|
|
alerts: SpecialAlertProps["alert"][]
|
|
facilities: {
|
|
id: FacilityEnum
|
|
name: string
|
|
}[]
|
|
slot?: React.ReactNode
|
|
}
|
|
|
|
export function HotelInfoCard({
|
|
hotel,
|
|
galleryImages,
|
|
address,
|
|
facilities,
|
|
alerts,
|
|
description,
|
|
slot,
|
|
}: HotelInfoCardProps) {
|
|
const intl = useIntl()
|
|
|
|
const firstFacilities = facilities.slice(0, 5)
|
|
|
|
return (
|
|
<article className={styles.container}>
|
|
<section className={styles.wrapper}>
|
|
<div className={styles.imageWrapper}>
|
|
<ImageGallery title={hotel.name} images={galleryImages} fill />
|
|
{hotel.ratings?.tripAdvisor && (
|
|
<TripAdvisorChip
|
|
rating={hotel.ratings.tripAdvisor.rating}
|
|
color="Neutral"
|
|
size="sm"
|
|
wrapper="x2"
|
|
/>
|
|
)}
|
|
</div>
|
|
<div className={styles.hotelContent}>
|
|
<div className={styles.hotelInformation}>
|
|
<Typography variant="Title/md">
|
|
<h1 className={styles.hotelName}>{hotel.name}</h1>
|
|
</Typography>
|
|
<div className={styles.hotelAddressDescription}>
|
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
|
<p className={styles.hotelAddress}>
|
|
{intl.formatMessage(
|
|
{
|
|
id: "hotelInfoCard.kmToCityCenter",
|
|
defaultMessage:
|
|
"{address}, {city} ∙ {distanceToCityCenterInKm} km to city center",
|
|
},
|
|
{
|
|
address: address.streetAddress,
|
|
city: address.city,
|
|
distanceToCityCenterInKm: getSingleDecimal(
|
|
address.kilometersToCentre
|
|
),
|
|
}
|
|
)}
|
|
</p>
|
|
</Typography>
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p className={styles.hotelDescription}>{description}</p>
|
|
</Typography>
|
|
<HotelDescription
|
|
description={description}
|
|
facilities={firstFacilities}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Divider variant="vertical" />
|
|
<div className={styles.facilities}>
|
|
<div className={styles.facilityList}>
|
|
{firstFacilities?.map((facility) => (
|
|
<div className={styles.facilitiesItem} key={facility.id}>
|
|
<FacilityToIcon id={facility.id} color="Icon/Default" />
|
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
|
<p>{facility.name}</p>
|
|
</Typography>
|
|
</div>
|
|
))}
|
|
</div>
|
|
{slot}
|
|
</div>
|
|
</div>
|
|
<div className={styles.slotWrapper}>{slot}</div>
|
|
</section>
|
|
{alerts.map((alert) => (
|
|
<SpecialAlert key={alert.id} alert={alert} />
|
|
))}
|
|
</article>
|
|
)
|
|
}
|
|
|
|
type SpecialAlertProps = {
|
|
alert: { id: string; type: AlertTypeEnum; heading: string; text: string }
|
|
}
|
|
function SpecialAlert({ alert }: SpecialAlertProps) {
|
|
return (
|
|
<div className={styles.hotelAlert} key={`wrapper_${alert.id}`}>
|
|
<Alert
|
|
key={alert.id}
|
|
type={alert.type}
|
|
heading={alert.heading}
|
|
text={alert.text}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function HotelInfoCardSkeleton() {
|
|
return (
|
|
<article className={styles.container}>
|
|
<section className={styles.wrapper}>
|
|
<div className={styles.imageWrapper}>
|
|
<SkeletonShimmer height="100%" width="100%" />
|
|
</div>
|
|
<div className={styles.hotelContent}>
|
|
<div className={styles.hotelInformation}>
|
|
<SkeletonShimmer width="60ch" height="40px" />
|
|
<div className={styles.hotelAddressDescription}>
|
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
|
<SkeletonShimmer width="40ch" />
|
|
</Typography>
|
|
<Typography variant="Body/Paragraph/mdRegular">
|
|
<p>
|
|
<SkeletonShimmer width="60ch" />
|
|
<SkeletonShimmer width="58ch" />
|
|
<SkeletonShimmer width="45ch" />
|
|
</p>
|
|
</Typography>
|
|
</div>
|
|
</div>
|
|
<Divider variant="vertical" />
|
|
<div className={styles.facilities}>
|
|
<div className={styles.facilityList}>
|
|
<Typography
|
|
variant="Body/Paragraph/mdBold"
|
|
className={styles.facilityTitle}
|
|
>
|
|
<SkeletonShimmer width="20ch" />
|
|
</Typography>
|
|
{[1, 2, 3, 4, 5]?.map((id) => {
|
|
return (
|
|
<div className={styles.facilitiesItem} key={id}>
|
|
<SkeletonShimmer width="10ch" />
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
<div className={styles.hotelAlert}>
|
|
<SkeletonShimmer width="18ch" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</article>
|
|
)
|
|
}
|