"use client" import { zodResolver } from "@hookform/resolvers/zod" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { useMediaQuery } from "usehooks-ts" import { trpc } from "@/lib/trpc/client" import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow" import Image from "@/components/Image" import Modal from "@/components/Modal" import Button from "@/components/TempDesignSystem/Button" import Divider from "@/components/TempDesignSystem/Divider" import Body from "@/components/TempDesignSystem/Text/Body" import { toast } from "@/components/TempDesignSystem/Toasts" import useLang from "@/hooks/useLang" import { formatPrice } from "@/utils/numberFormatting" import { generateDeliveryOptions } from "../../utils" import ConfirmationStep from "../ConfirmationStep" import DeliveryMethodStep from "../DeliveryDetailsStep" import { type AncillaryFormData, ancillaryFormSchema } from "../schema" import SelectQuantityStep from "../SelectQuantityStep" import styles from "./addAncillaryFlowModal.module.css" import type { AddAncillaryFlowModalProps } from "@/types/components/myPages/myStay/ancillaries" type FieldName = keyof AncillaryFormData const STEP_FIELD_MAP: Record = { 1: ["quantityWithPoints", "quantityWithCard"], 2: ["deliveryTime"], 3: ["termsAndConditions"], } export default function AddAncillaryFlowModal({ isOpen, onClose, booking, user, }: AddAncillaryFlowModalProps) { const { step, nextStep, prevStep, resetStore, selectedAncillary, confirmationNumber, openedFrom, setGridIsOpen, } = useAddAncillaryStore() const intl = useIntl() const lang = useLang() const isMobile = useMediaQuery("(max-width: 767px)") const deliveryTimeOptions = generateDeliveryOptions(booking.checkInDate) const defaultDeliveryTime = deliveryTimeOptions[0]?.value const formMethods = useForm({ defaultValues: { quantityWithPoints: null, quantityWithCard: user ? null : 1, deliveryTime: defaultDeliveryTime, optionalText: "", termsAndConditions: false, }, mode: "onSubmit", reValidateMode: "onChange", resolver: zodResolver(ancillaryFormSchema), }) const { reset, trigger, handleSubmit, formState } = formMethods const addAncillary = trpc.booking.packages.useMutation({ onSuccess: (data, variables) => { if (!data) { toast.error( intl.formatMessage( { id: "Something went wrong. {ancillary} could not be added to your booking!", }, { ancillary: selectedAncillary?.title } ) ) return } const description = variables.ancillaryDeliveryTime ? intl.formatMessage( { id: "Delivery between {deliveryTime}. Payment will be made on check-in.", }, { deliveryTime: variables.ancillaryDeliveryTime } ) : undefined toast.success( intl.formatMessage( { id: "{ancillary} added to your booking!" }, { ancillary: selectedAncillary?.title } ), { description } ) handleClose() }, onError: () => { toast.error( intl.formatMessage( { id: "Something went wrong. {ancillary} could not be added to your booking!", }, { ancillary: selectedAncillary?.title } ) ) }, }) const onSubmit = (data: AncillaryFormData) => { const packages = [] if (data.quantityWithCard) { packages.push({ code: selectedAncillary!.id, quantity: data.quantityWithCard, comment: data.optionalText || undefined, }) } if (selectedAncillary?.loyaltyCode && data.quantityWithPoints) { packages.push({ code: selectedAncillary.loyaltyCode, quantity: data.quantityWithPoints, comment: data.optionalText || undefined, }) } addAncillary.mutate({ confirmationNumber, ancillaryComment: data.optionalText ?? "", ancillaryDeliveryTime: data.deliveryTime ?? undefined, packages, language: lang, }) } const handleNextStep = async () => { let fieldsToValidate = [] if (isMobile && step === 1) { fieldsToValidate = [...STEP_FIELD_MAP[1]] if (selectedAncillary?.requiresDeliveryTime) { fieldsToValidate = [...fieldsToValidate, ...STEP_FIELD_MAP[2]] } } else if (step === 2) { fieldsToValidate = selectedAncillary?.requiresDeliveryTime ? STEP_FIELD_MAP[2] || [] : [] } else { fieldsToValidate = STEP_FIELD_MAP[step] || [] } if (await trigger(fieldsToValidate)) { nextStep() } } const handleBack = () => { if (step > 1) { prevStep() } else { handleClose() if (openedFrom === "grid") setGridIsOpen(true) } } const handleClose = () => { reset() resetStore() onClose() } if (!selectedAncillary) return null const confirmLabel = intl.formatMessage({ id: "Confirm" }) const continueLabel = intl.formatMessage({ id: "Continue" }) const confirmStep = isMobile || (!isMobile && !selectedAncillary.requiresDeliveryTime) ? 2 : 3 return (
{selectedAncillary.title}
{formatPrice( intl, selectedAncillary.price.total, selectedAncillary.price.currency )} {selectedAncillary.points && ( <> {selectedAncillary.points}{" "} {intl.formatMessage({ id: "points" })} )}
{selectedAncillary.description && (
)}
{isMobile ? ( <> {step === 1 && ( <> {selectedAncillary.requiresDeliveryTime && ( )} )} {step === 2 && } ) : ( <> {step === 1 && } {step === 2 && selectedAncillary.requiresDeliveryTime && ( )} {(step === 3 || (step === 2 && !selectedAncillary.requiresDeliveryTime)) && ( )} )}
) }