import { produce } from "immer" import { useContext } from "react" import { create, useStore } from "zustand" import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast" import { clearAncillarySessionData } from "@/components/HotelReservation/MyStay/utils/ancillaries" import { AddAncillaryContext } from "@/contexts/AddAncillary" import type { Ancillaries, Ancillary, SelectedAncillary, } from "@/types/components/myPages/myStay/ancillaries" import type { Room } from "@/types/stores/my-stay" export enum AncillaryStepEnum { selectQuantity = 0, selectDelivery = 1, confirmation = 2, } type Step = { step: AncillaryStepEnum isValid: boolean } type Steps = { [AncillaryStepEnum.selectQuantity]: Step [AncillaryStepEnum.selectDelivery]: Step [AncillaryStepEnum.confirmation]: Step } export type BreakfastData = { nrOfAdults: number nrOfPayingChildren: number nrOfFreeChildren: number nrOfNights: number priceAdult: number priceChild: number currency: string totalPrice: number } interface AddAncillaryState { currentStep: number steps: Steps booking: Room ancillaries: Ancillaries categories: Ancillary["translatedCategoryName"][] selectedCategory: string selectCategory: (category: string) => void ancillariesBySelectedCategory: Ancillary["ancillaryContent"] openModal: () => void closeModal: () => void prevStep: (isMobile: boolean) => void breakfastData: BreakfastData | null setBreakfastData: (breakfastData: BreakfastData | null) => void isBreakfast: boolean isOpen: boolean selectedAncillary: SelectedAncillary | null selectAncillary: (ancillary: SelectedAncillary) => void selectQuantity: () => void selectDeliveryTime: () => void selectQuantityAndDeliveryTime: () => void } function findAncillaryByCategory( ancillaries: Ancillaries, selectedCategory: string ) { return ( ancillaries.find( (ancillary) => ancillary.translatedCategoryName === selectedCategory )?.ancillaryContent ?? [] ) } export const createAddAncillaryStore = ( booking: Room, ancillaries: Ancillaries ) => { const selectedCategory = ancillaries[0].translatedCategoryName const ancillariesBySelectedCategory = findAncillaryByCategory( ancillaries, selectedCategory ) const categories = ancillaries .filter((anc) => !!anc.ancillaryContent.length) .map((ancillary) => ancillary.translatedCategoryName) const steps = { [AncillaryStepEnum.selectQuantity]: { step: AncillaryStepEnum.selectQuantity, isValid: false, }, [AncillaryStepEnum.selectDelivery]: { step: AncillaryStepEnum.selectDelivery, isValid: false, }, [AncillaryStepEnum.confirmation]: { step: AncillaryStepEnum.confirmation, isValid: false, }, } return create((set) => ({ booking, ancillaries, categories, selectedCategory, ancillariesBySelectedCategory, currentStep: AncillaryStepEnum.selectQuantity, selectedAncillary: null, breakfastData: null, isBreakfast: false, isOpen: false, steps, openModal: () => set( produce((state: AddAncillaryState) => { state.isOpen = true }) ), closeModal: () => set( produce((state: AddAncillaryState) => { state.currentStep = AncillaryStepEnum.selectQuantity state.isOpen = false clearAncillarySessionData() state.selectedAncillary = null state.steps = steps }) ), selectCategory: (category) => set( produce((state: AddAncillaryState) => { state.selectedCategory = category state.ancillariesBySelectedCategory = findAncillaryByCategory( state.ancillaries, category ) }) ), selectQuantity: () => set( produce((state: AddAncillaryState) => { if (state.selectedAncillary?.requiresDeliveryTime) { state.currentStep = AncillaryStepEnum.selectDelivery } else { state.steps[AncillaryStepEnum.selectDelivery].isValid = true state.currentStep = AncillaryStepEnum.confirmation } state.steps[AncillaryStepEnum.selectQuantity].isValid = true }) ), selectQuantityAndDeliveryTime: () => set( produce((state: AddAncillaryState) => { state.steps[AncillaryStepEnum.selectQuantity].isValid = true state.steps[AncillaryStepEnum.selectDelivery].isValid = true state.currentStep = AncillaryStepEnum.confirmation }) ), selectDeliveryTime: () => set( produce((state: AddAncillaryState) => { state.steps[AncillaryStepEnum.selectDelivery].isValid = true state.currentStep = AncillaryStepEnum.confirmation }) ), prevStep: (isMobile) => set( produce((state: AddAncillaryState) => { if (state.currentStep === AncillaryStepEnum.selectQuantity) { state.isOpen = false clearAncillarySessionData() state.selectedAncillary = null state.steps = steps } else { if ( (!state.selectedAncillary?.requiresDeliveryTime || isMobile) && state.currentStep === AncillaryStepEnum.confirmation ) { state.currentStep = AncillaryStepEnum.selectQuantity } else { state.currentStep = state.currentStep - 1 } } }) ), selectAncillary: (ancillary) => set( produce((state: AddAncillaryState) => { state.isOpen = true state.selectedAncillary = ancillary state.isBreakfast = ancillary.id === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST }) ), setBreakfastData: (breakfastData) => set( produce((state: AddAncillaryState) => { state.breakfastData = breakfastData }) ), })) } export const useAddAncillaryStore = ( selector: (state: AddAncillaryState) => T ) => { const store = useContext(AddAncillaryContext) if (!store) { throw new Error( "useAddAncillaryStore must be used within AddAncillaryProvider" ) } return useStore(store, selector) }