feat: bedtypes is selectable again
This commit is contained in:
committed by
Michael Zetterberg
parent
f62723c6e5
commit
afb37d0cc5
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user