"use client" import { usePathname, useRouter, useSearchParams } from "next/navigation" import { useCallback, useEffect, useMemo, useState } from "react" import { useIntl } from "react-intl" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import { trackLowestRoomPrice } from "@/utils/tracking" import { convertObjToSearchParams } from "@/utils/url" import RateSummary from "../RateSummary" import { RoomSelectionPanel } from "../RoomSelectionPanel" import { filterDuplicateRoomTypesByLowestPrice, parseRoomParams } 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 router = useRouter() const pathname = usePathname() const searchParams = useSearchParams() const hotelId = searchParams.get("hotel") const arrivalDate = searchParams.get("fromDate") const departureDate = searchParams.get("toDate") const searchedRoomsAndGuests = useMemo( () => parseRoomParams(searchParams), [searchParams] ) const isMultipleRooms = searchedRoomsAndGuests.length > 1 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( undefined ) const [selectedPackages, setSelectedPackages] = useState( [] ) 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) => { 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]) useEffect(() => { const pricesWithCurrencies = rooms.roomConfigurations.flatMap((room) => room.products.map((product) => ({ price: product.productType.public.localPrice.pricePerNight, currency: product.productType.public.localPrice.currency, })) ) const cheapestPrice = pricesWithCurrencies.reduce( (minPrice, { price }) => Math.min(minPrice, price), Infinity ) const currency = pricesWithCurrencies.find( ({ price }) => price === cheapestPrice )?.currency trackLowestRoomPrice({ hotelId, arrivalDate, departureDate, lowestPrice: cheapestPrice, currency: currency, }) }, [arrivalDate, departureDate, hotelId, rooms.roomConfigurations]) const queryParams = useMemo(() => { // TODO: handle multiple rooms const newSearchParams = convertObjToSearchParams( { rooms: [ { roomTypeCode: rateSummary?.roomTypeCode, rateCode: rateSummary?.public.rateCode, counterRateCode: rateSummary?.member?.rateCode, packages: selectedPackages, }, ], }, searchParams ) return newSearchParams }, [searchParams, rateSummary, selectedPackages]) function handleSubmit(e: React.FormEvent) { e.preventDefault() window.history.replaceState( null, "", `${pathname}?${queryParams.toString()}` ) router.push(`select-bed?${queryParams}`) } return (
{isMultipleRooms ? ( searchedRoomsAndGuests.map((room, index) => (
{intl.formatMessage( { id: room.children?.length ? "Room {roomIndex}, {adults} adults, {children} children" : "Room {roomIndex}, {adults} adults", }, { roomIndex: index + 1, adults: room.adults, children: room.children?.length, } )}
)) ) : ( )} {rateSummary && (
)}
) }