146 lines
5.0 KiB
TypeScript
146 lines
5.0 KiB
TypeScript
"use client"
|
|
|
|
import { zodResolver } from "@hookform/resolvers/zod"
|
|
import { useCallback, useEffect } from "react"
|
|
import { FormProvider, useForm } from "react-hook-form"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
|
import Body from "@scandic-hotels/design-system/Body"
|
|
import RadioCard from "@scandic-hotels/design-system/Form/RadioCard"
|
|
import BreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/BreakfastBuffetIcon"
|
|
import NoBreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/NoBreakfastBuffetIcon"
|
|
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
|
|
|
|
import { useRoomContext } from "../../../contexts/EnterDetails/RoomContext"
|
|
import { useEnterDetailsStore } from "../../../stores/enter-details"
|
|
import { useTrackingContext } from "../../../trackingContext"
|
|
import { type BreakfastFormSchema, breakfastFormSchema } from "./schema"
|
|
|
|
import styles from "./breakfast.module.css"
|
|
|
|
export default function Breakfast() {
|
|
const intl = useIntl()
|
|
const packages = useEnterDetailsStore((state) => state.breakfastPackages)
|
|
const hotelId = useEnterDetailsStore((state) => state.booking.hotelId)
|
|
const {
|
|
actions: { updateBreakfast },
|
|
room,
|
|
} = useRoomContext()
|
|
|
|
const { trackBreakfastSelection } = useTrackingContext()
|
|
|
|
const hasChildrenInRoom = !!room.childrenInRoom?.length
|
|
const totalPriceForNoBreakfast = 0
|
|
|
|
const breakfastSelection = room?.breakfast
|
|
? room.breakfast.code
|
|
: room?.breakfast === false
|
|
? "false"
|
|
: undefined
|
|
|
|
const methods = useForm<BreakfastFormSchema>({
|
|
criteriaMode: "all",
|
|
mode: "all",
|
|
resolver: zodResolver(breakfastFormSchema),
|
|
reValidateMode: "onChange",
|
|
values: breakfastSelection ? { breakfast: breakfastSelection } : undefined,
|
|
})
|
|
|
|
const onSubmit = useCallback(
|
|
(values: BreakfastFormSchema) => {
|
|
const pkg = packages.find((p) => p.code === values.breakfast)
|
|
if (pkg) {
|
|
updateBreakfast(pkg)
|
|
} else {
|
|
updateBreakfast(false)
|
|
}
|
|
|
|
trackBreakfastSelection({
|
|
breakfastPackage: pkg ?? packages[0],
|
|
hotelId,
|
|
units: pkg ? room.adults : 0,
|
|
})
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
[packages, hotelId, room.adults, updateBreakfast]
|
|
)
|
|
|
|
const selectedBreakfast = methods.watch("breakfast")
|
|
const handleSubmit = methods.handleSubmit
|
|
useEffect(() => {
|
|
if (selectedBreakfast) {
|
|
handleSubmit(onSubmit)()
|
|
}
|
|
}, [selectedBreakfast, handleSubmit, onSubmit])
|
|
|
|
return (
|
|
<FormProvider {...methods}>
|
|
<div className={styles.container}>
|
|
{hasChildrenInRoom ? (
|
|
<Body>
|
|
{intl.formatMessage({
|
|
defaultMessage:
|
|
"Children's breakfast is always free as part of the adult's breakfast.",
|
|
})}
|
|
</Body>
|
|
) : null}
|
|
<form className={styles.form} onSubmit={methods.handleSubmit(onSubmit)}>
|
|
{packages?.map((pkg) => (
|
|
<RadioCard
|
|
key={pkg.code}
|
|
name="breakfast"
|
|
value={pkg.code}
|
|
Icon={BreakfastBuffetIcon}
|
|
title={intl.formatMessage({
|
|
defaultMessage: "Breakfast buffet",
|
|
})}
|
|
subtitle={
|
|
pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST
|
|
? intl.formatMessage({
|
|
defaultMessage: "Included",
|
|
})
|
|
: `+ ${formatPrice(intl, pkg.localPrice.price, pkg.localPrice.currency ?? "")}`
|
|
}
|
|
subtitleSecondary={intl.formatMessage({
|
|
defaultMessage: "Per adult/night",
|
|
})}
|
|
description={
|
|
hasChildrenInRoom
|
|
? intl.formatMessage({
|
|
defaultMessage: "Free for kids aged 12 and under.",
|
|
})
|
|
: undefined
|
|
}
|
|
descriptionSecondary={intl.formatMessage({
|
|
defaultMessage:
|
|
"Includes vegan, gluten-free, and other allergy-friendly options.",
|
|
})}
|
|
/>
|
|
))}
|
|
<RadioCard
|
|
name="breakfast"
|
|
value="false"
|
|
Icon={NoBreakfastBuffetIcon}
|
|
title={intl.formatMessage({
|
|
defaultMessage: "No breakfast",
|
|
})}
|
|
subtitle={`+ ${formatPrice(intl, totalPriceForNoBreakfast, packages?.[0].localPrice.currency ?? "")}`}
|
|
descriptionSecondary={
|
|
hasChildrenInRoom
|
|
? intl.formatMessage({
|
|
defaultMessage:
|
|
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.",
|
|
})
|
|
: intl.formatMessage({
|
|
defaultMessage:
|
|
"Breakfast can be added after booking for an additional fee.",
|
|
})
|
|
}
|
|
/>
|
|
</form>
|
|
</div>
|
|
</FormProvider>
|
|
)
|
|
}
|