diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Room/PricesAndAvailabilityButton/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Room/PricesAndAvailabilityButton/index.tsx
index 83d210465..64cd242dd 100644
--- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Room/PricesAndAvailabilityButton/index.tsx
+++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Room/PricesAndAvailabilityButton/index.tsx
@@ -1,7 +1,8 @@
"use client"
+import { useBookingWidgetState } from "@scandic-hotels/booking-flow/hooks/useBookingWidgetState"
+import { serializeBookingSearchParams } from "@scandic-hotels/booking-flow/utils/url"
import { selectRateWithParams } from "@scandic-hotels/common/constants/routes/hotelReservation"
-import { dt } from "@scandic-hotels/common/dt"
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
import useLang from "@/hooks/useLang"
@@ -15,9 +16,15 @@ export default function PricesAndAvailabilityButton({
label,
}: PricesAndAvailabilityProps) {
const lang = useLang()
- const fromdate = dt().format("YYYY-MM-DD")
- const todate = dt().add(1, "day").format("YYYY-MM-DD")
- const selectRateURL = selectRateWithParams(lang, hotelId, fromdate, todate)
+ const { fromDate, toDate, rooms } = useBookingWidgetState()
+
+ const params = serializeBookingSearchParams({
+ hotelId,
+ fromDate,
+ toDate,
+ rooms,
+ })
+ const selectRateURL = selectRateWithParams(lang, params)
const { name, roomTypes } = room
diff --git a/packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm/index.tsx b/packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm/index.tsx
index 4091d9441..12952f6b0 100644
--- a/packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm/index.tsx
+++ b/packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm/index.tsx
@@ -13,6 +13,7 @@ import {
import { trackBookingSearchClick } from "@scandic-hotels/tracking/booking"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
+import { setBookingWidgetState } from "../../../hooks/useBookingWidgetState"
import useLang from "../../../hooks/useLang"
import {
BookingCodeFilterEnum,
@@ -68,7 +69,11 @@ export default function Form({ type, onClose }: BookingWidgetFormProps) {
// Followed current url structure to keep searchtype=redemption param incase of reward night
...(data.redemption ? { searchType: SEARCH_TYPE_REDEMPTION } : {}),
})
-
+ setBookingWidgetState({
+ fromDate: data.date.fromDate,
+ toDate: data.date.toDate,
+ rooms: data.rooms,
+ })
onClose()
startTransition(() => {
router.push(`${bookingFlowPage}?${bookingWidgetParams.toString()}`)
diff --git a/packages/booking-flow/lib/components/BookingWidget/Client.tsx b/packages/booking-flow/lib/components/BookingWidget/Client.tsx
index 1007f935c..825391c3b 100644
--- a/packages/booking-flow/lib/components/BookingWidget/Client.tsx
+++ b/packages/booking-flow/lib/components/BookingWidget/Client.tsx
@@ -15,6 +15,7 @@ import { trpc } from "@scandic-hotels/trpc/client"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { useBookingFlowConfig } from "../../bookingFlowConfig/bookingFlowConfigContext"
+import { useBookingWidgetState } from "../../hooks/useBookingWidgetState"
import useLang from "../../hooks/useLang"
import {
type bookingCodeSchema,
@@ -54,6 +55,7 @@ export default function BookingWidgetClient({
null
)
const { bookingCodeEnabled } = useBookingFlowConfig()
+ const storedBookingWidgetState = useBookingWidgetState()
const shouldFetchAutoComplete = !!data.hotelId || !!data.city
@@ -207,6 +209,24 @@ export default function BookingWidgetClient({
}
}, [methods, selectedBookingCode])
+ useEffect(() => {
+ if (
+ !data.fromDate &&
+ !data.toDate &&
+ !data.rooms &&
+ storedBookingWidgetState
+ ) {
+ methods.reset({
+ ...methods.getValues(),
+ date: {
+ fromDate: storedBookingWidgetState.fromDate,
+ toDate: storedBookingWidgetState.toDate,
+ },
+ rooms: storedBookingWidgetState.rooms,
+ })
+ }
+ }, [data, methods, storedBookingWidgetState])
+
if (shouldShowSkeleton) {
return
}
diff --git a/packages/booking-flow/lib/hooks/useBookingWidgetState.ts b/packages/booking-flow/lib/hooks/useBookingWidgetState.ts
new file mode 100644
index 000000000..fd0d16736
--- /dev/null
+++ b/packages/booking-flow/lib/hooks/useBookingWidgetState.ts
@@ -0,0 +1,92 @@
+import { useEffect, useState } from "react"
+import { z } from "zod"
+
+import { BOOKING_WIDGET_STATE } from "@scandic-hotels/common/constants/bookingWidget"
+import { dt } from "@scandic-hotels/common/dt"
+
+import { adultsSchema, childAgeSchema, childBedSchema } from "../utils/url"
+
+const DEFAULT_ROOMS = [{ adults: 1, childrenInRoom: [] }]
+
+const stateSchema = z.object({
+ fromDate: z.string(),
+ toDate: z.string(),
+ rooms: z.array(
+ z.object({
+ adults: adultsSchema,
+ childrenInRoom: z
+ .array(
+ z.object({
+ bed: childBedSchema,
+ age: childAgeSchema,
+ })
+ )
+ .optional(),
+ })
+ ),
+})
+
+type BookingWidgetState = z.infer
+
+export function useBookingWidgetState() {
+ const [bookingState, setBookingState] = useState({
+ fromDate: dt().format("YYYY-MM-DD"),
+ toDate: dt().add(1, "day").format("YYYY-MM-DD"),
+ rooms: DEFAULT_ROOMS,
+ })
+
+ useEffect(() => {
+ const now = dt()
+ const stored = getBookingWidgetState()
+ if (!stored) {
+ return
+ }
+ const storedFrom = dt(stored.fromDate)
+ const storedTo = dt(stored.toDate)
+
+ const isDateParamValid =
+ storedFrom.isValid() &&
+ storedTo.isValid() &&
+ storedFrom.isSameOrAfter(now, "day") &&
+ storedTo.isAfter(storedFrom)
+
+ if (isDateParamValid && stored.rooms?.length) {
+ setBookingState({
+ fromDate: storedFrom.format("YYYY-MM-DD"),
+ toDate: storedTo.format("YYYY-MM-DD"),
+ rooms: stored.rooms,
+ })
+ }
+ }, [])
+ return bookingState
+}
+
+function getBookingWidgetState(): BookingWidgetState | null {
+ if (typeof window === "undefined") {
+ return null
+ }
+ try {
+ const savedBookingWidgetState = sessionStorage.getItem(BOOKING_WIDGET_STATE)
+ if (savedBookingWidgetState) {
+ const stored = JSON.parse(savedBookingWidgetState)
+ return stateSchema.parse(stored)
+ }
+ } catch {
+ try {
+ sessionStorage.removeItem(BOOKING_WIDGET_STATE)
+ } catch {}
+ }
+ return null
+}
+
+export function setBookingWidgetState(state: BookingWidgetState): void {
+ if (typeof window === "undefined") {
+ return
+ }
+ try {
+ sessionStorage.setItem(
+ BOOKING_WIDGET_STATE,
+ JSON.stringify(stateSchema.parse(state))
+ )
+ } catch {}
+}
diff --git a/packages/booking-flow/lib/utils/url.ts b/packages/booking-flow/lib/utils/url.ts
index a6916a938..a66fe8a5c 100644
--- a/packages/booking-flow/lib/utils/url.ts
+++ b/packages/booking-flow/lib/utils/url.ts
@@ -39,9 +39,9 @@ const typeHints = {
filters: "COMMA_SEPARATED_ARRAY",
packages: "COMMA_SEPARATED_ARRAY",
} as const
-const adultsSchema = z.coerce.number().min(1).max(6).catch(0)
-const childAgeSchema = z.coerce.number().catch(-1)
-const childBedSchema = z.coerce.number().catch(-1)
+export const adultsSchema = z.coerce.number().min(1).max(6).catch(0)
+export const childAgeSchema = z.coerce.number().catch(-1)
+export const childBedSchema = z.coerce.number().catch(-1)
const searchTypeSchema = z.enum(bookingSearchTypes).optional().catch(undefined)
export function parseBookingWidgetSearchParams(
diff --git a/packages/booking-flow/package.json b/packages/booking-flow/package.json
index 4bec39e97..78cca3d0e 100644
--- a/packages/booking-flow/package.json
+++ b/packages/booking-flow/package.json
@@ -28,6 +28,7 @@
"./components/SidePeekAccordions/ParkingAccordionItem": "./lib/components/SidePeekAccordions/ParkingAccordionItem.tsx",
"./global.d.ts": "./global.d.ts",
"./hooks/useHandleBookingStatus": "./lib/hooks/useHandleBookingStatus.ts",
+ "./hooks/useBookingWidgetState": "./lib/hooks/useBookingWidgetState.ts",
"./pages/*": "./lib/pages/*.tsx",
"./stores/enter-details/types": "./lib/stores/enter-details/types.ts",
"./stores/hotels-map": "./lib/stores/hotels-map.ts",
diff --git a/packages/common/constants/bookingWidget.ts b/packages/common/constants/bookingWidget.ts
new file mode 100644
index 000000000..944106284
--- /dev/null
+++ b/packages/common/constants/bookingWidget.ts
@@ -0,0 +1 @@
+export const BOOKING_WIDGET_STATE = "bookingWidgetState"
diff --git a/packages/common/constants/routes/hotelReservation.ts b/packages/common/constants/routes/hotelReservation.ts
index a4a646e51..bdb771b3e 100644
--- a/packages/common/constants/routes/hotelReservation.ts
+++ b/packages/common/constants/routes/hotelReservation.ts
@@ -27,14 +27,8 @@ export function selectHotel(lang: Lang) {
export function selectHotelMap(lang: Lang) {
return `${hotelreservation(lang)}/select-hotel/map`
}
-
-export function selectRateWithParams(
- lang: Lang,
- hotelId: string,
- fromdate: string,
- todate: string
-) {
- return `${hotelreservation(lang)}/select-rate?room%5B0%5D.adults=1&fromdate=${fromdate}&todate=${todate}&hotel=${hotelId}`
+export function selectRateWithParams(lang: Lang, params: URLSearchParams) {
+ return `${hotelreservation(lang)}/select-rate?${params.toString()}`
}
export function alternativeHotels(lang: Lang) {
diff --git a/packages/common/package.json b/packages/common/package.json
index 840b611d1..c9654b894 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -14,6 +14,7 @@
"./polyfills": "./polyfills/index.ts",
"./constants/alert": "./constants/alert.ts",
"./constants/booking": "./constants/booking.ts",
+ "./constants/bookingWidget": "./constants/bookingWidget.ts",
"./constants/currency": "./constants/currency.ts",
"./constants/dateFormats": "./constants/dateFormats.ts",
"./constants/facilities": "./constants/facilities.ts",