Files
web/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomSelectionPanel/index.tsx
Hrishikesh Vaipurkar b0674d07f5 Merged in feat/SW-1308-booking-codes-track-b (pull request #1607)
Feat/SW-1308 booking codes track b

* feat: SW-1308 Booking codes track b

* feat: SW-1308 Booking codes Track B implementation

* feat: SW-1308 Optimized after rebase


Approved-by: Arvid Norlin
2025-03-24 11:23:11 +00:00

166 lines
5.8 KiB
TypeScript

"use client"
import { useSearchParams } from "next/navigation"
import { useEffect } from "react"
import { useIntl } from "react-intl"
import { alternativeHotels } from "@/constants/routes/hotelReservation"
import { useBookingCodeFilterStore } from "@/stores/bookingCode-filter"
import { useRatesStore } from "@/stores/select-rate"
import BookingCodeFilter from "@/components/HotelReservation/SelectHotel/BookingCodeFilter"
import Alert from "@/components/TempDesignSystem/Alert"
import { useRoomContext } from "@/contexts/SelectRate/Room"
import useLang from "@/hooks/useLang"
import RoomCard from "./RoomCard"
import RoomTypeFilter from "./RoomTypeFilter"
import styles from "./roomSelectionPanel.module.css"
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import { AlertTypeEnum } from "@/types/enums/alert"
import { BookingCodeFilterEnum } from "@/types/enums/bookingCodeFilter"
import { RateTypeEnum } from "@/types/enums/rateType"
export default function RoomSelectionPanel() {
const { rooms } = useRoomContext()
const isSingleRoomAndHasSelection = useRatesStore(
(state) => state.booking.rooms.length === 1 && !!state.rateSummary.length
)
const searchParams = useSearchParams()
const bookingCode = searchParams.get("bookingCode")
const intl = useIntl()
const lang = useLang()
const noAvailableRooms = rooms.every(
(roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
)
const activeCodeFilter = useBookingCodeFilterStore(
(state) => state.activeCodeFilter
)
const isVoucherOrCorpChequeRate = rooms.find((room) =>
room.products.some((product) => product.voucher || product.bonusCheque)
)
let isRegularRatesAvailableWithCode = false,
isBookingCodeRatesAvailable = false
let visibleRooms = rooms
if (bookingCode && !isVoucherOrCorpChequeRate) {
// Regular Rates (Save, Change and Flex) always should send both public and member rates
// so we can check public rates for availability
isRegularRatesAvailableWithCode = rooms.some(
(room) =>
room.status === AvailabilityEnum.Available &&
room.products.some(
(product) =>
product.public?.rateType === RateTypeEnum.Regular ||
product.member?.rateType === RateTypeEnum.Regular
)
)
// Booking codes rate comes with various rate types but Regular is reserved
// for non-booking code rates (Save, Change & Flex)
// With Booking code rates we will always obtain public rate and maybe a member rate
// so we check for public rate and ignore member rate
isBookingCodeRatesAvailable = rooms.some(
(room) =>
room.status === AvailabilityEnum.Available &&
room.products.some(
(product) =>
product.public?.rateType !== RateTypeEnum.Regular ||
product.member?.rateType !== RateTypeEnum.Regular
)
)
if (activeCodeFilter === BookingCodeFilterEnum.Discounted) {
visibleRooms = rooms.filter(
(room) =>
room.status === AvailabilityEnum.Available &&
room.products.every(
(product) => product.public?.rateType !== RateTypeEnum.Regular
)
)
} else if (activeCodeFilter === BookingCodeFilterEnum.Regular) {
visibleRooms = rooms.filter(
(room) =>
room.status === AvailabilityEnum.Available &&
room.products.every(
(product) =>
product.public?.rateType === RateTypeEnum.Regular ||
product.member?.rateType === RateTypeEnum.Regular
)
)
}
}
// Show booking code filter when both of the booking code rates or regular rates are available
const showBookingCodeFilter =
isRegularRatesAvailableWithCode && isBookingCodeRatesAvailable
useEffect(() => {
if (isSingleRoomAndHasSelection) {
// Required to prevent the history.pushState on the first selection
// to scroll user back to top
requestAnimationFrame(() => {
const SCROLL_OFFSET = 100
const selectedInputRoomCard = document.querySelector(
`.${styles.roomList} li:has(input[type=radio]:checked)`
)
if (selectedInputRoomCard) {
const elementPosition =
selectedInputRoomCard.getBoundingClientRect().top
const offsetPosition =
elementPosition + window.scrollY - SCROLL_OFFSET
window.scrollTo({
top: offsetPosition,
behavior: "instant",
})
}
})
}
}, [isSingleRoomAndHasSelection])
return (
<>
{noAvailableRooms ||
(bookingCode &&
!isBookingCodeRatesAvailable &&
!isVoucherOrCorpChequeRate) ? (
<div className={styles.hotelAlert}>
<Alert
type={AlertTypeEnum.Info}
heading={intl.formatMessage({ id: "No availability" })}
text={
bookingCode && !isBookingCodeRatesAvailable
? intl.formatMessage(
{
id: "We found no available rooms using this booking code ({bookingCode}). See available rates below.",
},
{ bookingCode }
)
: intl.formatMessage({
id: "There are no rooms available that match your request.",
})
}
link={{
title: intl.formatMessage({ id: "See alternative hotels" }),
url: `${alternativeHotels(lang)}`,
keepSearchParams: true,
}}
/>
</div>
) : null}
<RoomTypeFilter />
{showBookingCodeFilter ? <BookingCodeFilter /> : null}
<ul className={styles.roomList}>
{visibleRooms.map((roomConfiguration) => (
<RoomCard
key={roomConfiguration.roomTypeCode}
roomConfiguration={roomConfiguration}
/>
))}
</ul>
</>
)
}