Fix/linting * fix import issues and add lint check no-extraneous-dependencies * fix use type HotelType instead of string Approved-by: Anton Gunnarsson
264 lines
8.4 KiB
TypeScript
264 lines
8.4 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useIntl } from 'react-intl'
|
|
|
|
import { selectRate } from '@scandic-hotels/common/constants/routes/hotelReservation'
|
|
import Body from '../../../Body'
|
|
import Caption from '../../../Caption'
|
|
import Footnote from '../../../Footnote'
|
|
import { IconButton } from '../../../IconButton'
|
|
import { MaterialIcon } from '../../../Icons/MaterialIcon'
|
|
import Link from '../../../Link'
|
|
import { OldDSButton as Button } from '../../../OldDSButton'
|
|
import Subtitle from '../../../Subtitle'
|
|
import { Typography } from '../../../Typography'
|
|
|
|
import { NoPriceAvailableCard } from '../../NoPriceAvailableCard'
|
|
import { HotelCardDialogImage } from '../../HotelCardDialogImage'
|
|
|
|
import styles from './standaloneHotelCardDialog.module.css'
|
|
import { Lang } from '@scandic-hotels/common/constants/language'
|
|
import { HotelPin } from '../../../Map/types'
|
|
import { FacilityToIcon } from '../../../FacilityToIcon'
|
|
import { HotelPointsRow } from '../../HotelPointsRow'
|
|
|
|
interface StandaloneHotelCardProps {
|
|
data: HotelPin
|
|
lang: Lang
|
|
isUserLoggedIn: boolean
|
|
handleClose: () => void
|
|
onClick?: () => void
|
|
}
|
|
|
|
export function StandaloneHotelCardDialog({
|
|
data,
|
|
lang,
|
|
handleClose,
|
|
isUserLoggedIn,
|
|
onClick,
|
|
}: StandaloneHotelCardProps) {
|
|
const intl = useIntl()
|
|
const [imageError, setImageError] = useState(false)
|
|
const {
|
|
name,
|
|
chequePrice,
|
|
publicPrice,
|
|
memberPrice,
|
|
redemptionPrice,
|
|
voucherPrice,
|
|
currency,
|
|
amenities,
|
|
image,
|
|
ratings,
|
|
operaId,
|
|
hasEnoughPoints,
|
|
} = data
|
|
|
|
const notEnoughPointsLabel = intl.formatMessage({
|
|
defaultMessage: 'Not enough points',
|
|
})
|
|
|
|
const shouldShowNotEnoughPoints = redemptionPrice && !hasEnoughPoints
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
<IconButton
|
|
theme="Black"
|
|
style="Muted"
|
|
className={styles.closeButton}
|
|
onPress={handleClose}
|
|
aria-label={intl.formatMessage({
|
|
defaultMessage: 'Close',
|
|
})}
|
|
>
|
|
<MaterialIcon icon="close" size={22} color="CurrentColor" />
|
|
</IconButton>
|
|
<HotelCardDialogImage
|
|
firstImage={image?.url}
|
|
altText={image?.alt}
|
|
rating={{ tripAdvisor: ratings?.tripAdvisor ?? null }}
|
|
imageError={imageError}
|
|
setImageError={setImageError}
|
|
position="left"
|
|
/>
|
|
<div className={styles.content}>
|
|
<div className={styles.name}>
|
|
<Body textTransform="bold">{name}</Body>
|
|
</div>
|
|
<div className={styles.facilities}>
|
|
{amenities.slice(0, 3).map((facility) => {
|
|
const Icon = (
|
|
<FacilityToIcon id={facility.id} size={16} color="Icon/Default" />
|
|
)
|
|
return (
|
|
<div className={styles.facilitiesItem} key={facility.id}>
|
|
{Icon}
|
|
<Footnote color="uiTextMediumContrast">
|
|
{facility.name}
|
|
</Footnote>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
<div className={styles.pricesContainer}>
|
|
{publicPrice ||
|
|
memberPrice ||
|
|
redemptionPrice ||
|
|
voucherPrice ||
|
|
chequePrice ? (
|
|
<>
|
|
<div className={styles.priceCard}>
|
|
{redemptionPrice ? (
|
|
<Caption>
|
|
{intl.formatMessage({
|
|
defaultMessage: 'Available rates',
|
|
})}
|
|
</Caption>
|
|
) : (
|
|
<Caption type="bold">
|
|
{intl.formatMessage({
|
|
defaultMessage: 'From',
|
|
})}
|
|
</Caption>
|
|
)}
|
|
{chequePrice && (
|
|
<Subtitle type="two">
|
|
{intl.formatMessage(
|
|
{
|
|
defaultMessage: '{price} {currency}',
|
|
},
|
|
{
|
|
price: chequePrice.numberOfCheques,
|
|
currency: 'CC',
|
|
}
|
|
)}
|
|
{chequePrice.additionalPricePerStay > 0
|
|
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
|
' + ' +
|
|
intl.formatMessage(
|
|
{
|
|
defaultMessage: '{price} {currency}',
|
|
},
|
|
{
|
|
price: chequePrice.additionalPricePerStay,
|
|
currency: chequePrice.currency,
|
|
}
|
|
)
|
|
: null}
|
|
<Body asChild>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
<span>
|
|
/
|
|
{intl.formatMessage({
|
|
defaultMessage: 'night',
|
|
})}
|
|
</span>
|
|
</Body>
|
|
</Subtitle>
|
|
)}
|
|
{voucherPrice && (
|
|
<Subtitle type="two">
|
|
{intl.formatMessage(
|
|
{
|
|
defaultMessage: '{price} {currency}',
|
|
},
|
|
{
|
|
price: voucherPrice,
|
|
currency,
|
|
}
|
|
)}
|
|
<Body asChild>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
<span>
|
|
/
|
|
{intl.formatMessage({
|
|
defaultMessage: 'night',
|
|
})}
|
|
</span>
|
|
</Body>
|
|
</Subtitle>
|
|
)}
|
|
{publicPrice && !isUserLoggedIn && (
|
|
<Subtitle type="two">
|
|
{intl.formatMessage(
|
|
{
|
|
defaultMessage: '{price} {currency}',
|
|
},
|
|
{
|
|
price: publicPrice,
|
|
currency,
|
|
}
|
|
)}
|
|
<Body asChild>
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
<span>
|
|
/
|
|
{intl.formatMessage({
|
|
defaultMessage: 'night',
|
|
})}
|
|
</span>
|
|
</Body>
|
|
</Subtitle>
|
|
)}
|
|
{memberPrice && (
|
|
<Subtitle type="two" color="red">
|
|
{intl.formatMessage(
|
|
{
|
|
defaultMessage: '{price} {currency}',
|
|
},
|
|
{
|
|
price: memberPrice,
|
|
currency,
|
|
}
|
|
)}
|
|
<Body asChild color="red">
|
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
|
<span>
|
|
/
|
|
{intl.formatMessage({
|
|
defaultMessage: 'night',
|
|
})}
|
|
</span>
|
|
</Body>
|
|
</Subtitle>
|
|
)}
|
|
{redemptionPrice && (
|
|
<HotelPointsRow pointsPerStay={redemptionPrice} />
|
|
)}
|
|
</div>
|
|
{shouldShowNotEnoughPoints ? (
|
|
<div className={styles.notEnoughPointsButton}>
|
|
<Typography variant="Body/Paragraph/mdBold">
|
|
<span>{notEnoughPointsLabel}</span>
|
|
</Typography>
|
|
</div>
|
|
) : (
|
|
<Button
|
|
asChild
|
|
theme="base"
|
|
size="small"
|
|
className={styles.button}
|
|
onClick={onClick}
|
|
>
|
|
<Link
|
|
href={`${selectRate(lang)}?hotel=${operaId}`}
|
|
color="none"
|
|
keepSearchParams
|
|
>
|
|
{intl.formatMessage({
|
|
defaultMessage: 'See rooms',
|
|
})}
|
|
</Link>
|
|
</Button>
|
|
)}
|
|
</>
|
|
) : (
|
|
<NoPriceAvailableCard />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|