"use client" import { usePathname, useRouter, useSearchParams } from "next/navigation" import { useCallback, useEffect, useMemo, useState } from "react" import { useIntl } from "react-intl" import Caption from "@/components/TempDesignSystem/Text/Caption" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import { useRateSummary } from "@/hooks/selectRate/useRateSummary" import { useRoomFiltering } from "@/hooks/selectRate/useRoomFiltering" import { trackLowestRoomPrice } from "@/utils/tracking" import { convertObjToSearchParams } from "@/utils/url" import RateSummary from "../RateSummary" import { RoomSelectionPanel } from "../RoomSelectionPanel" import SelectedRoomPanel from "../SelectedRoomPanel" import { filterDuplicateRoomTypesByLowestPrice, parseRoomParams } from "./utils" import styles from "./rooms.module.css" import { type DefaultFilterOptions, RoomPackageCodeEnum, } 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" type SelectedRates = (RateCode | undefined)[] 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 [selectedRates, setSelectedRates] = useState( new Array(searchedRoomsAndGuests.length).fill(undefined) ) 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 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 { selectedPackagesByRoom, getRooms, handleFilter, getFilteredRooms } = useRoomFiltering({ roomsAvailability }) const rateSummary = useRateSummary({ searchedRoomsAndGuests, selectedRates, getFilteredRooms, selectedPackagesByRoom, availablePackages, roomCategories, }) useEffect(() => { if (!rateSummary?.some((rate) => rate === null)) return const hasAnySelection = selectedRates.some((rate) => rate !== undefined) if (!hasAnySelection) return }, [rateSummary, selectedRates]) useEffect(() => { const pricesWithCurrencies = visibleRooms.flatMap((room) => room.products.map((product) => ({ price: product.productType.public.localPrice.pricePerNight, currency: product.productType.public.localPrice.currency, })) ) const lowestPrice = pricesWithCurrencies.reduce( (minPrice, { price }) => Math.min(minPrice, price), Infinity ) const currency = pricesWithCurrencies[0]?.currency trackLowestRoomPrice({ hotelId, arrivalDate, departureDate, lowestPrice: lowestPrice, currency: currency, }) }, [arrivalDate, departureDate, hotelId, visibleRooms]) const queryParams = useMemo(() => { const rooms = rateSummary.map((rate, index) => ({ roomTypeCode: rate?.roomTypeCode, rateCode: rate?.public.rateCode, counterRateCode: rate?.member?.rateCode, packages: selectedPackagesByRoom[index] || [], })) const newSearchParams = convertObjToSearchParams({ rooms }, searchParams) return newSearchParams }, [searchParams, rateSummary, selectedPackagesByRoom]) function handleSubmit(e: React.FormEvent) { e.preventDefault() window.history.replaceState( null, "", `${pathname}?${queryParams.toString()}` ) router.push(`select-bed?${queryParams}`) } const setSelectedRateForRoom = useCallback( (index: number) => (value: React.SetStateAction) => { setSelectedRates((prev) => { const newRates = [...prev] newRates[index] = typeof value === "function" ? value(prev[index]) : value return newRates }) }, [] ) const handleFilterForRoom = useCallback( (index: number) => (filter: Record) => { handleFilter(filter, index) }, [handleFilter] ) return (
{isMultipleRooms ? ( searchedRoomsAndGuests.map((room, index) => (
{selectedRates[index] === undefined && ( {intl.formatMessage( { id: "Room {roomIndex}" }, { roomIndex: index + 1 } )} ,{" "} {intl.formatMessage( { id: room.children?.length ? "{adults} adults, {children} children" : "{adults} adults", }, { adults: room.adults, children: room.children?.length, } )} )}
)) ) : ( )} {rateSummary && (
summary !== null )} isUserLoggedIn={isUserLoggedIn} packages={availablePackages} roomsAvailability={roomsAvailability} /> )}
) }