fix: allow rates that only have either of member or public to be selectable * fix: allow rates that only have either of member or public to be selectable Approved-by: Michael Zetterberg
166 lines
4.9 KiB
TypeScript
166 lines
4.9 KiB
TypeScript
"use client"
|
|
import deepmerge from "deepmerge"
|
|
import { useEffect, useRef } from "react"
|
|
|
|
import { dt } from "@/lib/dt"
|
|
import { createDetailsStore } from "@/stores/enter-details"
|
|
import {
|
|
calcTotalPrice,
|
|
checkIsSameBooking as checkIsSameBooking,
|
|
clearSessionStorage,
|
|
readFromSessionStorage,
|
|
writeToSessionStorage,
|
|
} from "@/stores/enter-details/helpers"
|
|
|
|
import { multiroomDetailsSchema } from "@/components/HotelReservation/EnterDetails/Details/Multiroom/schema"
|
|
import { guestDetailsSchema } from "@/components/HotelReservation/EnterDetails/Details/RoomOne/schema"
|
|
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"
|
|
|
|
export default function EnterDetailsProvider({
|
|
booking,
|
|
breakfastPackages,
|
|
children,
|
|
rooms,
|
|
searchParamsStr,
|
|
user,
|
|
vat,
|
|
}: DetailsProviderProps) {
|
|
const storeRef = useRef<DetailsStore>()
|
|
if (!storeRef.current) {
|
|
const initialData: InitialState = {
|
|
booking,
|
|
rooms: rooms
|
|
.filter((r) => r.bedTypes?.length) // TODO: how to handle room without bedtypes?
|
|
.map((room) => ({
|
|
breakfastIncluded: !!room.breakfastIncluded,
|
|
cancellationText: room.cancellationText,
|
|
rateDetails: room.rateDetails,
|
|
roomFeatures: room.packages,
|
|
roomRate: room.roomRate,
|
|
roomType: room.roomType,
|
|
roomTypeCode: room.roomTypeCode,
|
|
bedTypes: room.bedTypes!,
|
|
bedType:
|
|
room.bedTypes?.length === 1
|
|
? {
|
|
roomTypeCode: room.bedTypes[0].value,
|
|
description: room.bedTypes[0].description,
|
|
}
|
|
: undefined,
|
|
})),
|
|
vat,
|
|
}
|
|
|
|
storeRef.current = createDetailsStore(
|
|
initialData,
|
|
searchParamsStr,
|
|
user,
|
|
breakfastPackages
|
|
)
|
|
}
|
|
|
|
useEffect(() => {
|
|
const storedValues = readFromSessionStorage()
|
|
if (!storedValues) {
|
|
return
|
|
}
|
|
const isSameBooking = checkIsSameBooking(storedValues.booking, booking)
|
|
if (!isSameBooking) {
|
|
clearSessionStorage()
|
|
return
|
|
}
|
|
|
|
const store = storeRef.current?.getState()
|
|
if (!store) {
|
|
return
|
|
}
|
|
|
|
const updatedRooms = storedValues.rooms.map((storedRoom, idx) => {
|
|
// Need to create a deep new copy
|
|
// since store is readonly
|
|
const currentRoom = deepmerge({}, store.rooms[idx])
|
|
|
|
if (!currentRoom.room.bedType && storedRoom.room.bedType) {
|
|
const sameBed = currentRoom.room.bedTypes.find(
|
|
(bedType) => bedType.value === storedRoom.room.bedType?.roomTypeCode
|
|
)
|
|
if (sameBed) {
|
|
currentRoom.room.bedType = {
|
|
description: sameBed.description,
|
|
roomTypeCode: sameBed.value,
|
|
}
|
|
currentRoom.steps[StepEnum.selectBed].isValid = true
|
|
}
|
|
}
|
|
|
|
if (
|
|
currentRoom.steps[StepEnum.breakfast] &&
|
|
currentRoom.room.breakfast === undefined &&
|
|
(storedRoom.room.breakfast || storedRoom.room.breakfast === false)
|
|
) {
|
|
currentRoom.room.breakfast = storedRoom.room.breakfast
|
|
currentRoom.steps[StepEnum.breakfast].isValid = true
|
|
}
|
|
|
|
// User is already added for main room
|
|
if (!user || (user && idx > 0)) {
|
|
currentRoom.room.guest = deepmerge(
|
|
currentRoom.room.guest,
|
|
storedRoom.room.guest
|
|
)
|
|
}
|
|
|
|
const validGuest =
|
|
idx > 0
|
|
? multiroomDetailsSchema.safeParse(currentRoom.room.guest)
|
|
: guestDetailsSchema.safeParse(currentRoom.room.guest)
|
|
if (validGuest.success) {
|
|
currentRoom.steps[StepEnum.details].isValid = true
|
|
}
|
|
|
|
const invalidStep = Object.values(currentRoom.steps).find(
|
|
(step) => !step.isValid
|
|
)
|
|
|
|
currentRoom.isComplete = !invalidStep
|
|
currentRoom.currentStep = invalidStep ? invalidStep.step : null
|
|
|
|
return currentRoom
|
|
})
|
|
|
|
const canProceedToPayment = updatedRooms.every((room) => room.isComplete)
|
|
|
|
const nights = dt(booking.toDate).diff(booking.fromDate, "days")
|
|
const currency = (updatedRooms[0].room.roomRate.publicRate?.localPrice
|
|
.currency ||
|
|
updatedRooms[0].room.roomRate.memberRate?.localPrice.currency)!
|
|
const totalPrice = calcTotalPrice(updatedRooms, currency, !!user, nights)
|
|
|
|
const activeRoom = updatedRooms.findIndex((room) => !room.isComplete)
|
|
|
|
writeToSessionStorage({
|
|
activeRoom,
|
|
booking,
|
|
rooms: updatedRooms,
|
|
})
|
|
|
|
storeRef.current?.setState({
|
|
activeRoom: storedValues.activeRoom,
|
|
canProceedToPayment,
|
|
rooms: updatedRooms,
|
|
totalPrice,
|
|
})
|
|
}, [booking, rooms, user])
|
|
|
|
return (
|
|
<DetailsContext.Provider value={storeRef.current}>
|
|
{children}
|
|
</DetailsContext.Provider>
|
|
)
|
|
}
|