Merged in feat/sw-2857-refactor-booking-flow-url-updates (pull request #2302)

feat(SW-2857): Refactor booking flow url updates

* Add support for removing parameters when using initial values in serializeSearchParams

* Don't manually write search params in rate store

* Booking is already from live search params so no need

* Fix input type in serializeBookingSearchParams


Approved-by: Linus Flood
This commit is contained in:
Anton Gunnarsson
2025-06-09 09:16:22 +00:00
parent 879a383b61
commit bff34b034e
12 changed files with 189 additions and 189 deletions

View File

@@ -45,9 +45,9 @@ export function findProduct(
}
export function findProductInRoom(
rateCode: string | undefined,
rateCode: string | undefined | null,
room: RoomConfiguration,
counterRateCode = ""
counterRateCode: string | undefined | null
) {
if (!rateCode) {
return null
@@ -55,7 +55,7 @@ export function findProductInRoom(
if (room.campaign.length) {
const campaignProduct = room.campaign.find((product) =>
findProduct(rateCode, product, counterRateCode)
findProduct(rateCode, product, counterRateCode || "")
)
if (campaignProduct) {
return campaignProduct
@@ -63,7 +63,7 @@ export function findProductInRoom(
}
if (room.code.length) {
const codeProduct = room.code.find((product) =>
findProduct(rateCode, product, counterRateCode)
findProduct(rateCode, product, counterRateCode || "")
)
if (codeProduct) {
return codeProduct
@@ -79,7 +79,7 @@ export function findProductInRoom(
}
if (room.regular.length) {
const regularProduct = room.regular.find((product) =>
findProduct(rateCode, product, counterRateCode)
findProduct(rateCode, product, counterRateCode || "")
)
if (regularProduct) {
return regularProduct
@@ -88,9 +88,9 @@ export function findProductInRoom(
}
export function findSelectedRate(
rateCode: string | undefined,
counterRateCode: string | undefined,
roomTypeCode: string | undefined,
rateCode: string | undefined | null,
counterRateCode: string | undefined | null,
roomTypeCode: string | undefined | null,
rooms: RoomConfiguration[] | AvailabilityError
) {
if (!Array.isArray(rooms)) {
@@ -109,17 +109,6 @@ export function findSelectedRate(
})
}
export function clearRoomSelectionFromUrl(
roomIdx: number,
searchParams: URLSearchParams
) {
searchParams.delete(`room[${roomIdx}].bookingCode`)
searchParams.delete(`room[${roomIdx}].counterratecode`)
searchParams.delete(`room[${roomIdx}].ratecode`)
searchParams.delete(`room[${roomIdx}].roomtype`)
return searchParams
}
export function findDefaultCurrency(
roomsAvailability: (RoomsAvailability | AvailabilityError)[] | undefined
) {

View File

@@ -5,9 +5,9 @@ import { create, useStore } from "zustand"
import { REDEMPTION } from "@/constants/booking"
import { RatesContext } from "@/contexts/Rates"
import { serializeBookingSearchParams } from "@/utils/url"
import {
clearRoomSelectionFromUrl,
findDefaultCurrency,
findProductInRoom,
findSelectedRate,
@@ -27,9 +27,16 @@ export function createRatesStore({
pathname,
roomCategories,
roomsAvailability,
searchParams,
initialActiveRoom,
vat,
}: InitialState) {
function updateUrl(booking: RatesState["booking"]) {
const searchParams = serializeBookingSearchParams(booking, {
initialSearchParams: new URLSearchParams(window.location.search),
})
window.history.replaceState({}, "", `${pathname}?${searchParams}`)
}
const packageOptions = [
{
code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
@@ -73,13 +80,8 @@ export function createRatesStore({
)
if (!selectedRoom) {
const updatedSearchParams = clearRoomSelectionFromUrl(idx, searchParams)
searchParams = updatedSearchParams
window.history.replaceState(
{},
"",
`${pathname}?${updatedSearchParams}`
)
booking.rooms[idx] = roomWithoutSelection(room)
updateUrl(booking)
continue
}
@@ -108,8 +110,8 @@ export function createRatesStore({
}
let activeRoom = rateSummary.length
if (searchParams.has("modifyRateIndex")) {
activeRoom = Number(searchParams.get("modifyRateIndex"))
if (initialActiveRoom) {
activeRoom = initialActiveRoom
} else if (rateSummary.length === booking.rooms.length) {
// Finds the first unselected room and sets that to active
// if no unselected rooms it will return -1 and close all rooms
@@ -128,13 +130,11 @@ export function createRatesStore({
packageOptions,
hotelType,
isRedemptionBooking,
pathname,
rateSummary,
roomConfigurations,
roomCategories,
roomsPackages,
roomsAvailability,
searchParams,
vat,
defaultCurrency,
rooms: booking.rooms.map((room, idx) => {
@@ -266,23 +266,14 @@ export function createRatesStore({
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
if (filteredSelectedPackages.length) {
searchParams.set(
`room[${idx}].packages`,
filteredSelectedPackages.map((pkg) => pkg.code).join(",")
)
state.booking.rooms[idx].packages =
filteredSelectedPackages.map((pkg) => pkg.code)
} else {
searchParams.delete(`room[${idx}].packages`)
state.booking.rooms[idx].packages = null
}
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
updateUrl(state.booking)
})
)
},
@@ -300,36 +291,8 @@ export function createRatesStore({
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
searchParams.delete(`room[${idx}].packages`)
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
})
)
},
removeSelectedRoom() {
return set(
produce((state: RatesState) => {
state.rateSummary[idx] = null
const searchParams = state.searchParams
searchParams.delete(`room[${idx}].counterratecode`)
searchParams.delete(`room[${idx}].ratecode`)
searchParams.delete(`room[${idx}].roomtype`)
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
state.booking.rooms[idx].packages = null
updateUrl(state.booking)
})
)
},
@@ -408,43 +371,33 @@ export function createRatesStore({
state.rooms[idx].bookingRoom.bookingCode =
selectedRate.product.bookingCode
const searchParams = new URLSearchParams(state.searchParams)
const counterratecode = isMemberRate
? productRateCode
: memberRateCode
if (counterratecode) {
searchParams.set(
`room[${idx}].counterratecode`,
counterratecode
)
state.booking.rooms[idx].counterRateCode = counterratecode
} else {
if (searchParams.has(`room[${idx}].counterratecode`)) {
searchParams.delete(`room[${idx}].counterratecode`)
}
state.booking.rooms[idx].counterRateCode = null
}
const rateCode = isMemberRate
? memberRateCode
: productRateCode
if (rateCode) {
searchParams.set(`room[${idx}].ratecode`, rateCode)
state.booking.rooms[idx].rateCode = rateCode
}
if (selectedRate.product.bookingCode) {
searchParams.set(
`room[${idx}].bookingCode`,
state.booking.rooms[idx].bookingCode =
selectedRate.product.bookingCode
)
} else {
if (searchParams.has(`room[${idx}].bookingCode`)) {
searchParams.delete(`room[${idx}].bookingCode`)
if (state.booking.rooms[idx].bookingCode) {
state.booking.rooms[idx].bookingCode = null
}
}
searchParams.set(
`room[${idx}].roomtype`,
state.booking.rooms[idx].roomTypeCode =
selectedRate.roomTypeCode
)
if (state.rateSummary.length === state.booking.rooms.length) {
state.activeRoom = -1
@@ -452,13 +405,7 @@ export function createRatesStore({
state.activeRoom = idx + 1
}
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
updateUrl(state.booking)
})
)
},
@@ -479,23 +426,13 @@ export function createRatesStore({
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
if (selectedPackages.length) {
searchParams.set(
`room[${idx}].packages`,
selectedPackages.join(",")
)
state.booking.rooms[idx].packages = selectedPackages
} else {
searchParams.delete(`room[${idx}].packages`)
state.booking.rooms[idx].packages = null
}
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
updateUrl(state.booking)
})
)
},
@@ -519,36 +456,27 @@ export function createRatesStore({
rateSummaryRoom.packages =
state.rooms[idx].selectedPackages
} else {
const searchParams = clearRoomSelectionFromUrl(
idx,
state.searchParams
state.booking.rooms[idx] = roomWithoutSelection(
state.booking.rooms[idx]
)
state.searchParams = searchParams
state.rateSummary[idx] = null
state.rooms[idx].selectedRate = null
window.history.replaceState(
{},
"",
`${pathname}?${searchParams}`
)
updateUrl(state.booking)
}
}
} else {
state.rooms[idx].rooms = []
if (state.rateSummary[idx]) {
const searchParams = clearRoomSelectionFromUrl(
idx,
state.searchParams
state.booking.rooms[idx] = roomWithoutSelection(
state.booking.rooms[idx]
)
state.searchParams = searchParams
state.rateSummary[idx] = null
state.rooms[idx].selectedRate = null
window.history.replaceState(
{},
"",
`${pathname}?${searchParams}`
)
updateUrl(state.booking)
}
}
})
@@ -587,3 +515,15 @@ export function useRatesStore<T>(selector: (store: RatesState) => T) {
return useStore(store, selector)
}
function roomWithoutSelection(
room: RatesState["booking"]["rooms"][number]
): RatesState["booking"]["rooms"][number] {
return {
...room,
rateCode: null,
counterRateCode: null,
roomTypeCode: null,
bookingCode: null,
}
}