feat: prevent users from selecting the same room when there is no vacancy for it
This commit is contained in:
committed by
Michael Zetterberg
parent
4f0c61f68f
commit
1f1bcd480b
@@ -3,7 +3,9 @@
|
|||||||
import { useRatesStore } from "@/stores/select-rate"
|
import { useRatesStore } from "@/stores/select-rate"
|
||||||
|
|
||||||
import { RoomContext } from "@/contexts/SelectRate/Room"
|
import { RoomContext } from "@/contexts/SelectRate/Room"
|
||||||
|
import { sortRoomConfigs } from "@/utils/sort"
|
||||||
|
|
||||||
|
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
|
||||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||||
import type { RoomProviderProps } from "@/types/providers/select-rate/room"
|
import type { RoomProviderProps } from "@/types/providers/select-rate/room"
|
||||||
|
|
||||||
@@ -12,19 +14,63 @@ export default function RoomProvider({
|
|||||||
idx,
|
idx,
|
||||||
room,
|
room,
|
||||||
}: RoomProviderProps) {
|
}: RoomProviderProps) {
|
||||||
const { activeRoom, roomAvailability, roomPackages } = useRatesStore(
|
const { activeRoom, rateSummary, roomAvailability, roomPackages } =
|
||||||
(state) => ({
|
useRatesStore((state) => ({
|
||||||
activeRoom: state.activeRoom,
|
activeRoom: state.activeRoom,
|
||||||
|
rateSummary: state.rateSummary,
|
||||||
roomPackages: state.roomsPackages[idx],
|
roomPackages: state.roomsPackages[idx],
|
||||||
roomAvailability: state.roomsAvailability?.[idx],
|
roomAvailability: state.roomsAvailability?.[idx],
|
||||||
})
|
}))
|
||||||
)
|
|
||||||
const roomNr = idx + 1
|
const roomNr = idx + 1
|
||||||
|
|
||||||
const petRoomPackage = roomPackages.find(
|
const petRoomPackage = roomPackages.find(
|
||||||
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
|
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const selectedRoomsCount = rateSummary.reduce<Record<string, number>>(
|
||||||
|
(roomsCount, selectedRoom) => {
|
||||||
|
if (selectedRoom) {
|
||||||
|
if (!roomsCount[selectedRoom.roomTypeCode]) {
|
||||||
|
roomsCount[selectedRoom.roomTypeCode] = 0
|
||||||
|
}
|
||||||
|
roomsCount[selectedRoom.roomTypeCode] =
|
||||||
|
roomsCount[selectedRoom.roomTypeCode] + 1
|
||||||
|
}
|
||||||
|
return roomsCount
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const rooms = room.rooms
|
||||||
|
.map((r) => {
|
||||||
|
// Need to copy (shallow) since using immer with
|
||||||
|
// Zustand uses Proxy objects which results in
|
||||||
|
// properties being read-only thus causing errors
|
||||||
|
// when trying to modify roomsLeft etc.
|
||||||
|
const rCopy = { ...r }
|
||||||
|
if (selectedRoomsCount[r.roomTypeCode]) {
|
||||||
|
rCopy.roomsLeft =
|
||||||
|
rCopy.roomsLeft - selectedRoomsCount[rCopy.roomTypeCode]
|
||||||
|
|
||||||
|
const selectedRoom = rateSummary[idx]
|
||||||
|
const isCurrentlySelectedRoom =
|
||||||
|
selectedRoom && selectedRoom.roomTypeCode === rCopy.roomTypeCode
|
||||||
|
if (isCurrentlySelectedRoom) {
|
||||||
|
// Need to add 1 roomsLeft back to tally since
|
||||||
|
// our selectedRoom was included in selectedRoomsCount
|
||||||
|
rCopy.roomsLeft = rCopy.roomsLeft + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rCopy.roomsLeft <= 0) {
|
||||||
|
rCopy.status = AvailabilityEnum.NotAvailable
|
||||||
|
rCopy.roomsLeft = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rCopy
|
||||||
|
})
|
||||||
|
.sort(sortRoomConfigs)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RoomContext.Provider
|
<RoomContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@@ -35,6 +81,7 @@ export default function RoomProvider({
|
|||||||
roomAvailability,
|
roomAvailability,
|
||||||
roomPackages,
|
roomPackages,
|
||||||
roomNr,
|
roomNr,
|
||||||
|
rooms,
|
||||||
totalRooms: room.rooms.length,
|
totalRooms: room.rooms.length,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { z } from "zod"
|
|||||||
|
|
||||||
import { toLang } from "@/server/utils"
|
import { toLang } from "@/server/utils"
|
||||||
|
|
||||||
|
import { sortRoomConfigs } from "@/utils/sort"
|
||||||
import { nullableStringValidator } from "@/utils/zod/stringValidator"
|
import { nullableStringValidator } from "@/utils/zod/stringValidator"
|
||||||
|
|
||||||
import { occupancySchema } from "./schemas/availability/occupancy"
|
import { occupancySchema } from "./schemas/availability/occupancy"
|
||||||
@@ -26,7 +27,6 @@ import {
|
|||||||
import { relationshipsSchema } from "./schemas/relationships"
|
import { relationshipsSchema } from "./schemas/relationships"
|
||||||
import { roomConfigurationSchema } from "./schemas/roomAvailability/configuration"
|
import { roomConfigurationSchema } from "./schemas/roomAvailability/configuration"
|
||||||
import { rateDefinitionSchema } from "./schemas/roomAvailability/rateDefinition"
|
import { rateDefinitionSchema } from "./schemas/roomAvailability/rateDefinition"
|
||||||
import { sortRoomConfigs } from "./utils"
|
|
||||||
|
|
||||||
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
|
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
|
||||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { toApiLang } from "@/server/utils"
|
|||||||
import { generateChildrenString } from "@/components/HotelReservation/utils"
|
import { generateChildrenString } from "@/components/HotelReservation/utils"
|
||||||
import { getCacheClient } from "@/services/dataCache"
|
import { getCacheClient } from "@/services/dataCache"
|
||||||
import { cache } from "@/utils/cache"
|
import { cache } from "@/utils/cache"
|
||||||
|
import { sortRoomConfigs } from "@/utils/sort"
|
||||||
|
|
||||||
import { getHotelPageUrls } from "../contentstack/hotelPage/utils"
|
import { getHotelPageUrls } from "../contentstack/hotelPage/utils"
|
||||||
import { type RoomFeaturesInput } from "./input"
|
import { type RoomFeaturesInput } from "./input"
|
||||||
@@ -1215,18 +1216,6 @@ export function getSelectedRoomAvailability(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to ensure `Available` rooms
|
|
||||||
// are shown before all `NotAvailable`
|
|
||||||
const statusLookup = {
|
|
||||||
[AvailabilityEnum.Available]: 1,
|
|
||||||
[AvailabilityEnum.NotAvailable]: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sortRoomConfigs(a: RoomConfiguration, b: RoomConfiguration) {
|
|
||||||
// @ts-expect-error - array indexing
|
|
||||||
return statusLookup[a.status] - statusLookup[b.status]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBedTypes(
|
export function getBedTypes(
|
||||||
rooms: RoomConfiguration[],
|
rooms: RoomConfiguration[],
|
||||||
roomType: string,
|
roomType: string,
|
||||||
|
|||||||
@@ -128,6 +128,11 @@ export function createRatesStore({
|
|||||||
pathname,
|
pathname,
|
||||||
rateSummary,
|
rateSummary,
|
||||||
roomConfigurations,
|
roomConfigurations,
|
||||||
|
roomCategories,
|
||||||
|
roomsPackages,
|
||||||
|
roomsAvailability,
|
||||||
|
searchParams,
|
||||||
|
vat,
|
||||||
rooms: booking.rooms.map((room, idx) => {
|
rooms: booking.rooms.map((room, idx) => {
|
||||||
const roomConfiguration = roomConfigurations[idx]
|
const roomConfiguration = roomConfigurations[idx]
|
||||||
const roomPackages = roomsPackages[idx]
|
const roomPackages = roomsPackages[idx]
|
||||||
@@ -304,6 +309,26 @@ export function createRatesStore({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
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}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
selectFilter(filter) {
|
selectFilter(filter) {
|
||||||
return set(
|
return set(
|
||||||
produce((state: RatesState) => {
|
produce((state: RatesState) => {
|
||||||
@@ -545,11 +570,6 @@ export function createRatesStore({
|
|||||||
: null,
|
: null,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
roomCategories,
|
|
||||||
roomsPackages,
|
|
||||||
roomsAvailability,
|
|
||||||
searchParams,
|
|
||||||
vat,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ interface Actions {
|
|||||||
modifyRate: () => void
|
modifyRate: () => void
|
||||||
removeSelectedPackage: (code: PackageEnum) => void
|
removeSelectedPackage: (code: PackageEnum) => void
|
||||||
removeSelectedPackages: () => void
|
removeSelectedPackages: () => void
|
||||||
|
removeSelectedRoom: () => void
|
||||||
selectFilter: (filter: BookingCodeFilterEnum) => void
|
selectFilter: (filter: BookingCodeFilterEnum) => void
|
||||||
selectPackages: (codes: PackageEnum[]) => void
|
selectPackages: (codes: PackageEnum[]) => void
|
||||||
selectRate: (rate: SelectedRate, isUserLoggedIn: boolean) => void
|
selectRate: (rate: SelectedRate, isUserLoggedIn: boolean) => void
|
||||||
|
|||||||
14
apps/scandic-web/utils/sort.ts
Normal file
14
apps/scandic-web/utils/sort.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
|
||||||
|
import type { RoomConfiguration } from "@/types/trpc/routers/hotel/roomAvailability"
|
||||||
|
|
||||||
|
// Used to ensure `Available` rooms
|
||||||
|
// are shown before all `NotAvailable`
|
||||||
|
const statusLookup = {
|
||||||
|
[AvailabilityEnum.Available]: 1,
|
||||||
|
[AvailabilityEnum.NotAvailable]: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sortRoomConfigs(a: RoomConfiguration, b: RoomConfiguration) {
|
||||||
|
// @ts-expect-error - array indexing
|
||||||
|
return statusLookup[a.status] - statusLookup[b.status]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user