Files
web/packages/booking-flow/lib/pages/EnterDetailsPage.tsx
Anton Gunnarsson c435cdba68 Merged in fix/sw-3551-rsc-bookingflowconfig (pull request #2988)
fix(SW-3551): Fix issue with BookingConfigProvider in RSC

* wip move config to pages

* Move config providing to pages
2025-10-22 07:04:21 +00:00

174 lines
5.8 KiB
TypeScript

import { cookies } from "next/headers"
import { notFound } from "next/navigation"
import { Suspense } from "react"
import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAndFriends"
import { BookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import HotelHeader from "../components/EnterDetails/Header"
import Payment from "../components/EnterDetails/Payment"
import Multiroom from "../components/EnterDetails/Room/Multiroom"
import RoomOne from "../components/EnterDetails/Room/One"
import DesktopSummary from "../components/EnterDetails/Summary/Desktop"
import MobileSummary from "../components/EnterDetails/Summary/Mobile"
import EnterDetailsTrackingWrapper from "../components/EnterDetails/Tracking"
import FnFNotAllowedAlert from "../components/FnFNotAllowedAlert"
import EnterDetailsProvider from "../contexts/EnterDetails/EnterDetailsContext"
import { RoomProvider } from "../contexts/EnterDetails/RoomContext"
import { getBreakfastPackages } from "../trpc/memoizedRequests/getBreakfastPackages"
import { getHotel } from "../trpc/memoizedRequests/getHotel"
import { getProfileSafely } from "../trpc/memoizedRequests/getProfile"
import { getSelectedRoomsAvailabilityEnterDetails } from "../trpc/memoizedRequests/getSelectedRoomsAvailabilityEnterDetails"
import { parseDetailsSearchParams } from "../utils/url"
import styles from "./EnterDetailsPage.module.css"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { NextSearchParams } from "../types"
export async function EnterDetailsPage({
lang,
searchParams,
config,
}: {
lang: Lang
searchParams: NextSearchParams
config: BookingFlowConfig
}) {
const selectRoomParams = new URLSearchParams(
searchParams as Record<string, string>
)
const booking = parseDetailsSearchParams(searchParams)
if (!booking) return notFound()
if (selectRoomParams.has("activeRoomIndex")) {
selectRoomParams.delete("activeRoomIndex")
}
if (
booking.bookingCode &&
FamilyAndFriendsCodes.includes(booking.bookingCode)
) {
const cookieStore = await cookies()
const isInValidFNF = cookieStore.get("sc")?.value !== "1"
if (isInValidFNF) {
return <FnFNotAllowedAlert />
}
}
const breakfastInput = {
adults: 1,
fromDate: booking.fromDate,
hotelId: booking.hotelId,
toDate: booking.toDate,
}
const hotelInput = {
hotelId: booking.hotelId,
// TODO: Remove this from input since it forces
// waterfalls for no other reason than to
// set merchantInformationData.alternatePaymentOptions
// to an empty array
isCardOnlyPayment: false,
language: lang,
}
const getHotelPromise = getHotel(hotelInput)
const getBreakfastPackagesPromise = getBreakfastPackages(breakfastInput)
const getProfilePromise = getProfileSafely()
const rooms = await getSelectedRoomsAvailabilityEnterDetails({
booking,
lang,
})
const hotelData = await getHotelPromise
if (!hotelData || !rooms.length) {
return notFound()
}
const breakfastPackages = await getBreakfastPackagesPromise
const user = await getProfilePromise
const isCardOnlyPayment = rooms.some((room) => room.mustBeGuaranteed)
const { hotel } = hotelData
// TODO: Temp fix to avoid waterfall fetch and moving this
// logic from the route here for now
if (isCardOnlyPayment) {
hotel.merchantInformationData.alternatePaymentOptions = []
}
const firstRoom = rooms[0]
const multirooms = rooms.slice(1)
const { rateDefinition, rateDefinitionMember } = firstRoom.roomRate
if (user && rateDefinitionMember) {
const rateCode = selectRoomParams.get("room[0].ratecode")
if (rateDefinitionMember.rateCode !== rateCode) {
booking.rooms[0].rateCode = rateDefinitionMember.rateCode
selectRoomParams.set("room[0].ratecode", rateDefinitionMember.rateCode)
booking.rooms[0].counterRateCode = rateDefinition.rateCode
selectRoomParams.set("room[0].counterratecode", rateDefinition.rateCode)
}
}
// attribute data-footer-spacing used to add spacing
// beneath footer to be able to show entire footer upon
// scrolling down to the bottom of the page
return (
<BookingFlowConfig config={config}>
<main data-footer-spacing>
<EnterDetailsProvider
booking={booking}
breakfastPackages={breakfastPackages}
lang={lang}
rooms={rooms}
searchParamsStr={selectRoomParams.toString()}
user={user}
vat={hotel.vat}
roomCategories={hotelData.roomCategories}
>
<HotelHeader hotelData={hotelData} />
<div className={styles.container}>
<div className={styles.content}>
<RoomProvider idx={0} room={firstRoom}>
<RoomOne user={user} />
</RoomProvider>
{multirooms.map((room, idx) => (
// Need to start idx from 1 since first room is
// rendered above
<RoomProvider key={idx + 1} idx={idx + 1} room={room}>
<Multiroom />
</RoomProvider>
))}
<Suspense>
<Payment
otherPaymentOptions={
hotel.merchantInformationData.alternatePaymentOptions
}
supportedCards={hotel.merchantInformationData.cards}
/>
</Suspense>
</div>
<aside className={styles.summary}>
<MobileSummary isUserLoggedIn={!!user} />
<DesktopSummary isUserLoggedIn={!!user} />
</aside>
</div>
<EnterDetailsTrackingWrapper
booking={booking}
hotel={hotel}
isMember={!!user}
lang={lang}
rooms={rooms}
/>
</EnterDetailsProvider>
</main>
</BookingFlowConfig>
)
}