"use client" import { cx } from "class-variance-authority" import { type ReadonlyURLSearchParams, useParams, useRouter, useSearchParams, } from "next/navigation" import { memo } from "react" import { useIntl } from "react-intl" import TripAdvisorChip from "@scandic-hotels/booking-flow/components/TripAdvisorChip" import { alternativeHotelsMap, selectHotelMap, selectRate, } from "@scandic-hotels/common/constants/routes/hotelReservation" import Caption from "@scandic-hotels/design-system/Caption" import { Divider } from "@scandic-hotels/design-system/Divider" import HotelLogoIcon from "@scandic-hotels/design-system/Icons/HotelLogoIcon" import Link from "@scandic-hotels/design-system/Link" import { Typography } from "@scandic-hotels/design-system/Typography" import { useHotelsMapStore } from "@/stores/hotels-map" import BookingCodeChip from "@/components/BookingCodeChip" import { FacilityToIcon } from "@/components/ContentType/HotelPage/data" import ImageGallery from "@/components/ImageGallery" import { mapApiImagesToGalleryImages } from "@/utils/imageGallery" import { getSingleDecimal } from "@/utils/numberFormatting" import ReadMore from "../ReadMore" import HotelChequeCard from "./HotelChequeCard" import HotelPointsRow from "./HotelPointsRow" import HotelPriceCard from "./HotelPriceCard" import HotelVoucherCard from "./HotelVoucherCard" import NoPriceAvailableCard from "./NoPriceAvailableCard" import { hotelCardVariants } from "./variants" import styles from "./hotelCard.module.css" import type { Lang } from "@scandic-hotels/common/constants/language" import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps" import { SidePeekEnum } from "@/types/components/hotelReservation/sidePeek" function HotelCard({ hotelData: { availability, hotel }, isUserLoggedIn, state = "default", type = HotelCardListingTypeEnum.PageListing, bookingCode = "", isAlternative, }: HotelCardProps) { const params = useParams() const searchParams = useSearchParams() const lang = params.lang as Lang const intl = useIntl() const { activate, engage, disengage, disengageAfterDelay } = useHotelsMapStore() const amenities = hotel.detailedFacilities.slice(0, 5) const router = useRouter() const classNames = hotelCardVariants({ type, state, }) const mapUrl = isAlternative ? alternativeHotelsMap(lang) : selectHotelMap(lang) const handleAddressClick = (event: React.MouseEvent) => { event.preventDefault() disengage() // Disengage the current hotel to avoid the hover state from being active when clicking on the address activate(hotel.name) router.push(`${mapUrl}?${searchParams.toString()}`) } const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}` const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || []) const fullPrice = !availability.bookingCode const price = availability.productType const hasInsufficientPoints = !price?.redemptions?.some( (r) => r.hasEnoughPoints ) const notEnoughPointsLabel = intl.formatMessage({ defaultMessage: "Not enough points", }) const isDisabled = price?.redemptions?.length && hasInsufficientPoints return (
engage(hotel.name)} onMouseLeave={() => disengageAfterDelay()} >
{hotel.ratings?.tripAdvisor && ( )}

{hotel.name}

{type == HotelCardListingTypeEnum.MapListing ? (

{addressStr}

) : (

{addressStr}

)}
{intl.formatMessage( { defaultMessage: "{number} km to city center", }, { number: getSingleDecimal( hotel.location.distanceToCentre / 1000 ), } )}
{hotel.hotelContent.texts.descriptions ? (

{hotel.hotelContent.texts.descriptions.short}

) : null}
{amenities.map((facility) => (
{facility.name}
))}
{!availability.productType ? ( ) : ( <> {bookingCode && ( )} {(!isUserLoggedIn || !price?.member || (bookingCode && !fullPrice)) && price?.public && ( )} {availability.productType.member && ( )} {price?.voucher && ( )} {price?.bonusCheque && ( )} {price?.redemptions?.length ? (
{intl.formatMessage({ defaultMessage: "Available rates", })} {price.redemptions.map((redemption) => ( ))}
) : null} {isDisabled ? (
{notEnoughPointsLabel}
) : (
{intl.formatMessage({ defaultMessage: "See rooms", })}
)} )}
) } interface PricesWrapperProps { children: React.ReactNode isClickable?: boolean hotelId: string pathname: string removeBookingCodeFromSearchParams: boolean searchParams: ReadonlyURLSearchParams } function PricesWrapper({ children, hotelId, isClickable, pathname, removeBookingCodeFromSearchParams, searchParams, }: PricesWrapperProps) { const content =
{children}
if (!isClickable) { return content } const params = new URLSearchParams(searchParams) params.delete("city") params.set("hotel", hotelId) if (removeBookingCodeFromSearchParams) { params.delete("bookingCode") } const href = `${pathname}?${params.toString()}` return ( {content} ) } export default memo(HotelCard)