Files
web/packages/booking-flow/lib/components/EnterDetails/Breakfast/index.tsx
Joakim Jäderberg 7dee6d5083 Merged in chore/move-enter-details (pull request #2778)
Chore/move enter details

Approved-by: Anton Gunnarsson
2025-09-11 07:16:24 +00:00

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>
)
}