Files
web/components/HotelReservation/SelectRate/Rooms/index.tsx
2025-01-13 13:35:03 +01:00

200 lines
5.5 KiB
TypeScript

"use client"
import { useCallback, useEffect, useMemo, useState } from "react"
import { useIntl } from "react-intl"
import RoomFilter from "../RoomFilter"
import RoomSelection from "../RoomSelection"
import { filterDuplicateRoomTypesByLowestPrice } from "./utils"
import styles from "./rooms.module.css"
import {
type DefaultFilterOptions,
RoomPackageCodeEnum,
type RoomPackageCodes,
} from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
import type {
Rate,
RateCode,
} from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomConfiguration } from "@/server/routers/hotels/output"
export default function Rooms({
roomsAvailability,
roomCategories = [],
availablePackages,
hotelType,
isUserLoggedIn,
}: SelectRateProps) {
const intl = useIntl()
const visibleRooms: RoomConfiguration[] = useMemo(() => {
const deduped = filterDuplicateRoomTypesByLowestPrice(
roomsAvailability.roomConfigurations
)
const separated = deduped.reduce<{
available: RoomConfiguration[]
notAvailable: RoomConfiguration[]
}>(
(acc, curr) => {
if (curr.status === "NotAvailable") {
return { ...acc, notAvailable: [...acc.notAvailable, curr] }
}
return { ...acc, available: [...acc.available, curr] }
},
{ available: [], notAvailable: [] }
)
return [...separated.available, ...separated.notAvailable]
}, [roomsAvailability.roomConfigurations])
const [selectedRate, setSelectedRate] = useState<RateCode | undefined>(
undefined
)
const [selectedPackages, setSelectedPackages] = useState<RoomPackageCodes[]>(
[]
)
const defaultPackages: DefaultFilterOptions[] = useMemo(
() => [
{
code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
description: intl.formatMessage({ id: "Accessible Room" }),
itemCode: availablePackages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM
)?.itemCode,
},
{
code: RoomPackageCodeEnum.ALLERGY_ROOM,
description: intl.formatMessage({ id: "Allergy Room" }),
itemCode: availablePackages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.ALLERGY_ROOM
)?.itemCode,
},
{
code: RoomPackageCodeEnum.PET_ROOM,
description: intl.formatMessage({ id: "Pet Room" }),
itemCode: availablePackages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
)?.itemCode,
},
],
[availablePackages, intl]
)
const handleFilter = useCallback(
(filter: Record<RoomPackageCodeEnum, boolean | undefined>) => {
const filteredPackages = Object.keys(filter).filter(
(key) => filter[key as RoomPackageCodeEnum]
) as RoomPackageCodeEnum[]
setSelectedPackages(filteredPackages)
},
[]
)
const filteredRooms = useMemo(() => {
return visibleRooms.filter((room) =>
selectedPackages.every((filteredPackage) =>
room.features.some((feature) => feature.code === filteredPackage)
)
)
}, [visibleRooms, selectedPackages])
const rooms = useMemo(() => {
if (selectedPackages.length === 0) {
return {
...roomsAvailability,
roomConfigurations: visibleRooms,
}
}
return {
...roomsAvailability,
roomConfigurations: [...filteredRooms],
}
}, [roomsAvailability, visibleRooms, selectedPackages, filteredRooms])
const rateSummary: Rate | null = useMemo(() => {
const room = filteredRooms.find(
(room) => room.roomTypeCode === selectedRate?.roomTypeCode
)
if (!room) return null
const product = room.products.find(
(product) =>
product.productType.public.rateCode === selectedRate?.publicRateCode
)
if (!product) return null
const petRoomPackage =
(selectedPackages.includes(RoomPackageCodeEnum.PET_ROOM) &&
availablePackages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
)) ||
undefined
const features = filteredRooms.find((room) =>
room.features.some(
(feature) => feature.code === RoomPackageCodeEnum.PET_ROOM
)
)?.features
const roomType = roomCategories.find((roomCategory) =>
roomCategory.roomTypes.some(
(roomType) => roomType.code === room.roomTypeCode
)
)
const rateSummary: Rate = {
features: petRoomPackage && features ? features : [],
priceName: selectedRate?.name,
priceTerm: selectedRate?.paymentTerm,
public: product.productType.public,
member: product.productType.member,
roomType: roomType?.name || room.roomType,
roomTypeCode: room.roomTypeCode,
}
return rateSummary
}, [
filteredRooms,
availablePackages,
selectedPackages,
selectedRate,
roomCategories,
])
useEffect(() => {
if (rateSummary) return
if (!selectedRate) return
setSelectedRate(undefined)
}, [rateSummary, selectedRate])
return (
<div className={styles.content}>
<RoomFilter
numberOfRooms={rooms.roomConfigurations.length}
onFilter={handleFilter}
filterOptions={defaultPackages}
/>
<RoomSelection
roomsAvailability={rooms}
roomCategories={roomCategories}
availablePackages={availablePackages}
selectedPackages={selectedPackages}
setRateCode={setSelectedRate}
rateSummary={rateSummary}
hotelType={hotelType}
isUserLoggedIn={isUserLoggedIn}
/>
</div>
)
}