diff --git a/__mocks__/hotelReservation/index.ts b/__mocks__/hotelReservation/index.ts
index c566acad1..8b3c621e9 100644
--- a/__mocks__/hotelReservation/index.ts
+++ b/__mocks__/hotelReservation/index.ts
@@ -22,7 +22,7 @@ export const booking: SelectRateSearchParams = {
rooms: [
{
adults: 2,
- roomTypeCode: "",
+ roomTypeCode: "SKS",
rateCode: "",
counterRateCode: "",
childrenInRoom: [{ bed: ChildBedMapEnum.IN_EXTRA_BED, age: 5 }],
@@ -30,7 +30,7 @@ export const booking: SelectRateSearchParams = {
},
{
adults: 2,
- roomTypeCode: "",
+ roomTypeCode: "SKS",
rateCode: "",
counterRateCode: "",
childrenInRoom: [{ bed: ChildBedMapEnum.IN_EXTRA_BED, age: 5 }],
@@ -128,6 +128,16 @@ export const bedType: { [x: string]: BedTypeSelection } = {
},
extraBed: undefined,
},
+ single: {
+ type: BedTypeEnum.Single,
+ description: "Single bed",
+ size: {
+ max: 140,
+ min: 100,
+ },
+ value: "CSR",
+ extraBed: undefined,
+ },
}
export const guestDetailsNonMember: DetailsSchema = {
diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx
index 1fd366a7a..16e01506f 100644
--- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx
+++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx
@@ -151,7 +151,7 @@ export default async function DetailsPage({
// }
const showBreakfastStep = Boolean(
- breakfastPackages?.length && !roomsData[0].breakfastIncluded
+ breakfastPackages?.length && !roomsData[0]?.breakfastIncluded
)
return (
@@ -244,11 +244,11 @@ export default async function DetailsPage({
diff --git a/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx b/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx
index 6c8620ce6..81510f33d 100644
--- a/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx
+++ b/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx
@@ -9,7 +9,7 @@ import LoadingSpinner from "@/components/LoadingSpinner"
import { trackPaymentEvent } from "@/utils/tracking"
import { convertObjToSearchParams } from "@/utils/url"
-// import type { PersistedState } from "@/types/stores/enter-details"
+import type { PersistedState } from "@/types/stores/enter-details"
export default function PaymentCallback({
returnUrl,
@@ -28,7 +28,7 @@ export default function PaymentCallback({
const bookingData = window.sessionStorage.getItem(detailsStorageName)
if (bookingData) {
- const detailsStorage: any = JSON.parse(bookingData) // TODO: fix type here
+ const detailsStorage: PersistedState = JSON.parse(bookingData)
const searchParams = convertObjToSearchParams(
detailsStorage.booking,
searchObject
diff --git a/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx b/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx
index d0800ba65..e6c607f12 100644
--- a/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx
+++ b/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx
@@ -78,16 +78,14 @@ export default function SectionAccordion({
function close() {
setIsOpen(false)
- const isLastStep = step === StepEnum.details
- const hasNextRoom = roomIndex + 1 <= roomStatuses.length
- if (!isLastStep) {
- const nextStep = selectNextStep(roomStatus)
- if (nextStep) {
- setStep(nextStep, roomIndex)
- }
- } else if (isLastStep && hasNextRoom) {
- setStep(StepEnum.selectBed, roomIndex + 1)
+ const nextRoom = roomStatuses.find((room) => !room.isComplete)
+ const nextStep = nextRoom
+ ? Object.values(nextRoom.steps).find((step) => !step.isValid)?.step
+ : null
+
+ if (nextRoom !== undefined && nextStep !== undefined) {
+ setStep(nextStep, roomStatuses.indexOf(nextRoom))
} else {
// Time for payment, collapse any open step
setStep(null)
diff --git a/components/HotelReservation/EnterDetails/SelectedRoom/index.tsx b/components/HotelReservation/EnterDetails/SelectedRoom/index.tsx
index 76ca0f10d..e9c28348a 100644
--- a/components/HotelReservation/EnterDetails/SelectedRoom/index.tsx
+++ b/components/HotelReservation/EnterDetails/SelectedRoom/index.tsx
@@ -36,9 +36,7 @@ export default function SelectedRoom({
function changeRoom() {
modifyRate(roomIndex)
startTransition(() => {
- const newSearchParams = new URLSearchParams(searchParamsStr)
- newSearchParams.set("modifyRateIndex", roomIndex.toString())
- router.push(`${selectRate(lang)}?${newSearchParams.toString()}`)
+ router.push(`${selectRate(lang)}?${searchParamsStr}`)
})
}
diff --git a/providers/EnterDetailsProvider.tsx b/providers/EnterDetailsProvider.tsx
index 916e96689..ee5a7df63 100644
--- a/providers/EnterDetailsProvider.tsx
+++ b/providers/EnterDetailsProvider.tsx
@@ -3,7 +3,8 @@ import { useEffect, useRef } from "react"
import { createDetailsStore } from "@/stores/enter-details"
import {
- checkIsSameRoom,
+ checkIsSameBedTypes,
+ checkIsSameBooking as checkIsSameBooking,
clearSessionStorage,
readFromSessionStorage,
} from "@/stores/enter-details/helpers"
@@ -11,6 +12,7 @@ import {
import { DetailsContext } from "@/contexts/Details"
import type { DetailsStore } from "@/types/contexts/enter-details"
+import { StepEnum } from "@/types/enums/step"
import type { DetailsProviderProps } from "@/types/providers/enter-details"
import type { InitialState } from "@/types/stores/enter-details"
@@ -58,19 +60,73 @@ export default function EnterDetailsProvider({
if (!storedValues) {
return
}
- const isSameRoom = checkIsSameRoom(storedValues.booking, booking)
- if (!isSameRoom) {
+ const isSameBooking = checkIsSameBooking(storedValues.booking, booking)
+ if (!isSameBooking) {
clearSessionStorage()
return
}
- const state = storeRef.current?.getState()
- storeRef.current?.setState({
- ...state,
- rooms: storedValues.rooms,
- bookingProgress: storedValues.bookingProgress,
+ const updatedRooms = storedValues.rooms.map((storedRoom, idx) => {
+ const currentRoom = booking.rooms[idx]
+ const roomData = roomsData[idx]
+
+ if (!storedRoom.bedType) {
+ return storedRoom
+ }
+
+ const isSameBedTypes = checkIsSameBedTypes(
+ storedRoom.bedType.roomTypeCode,
+ currentRoom.roomTypeCode
+ )
+ if (isSameBedTypes) {
+ return storedRoom
+ }
+
+ if (roomData?.bedTypes?.length === 1 && roomData.bedTypes[0]) {
+ return {
+ ...storedRoom,
+ bedType: {
+ roomTypeCode: roomData.bedTypes[0].value,
+ description: roomData.bedTypes[0].description,
+ },
+ }
+ }
+
+ // Remove bed type selection if bedtypes change
+ return {
+ ...storedRoom,
+ bedType: undefined,
+ }
})
- }, [booking])
+
+ const updatedProgress = {
+ ...storedValues.bookingProgress,
+ roomStatuses: storedValues.bookingProgress.roomStatuses.map(
+ (status, idx) => {
+ const hasValidBedType = Boolean(updatedRooms[idx].bedType)
+ if (hasValidBedType) return status
+
+ return {
+ ...status,
+ steps: {
+ ...status.steps,
+ [StepEnum.selectBed]: {
+ step: StepEnum.selectBed,
+ isValid: false,
+ },
+ },
+ currentStep: StepEnum.selectBed,
+ isComplete: false,
+ }
+ }
+ ),
+ }
+
+ storeRef.current?.setState({
+ rooms: updatedRooms,
+ bookingProgress: updatedProgress,
+ })
+ }, [booking, roomsData])
return (
diff --git a/stores/enter-details/helpers.ts b/stores/enter-details/helpers.ts
index 93832c7ff..c373cc65f 100644
--- a/stores/enter-details/helpers.ts
+++ b/stores/enter-details/helpers.ts
@@ -27,19 +27,26 @@ export function extractGuestFromUser(user: NonNullable) {
}
}
-export function checkIsSameRoom(
+export function checkIsSameBedTypes(
+ storedBedTypes: string,
+ bedTypesData: string
+) {
+ return storedBedTypes === bedTypesData
+}
+
+export function checkIsSameBooking(
prev: SelectRateSearchParams,
next: SelectRateSearchParams
) {
const { rooms: prevRooms, ...prevBooking } = prev
const prevRoomsWithoutRateCodes = prevRooms.map(
- ({ rateCode, counterRateCode, ...room }) => room
+ ({ rateCode, counterRateCode, roomTypeCode, ...room }) => room
)
const { rooms: nextRooms, ...nextBooking } = next
const nextRoomsWithoutRateCodes = nextRooms.map(
- ({ rateCode, counterRateCode, ...room }) => room
+ ({ rateCode, counterRateCode, roomTypeCode, ...room }) => room
)
return isEqual(
@@ -313,8 +320,9 @@ export function handleStepProgression(state: DetailsState) {
const roomStatus = selectRoomStatus(state)
if (roomStatus.isComplete) {
- const nextRoomIndex = state.bookingProgress.currentRoomIndex + 1
-
+ const nextRoomIndex = state.bookingProgress.roomStatuses.findIndex(
+ (room) => !room.isComplete
+ )
roomStatus.lastCompletedStep = roomStatus.currentStep ?? undefined
roomStatus.currentStep = null
const nextRoomStatus = selectRoomStatus(state, nextRoomIndex)
diff --git a/stores/enter-details/useEnterDetailsStore.test.tsx b/stores/enter-details/useEnterDetailsStore.test.tsx
index 261b68da2..5519f4835 100644
--- a/stores/enter-details/useEnterDetailsStore.test.tsx
+++ b/stores/enter-details/useEnterDetailsStore.test.tsx
@@ -1,5 +1,5 @@
import { describe, expect, test } from "@jest/globals"
-import { act, renderHook } from "@testing-library/react"
+import { act, renderHook, waitFor } from "@testing-library/react"
import { type PropsWithChildren } from "react"
import { Lang } from "@/constants/languages"
@@ -18,6 +18,8 @@ import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
import { selectRoom, selectRoomStatus } from "./helpers"
import { detailsStorageName, useEnterDetailsStore } from "."
+import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType"
+import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { StepEnum } from "@/types/enums/step"
import type { PersistedState } from "@/types/stores/enter-details"
@@ -38,7 +40,8 @@ interface CreateWrapperParams {
showBreakfastStep?: boolean
breakfastIncluded?: boolean
mustBeGuaranteed?: boolean
- onlyOneBedType?: boolean
+ bookingParams?: SelectRateSearchParams
+ bedTypes?: BedTypeSelection[]
}
function createWrapper(params: Partial = {}) {
@@ -46,19 +49,18 @@ function createWrapper(params: Partial = {}) {
showBreakfastStep = true,
breakfastIncluded = false,
mustBeGuaranteed = false,
- onlyOneBedType = false,
+ bookingParams = booking,
+ bedTypes = [bedType.king, bedType.queen],
} = params
return function Wrapper({ children }: PropsWithChildren) {
return (
= {}) {
roomRate: roomRate,
},
{
- bedTypes: onlyOneBedType
- ? [bedType.king]
- : [bedType.king, bedType.queen],
+ bedTypes,
packages: null,
mustBeGuaranteed,
breakfastIncluded,
@@ -95,102 +95,104 @@ describe("Enter Details Store", () => {
window.sessionStorage.clear()
})
- test("initialize with correct default values", () => {
- const { result } = renderHook(
- () => useEnterDetailsStore((state) => state),
- {
- wrapper: createWrapper(),
- }
- )
- const state = result.current
+ describe("initial state", () => {
+ test("initialize with correct default values", () => {
+ const { result } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper(),
+ }
+ )
+ const state = result.current
- expect(state.booking).toEqual(booking)
- expect(state.breakfast).toEqual(undefined)
+ expect(state.booking).toEqual(booking)
+ expect(state.breakfast).toEqual(undefined)
- // room 1
- const room1Status = selectRoomStatus(result.current, 0)
- const room1 = selectRoom(result.current, 0)
+ // room 1
+ const room1Status = selectRoomStatus(result.current, 0)
+ const room1 = selectRoom(result.current, 0)
- expect(room1Status.currentStep).toBe(StepEnum.selectBed)
+ expect(room1Status.currentStep).toBe(StepEnum.selectBed)
- expect(room1.roomPrice.perNight.local.price).toEqual(
- roomRate.publicRate.localPrice.pricePerNight
- )
- expect(room1.bedType).toEqual(undefined)
- expect(Object.values(room1.guest).every((value) => value === ""))
+ expect(room1.roomPrice.perNight.local.price).toEqual(
+ roomRate.publicRate.localPrice.pricePerNight
+ )
+ expect(room1.bedType).toEqual(undefined)
+ expect(Object.values(room1.guest).every((value) => value === ""))
- // room 2
- const room2Status = selectRoomStatus(result.current, 1)
- const room2 = selectRoom(result.current, 1)
+ // room 2
+ const room2Status = selectRoomStatus(result.current, 1)
+ const room2 = selectRoom(result.current, 1)
- expect(room2Status.currentStep).toBe(null)
- expect(room2.roomPrice.perNight.local.price).toEqual(
- room2.roomRate.publicRate.localPrice.pricePerNight
- )
- expect(room2.bedType).toEqual(undefined)
- expect(Object.values(room2.guest).every((value) => value === ""))
- })
+ expect(room2Status.currentStep).toBe(null)
+ expect(room2.roomPrice.perNight.local.price).toEqual(
+ room2.roomRate.publicRate.localPrice.pricePerNight
+ )
+ expect(room2.bedType).toEqual(undefined)
+ expect(Object.values(room2.guest).every((value) => value === ""))
+ })
- test("initialize with correct values from session storage", () => {
- const storage: PersistedState = {
- booking: booking,
- bookingProgress: {
- currentRoomIndex: 0,
- canProceedToPayment: true,
- roomStatuses: [
- {
- isComplete: false,
- currentStep: StepEnum.selectBed,
- lastCompletedStep: undefined,
- steps: {
- [StepEnum.selectBed]: {
- step: StepEnum.selectBed,
- isValid: true,
- },
- [StepEnum.breakfast]: {
- step: StepEnum.breakfast,
- isValid: true,
- },
- [StepEnum.details]: {
- step: StepEnum.details,
- isValid: true,
+ test("initialize with correct values from session storage", () => {
+ const storage: PersistedState = {
+ booking: booking,
+ bookingProgress: {
+ currentRoomIndex: 0,
+ canProceedToPayment: true,
+ roomStatuses: [
+ {
+ isComplete: false,
+ currentStep: StepEnum.selectBed,
+ lastCompletedStep: undefined,
+ steps: {
+ [StepEnum.selectBed]: {
+ step: StepEnum.selectBed,
+ isValid: true,
+ },
+ [StepEnum.breakfast]: {
+ step: StepEnum.breakfast,
+ isValid: true,
+ },
+ [StepEnum.details]: {
+ step: StepEnum.details,
+ isValid: true,
+ },
},
},
+ ],
+ },
+ rooms: [
+ {
+ roomFeatures: null,
+ roomRate: roomRate,
+ roomType: "Classic Double",
+ cancellationText: "Non-refundable",
+ rateDetails: [],
+ bedType: {
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ },
+ adults: 1,
+ childrenInRoom: [],
+ breakfast: breakfastPackage,
+ guest: guestDetailsNonMember,
+ roomPrice: roomPrice,
},
],
- },
- rooms: [
- {
- roomFeatures: null,
- roomRate: roomRate,
- roomType: "Classic Double",
- cancellationText: "Non-refundable",
- rateDetails: [],
- bedType: {
- roomTypeCode: bedType.king.value,
- description: bedType.king.description,
- },
- adults: 1,
- childrenInRoom: [],
- breakfast: breakfastPackage,
- guest: guestDetailsNonMember,
- roomPrice: roomPrice,
- },
- ],
- }
-
- window.sessionStorage.setItem(detailsStorageName, JSON.stringify(storage))
-
- const { result } = renderHook(
- () => useEnterDetailsStore((state) => state),
- {
- wrapper: createWrapper(),
}
- )
- expect(result.current.booking).toEqual(storage.booking)
- expect(result.current.rooms[0]).toEqual(storage.rooms[0])
- expect(result.current.bookingProgress).toEqual(storage.bookingProgress)
+ window.sessionStorage.setItem(detailsStorageName, JSON.stringify(storage))
+
+ const { result } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper(),
+ }
+ )
+
+ expect(result.current.booking).toEqual(storage.booking)
+ expect(result.current.rooms[0]).toEqual(storage.rooms[0])
+ expect(result.current.bookingProgress).toEqual(storage.bookingProgress)
+ })
})
test("add bedtype and proceed to next step", async () => {
@@ -349,86 +351,6 @@ describe("Enter Details Store", () => {
expect(result.current.bookingProgress.currentRoomIndex).toEqual(1)
})
- test("total price should be set properly", async () => {
- const { result } = renderHook(
- () => useEnterDetailsStore((state) => state),
- {
- wrapper: createWrapper(),
- }
- )
-
- const publicRate = roomRate.publicRate.localPrice.pricePerStay
- const memberRate = roomRate.memberRate?.localPrice.pricePerStay ?? 0
-
- const initialTotalPrice = publicRate * result.current.rooms.length
- expect(result.current.totalPrice.local.price).toEqual(initialTotalPrice)
-
- // room 1
- await act(async () => {
- result.current.actions.updateBedType({
- roomTypeCode: bedType.king.value,
- description: bedType.king.description,
- })
- result.current.actions.updateBreakfast(breakfastPackage)
- })
-
- let expectedTotalPrice =
- initialTotalPrice + Number(breakfastPackage.localPrice.price)
- expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
-
- await act(async () => {
- result.current.actions.updateDetails(guestDetailsMember)
- })
-
- expectedTotalPrice =
- memberRate + publicRate + Number(breakfastPackage.localPrice.price)
- expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
-
- // room 2
- await act(async () => {
- result.current.actions.updateBedType({
- roomTypeCode: bedType.king.value,
- description: bedType.king.description,
- })
- result.current.actions.updateBreakfast(breakfastPackage)
- })
-
- expectedTotalPrice =
- memberRate + publicRate + Number(breakfastPackage.localPrice.price) * 2
- expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
-
- await act(async () => {
- result.current.actions.updateDetails(guestDetailsNonMember)
- })
-
- expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
- })
-
- test("room price should be set properly", async () => {
- const { result } = renderHook(
- () => useEnterDetailsStore((state) => state),
- {
- wrapper: createWrapper(),
- }
- )
-
- const publicRate = roomRate.publicRate.localPrice.pricePerStay
- const memberRate = roomRate.memberRate?.localPrice.pricePerStay ?? 0
-
- let room1 = selectRoom(result.current, 0)
- expect(room1.roomPrice.perStay.local.price).toEqual(publicRate)
-
- let room2 = selectRoom(result.current, 0)
- expect(room2.roomPrice.perStay.local.price).toEqual(publicRate)
-
- await act(async () => {
- result.current.actions.updateDetails(guestDetailsMember)
- })
-
- room1 = selectRoom(result.current, 0)
- expect(room1.roomPrice.perStay.local.price).toEqual(memberRate)
- })
-
test("breakfast step should be hidden when breakfast is included", async () => {
const { result } = renderHook(
() => useEnterDetailsStore((state) => state),
@@ -448,7 +370,7 @@ describe("Enter Details Store", () => {
const { result } = renderHook(
() => useEnterDetailsStore((state) => state),
{
- wrapper: createWrapper({ onlyOneBedType: true }),
+ wrapper: createWrapper({ bedTypes: [bedType.queen] }),
}
)
@@ -460,4 +382,252 @@ describe("Enter Details Store", () => {
expect(room2Status.steps[StepEnum.selectBed].isValid).toEqual(true)
expect(room2Status.currentStep).toEqual(null)
})
+
+ describe("price calculation", () => {
+ test("total price should be set properly", async () => {
+ const { result } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper(),
+ }
+ )
+
+ const publicRate = roomRate.publicRate.localPrice.pricePerStay
+ const memberRate = roomRate.memberRate?.localPrice.pricePerStay ?? 0
+
+ const initialTotalPrice = publicRate * result.current.rooms.length
+ expect(result.current.totalPrice.local.price).toEqual(initialTotalPrice)
+
+ // room 1
+ await act(async () => {
+ result.current.actions.updateBedType({
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ })
+ result.current.actions.updateBreakfast(breakfastPackage)
+ })
+
+ let expectedTotalPrice =
+ initialTotalPrice + Number(breakfastPackage.localPrice.price)
+ expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
+
+ await act(async () => {
+ result.current.actions.updateDetails(guestDetailsMember)
+ })
+
+ expectedTotalPrice =
+ memberRate + publicRate + Number(breakfastPackage.localPrice.price)
+ expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
+
+ // room 2
+ await act(async () => {
+ result.current.actions.updateBedType({
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ })
+ result.current.actions.updateBreakfast(breakfastPackage)
+ })
+
+ expectedTotalPrice =
+ memberRate + publicRate + Number(breakfastPackage.localPrice.price) * 2
+ expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
+
+ await act(async () => {
+ result.current.actions.updateDetails(guestDetailsNonMember)
+ })
+
+ expect(result.current.totalPrice.local.price).toEqual(expectedTotalPrice)
+ })
+
+ test("room price should be set properly", async () => {
+ const { result } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper(),
+ }
+ )
+
+ const publicRate = roomRate.publicRate.localPrice.pricePerStay
+ const memberRate = roomRate.memberRate?.localPrice.pricePerStay ?? 0
+
+ let room1 = selectRoom(result.current, 0)
+ expect(room1.roomPrice.perStay.local.price).toEqual(publicRate)
+
+ let room2 = selectRoom(result.current, 0)
+ expect(room2.roomPrice.perStay.local.price).toEqual(publicRate)
+
+ await act(async () => {
+ result.current.actions.updateDetails(guestDetailsMember)
+ })
+
+ room1 = selectRoom(result.current, 0)
+ expect(room1.roomPrice.perStay.local.price).toEqual(memberRate)
+ })
+ })
+
+ describe("change room", () => {
+ test("changing to room with new bedtypes requires selecting bed again", async () => {
+ const { result: firstRun } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper({ bedTypes: [bedType.king, bedType.queen] }),
+ }
+ )
+
+ const selectedBedType = {
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ }
+
+ // add bedtype
+ await act(async () => {
+ firstRun.current.actions.updateBedType(selectedBedType)
+ })
+
+ await act(async () => {
+ firstRun.current.actions.updateBreakfast(false) // 'no breakfast' selected
+ })
+
+ await act(async () => {
+ firstRun.current.actions.updateDetails(guestDetailsNonMember)
+ })
+
+ const updatedBooking = {
+ ...booking,
+ rooms: booking.rooms.map((r) => ({
+ ...r,
+ roomTypeCode: "NEW",
+ })),
+ }
+
+ // render again to change the bedtypes
+ const { result: secondRun } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper({
+ bookingParams: updatedBooking,
+ bedTypes: [bedType.single, bedType.queen],
+ }),
+ }
+ )
+
+ await waitFor(() => {
+ const room = selectRoom(secondRun.current, 0)
+ const roomStatus = selectRoomStatus(secondRun.current, 0)
+
+ // bed type should be unset since the bed types have changed
+ expect(room.bedType).toEqual(undefined)
+
+ // bed step should be unselected
+ expect(roomStatus.currentStep).toBe(StepEnum.selectBed)
+ expect(roomStatus.steps[StepEnum.selectBed].isValid).toBe(false)
+
+ // other steps should still be selected
+ expect(room.breakfast).toBe(false)
+ expect(roomStatus.steps[StepEnum.breakfast]?.isValid).toBe(true)
+ expect(room.guest).toEqual(guestDetailsNonMember)
+ expect(roomStatus.steps[StepEnum.details].isValid).toBe(true)
+ })
+ })
+
+ test("changing to room with single bedtype option should skip step", async () => {
+ const { result: firstRun } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper({ bedTypes: [bedType.king, bedType.queen] }),
+ }
+ )
+
+ const selectedBedType = {
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ }
+
+ // add bedtype
+ await act(async () => {
+ firstRun.current.actions.updateBedType(selectedBedType)
+ })
+
+ await act(async () => {
+ firstRun.current.actions.updateBreakfast(breakfastPackage)
+ })
+
+ const updatedBooking = {
+ ...booking,
+ rooms: booking.rooms.map((r) => ({
+ ...r,
+ roomTypeCode: "NEW",
+ })),
+ }
+
+ // render again to change the bedtypes
+ const { result: secondRun } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper({
+ bookingParams: updatedBooking,
+ bedTypes: [bedType.queen],
+ }),
+ }
+ )
+
+ await waitFor(() => {
+ const room = selectRoom(secondRun.current, 0)
+ const roomStatus = selectRoomStatus(secondRun.current, 0)
+
+ expect(room.bedType).toEqual({
+ roomTypeCode: bedType.queen.value,
+ description: bedType.queen.description,
+ })
+
+ expect(roomStatus.steps[StepEnum.selectBed].isValid).toBe(true)
+ expect(roomStatus.steps[StepEnum.breakfast]?.isValid).toBe(true)
+
+ expect(roomStatus.steps[StepEnum.details].isValid).toBe(false)
+ expect(roomStatus.currentStep).toBe(StepEnum.details)
+ })
+ })
+
+ test("if booking has changed, stored values should be discarded", async () => {
+ const { result: firstRun } = renderHook(
+ () => useEnterDetailsStore((state) => state),
+ {
+ wrapper: createWrapper({ bedTypes: [bedType.king, bedType.queen] }),
+ }
+ )
+
+ const selectedBedType = {
+ roomTypeCode: bedType.king.value,
+ description: bedType.king.description,
+ }
+
+ // add bedtype
+ await act(async () => {
+ firstRun.current.actions.updateBedType(selectedBedType)
+ })
+
+ await act(async () => {
+ firstRun.current.actions.updateBreakfast(breakfastPackage)
+ })
+
+ const updatedBooking = {
+ ...booking,
+ hotelId: "0001",
+ fromDate: "2030-01-01",
+ toDate: "2030-01-02",
+ }
+
+ renderHook(() => useEnterDetailsStore((state) => state), {
+ wrapper: createWrapper({
+ bookingParams: updatedBooking,
+ bedTypes: [bedType.queen],
+ }),
+ })
+
+ await waitFor(() => {
+ const storageItem = window.sessionStorage.getItem(detailsStorageName)
+ expect(storageItem).toBe(null)
+ })
+ })
+ })
})