Files
web/apps/scandic-web/stores/my-stay/add-ancillary-flow.ts
Bianca Widstam 7070770581 Merged in fix/SW-2406-update-modal-ancillaries (pull request #1911)
fix(SW-2406): update modal for ancillaries

* fix(SW-2406): update modal for ancillaries

* fix(SW-2406): revert translations


Approved-by: Niclas Edenvin
Approved-by: Erik Tiekstra
2025-04-30 08:20:57 +00:00

249 lines
7.5 KiB
TypeScript

import { produce } from "immer"
import { useContext } from "react"
import { create, useStore } from "zustand"
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 { BreakfastPackageEnum } from "@/types/enums/breakfast"
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
export enum AncillaryStepEnum {
selectAncillary = 0,
selectQuantity = 1,
selectDelivery = 2,
confirmation = 3,
}
type Step = {
step: AncillaryStepEnum
isValid: boolean
}
type Steps = {
[AncillaryStepEnum.selectAncillary]?: Step
[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
}
export interface AddAncillaryState {
currentStep: number
steps: Steps
booking: BookingConfirmation["booking"]
ancillaries: Ancillaries
categories: Ancillary["categoryName"][]
selectedCategory: string
selectCategory: (category: string) => void
ancillariesBySelectedCategory: Ancillary["ancillaryContent"]
openModal: () => void
closeModal: () => void
prevStep: () => void
prevStepMobile: () => 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.categoryName === selectedCategory)
?.ancillaryContent ?? []
)
}
export const createAddAncillaryStore = (
booking: BookingConfirmation["booking"],
ancillaries: Ancillaries
) => {
const selectedCategory = ancillaries[0].categoryName
const ancillariesBySelectedCategory = findAncillaryByCategory(
ancillaries,
selectedCategory
)
const categories = ancillaries.map((ancillary) => ancillary.categoryName)
const steps = {
[AncillaryStepEnum.selectAncillary]: {
step: AncillaryStepEnum.selectAncillary,
isValid: true,
},
[AncillaryStepEnum.selectQuantity]: {
step: AncillaryStepEnum.selectQuantity,
isValid: false,
},
[AncillaryStepEnum.selectDelivery]: {
step: AncillaryStepEnum.selectDelivery,
isValid: false,
},
[AncillaryStepEnum.confirmation]: {
step: AncillaryStepEnum.confirmation,
isValid: false,
},
}
return create<AddAncillaryState>((set) => ({
booking,
ancillaries,
categories,
selectedCategory,
ancillariesBySelectedCategory,
currentStep: AncillaryStepEnum.selectAncillary,
selectedAncillary: null,
breakfastData: null,
isBreakfast: false,
isOpen: false,
steps,
openModal: () =>
set(
produce((state: AddAncillaryState) => {
state.isOpen = true
state.currentStep = AncillaryStepEnum.selectAncillary
})
),
closeModal: () =>
set(
produce((state: AddAncillaryState) => {
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: () =>
set(
produce((state: AddAncillaryState) => {
if (
state.currentStep === AncillaryStepEnum.selectAncillary ||
(state.currentStep === AncillaryStepEnum.selectQuantity &&
!state.steps[AncillaryStepEnum.selectAncillary])
) {
state.isOpen = false
clearAncillarySessionData()
state.selectedAncillary = null
state.steps = steps
} else {
if (
!state.selectedAncillary?.requiresDeliveryTime &&
state.currentStep === AncillaryStepEnum.confirmation
) {
state.currentStep = AncillaryStepEnum.selectQuantity
} else if (state.currentStep === AncillaryStepEnum.selectQuantity) {
state.currentStep = state.currentStep - 1
state.selectedAncillary = null
} else {
state.currentStep = state.currentStep - 1
}
}
})
),
prevStepMobile: () =>
set(
produce((state: AddAncillaryState) => {
if (state.currentStep === AncillaryStepEnum.selectQuantity) {
state.isOpen = false
clearAncillarySessionData()
state.selectedAncillary = null
state.steps = steps
} else {
if (state.currentStep === AncillaryStepEnum.confirmation) {
state.currentStep = AncillaryStepEnum.selectQuantity
} else {
state.currentStep = state.currentStep - 1
}
}
})
),
selectAncillary: (ancillary) =>
set(
produce((state: AddAncillaryState) => {
if (state.isOpen) {
state.steps[AncillaryStepEnum.selectAncillary]!.isValid = true
} else {
state.isOpen = true
delete state.steps[AncillaryStepEnum.selectAncillary]
}
state.selectedAncillary = ancillary
state.currentStep = AncillaryStepEnum.selectQuantity
state.isBreakfast =
ancillary.id === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
})
),
setBreakfastData: (breakfastData) =>
set(
produce((state: AddAncillaryState) => {
state.breakfastData = breakfastData
})
),
}))
}
export const useAddAncillaryStore = <T>(
selector: (state: AddAncillaryState) => T
) => {
const store = useContext(AddAncillaryContext)
if (!store) {
throw new Error(
"useAddAncillaryStore must be used within AddAncillaryProvider"
)
}
return useStore(store, selector)
}