fix: we showed duplicate rooms because every bed represents a room
This commit is contained in:
@@ -17,94 +17,89 @@ import styles from "./hotelInfoCard.module.css"
|
||||
|
||||
import type { HotelInfoCardProps } from "@/types/components/hotelReservation/selectRate/hotelInfoCard"
|
||||
|
||||
export default async function HotelInfoCard({ hotelData }: HotelInfoCardProps) {
|
||||
const hotel = hotelData?.hotel
|
||||
export default async function HotelInfoCard({ hotel }: HotelInfoCardProps) {
|
||||
const intl = await getIntl()
|
||||
|
||||
const sortedFacilities = hotel?.detailedFacilities
|
||||
const sortedFacilities = hotel.detailedFacilities
|
||||
.sort((a, b) => b.sortOrder - a.sortOrder)
|
||||
.slice(0, 5)
|
||||
|
||||
const galleryImages = mapApiImagesToGalleryImages(hotel?.galleryImages || [])
|
||||
const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || [])
|
||||
|
||||
return (
|
||||
<article className={styles.container}>
|
||||
{hotel && (
|
||||
<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}>
|
||||
<Title as="h2" textTransform="uppercase">
|
||||
{hotel.name}
|
||||
</Title>
|
||||
<div className={styles.hotelAddressDescription}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{address}, {city} ∙ {distanceToCityCenterInKm} km to city center",
|
||||
},
|
||||
{
|
||||
address: hotel.address.streetAddress,
|
||||
city: hotel.address.city,
|
||||
distanceToCityCenterInKm: getSingleDecimal(
|
||||
hotel.location.distanceToCentre / 1000
|
||||
),
|
||||
}
|
||||
)}
|
||||
</Caption>
|
||||
<Body color="uiTextHighContrast">
|
||||
{hotel.hotelContent.texts.descriptions?.medium}
|
||||
</Body>
|
||||
</div>
|
||||
</div>
|
||||
<Divider color="subtle" variant="vertical" />
|
||||
<div className={styles.facilities}>
|
||||
<div className={styles.facilityList}>
|
||||
<Body textTransform="bold" className={styles.facilityTitle}>
|
||||
{intl.formatMessage({ id: "At the hotel" })}
|
||||
</Body>
|
||||
{sortedFacilities?.map((facility) => {
|
||||
const IconComponent = mapFacilityToIcon(facility.id)
|
||||
return (
|
||||
<div className={styles.facilitiesItem} key={facility.id}>
|
||||
{IconComponent && (
|
||||
<IconComponent
|
||||
className={styles.facilitiesIcon}
|
||||
color="grey80"
|
||||
/>
|
||||
)}
|
||||
<Body color="uiTextHighContrast">{facility.name}</Body>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<ReadMore
|
||||
label={intl.formatMessage({ id: "See all amenities" })}
|
||||
hotelId={hotel.operaId}
|
||||
hotel={hotel}
|
||||
showCTA={false}
|
||||
/>
|
||||
<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}>
|
||||
<Title as="h2" textTransform="uppercase">
|
||||
{hotel.name}
|
||||
</Title>
|
||||
<div className={styles.hotelAddressDescription}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{address}, {city} ∙ {distanceToCityCenterInKm} km to city center",
|
||||
},
|
||||
{
|
||||
address: hotel.address.streetAddress,
|
||||
city: hotel.address.city,
|
||||
distanceToCityCenterInKm: getSingleDecimal(
|
||||
hotel.location.distanceToCentre / 1000
|
||||
),
|
||||
}
|
||||
)}
|
||||
</Caption>
|
||||
<Body color="uiTextHighContrast">
|
||||
{hotel.hotelContent.texts.descriptions?.medium}
|
||||
</Body>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
{hotel?.specialAlerts.map((alert) => {
|
||||
return (
|
||||
<div className={styles.hotelAlert} key={`wrapper_${alert.id}`}>
|
||||
<Alert
|
||||
key={alert.id}
|
||||
type={alert.type}
|
||||
heading={alert.heading}
|
||||
text={alert.text}
|
||||
<Divider color="subtle" variant="vertical" />
|
||||
<div className={styles.facilities}>
|
||||
<div className={styles.facilityList}>
|
||||
<Body textTransform="bold" className={styles.facilityTitle}>
|
||||
{intl.formatMessage({ id: "At the hotel" })}
|
||||
</Body>
|
||||
{sortedFacilities?.map((facility) => {
|
||||
const IconComponent = mapFacilityToIcon(facility.id)
|
||||
return (
|
||||
<div className={styles.facilitiesItem} key={facility.id}>
|
||||
{IconComponent && (
|
||||
<IconComponent
|
||||
className={styles.facilitiesIcon}
|
||||
color="grey80"
|
||||
/>
|
||||
)}
|
||||
<Body color="uiTextHighContrast">{facility.name}</Body>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<ReadMore
|
||||
label={intl.formatMessage({ id: "See all amenities" })}
|
||||
hotelId={hotel.operaId}
|
||||
hotel={hotel}
|
||||
showCTA={false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
{hotel.specialAlerts.map((alert) => (
|
||||
<div className={styles.hotelAlert} key={`wrapper_${alert.id}`}>
|
||||
<Alert
|
||||
key={alert.id}
|
||||
type={alert.type}
|
||||
heading={alert.heading}
|
||||
text={alert.text}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,8 +69,6 @@ function getBreakfastMessage(
|
||||
|
||||
export default function RoomCard({ roomConfiguration }: RoomCardProps) {
|
||||
const intl = useIntl()
|
||||
const lessThanFiveRoomsLeft =
|
||||
roomConfiguration.roomsLeft > 0 && roomConfiguration.roomsLeft < 5
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const bookingCode = searchParams.get("bookingCode")
|
||||
@@ -85,6 +83,8 @@ export default function RoomCard({ roomConfiguration }: RoomCardProps) {
|
||||
}))
|
||||
const { isMainRoom, roomAvailability, roomNr, selectedPackage } =
|
||||
useRoomContext()
|
||||
const showLowInventory =
|
||||
roomConfiguration.roomsLeft > 0 && roomConfiguration.roomsLeft < 5
|
||||
|
||||
if (!roomAvailability || !("rateDefinitions" in roomAvailability)) {
|
||||
return null
|
||||
@@ -177,7 +177,7 @@ export default function RoomCard({ roomConfiguration }: RoomCardProps) {
|
||||
<li className={classNames}>
|
||||
<div className={styles.imageContainer}>
|
||||
<div className={styles.chipContainer}>
|
||||
{lessThanFiveRoomsLeft ? (
|
||||
{showLowInventory ? (
|
||||
<span className={styles.chip}>
|
||||
<Footnote color="burgundy" textTransform="uppercase">
|
||||
{intl.formatMessage(
|
||||
@@ -211,16 +211,16 @@ export default function RoomCard({ roomConfiguration }: RoomCardProps) {
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{occupancy.max === occupancy.min
|
||||
? intl.formatMessage(
|
||||
{ id: "{guests, plural, one {# guest} other {# guests}}" },
|
||||
{ guests: occupancy.max }
|
||||
)
|
||||
{ id: "{guests, plural, one {# guest} other {# guests}}" },
|
||||
{ guests: occupancy.max }
|
||||
)
|
||||
: intl.formatMessage(
|
||||
{ id: "{min}-{max} guests" },
|
||||
{
|
||||
min: occupancy.min,
|
||||
max: occupancy.max,
|
||||
}
|
||||
)}
|
||||
{ id: "{min}-{max} guests" },
|
||||
{
|
||||
min: occupancy.min,
|
||||
max: occupancy.max,
|
||||
}
|
||||
)}
|
||||
</Caption>
|
||||
)}
|
||||
<RoomSize roomSize={roomSize} />
|
||||
@@ -293,7 +293,7 @@ export default function RoomCard({ roomConfiguration }: RoomCardProps) {
|
||||
title={rateTitle}
|
||||
rateTitle={
|
||||
product.public &&
|
||||
product.public?.rateType !== RateTypeEnum.Regular
|
||||
product.public?.rateType !== RateTypeEnum.Regular
|
||||
? rateDefinition?.title
|
||||
: undefined
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ export function RoomsContainer({
|
||||
childArray,
|
||||
fromDate,
|
||||
hotelData,
|
||||
hotelId,
|
||||
isUserLoggedIn,
|
||||
toDate,
|
||||
}: RoomsContainerProps) {
|
||||
@@ -29,7 +28,7 @@ export function RoomsContainer({
|
||||
const { data: roomsAvailability, isPending: isLoadingAvailability } =
|
||||
useRoomsAvailability(
|
||||
adultArray,
|
||||
hotelId,
|
||||
hotelData.hotel.id,
|
||||
fromDateString,
|
||||
toDateString,
|
||||
lang,
|
||||
@@ -42,7 +41,7 @@ export function RoomsContainer({
|
||||
childArray,
|
||||
fromDateString,
|
||||
toDateString,
|
||||
hotelId,
|
||||
hotelData.hotel.id,
|
||||
lang
|
||||
)
|
||||
|
||||
@@ -50,10 +49,6 @@ export function RoomsContainer({
|
||||
return <RoomsContainerSkeleton />
|
||||
}
|
||||
|
||||
if (!hotelData?.hotel) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (packages === null) {
|
||||
// TODO: Log packages error
|
||||
console.error("[RoomsContainer] unable to fetch packages")
|
||||
|
||||
@@ -5,9 +5,7 @@ import { Suspense } from "react"
|
||||
import { getHotel } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import { auth } from "@/auth"
|
||||
import HotelInfoCard, {
|
||||
HotelInfoCardSkeleton,
|
||||
} from "@/components/HotelReservation/SelectRate/HotelInfoCard"
|
||||
import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard"
|
||||
import { RoomsContainer } from "@/components/HotelReservation/SelectRate/RoomsContainer"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { setLang } from "@/i18n/serverContext"
|
||||
@@ -33,17 +31,21 @@ export default async function SelectRatePage({
|
||||
const { adultsInRoom, childrenInRoom, hotel, noOfRooms, selectHotelParams } =
|
||||
searchDetails
|
||||
|
||||
const { fromDate, toDate } = getValidDates(
|
||||
selectHotelParams.fromDate,
|
||||
selectHotelParams.toDate
|
||||
)
|
||||
|
||||
const hotelData = await getHotel({
|
||||
hotelId: hotel.id,
|
||||
isCardOnlyPayment: false,
|
||||
language: params.lang,
|
||||
})
|
||||
|
||||
if (!hotelData) {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
const { fromDate, toDate } = getValidDates(
|
||||
selectHotelParams.fromDate,
|
||||
selectHotelParams.toDate
|
||||
)
|
||||
|
||||
const session = await auth()
|
||||
const isUserLoggedIn = isValidSession(session)
|
||||
|
||||
@@ -59,20 +61,17 @@ export default async function SelectRatePage({
|
||||
hotel.id,
|
||||
hotel.name,
|
||||
noOfRooms,
|
||||
hotelData?.hotel.address.country,
|
||||
hotelData?.hotel.address.city,
|
||||
hotelData.hotel.address.country,
|
||||
hotelData.hotel.address.city,
|
||||
selectHotelParams.city
|
||||
)
|
||||
|
||||
const booking = convertSearchParamsToObj<SelectRateSearchParams>(searchParams)
|
||||
|
||||
const hotelId = +hotel.id
|
||||
const suspenseKey = stringify(searchParams)
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<HotelInfoCardSkeleton />}>
|
||||
<HotelInfoCard hotelData={hotelData} />
|
||||
</Suspense>
|
||||
<HotelInfoCard hotel={hotelData.hotel} />
|
||||
|
||||
<RoomsContainer
|
||||
adultArray={adultsInRoom}
|
||||
@@ -80,7 +79,6 @@ export default async function SelectRatePage({
|
||||
childArray={childrenInRoom}
|
||||
fromDate={arrivalDate}
|
||||
hotelData={hotelData}
|
||||
hotelId={hotelId}
|
||||
isUserLoggedIn={isUserLoggedIn}
|
||||
toDate={departureDate}
|
||||
/>
|
||||
|
||||
@@ -6,38 +6,22 @@ import type { ChildrenInRoom } from "@/utils/hotelSearchDetails"
|
||||
|
||||
export function useRoomsAvailability(
|
||||
adultsCount: number[],
|
||||
hotelId: number,
|
||||
hotelId: string,
|
||||
fromDateString: string,
|
||||
toDateString: string,
|
||||
lang: Lang,
|
||||
childArray: ChildrenInRoom,
|
||||
bookingCode?: string
|
||||
) {
|
||||
const roomsAvailability =
|
||||
trpc.hotel.availability.roomsCombinedAvailability.useQuery({
|
||||
adultsCount,
|
||||
bookingCode,
|
||||
childArray,
|
||||
hotelId,
|
||||
lang,
|
||||
roomStayEndDate: toDateString,
|
||||
roomStayStartDate: fromDateString,
|
||||
})
|
||||
|
||||
const data = roomsAvailability.data?.map((ra) => {
|
||||
if (ra.status === "fulfilled") {
|
||||
return ra.value
|
||||
}
|
||||
return {
|
||||
details: ra.reason,
|
||||
error: "request_failure",
|
||||
}
|
||||
return trpc.hotel.availability.roomsCombinedAvailability.useQuery({
|
||||
adultsCount,
|
||||
bookingCode,
|
||||
childArray,
|
||||
hotelId,
|
||||
lang,
|
||||
roomStayEndDate: toDateString,
|
||||
roomStayStartDate: fromDateString,
|
||||
})
|
||||
|
||||
return {
|
||||
...roomsAvailability,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
export function useHotelPackages(
|
||||
@@ -45,14 +29,14 @@ export function useHotelPackages(
|
||||
childArray: ChildrenInRoom,
|
||||
fromDateString: string,
|
||||
toDateString: string,
|
||||
hotelId: number,
|
||||
hotelId: string,
|
||||
lang: Lang
|
||||
) {
|
||||
return trpc.hotel.packages.get.useQuery({
|
||||
adults: adultArray[0], // Using the first adult count
|
||||
children: childArray?.[0]?.length, // Using the first children count
|
||||
endDate: toDateString,
|
||||
hotelId: hotelId.toString(),
|
||||
hotelId,
|
||||
packageCodes: [
|
||||
RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
|
||||
RoomPackageCodeEnum.PET_ROOM,
|
||||
|
||||
Reference in New Issue
Block a user