Files
web/apps/scandic-web/components/HotelReservation/EnterDetails/Breakfast/index.tsx
Chuma Mcphoy (We Ahead) e45fea6de4 Merged in feat/SW-1890-New-Breakfast-Component (pull request #1666)
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
2025-04-01 10:03:18 +00:00

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