"use client" import { useEffect, useRef } from "react" import { createDetailsStore } from "@/stores/enter-details" import { calcTotalMemberPrice, calcTotalPublicPrice, navigate, writeToSessionStorage, } from "@/stores/enter-details/helpers" import { bedTypeSchema } from "@/components/HotelReservation/EnterDetails/BedType/schema" import { breakfastStoreSchema } from "@/components/HotelReservation/EnterDetails/Breakfast/schema" import { guestDetailsSchema, signedInDetailsSchema, } from "@/components/HotelReservation/EnterDetails/Details/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 { DetailsState, InitialState } from "@/types/stores/enter-details" export default function EnterDetailsProvider({ bedTypes, booking, breakfastPackages, children, packages, roomRate, searchParamsStr, step, user, vat, }: DetailsProviderProps) { const storeRef = useRef() if (!storeRef.current) { const initialData: InitialState = { booking, packages, roomRate, vat } if (bedTypes.length === 1) { initialData.bedType = { description: bedTypes[0].description, roomTypeCode: bedTypes[0].value, } } if (!breakfastPackages?.length) { initialData.breakfast = false } storeRef.current = createDetailsStore( initialData, step, searchParamsStr, user ) } useEffect(() => { if (storeRef.current) { storeRef.current.setState((state) => { const newState: DetailsState = { ...state } newState.bedType = state.formValues.bedType newState.breakfast = state.formValues.breakfast if (state.formValues.guest && !user) { newState.guest = state.formValues.guest } if ( (newState.guest!.join || newState.guest!.membershipNo || user) && state.roomRate.memberRate ) { const memberPrice = calcTotalMemberPrice(newState) newState.roomPrice = memberPrice.roomPrice newState.totalPrice = memberPrice.totalPrice } else { const publicPrice = calcTotalPublicPrice(newState) newState.roomPrice = publicPrice.roomPrice newState.totalPrice = publicPrice.totalPrice } const isValid = { ...newState.isValid } const validateBooking = state.formValues const validPaths = [StepEnum.selectBed] const validatedBedType = bedTypeSchema.safeParse(validateBooking) if (validatedBedType.success) { isValid[StepEnum.selectBed] = true validPaths.push(state.steps[1]) } const validatedBreakfast = breakfastStoreSchema.safeParse(validateBooking) if (validatedBreakfast.success) { isValid[StepEnum.breakfast] = true validPaths.push(StepEnum.details) } const detailsSchema = user ? signedInDetailsSchema : guestDetailsSchema const validatedDetails = detailsSchema.safeParse(validateBooking.guest) /** * Need to add the breakfast check here too since * when a member comes into the flow, their data is * already added and valid, and thus to avoid showing a * step the user hasn't been on yet as complete */ if (isValid.breakfast && validatedDetails.success) { isValid[StepEnum.details] = true validPaths.push(StepEnum.payment) } if (!validPaths.includes(newState.currentStep!)) { newState.currentStep = validPaths.at(-1)! } if (step !== newState.currentStep) { const stateCurrentStep = newState.currentStep! setTimeout(() => { navigate(stateCurrentStep, searchParamsStr) }) } writeToSessionStorage({ bedType: newState.bedType, booking: newState.booking, breakfast: newState.breakfast, guest: newState.guest, }) return { ...newState, isValid } }) } }, [searchParamsStr, step, user]) return ( {children} ) }