173 lines
5.2 KiB
TypeScript
173 lines
5.2 KiB
TypeScript
"use client"
|
|
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
|
import { useSession } from "next-auth/react"
|
|
import { useCallback, useEffect, useMemo, useRef } from "react"
|
|
|
|
import { debounce } from "@/utils/debounce"
|
|
import { isValidSession } from "@/utils/session"
|
|
|
|
import RateSummary from "./RateSummary"
|
|
import RoomCard from "./RoomCard"
|
|
import {
|
|
getHotelReservationQueryParams,
|
|
RATE_CARD_EQUAL_HEIGHT_CLASS,
|
|
RATE_CARDS_AVAILABLE_HEIGHT_CLASS,
|
|
RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS,
|
|
} from "./utils"
|
|
|
|
import styles from "./roomSelection.module.css"
|
|
|
|
import type { RoomSelectionProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
|
|
|
|
export default function RoomSelection({
|
|
roomsAvailability,
|
|
roomCategories,
|
|
availablePackages,
|
|
selectedPackages,
|
|
isUserLoggedIn,
|
|
setRateCode,
|
|
rateSummary,
|
|
hotelType,
|
|
}: RoomSelectionProps) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
const searchParams = useSearchParams()
|
|
const roomRefs = useRef<HTMLLIElement[]>([])
|
|
const { roomConfigurations, rateDefinitions } = roomsAvailability
|
|
|
|
const equalizePriceOptionHeights = useCallback(() => {
|
|
if (!roomRefs.current.length) return
|
|
|
|
const optionsSelector = `.${RATE_CARD_EQUAL_HEIGHT_CLASS}`
|
|
const availableSelector = `.${RATE_CARDS_AVAILABLE_HEIGHT_CLASS}`
|
|
const notAvailableSelector = `.${RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS}`
|
|
const DEFAULT_RATE_CARD_HEIGHT = 380
|
|
|
|
const maxOptionHeights: number[] = []
|
|
let maxPriceCardHeight = DEFAULT_RATE_CARD_HEIGHT
|
|
|
|
roomRefs.current.forEach((room) => {
|
|
const options = room.querySelectorAll<HTMLDivElement>(optionsSelector)
|
|
options.forEach((option, i) => {
|
|
option.style.height = "auto"
|
|
const optionHeight = option.getBoundingClientRect().height
|
|
maxOptionHeights[i] = Math.max(maxOptionHeights[i] || 0, optionHeight)
|
|
})
|
|
|
|
const priceCard = room.querySelector(availableSelector) as HTMLElement
|
|
if (priceCard) {
|
|
const priceCardHeight = priceCard.getBoundingClientRect().height
|
|
maxPriceCardHeight = Math.max(maxPriceCardHeight, priceCardHeight)
|
|
}
|
|
})
|
|
|
|
roomRefs.current.forEach((room) => {
|
|
const options = room.querySelectorAll<HTMLDivElement>(optionsSelector)
|
|
options.forEach((option, i) => {
|
|
if (option) {
|
|
option.style.height = `${maxOptionHeights[i]}px`
|
|
}
|
|
})
|
|
|
|
const noPriceCard = room.querySelector(
|
|
notAvailableSelector
|
|
) as HTMLElement
|
|
if (noPriceCard) {
|
|
noPriceCard.style.height = `${maxPriceCardHeight}px`
|
|
}
|
|
})
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
const debouncedResizeHandler = debounce(function () {
|
|
equalizePriceOptionHeights()
|
|
})
|
|
|
|
const observer = new ResizeObserver(debouncedResizeHandler)
|
|
|
|
observer.observe(document.documentElement)
|
|
|
|
return () => {
|
|
if (observer) {
|
|
observer.unobserve(document.documentElement)
|
|
}
|
|
}
|
|
}, [roomRefs, equalizePriceOptionHeights])
|
|
|
|
const queryParams = useMemo(() => {
|
|
const params = new URLSearchParams(searchParams)
|
|
const searchParamsObject = getHotelReservationQueryParams(searchParams)
|
|
|
|
searchParamsObject.room.forEach((item, index) => {
|
|
if (rateSummary?.roomTypeCode) {
|
|
params.set(`room[${index}].roomtype`, rateSummary.roomTypeCode)
|
|
}
|
|
if (rateSummary?.public?.rateCode) {
|
|
params.set(`room[${index}].ratecode`, rateSummary.public.rateCode)
|
|
}
|
|
if (rateSummary?.member?.rateCode) {
|
|
params.set(
|
|
`room[${index}].counterratecode`,
|
|
rateSummary.member.rateCode
|
|
)
|
|
}
|
|
selectedPackages.length > 0
|
|
? params.set(`room[${index}].packages`, selectedPackages.join(","))
|
|
: params.delete(`room[${index}].packages`)
|
|
})
|
|
|
|
return params
|
|
}, [searchParams, rateSummary, selectedPackages])
|
|
|
|
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
e.preventDefault()
|
|
|
|
window.history.replaceState(
|
|
null,
|
|
"",
|
|
`${pathname}?${queryParams.toString()}`
|
|
)
|
|
router.push(`select-bed?${queryParams}`)
|
|
}
|
|
|
|
return (
|
|
<div className={styles.wrapper}>
|
|
<form
|
|
method="GET"
|
|
action={`select-bed?${searchParams}`}
|
|
onSubmit={handleSubmit}
|
|
>
|
|
<ul className={styles.roomList}>
|
|
{roomConfigurations.map((roomConfiguration, index) => (
|
|
<li
|
|
key={roomConfiguration.roomTypeCode}
|
|
ref={(el) => {
|
|
if (el) roomRefs.current[index] = el
|
|
}}
|
|
>
|
|
<RoomCard
|
|
hotelId={roomsAvailability.hotelId.toString()}
|
|
hotelType={hotelType}
|
|
rateDefinitions={rateDefinitions}
|
|
roomConfiguration={roomConfiguration}
|
|
roomCategories={roomCategories}
|
|
handleSelectRate={setRateCode}
|
|
selectedPackages={selectedPackages}
|
|
packages={availablePackages}
|
|
/>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
{rateSummary && (
|
|
<RateSummary
|
|
rateSummary={rateSummary}
|
|
isUserLoggedIn={isUserLoggedIn}
|
|
packages={availablePackages}
|
|
roomsAvailability={roomsAvailability}
|
|
/>
|
|
)}
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|