Files
web/packages/design-system/lib/components/HotelInfoCard/index.tsx
Joakim Jäderberg aafad9781f Merged in feat/lokalise-rebuild (pull request #2993)
Feat/lokalise rebuild

* chore(lokalise): update translation ids

* chore(lokalise): easier to switch between projects

* chore(lokalise): update translation ids

* .

* .

* .

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* chore(lokalise): new translations

* merge

* switch to errors for missing id's

* merge

* sync translations


Approved-by: Linus Flood
2025-10-22 11:00:03 +00:00

187 lines
5.9 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} />
)}
</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>
)
}