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) + }) + }) + }) })