{city.name}
@@ -94,6 +128,7 @@ export default async function SelectHotelPage({
{
+ beforeAll(() => {
+ jest.useFakeTimers({ now: NOW })
+ })
+
+ afterAll(() => {
+ jest.useRealTimers()
+ })
+
+ describe("getValidFromDate", () => {
+ it("returns today when empty string is provided", () => {
+ const actual = getValidFromDate("")
+ expect(actual.toISOString()).toBe("2020-10-01T00:00:00.000Z")
+ })
+
+ it("returns today when undefined is provided", () => {
+ const actual = getValidFromDate(undefined)
+ expect(actual.toISOString()).toBe("2020-10-01T00:00:00.000Z")
+ })
+
+ it("returns given date in utc", () => {
+ const actual = getValidFromDate("2024-01-01")
+ expect(actual.toISOString()).toBe("2024-01-01T00:00:00.000Z")
+ })
+ })
+
+ describe("getValidToDate", () => {
+ it("returns day after fromDate when empty string is provided", () => {
+ const actual = getValidToDate("", NOW)
+ expect(actual.toISOString()).toBe("2020-10-02T00:00:00.000Z")
+ })
+
+ it("returns day after fromDate when undefined is provided", () => {
+ const actual = getValidToDate(undefined, NOW)
+ expect(actual.toISOString()).toBe("2020-10-02T00:00:00.000Z")
+ })
+
+ it("returns given date in utc", () => {
+ const actual = getValidToDate("2024-01-01", NOW)
+ expect(actual.toISOString()).toBe("2024-01-01T00:00:00.000Z")
+ })
+
+ it("fallsback to day after fromDate when given date is before fromDate", () => {
+ const actual = getValidToDate("2020-09-30", NOW)
+ expect(actual.toISOString()).toBe("2020-10-02T00:00:00.000Z")
+ })
+ })
+})
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/getValidDates.ts b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/getValidDates.ts
new file mode 100644
index 000000000..d9bcbf09e
--- /dev/null
+++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/getValidDates.ts
@@ -0,0 +1,55 @@
+import { Dayjs } from "dayjs"
+
+import { dt } from "@/lib/dt"
+
+/**
+ * Get valid dates from stringFromDate and stringToDate making sure that they are not in the past and chronologically correct
+ * @example const { fromDate, toDate} = getValidDates("2021-01-01", "2021-01-02")
+ */
+export function getValidDates(
+ stringFromDate: string | undefined,
+ stringToDate: string | undefined
+): { fromDate: Dayjs; toDate: Dayjs } {
+ const fromDate = getValidFromDate(stringFromDate)
+ const toDate = getValidToDate(stringToDate, fromDate)
+
+ return { fromDate, toDate }
+}
+
+/**
+ * Get valid fromDate from stringFromDate making sure that it is not in the past
+ */
+export function getValidFromDate(stringFromDate: string | undefined): Dayjs {
+ const now = dt().utc()
+ if (!stringFromDate) {
+ return now
+ }
+ const toDate = dt(stringFromDate)
+
+ const yesterday = now.subtract(1, "day")
+ if (!toDate.isAfter(yesterday)) {
+ return now
+ }
+
+ return toDate
+}
+
+/**
+ * Get valid toDate from stringToDate making sure that it is after fromDate
+ */
+export function getValidToDate(
+ stringToDate: string | undefined,
+ fromDate: Dayjs | Date
+): Dayjs {
+ const tomorrow = dt().utc().add(1, "day")
+ if (!stringToDate) {
+ return tomorrow
+ }
+
+ const toDate = dt(stringToDate)
+ if (toDate.isAfter(fromDate)) {
+ return toDate
+ }
+
+ return tomorrow
+}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
index fd9db4d6c..fa32a54cd 100644
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
+++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx
@@ -1,22 +1,17 @@
import { notFound } from "next/navigation"
+import { Suspense } from "react"
-import { dt } from "@/lib/dt"
-import {
- getHotelData,
- getLocations,
- getProfileSafely,
-} from "@/lib/trpc/memoizedRequests"
-import { serverClient } from "@/lib/trpc/server"
+import { getHotelData, getLocations } from "@/lib/trpc/memoizedRequests"
import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard"
-import Rooms from "@/components/HotelReservation/SelectRate/Rooms"
-import {
- generateChildrenString,
- getHotelReservationQueryParams,
-} from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
+import { RoomsContainer } from "@/components/HotelReservation/SelectRate/Rooms/RoomsContainer"
+import { RoomsContainerSkeleton } from "@/components/HotelReservation/SelectRate/Rooms/RoomsContainerSkeleton"
+import { getHotelReservationQueryParams } from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import { setLang } from "@/i18n/serverContext"
+import { safeTry } from "@/utils/safeTry"
+
+import { getValidDates } from "./getValidDates"
-import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { LangParams, PageArgs } from "@/types/params"
@@ -45,71 +40,44 @@ export default async function SelectRatePage({
return notFound()
}
- const validFromDate =
- searchParams.fromDate &&
- dt(searchParams.fromDate).isAfter(dt().subtract(1, "day"))
- ? searchParams.fromDate
- : dt().utc().format("YYYY-MM-DD")
- const validToDate =
- searchParams.toDate && dt(searchParams.toDate).isAfter(validFromDate)
- ? searchParams.toDate
- : dt().utc().add(1, "day").format("YYYY-MM-DD")
- const adults = selectRoomParamsObject.room[0].adults || 1 // TODO: Handle multiple rooms
- const childrenCount = selectRoomParamsObject.room[0].child?.length
- const children = selectRoomParamsObject.room[0].child
- ? generateChildrenString(selectRoomParamsObject.room[0].child)
- : undefined // TODO: Handle multiple rooms
-
- const [hotelData, roomsAvailability, packages, user] = await Promise.all([
- getHotelData({ hotelId: searchParams.hotel, language: params.lang }),
- serverClient().hotel.availability.rooms({
- hotelId: parseInt(searchParams.hotel, 10),
- roomStayStartDate: validFromDate,
- roomStayEndDate: validToDate,
- adults,
- children,
- }),
- serverClient().hotel.packages.get({
- hotelId: searchParams.hotel,
- startDate: searchParams.fromDate,
- endDate: searchParams.toDate,
- adults,
- children: childrenCount,
- packageCodes: [
- RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
- RoomPackageCodeEnum.PET_ROOM,
- RoomPackageCodeEnum.ALLERGY_ROOM,
- ],
- }),
- getProfileSafely(),
- ])
-
- if (!roomsAvailability) {
- return "No rooms found" // TODO: Add a proper error message
- }
-
- if (!hotelData) {
- return "No hotel data found" // TODO: Add a proper error message
- }
-
- const roomCategories = hotelData?.included
-
- const noRoomsAvailable = roomsAvailability.roomConfigurations.reduce(
- (acc, room) => {
- return acc && room.status === "NotAvailable"
- },
- true
+ const { fromDate, toDate } = getValidDates(
+ searchParams.fromDate,
+ searchParams.toDate
)
+ const adults = selectRoomParamsObject.room[0].adults || 1 // TODO: Handle multiple rooms
+ const children = selectRoomParamsObject.room[0].child // TODO: Handle multiple rooms
+
+ const [hotelData, hotelDataError] = await safeTry(
+ getHotelData({ hotelId: searchParams.hotel, language: params.lang })
+ )
+
+ if (!hotelData && !hotelDataError) {
+ return notFound()
+ }
+
+ const hotelId = +searchParams.hotel
return (
<>
-
-
+
+ }>
+
+
>
)
}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/loading.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/loading.tsx
deleted file mode 100644
index 0fad268cc..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/loading.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import LoadingSpinner from "@/components/LoadingSpinner"
-
-export default function LoadingHotelHeader() {
- return
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.module.css b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.module.css
deleted file mode 100644
index 82d6353ac..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.module.css
+++ /dev/null
@@ -1,64 +0,0 @@
-.header {
- background-color: var(--Base-Surface-Subtle-Normal);
- padding: var(--Spacing-x3) var(--Spacing-x2);
-}
-
-.wrapper {
- display: flex;
- flex-direction: column;
- gap: var(--Spacing-x3);
- justify-content: center;
-}
-
-.titleContainer {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: center;
- gap: var(--Spacing-x1);
-}
-
-.descriptionContainer {
- display: flex;
- flex-direction: column;
- gap: var(--Spacing-x-one-and-half);
-}
-
-.address {
- display: flex;
- gap: var(--Spacing-x-one-and-half);
- font-style: normal;
-}
-
-.dividerContainer {
- display: none;
-}
-
-@media (min-width: 768px) {
- .header {
- padding: var(--Spacing-x4) 0;
- }
-
- .wrapper {
- flex-direction: row;
- gap: var(--Spacing-x6);
- margin: 0 auto;
- /* simulates padding on viewport smaller than --max-width-navigation */
- width: min(
- calc(100dvw - (var(--Spacing-x2) * 2)),
- var(--max-width-navigation)
- );
- }
-
- .titleContainer > h1 {
- white-space: nowrap;
- }
-
- .dividerContainer {
- display: block;
- }
-
- .address {
- gap: var(--Spacing-x3);
- }
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.tsx
deleted file mode 100644
index 83412f1d1..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@hotelHeader/page.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { redirect } from "next/navigation"
-
-import { getHotelData } from "@/lib/trpc/memoizedRequests"
-
-import Divider from "@/components/TempDesignSystem/Divider"
-import Body from "@/components/TempDesignSystem/Text/Body"
-import Caption from "@/components/TempDesignSystem/Text/Caption"
-import Title from "@/components/TempDesignSystem/Text/Title"
-import { getIntl } from "@/i18n"
-
-import styles from "./page.module.css"
-
-import type { LangParams, PageArgs } from "@/types/params"
-
-export default async function HotelHeader({
- params,
- searchParams,
-}: PageArgs) {
- const home = `/${params.lang}`
- if (!searchParams.hotel) {
- redirect(home)
- }
- const hotelData = await getHotelData({
- hotelId: searchParams.hotel,
- language: params.lang,
- })
- if (!hotelData?.data) {
- redirect(home)
- }
-
- const intl = await getIntl()
- const hotel = hotelData.data.attributes
- return (
-
- )
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/loading.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/loading.tsx
deleted file mode 100644
index 78b79a040..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/loading.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import LoadingSpinner from "@/components/LoadingSpinner"
-
-export default function LoadingSummaryHeader() {
- return
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.module.css b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.module.css
deleted file mode 100644
index f680a23a1..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.module.css
+++ /dev/null
@@ -1,68 +0,0 @@
-.mobileSummary {
- display: block;
-}
-
-.desktopSummary {
- display: none;
-}
-
-.summary {
- background-color: var(--Main-Grey-White);
-
- border-color: var(--Primary-Light-On-Surface-Divider-subtle);
- border-style: solid;
- border-width: 1px;
- border-bottom: none;
- z-index: 10;
-}
-
-.hider {
- display: none;
-}
-
-.shadow {
- display: none;
-}
-
-@media screen and (min-width: 1367px) {
- .mobileSummary {
- display: none;
- }
-
- .desktopSummary {
- display: grid;
- grid-template-rows: auto auto 1fr;
- margin-top: calc(0px - var(--Spacing-x9));
- }
-
- .summary {
- position: sticky;
- top: calc(
- var(--booking-widget-desktop-height) + var(--Spacing-x2) +
- var(--Spacing-x-half)
- );
- z-index: 10;
- border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0;
- margin-top: calc(0px - var(--Spacing-x9));
- }
-
- .shadow {
- display: block;
- background-color: var(--Main-Grey-White);
- border-color: var(--Primary-Light-On-Surface-Divider-subtle);
- border-style: solid;
- border-left-width: 1px;
- border-right-width: 1px;
- border-top: none;
- border-bottom: none;
- }
-
- .hider {
- display: block;
- background-color: var(--Scandic-Brand-Warm-White);
- position: sticky;
- top: calc(var(--booking-widget-desktop-height) - 6px);
- margin-top: var(--Spacing-x4);
- height: 40px;
- }
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.tsx
deleted file mode 100644
index 0444913f1..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/@summary/page.tsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import { redirect } from "next/navigation"
-
-import { selectRate } from "@/constants/routes/hotelReservation"
-import {
- getPackages,
- getProfileSafely,
- getSelectedRoomAvailability,
-} from "@/lib/trpc/memoizedRequests"
-
-import Summary from "@/components/HotelReservation/EnterDetails/Summary"
-import { SummaryBottomSheet } from "@/components/HotelReservation/EnterDetails/Summary/BottomSheet"
-import {
- generateChildrenString,
- getQueryParamsForEnterDetails,
-} from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
-
-import styles from "./page.module.css"
-
-import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
-import { LangParams, PageArgs, SearchParams } from "@/types/params"
-
-export default async function SummaryPage({
- params,
- searchParams,
-}: PageArgs>) {
- const selectRoomParams = new URLSearchParams(searchParams)
- const { hotel, rooms, fromDate, toDate } =
- getQueryParamsForEnterDetails(selectRoomParams)
-
- const {
- adults,
- children,
- roomTypeCode,
- rateCode,
- packages: packageCodes,
- } = rooms[0] // TODO: Handle multiple rooms
-
- const availability = await getSelectedRoomAvailability({
- hotelId: hotel,
- adults,
- children: children ? generateChildrenString(children) : undefined,
- roomStayStartDate: fromDate,
- roomStayEndDate: toDate,
- rateCode,
- roomTypeCode,
- packageCodes,
- })
- const user = await getProfileSafely()
-
- const packages = packageCodes
- ? await getPackages({
- hotelId: hotel,
- startDate: fromDate,
- endDate: toDate,
- adults,
- children: children?.length,
- packageCodes,
- })
- : null
-
- if (!availability || !availability.selectedRoom) {
- console.error("No hotel or availability data", availability)
- // TODO: handle this case
- redirect(selectRate(params.lang))
- }
-
- const prices =
- user && availability.memberRate
- ? {
- local: {
- price: availability.memberRate.localPrice.pricePerStay,
- currency: availability.memberRate.localPrice.currency,
- },
- euro: availability.memberRate.requestedPrice
- ? {
- price: availability.memberRate.requestedPrice.pricePerStay,
- currency: availability.memberRate.requestedPrice.currency,
- }
- : undefined,
- }
- : {
- local: {
- price: availability.publicRate.localPrice.pricePerStay,
- currency: availability.publicRate.localPrice.currency,
- },
- euro: availability.publicRate?.requestedPrice
- ? {
- price: availability.publicRate?.requestedPrice.pricePerStay,
- currency: availability.publicRate?.requestedPrice.currency,
- }
- : undefined,
- }
-
- return (
- <>
-
-
- >
- )
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/_preload.ts b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/_preload.ts
deleted file mode 100644
index 6013a49cc..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/_preload.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import {
- getCreditCardsSafely,
- getProfileSafely,
-} from "@/lib/trpc/memoizedRequests"
-
-export function preload() {
- void getProfileSafely()
- void getCreditCardsSafely()
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/enterDetailsLayout.css b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/enterDetailsLayout.css
deleted file mode 100644
index 0322e44a7..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/enterDetailsLayout.css
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Due to css import issues with parallel routes we are forced to
- * use a regular css file and import it in the page.tsx
- * This is addressed in Next 15: https://github.com/vercel/next.js/pull/66300
- */
-
-.enter-details-layout {
- background-color: var(--Scandic-Brand-Warm-White);
-}
-
-.enter-details-layout__container {
- display: grid;
- gap: var(--Spacing-x3) var(--Spacing-x9);
- /* simulates padding on viewport smaller than --max-width-navigation */
-}
-
-.enter-details-layout__content {
- margin: var(--Spacing-x3) var(--Spacing-x2) 0;
-}
-
-.enter-details-layout__summaryContainer {
- position: sticky;
- bottom: 0;
- left: 0;
- right: 0;
-}
-
-@media screen and (min-width: 1367px) {
- .enter-details-layout__container {
- grid-template-columns: 1fr 340px;
- grid-template-rows: auto 1fr;
- margin: var(--Spacing-x5) auto 0;
- width: min(
- calc(100dvw - (var(--Spacing-x2) * 2)),
- var(--max-width-navigation)
- );
- }
-
- .enter-details-layout__summaryContainer {
- position: static;
- display: grid;
- grid-column: 2/3;
- grid-row: 1/-1;
- }
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/layout.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/layout.tsx
deleted file mode 100644
index 2bd8a5102..000000000
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/layout.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
-
-import { setLang } from "@/i18n/serverContext"
-import DetailsProvider from "@/providers/DetailsProvider"
-
-import { preload } from "./_preload"
-
-import type { LangParams, LayoutArgs } from "@/types/params"
-
-export default async function StepLayout({
- children,
- hotelHeader,
- params,
- summary,
-}: React.PropsWithChildren<
- LayoutArgs & {
- hotelHeader: React.ReactNode
- summary: React.ReactNode
- }
->) {
- setLang(params.lang)
- preload()
-
- const user = await getProfileSafely()
-
- return (
-
-
- {hotelHeader}
-
-
-
- )
-}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.module.css b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.module.css
new file mode 100644
index 000000000..5c757de70
--- /dev/null
+++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.module.css
@@ -0,0 +1,35 @@
+.container {
+ display: grid;
+ gap: var(--Spacing-x3) var(--Spacing-x9);
+}
+
+.content {
+ margin: var(--Spacing-x3) var(--Spacing-x2) 0;
+}
+
+.summary {
+ position: sticky;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+
+@media screen and (min-width: 1367px) {
+ .container {
+ grid-template-columns: 1fr 340px;
+ grid-template-rows: auto 1fr;
+ margin: var(--Spacing-x5) auto 0;
+ /* simulates padding on viewport smaller than --max-width-navigation */
+ width: min(
+ calc(100dvw - (var(--Spacing-x2) * 2)),
+ var(--max-width-navigation)
+ );
+ }
+
+ .summary {
+ position: static;
+ display: grid;
+ grid-column: 2/3;
+ grid-row: 1/-1;
+ }
+}
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.tsx
index d175fc25f..bcfcca8c6 100644
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.tsx
+++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/step/page.tsx
@@ -1,11 +1,11 @@
-import "./enterDetailsLayout.css"
-
import { notFound } from "next/navigation"
+import { Suspense } from "react"
import {
getBreakfastPackages,
getCreditCardsSafely,
getHotelData,
+ getPackages,
getProfileSafely,
getSelectedRoomAvailability,
} from "@/lib/trpc/memoizedRequests"
@@ -13,16 +13,21 @@ import {
import BedType from "@/components/HotelReservation/EnterDetails/BedType"
import Breakfast from "@/components/HotelReservation/EnterDetails/Breakfast"
import Details from "@/components/HotelReservation/EnterDetails/Details"
+import HotelHeader from "@/components/HotelReservation/EnterDetails/Header"
import HistoryStateManager from "@/components/HotelReservation/EnterDetails/HistoryStateManager"
import Payment from "@/components/HotelReservation/EnterDetails/Payment"
import SectionAccordion from "@/components/HotelReservation/EnterDetails/SectionAccordion"
import SelectedRoom from "@/components/HotelReservation/EnterDetails/SelectedRoom"
+import Summary from "@/components/HotelReservation/EnterDetails/Summary"
import {
generateChildrenString,
getQueryParamsForEnterDetails,
} from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import { getIntl } from "@/i18n"
-import StepsProvider from "@/providers/StepsProvider"
+import { setLang } from "@/i18n/serverContext"
+import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
+
+import styles from "./page.module.css"
import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { StepEnum } from "@/types/enums/step"
@@ -36,60 +41,78 @@ export default async function StepPage({
params: { lang },
searchParams,
}: PageArgs) {
+ if (!isValidStep(searchParams.step)) {
+ return notFound()
+ }
+ setLang(lang)
+
const intl = await getIntl()
const selectRoomParams = new URLSearchParams(searchParams)
+ // Deleting step to avoid double searchparams after rewrite
selectRoomParams.delete("step")
- const searchParamsString = selectRoomParams.toString()
+ const booking = getQueryParamsForEnterDetails(selectRoomParams)
+
const {
hotel: hotelId,
- rooms,
+ rooms: [
+ { adults, children, roomTypeCode, rateCode, packages: packageCodes },
+ ], // TODO: Handle multiple rooms
fromDate,
toDate,
- } = getQueryParamsForEnterDetails(selectRoomParams)
-
- const {
- adults,
- children,
- roomTypeCode,
- rateCode,
- packages: packageCodes,
- } = rooms[0] // TODO: Handle multiple rooms
+ } = booking
const childrenAsString = children && generateChildrenString(children)
-
const breakfastInput = { adults, fromDate, hotelId, toDate }
- void getBreakfastPackages(breakfastInput)
- void getSelectedRoomAvailability({
- hotelId,
+ const selectedRoomAvailabilityInput = {
adults,
children: childrenAsString,
+ hotelId,
+ packageCodes,
+ rateCode,
roomStayStartDate: fromDate,
roomStayEndDate: toDate,
- rateCode,
roomTypeCode,
- packageCodes,
- })
+ }
- const roomAvailability = await getSelectedRoomAvailability({
- hotelId,
- adults,
- children: childrenAsString,
- roomStayStartDate: fromDate,
- roomStayEndDate: toDate,
- rateCode,
- roomTypeCode,
- packageCodes,
- })
+ void getProfileSafely()
+ void getCreditCardsSafely()
+ void getBreakfastPackages(breakfastInput)
+ void getSelectedRoomAvailability(selectedRoomAvailabilityInput)
+ if (packageCodes?.length) {
+ void getPackages({
+ adults,
+ children: children?.length,
+ endDate: toDate,
+ hotelId,
+ packageCodes,
+ startDate: fromDate,
+ })
+ }
+
+ const packages = packageCodes
+ ? await getPackages({
+ adults,
+ children: children?.length,
+ endDate: toDate,
+ hotelId,
+ packageCodes,
+ startDate: fromDate,
+ })
+ : null
+
+ const roomAvailability = await getSelectedRoomAvailability(
+ selectedRoomAvailabilityInput
+ )
const hotelData = await getHotelData({
hotelId,
- language: lang,
isCardOnlyPayment: roomAvailability?.mustBeGuaranteed,
+ language: lang,
})
const breakfastPackages = await getBreakfastPackages(breakfastInput)
const user = await getProfileSafely()
const savedCreditCards = await getCreditCardsSafely()
- if (!isValidStep(searchParams.step) || !hotelData || !roomAvailability) {
+ if (!hotelData || !roomAvailability) {
return notFound()
}
@@ -121,66 +144,96 @@ export default async function StepPage({
: undefined
return (
-
-
-
-
+
+
+
+
+
+
+
- {/* TODO: How to handle no beds found? */}
- {roomAvailability.bedTypes ? (
-
-
-
- ) : null}
+ {/* TODO: How to handle no beds found? */}
+ {roomAvailability.bedTypes ? (
+
+
+
+ ) : null}
- {breakfastPackages?.length ? (
-
-
-
- ) : null}
+ {breakfastPackages?.length ? (
+
+
+
+ ) : null}
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
)
}
diff --git a/app/[lang]/(live)/layout.tsx b/app/[lang]/(live)/layout.tsx
index 511e59469..353273141 100644
--- a/app/[lang]/(live)/layout.tsx
+++ b/app/[lang]/(live)/layout.tsx
@@ -9,6 +9,7 @@ import TrpcProvider from "@/lib/trpc/Provider"
import TokenRefresher from "@/components/Auth/TokenRefresher"
import AdobeSDKScript from "@/components/Current/AdobeSDKScript"
import VwoScript from "@/components/Current/VwoScript"
+import StorageCleaner from "@/components/HotelReservation/EnterDetails/StorageCleaner"
import { ToastHandler } from "@/components/TempDesignSystem/Toasts"
import { preloadUserTracking } from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
@@ -64,6 +65,7 @@ export default async function RootLayout({
{footer}
+