Feat/SW-1890 New Breakfast Component Design * refactor(SW-1890): Replace BreakfastChoiceCard with RadioCard component and update styles - Removed BreakfastChoiceCard component and its associated styles. - extemded RadioCard component to additional UI. - Updated breakfast.module.css to adjust container width. - Added new properties for subtitleSecondary and description in RadioCard. - Updated translations for breakfast-related messages in en.json. * feat(SW-1890): Add hover state to RadioCard * chore(SW1890): Update translation for breakfast cost message to clarify age range * chore(SW-1890): Updated breakfast cost display to use formatPrice utility * fix(SW-1890): Set fixed size for CoffeeIcon component * fix(SW-1890): Add missing translations for breakfast-related messages * feat(SW-1890): Introduce new breakfast icons and update Breakfast component - Replaced CoffeeIcon with BreakfastBuffetIcon and NoBreakfastBuffetIcon in the Breakfast component. - Added new BreakfastBuffetIcon and NoBreakfastBuffetIcon components to the design system. - Updated imports in the Breakfast component to reflect the new icons. Approved-by: Christian Andolf
130 lines
4.1 KiB
TypeScript
130 lines
4.1 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 {
|
|
BreakfastBuffetIcon,
|
|
NoBreakfastBuffetIcon,
|
|
} from "@scandic-hotels/design-system/Icons"
|
|
|
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
|
|
|
import RadioCard from "@/components/TempDesignSystem/Form/RadioCard"
|
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
|
import { useRoomContext } from "@/contexts/Details/Room"
|
|
import { formatPrice } from "@/utils/numberFormatting"
|
|
|
|
import { breakfastFormSchema } from "./schema"
|
|
|
|
import styles from "./breakfast.module.css"
|
|
|
|
import type { BreakfastFormSchema } from "@/types/components/hotelReservation/breakfast"
|
|
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
|
|
|
export default function Breakfast() {
|
|
const intl = useIntl()
|
|
const packages = useEnterDetailsStore((state) => state.breakfastPackages)
|
|
const {
|
|
actions: { updateBreakfast },
|
|
room,
|
|
} = useRoomContext()
|
|
|
|
const hasChildrenInRoom = !!room.childrenInRoom?.length
|
|
const totalPriceForNoBreakfast = 0
|
|
|
|
const breakfastSelection = room?.breakfast
|
|
? room.breakfast.code
|
|
: room?.breakfast === false
|
|
? "false"
|
|
: undefined
|
|
|
|
const methods = useForm<BreakfastFormSchema>({
|
|
defaultValues: breakfastSelection
|
|
? { breakfast: breakfastSelection }
|
|
: undefined,
|
|
criteriaMode: "all",
|
|
mode: "all",
|
|
resolver: zodResolver(breakfastFormSchema),
|
|
reValidateMode: "onChange",
|
|
})
|
|
|
|
const onSubmit = useCallback(
|
|
(values: BreakfastFormSchema) => {
|
|
const pkg = packages?.find((p) => p.code === values.breakfast)
|
|
if (pkg) {
|
|
updateBreakfast(pkg)
|
|
} else {
|
|
updateBreakfast(false)
|
|
}
|
|
},
|
|
[packages, updateBreakfast]
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (methods.formState.isSubmitting) {
|
|
return
|
|
}
|
|
methods.watch(() => methods.handleSubmit(onSubmit)())
|
|
}, [methods, onSubmit])
|
|
|
|
return (
|
|
<FormProvider {...methods}>
|
|
<div className={styles.container}>
|
|
{hasChildrenInRoom ? (
|
|
<Body>
|
|
{intl.formatMessage({
|
|
id: "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({ id: "Breakfast buffet" })}
|
|
subtitle={
|
|
pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST
|
|
? intl.formatMessage({ id: "Included" })
|
|
: `+ ${formatPrice(intl, pkg.localPrice.price, pkg.localPrice.currency ?? "")}`
|
|
}
|
|
subtitleSecondary={intl.formatMessage({ id: "Per adult/night" })}
|
|
description={
|
|
hasChildrenInRoom
|
|
? intl.formatMessage({
|
|
id: "Free for kids aged 12 and under.",
|
|
})
|
|
: undefined
|
|
}
|
|
descriptionSecondary={intl.formatMessage({
|
|
id: "Includes vegan, gluten-free, and other allergy-friendly options.",
|
|
})}
|
|
/>
|
|
))}
|
|
<RadioCard
|
|
name="breakfast"
|
|
value="false"
|
|
Icon={NoBreakfastBuffetIcon}
|
|
title={intl.formatMessage({ id: "No breakfast" })}
|
|
subtitle={`+ ${formatPrice(intl, totalPriceForNoBreakfast, packages?.[0].localPrice.currency ?? "")}`}
|
|
descriptionSecondary={
|
|
hasChildrenInRoom
|
|
? intl.formatMessage({
|
|
id: "Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.",
|
|
})
|
|
: intl.formatMessage({
|
|
id: "Breakfast can be added after booking for an additional fee.",
|
|
})
|
|
}
|
|
/>
|
|
</form>
|
|
</div>
|
|
</FormProvider>
|
|
)
|
|
}
|