feat: bedtypes is selectable again

This commit is contained in:
Simon Emanuelsson
2025-04-07 13:43:52 +02:00
committed by Michael Zetterberg
parent f62723c6e5
commit afb37d0cc5
69 changed files with 2135 additions and 2349 deletions

View File

@@ -107,15 +107,13 @@ export function isRoomPackageCode(
)
}
export function filterRoomsBySelectedPackages(
selectedPackages: RoomPackageCodeEnum[],
rooms: RoomConfiguration[]
export function clearRoomSelectionFromUrl(
roomIdx: number,
searchParams: URLSearchParams
) {
if (!selectedPackages.length) {
return rooms
}
return rooms.filter((r) =>
selectedPackages.every((pkg) => r.features.find((f) => f.code === pkg))
)
searchParams.delete(`room[${roomIdx}].bookingCode`)
searchParams.delete(`room[${roomIdx}].counterratecode`)
searchParams.delete(`room[${roomIdx}].ratecode`)
searchParams.delete(`room[${roomIdx}].roomtype`)
return searchParams
}

View File

@@ -1,12 +1,13 @@
import { produce } from "immer"
import { ReadonlyURLSearchParams } from "next/navigation"
import { useContext } from "react"
import { create, useStore } from "zustand"
import { REDEMPTION } from "@/constants/booking"
import { RatesContext } from "@/contexts/Rates"
import {
filterRoomsBySelectedPackages,
clearRoomSelectionFromUrl,
findProductInRoom,
findSelectedRate,
} from "./helpers"
@@ -14,18 +15,15 @@ import {
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import { BookingCodeFilterEnum } from "@/types/enums/bookingCodeFilter"
import { RateTypeEnum } from "@/types/enums/rateType"
import type { Package, Packages } from "@/types/requests/packages"
import type { InitialState, RatesState } from "@/types/stores/rates"
import type {
PriceProduct,
RoomConfiguration,
} from "@/types/trpc/routers/hotel/roomAvailability"
import type { PriceProduct } from "@/types/trpc/routers/hotel/roomAvailability"
export function createRatesStore({
booking,
hotelType,
isUserLoggedIn,
labels,
packages,
pathname,
roomCategories,
roomsAvailability,
@@ -36,34 +34,28 @@ export function createRatesStore({
{
code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM,
description: labels.accessibilityRoom,
itemCode: packages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM
)?.itemCode,
},
{
code: RoomPackageCodeEnum.ALLERGY_ROOM,
description: labels.allergyRoom,
itemCode: packages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.ALLERGY_ROOM
)?.itemCode,
},
{
code: RoomPackageCodeEnum.PET_ROOM,
description: labels.petRoom,
itemCode: packages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
)?.itemCode,
},
]
let roomConfigurations: RatesState["roomConfigurations"] = []
const roomsPackages: NonNullable<Packages>[] = []
const roomConfigurations: RatesState["roomConfigurations"] = []
if (roomsAvailability) {
for (const availability of roomsAvailability) {
if ("error" in availability) {
// Availability request failed, default to empty array
roomConfigurations.push([])
roomsPackages.push([])
} else {
roomConfigurations.push(availability.roomConfigurations)
roomsPackages.push(availability.packages)
}
}
}
@@ -72,21 +64,22 @@ export function createRatesStore({
for (const [idx, room] of booking.rooms.entries()) {
if (room.rateCode && room.roomTypeCode) {
const roomConfiguration = roomConfigurations?.[idx]
const selectedPackages = room.packages ?? []
let rooms: RoomConfiguration[] = filterRoomsBySelectedPackages(
selectedPackages,
roomConfiguration
)
const selectedRoom = findSelectedRate(
room.rateCode,
room.counterRateCode,
room.roomTypeCode,
rooms
roomConfiguration
)
if (!selectedRoom) {
const updatedSearchParams = clearRoomSelectionFromUrl(idx, searchParams)
searchParams = updatedSearchParams
window.history.replaceState(
{},
"",
`${pathname}?${updatedSearchParams}`
)
continue
}
@@ -99,7 +92,9 @@ export function createRatesStore({
rateSummary[idx] = {
features: selectedRoom.features,
product,
packages: room.packages ?? [],
packages: roomsPackages[idx].filter((pkg) =>
room.packages?.includes(pkg.code)
),
rate: product.rate,
roomType: selectedRoom.roomType,
roomTypeCode: selectedRoom.roomTypeCode,
@@ -126,22 +121,20 @@ export function createRatesStore({
booking,
packageOptions,
hotelType,
isRedemptionBooking: searchParams.has("searchType")
? searchParams.get("searchType") === REDEMPTION
: false,
isUserLoggedIn,
packages,
pathname,
petRoomPackage: packages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
),
rateSummary,
roomConfigurations,
rooms: booking.rooms.map((room, idx) => {
const roomConfiguration = roomConfigurations[idx]
const selectedPackages = room.packages ?? []
let rooms: RoomConfiguration[] = filterRoomsBySelectedPackages(
selectedPackages,
roomConfiguration
)
const roomPackages = roomsPackages[idx]
const selectedPackages =
room.packages
?.map((code) => roomPackages.find((pkg) => pkg.code === code))
.filter((pkg): pkg is Package => Boolean(pkg)) ?? []
const selectedRate =
findSelectedRate(
@@ -159,91 +152,63 @@ export function createRatesStore({
room.counterRateCode
)
}
let selectedFilter
const bookingCode = room.rateCode
? room.bookingCode
: booking.bookingCode
if (bookingCode) {
selectedFilter = BookingCodeFilterEnum.Discounted
} else {
selectedFilter = BookingCodeFilterEnum.Regular
}
return {
actions: {
appendRegularRates(roomConfigurations) {
return set(
produce((state: RatesState) => {
const rooms = state.rooms[idx].rooms
const updatedRooms = rooms.map((currentRoom) => {
const incomingRoom = roomConfigurations.find(
(room) =>
room.roomType === currentRoom.roomType &&
room.roomTypeCode === currentRoom.roomTypeCode
)
state.rooms[idx].isFetchingAdditionalRate = false
if (roomConfigurations) {
const rooms = state.rooms[idx].rooms
const updatedRooms = rooms.map((currentRoom) => {
const incomingRoom = roomConfigurations.find(
(room) =>
room.roomType === currentRoom.roomType &&
room.roomTypeCode === currentRoom.roomTypeCode
)
if (incomingRoom) {
let campaign = currentRoom.campaign
if (incomingRoom.campaign.length) {
const newCampaign = [
...campaign,
...incomingRoom.campaign,
].reduce((cpns, cpn) => {
if (cpns.has(cpn.rateDefinition.rateCode)) {
if (incomingRoom) {
let campaign = currentRoom.campaign
if (incomingRoom.campaign.length) {
const newCampaign = [
...campaign,
...incomingRoom.campaign,
].reduce((cpns, cpn) => {
if (cpns.has(cpn.rateDefinition.rateCode)) {
return cpns
}
cpns.set(cpn.rateDefinition.rateCode, cpn)
return cpns
}
cpns.set(cpn.rateDefinition.rateCode, cpn)
return cpns
}, new Map<string, PriceProduct>())
campaign = Array.from(newCampaign.values())
}, new Map<string, PriceProduct>())
campaign = Array.from(newCampaign.values())
}
return {
...currentRoom,
campaign,
products: [
...currentRoom.products,
...incomingRoom.products,
],
regular: incomingRoom.regular,
}
}
return {
...currentRoom,
campaign,
products: [
...currentRoom.products,
...incomingRoom.products,
],
regular: incomingRoom.regular,
}
}
return currentRoom
})
return currentRoom
})
state.rooms[idx].rooms = updatedRooms
})
)
},
addRoomFeatures(roomFeatures) {
return set(
produce((state: RatesState) => {
const selectedPackages = state.rooms[idx].selectedPackages
const rateSummaryItem = state.rateSummary[idx]
state.roomConfigurations[idx].forEach((room) => {
const features = roomFeatures.find(
(feat) => feat.roomTypeCode === room.roomTypeCode
)?.features
if (features) {
room.features = features
if (rateSummaryItem) {
rateSummaryItem.packages = selectedPackages
rateSummaryItem.features = features
}
}
})
state.rateSummary[idx] = rateSummaryItem
state.rooms[idx].rooms = filterRoomsBySelectedPackages(
selectedPackages,
state.roomConfigurations[idx]
)
const selectedRate = findSelectedRate(
room.rateCode,
room.counterRateCode,
room.roomTypeCode,
state.rooms[idx].rooms
)
if (!selectedRate) {
state.rooms[idx].selectedRate = null
state.rateSummary[idx] = null
state.rooms[idx].rooms = updatedRooms
} else {
state.rooms[idx].rooms = []
}
})
)
@@ -266,70 +231,75 @@ export function createRatesStore({
})
)
},
removeSelectedPackage(code) {
return set(
produce((state: RatesState) => {
state.rooms[idx].isFetchingPackages = true
const filteredSelectedPackages = state.rooms[
idx
].selectedPackages.filter((c) => c.code !== code)
state.rooms[idx].selectedPackages = filteredSelectedPackages
if (
state.rooms[idx].selectedRate?.product.bookingCode ||
state.booking.bookingCode
) {
state.rooms[idx].selectedFilter =
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
if (filteredSelectedPackages.length) {
searchParams.set(
`room[${idx}].packages`,
filteredSelectedPackages.map((pkg) => pkg.code).join(",")
)
} else {
searchParams.delete(`room[${idx}].packages`)
}
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
})
)
},
removeSelectedPackages() {
return set(
produce((state: RatesState) => {
state.rooms[idx].isFetchingPackages = true
state.rooms[idx].selectedPackages = []
if (
state.rooms[idx].selectedRate?.product.bookingCode ||
state.booking.bookingCode
) {
state.rooms[idx].selectedFilter =
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
searchParams.delete(`room[${idx}].packages`)
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
})
)
},
selectFilter(filter) {
return set(
produce((state: RatesState) => {
state.rooms[idx].selectedFilter = filter
})
)
},
togglePackages(selectedPackages) {
return set(
produce((state: RatesState) => {
state.rooms[idx].selectedPackages = selectedPackages
const rateSummaryItem = state.rateSummary[idx]
const roomConfiguration = state.roomConfigurations[idx]
if (roomConfiguration) {
const searchParams = new URLSearchParams(state.searchParams)
if (selectedPackages.length) {
searchParams.set(
`room[${idx}].packages`,
selectedPackages.join(",")
)
if (rateSummaryItem) {
rateSummaryItem.packages = selectedPackages
}
} else {
state.rooms[idx].rooms = roomConfiguration
if (rateSummaryItem) {
rateSummaryItem.packages = []
}
searchParams.delete(`room[${idx}].packages`)
}
// If we already have the features data 'addRoomFeatures' wont run
// so we need to do additional filtering here if thats the case
const filteredRooms = filterRoomsBySelectedPackages(
selectedPackages,
state.roomConfigurations[idx]
)
if (filteredRooms.length) {
const selectedRate = findSelectedRate(
room.rateCode,
room.counterRateCode,
room.roomTypeCode,
state.rooms[idx].rooms
)
if (!selectedRate) {
state.rooms[idx].selectedRate = null
state.rateSummary[idx] = null
}
}
state.searchParams = new ReadonlyURLSearchParams(
searchParams
)
window.history.pushState(
{},
"",
`${state.pathname}?${searchParams}`
)
}
state.rooms[idx].isFetchingAdditionalRate = true
})
)
},
@@ -393,6 +363,19 @@ export function createRatesStore({
isMainRoom &&
hasMemberRate &&
isRegularRate
state.rooms[idx].bookingRoom.rateCode = isMemberRate
? memberRateCode
: productRateCode
if (!isMemberRate && hasMemberRate) {
state.rooms[idx].bookingRoom.counterRateCode =
memberRateCode
}
state.rooms[idx].bookingRoom.roomTypeCode =
selectedRate.roomTypeCode
state.rooms[idx].bookingRoom.bookingCode =
selectedRate.product.bookingCode
const searchParams = new URLSearchParams(state.searchParams)
const counterratecode = isMemberRate
? productRateCode
@@ -411,6 +394,17 @@ export function createRatesStore({
searchParams.set(`room[${idx}].ratecode`, rateCode)
}
if (selectedRate.product.bookingCode) {
searchParams.set(
`room[${idx}].bookingCode`,
selectedRate.product.bookingCode
)
} else {
if (searchParams.has(`room[${idx}].bookingCode`)) {
searchParams.delete(`room[${idx}].bookingCode`)
}
}
searchParams.set(
`room[${idx}].roomtype`,
selectedRate.roomTypeCode
@@ -422,8 +416,9 @@ export function createRatesStore({
state.activeRoom = idx + 1
}
state.searchParams = new ReadonlyURLSearchParams(searchParams)
window.history.pushState(
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
@@ -431,13 +426,105 @@ export function createRatesStore({
})
)
},
selectPackages(selectedPackages) {
return set(
produce((state: RatesState) => {
state.rooms[idx].isFetchingPackages = true
const pkgs = state.roomsPackages[idx].filter((pkg) =>
selectedPackages.includes(pkg.code)
)
state.rooms[idx].selectedPackages = pkgs
if (
state.rooms[idx].selectedRate?.product.bookingCode ||
state.booking.bookingCode
) {
state.rooms[idx].selectedFilter =
BookingCodeFilterEnum.Discounted
}
const searchParams = state.searchParams
if (selectedPackages.length) {
searchParams.set(
`room[${idx}].packages`,
selectedPackages.join(",")
)
} else {
searchParams.delete(`room[${idx}].packages`)
}
state.searchParams = searchParams
window.history.replaceState(
{},
"",
`${state.pathname}?${searchParams}`
)
})
)
},
updateRooms(rooms) {
return set(
produce((state: RatesState) => {
state.rooms[idx].isFetchingPackages = false
if (rooms) {
state.rooms[idx].rooms = rooms
const rateSummaryRoom = state.rateSummary[idx]
if (rateSummaryRoom) {
const room = state.rooms[idx].bookingRoom
const selectedRoom = findSelectedRate(
room.rateCode,
room.counterRateCode,
room.roomTypeCode,
rooms
)
if (selectedRoom) {
rateSummaryRoom.packages =
state.rooms[idx].selectedPackages
} else {
const searchParams = clearRoomSelectionFromUrl(
idx,
state.searchParams
)
state.searchParams = searchParams
state.rateSummary[idx] = null
state.rooms[idx].selectedRate = null
window.history.replaceState(
{},
"",
`${pathname}?${searchParams}`
)
}
}
} else {
state.rooms[idx].rooms = []
if (state.rateSummary[idx]) {
const searchParams = clearRoomSelectionFromUrl(
idx,
state.searchParams
)
state.searchParams = searchParams
state.rateSummary[idx] = null
state.rooms[idx].selectedRate = null
window.history.replaceState(
{},
"",
`${pathname}?${searchParams}`
)
}
}
})
)
},
},
bookingRoom: room,
rooms,
selectedFilter: booking.bookingCode
? BookingCodeFilterEnum.Discounted
: BookingCodeFilterEnum.All,
isFetchingAdditionalRate: false,
isFetchingPackages: false,
rooms: roomConfiguration,
selectedFilter,
selectedPackages,
selectedRate:
selectedRate && product
@@ -452,6 +539,7 @@ export function createRatesStore({
}
}),
roomCategories,
roomsPackages,
roomsAvailability,
searchParams,
vat,