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
This commit is contained in:
Chuma Mcphoy (We Ahead)
2025-04-01 10:03:18 +00:00
parent df32c08350
commit e45fea6de4
17 changed files with 242 additions and 88 deletions

View File

@@ -1,3 +0,0 @@
.ancillaryChoiceCard:hover {
cursor: pointer;
}

View File

@@ -1,39 +0,0 @@
import { useFormContext } from "react-hook-form"
import { AncillaryCard } from "@/components/TempDesignSystem/AncillaryCard"
import styles from "./ancillaryChoiceCard.module.css"
import type { BreakfastChoiceCardProps } from "@/types/components/ancillaryCard"
export default function BreakfastChoiceCard({
name,
id,
value,
ancillary,
}: BreakfastChoiceCardProps) {
const { register, setValue } = useFormContext()
function onLabelClick(event: React.MouseEvent) {
// Preventing click event on label elements firing twice: https://github.com/facebook/react/issues/14295
event.preventDefault()
setValue(name, value)
}
return (
<label
onClick={onLabelClick}
tabIndex={0}
className={styles.ancillaryChoiceCard}
>
<AncillaryCard ancillary={ancillary} />
<input
{...register(name)}
aria-hidden
id={id || name}
hidden
type="radio"
value={value}
/>
</label>
)
}

View File

@@ -8,5 +8,5 @@
display: grid;
gap: var(--Spacing-x2);
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
width: min(600px, 100%);
width: min(700px, 100%);
}

View File

@@ -5,11 +5,17 @@ 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 BreakfastChoiceCard from "@/components/HotelReservation/EnterDetails/Breakfast/BreakfastChoiceCard"
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"
@@ -26,6 +32,9 @@ export default function Breakfast() {
room,
} = useRoomContext()
const hasChildrenInRoom = !!room.childrenInRoom?.length
const totalPriceForNoBreakfast = 0
const breakfastSelection = room?.breakfast
? room.breakfast.code
: room?.breakfast === false
@@ -64,7 +73,7 @@ export default function Breakfast() {
return (
<FormProvider {...methods}>
<div className={styles.container}>
{room.childrenInRoom?.length ? (
{hasChildrenInRoom ? (
<Body>
{intl.formatMessage({
id: "Children's breakfast is always free as part of the adult's breakfast.",
@@ -73,42 +82,45 @@ export default function Breakfast() {
) : null}
<form className={styles.form} onSubmit={methods.handleSubmit(onSubmit)}>
{packages?.map((pkg) => (
<BreakfastChoiceCard
<RadioCard
key={pkg.code}
name="breakfast"
ancillary={{
title: intl.formatMessage({ id: "Breakfast buffet" }),
price: {
total: pkg.localPrice.price,
currency: pkg.localPrice.currency,
included:
pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST,
text: intl.formatMessage({ id: "/night per adult" }),
},
description: intl.formatMessage({
id: "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.",
}),
imageUrl: "/_static/img/enter-details/breakfast.png", // TODO: Add dynamic image
}}
value={pkg.code}
id={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.",
})}
/>
))}
<BreakfastChoiceCard
<RadioCard
name="breakfast"
ancillary={{
title: intl.formatMessage({ id: "No breakfast" }),
price: {
total: 0,
currency: packages?.[0].localPrice.currency ?? "",
},
description: intl.formatMessage({
id: "You can always change your mind later and add breakfast at the hotel.",
}),
imageUrl: "/_static/img/enter-details/breakfast.png", // TODO: Add dynamic image
imageOpacity: 0.1,
}}
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>

View File

@@ -6,6 +6,8 @@ import { useFormContext } from "react-hook-form"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Divider from "@/components/TempDesignSystem/Divider"
import styles from "./radioCard.module.css"
import type { RadioCardProps } from "./types"
@@ -15,10 +17,13 @@ export default function RadioCard({
iconHeight = 32,
id,
name,
subtitle,
title,
subtitleSecondary,
subtitle,
value,
disabled = false,
description,
descriptionSecondary,
}: RadioCardProps) {
const { register, setValue } = useFormContext()
@@ -52,9 +57,44 @@ export default function RadioCard({
<Typography variant="Body/Paragraph/mdBold" className={styles.title}>
<p>{title}</p>
</Typography>
{subtitleSecondary ? (
<Typography
variant="Body/Supporting text (caption)/smRegular"
className={styles.subtitleSecondary}
>
<p>{subtitleSecondary}</p>
</Typography>
) : null}
<Typography variant="Body/Paragraph/mdBold" className={styles.subtitle}>
<p>{subtitle}</p>
</Typography>
{description || descriptionSecondary ? (
<Divider
className={styles.divider}
variant="horizontal"
color="subtle"
/>
) : null}
{description ? (
<Typography
variant="Body/Supporting text (caption)/smRegular"
className={styles.description}
>
<p>{description}</p>
</Typography>
) : null}
{descriptionSecondary ? (
<Typography
variant="Body/Supporting text (caption)/smRegular"
className={styles.descriptionSecondary}
>
<p>{descriptionSecondary}</p>
</Typography>
) : null}
<input
{...register(name)}
aria-hidden

View File

@@ -3,12 +3,22 @@
cursor: pointer;
display: grid;
grid-template-columns: 1fr auto;
grid-template-areas: "icon icon" "title subtitle";
grid-auto-rows: min-content;
grid-template-areas:
"icon subtitleSecondary"
"title subtitle";
border-radius: var(--Corner-radius-md);
border: 1px solid var(--Border-Intense);
background: var(--Surface-Primary-Default);
padding: var(--Space-x2) var(--Space-x3);
gap: var(--Space-x1);
transition:
background 0.2s ease,
border-color 0.2s ease;
}
.label:hover:not(.disabled) {
background: var(--Surface-Primary-Hover);
}
.label.disabled {
@@ -44,12 +54,34 @@
grid-area: icon;
}
.subtitle {
grid-area: subtitle;
color: var(--Text-Default);
}
.title {
grid-area: title;
color: var(--Text-Default);
}
.subtitle {
grid-area: subtitle;
color: var(--Text-Default);
justify-self: end;
}
.subtitleSecondary {
grid-area: subtitleSecondary;
place-self: end;
color: var(--Text-Default);
}
.divider {
grid-column: 1 / -1;
margin: var(--Space-x1) 0;
}
.description {
grid-column: 1 / -1;
color: var(--Text-Default);
}
.descriptionSecondary {
grid-column: 1 / -1;
color: var(--Text-Secondary);
}

View File

@@ -5,8 +5,11 @@ export interface RadioCardProps
Icon?: (props: IconProps) => JSX.Element
iconHeight?: number
name: string
subtitle?: React.ReactNode
subtitle: React.ReactNode
subtitleSecondary?: React.ReactNode
title: React.ReactNode
value?: string
disabled?: boolean
description?: React.ReactNode
descriptionSecondary?: React.ReactNode
}

View File

@@ -132,6 +132,8 @@
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Morgenmad ({totalChildren, plural, one {# barn} other {# børn}}) x {totalBreakfasts}",
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Morgenbuffet",
"Breakfast can be added after booking for an additional fee.": "Morgenmad kan tilføjes efter booking for en ekstra omkostning.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Morgenmad kan tilføjes efter booking for en ekstra omkostning for voksne og børn fra 4 år.",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Morgenmad kan kun tilføjes for hele opholdets varighed og for alle gæster.",
"Breakfast charge": "Morgenmadsgebyr",
"Breakfast deal can be purchased at the hotel.": "Morgenmad kan købes på hotellet.",
@@ -312,6 +314,7 @@
"Former Scandic Hotel": "Tidligere Scandic Hotel",
"Free": "Gratis",
"Free cancellation": "Gratis afbestilling",
"Free for kids aged 12 and under.": "Gratis for børn under 12 år.",
"Free parking": "Gratis parkering",
"Free rebooking": "Gratis ombooking",
"Free until": "Free until",
@@ -394,6 +397,7 @@
"In order to view your booking, please log in.": "Log ind for at se din reservation.",
"Incl. VAT": "Inkl. moms",
"Included": "Inkluderet",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Inkluderer veganske, glutenfrie og andre allergivenlige muligheder.",
"Indoor pool": "Indendørs pool",
"Indoor windows and excellent lighting": "Indoor windows and excellent lighting",
"Indoor windows facing the hotel": "Indoor windows facing the hotel",
@@ -595,6 +599,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Betaling vil ske ved check-in. Kortet vil kun blive brugt til at garantere tillægget i tilfælde af en no-show.",
"Per adult/night": "Pr. voksen/nat",
"Per night from": "Per nat fra",
"Pet room": "Kæledyrsrum",
"Pet room charge including VAT": "Gebyr for kæledyrsværelse inkl. moms",

View File

@@ -133,6 +133,8 @@
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Frühstück ({totalChildren, plural, one {# kind} other {# kinder}}) x {totalBreakfasts}",
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Frühstücksbuffet",
"Breakfast can be added after booking for an additional fee.": "Frühstück kann nach der Buchung für einen Aufpreis hinzugefügt werden.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Frühstück kann nach der Buchung für einen Aufpreis für Erwachsene und Kinder ab 4 Jahren hinzugefügt werden.",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Frühstück kann nur für die gesamte Aufenthaltsdauer und für alle Gäste hinzugefügt werden.",
"Breakfast charge": "Frühstücksgebühr",
"Breakfast deal can be purchased at the hotel.": "Frühstücksangebot kann im Hotel gekauft werden.",
@@ -313,6 +315,7 @@
"Former Scandic Hotel": "Ehemaliges Scandic Hotel",
"Free": "Kostenlos",
"Free cancellation": "Kostenlose Stornierung",
"Free for kids aged 12 and under.": "Kostenlos für Kinder bis 12 Jahre.",
"Free parking": "Kostenloses Parken",
"Free rebooking": "Kostenlose Umbuchung",
"Free until": "Free until",
@@ -395,6 +398,7 @@
"In order to view your booking, please log in.": "Um Ihre Buchung einzusehen, loggen Sie sich bitte ein.",
"Incl. VAT": "Inkl. MwSt.",
"Included": "Iinklusive",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Enthält vegane, glutenfreie und andere allergiefreundliche Optionen.",
"Indoor pool": "Innenpool",
"Indoor windows and excellent lighting": "Indoor windows and excellent lighting",
"Indoor windows facing the hotel": "Indoor windows facing the hotel",
@@ -594,6 +598,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Die Zahlung erfolgt beim Check-in. Die Karte wird nur zur Garantie der Nebenkosten im Falle eines No-Shows verwendet.",
"Per adult/night": "Pro Erwachsenem/Nacht",
"Per night from": "Pro Nacht ab",
"Pet room": "Haustierzimmer",
"Pet room charge including VAT": "Haustierzimmergebühr inkl. MwSt.",

View File

@@ -132,6 +132,9 @@
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Breakfast buffet",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Breakfast can only be added for the entire duration of the stay and for all guests.",
"Breakfast can be added after booking for an additional fee.": "Breakfast can be added after booking for an additional fee.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.",
"Breakfast can only be added for the entire duration of the stayand for all guests.": "Breakfast can only be added for the entire duration of the stayand for all guests.",
"Breakfast charge": "Breakfast charge",
"Breakfast deal can be purchased at the hotel.": "Breakfast deal can be purchased at the hotel.",
"Breakfast excluded": "Breakfast excluded",
@@ -311,6 +314,7 @@
"Former Scandic Hotel": "Former Scandic Hotel",
"Free": "Free",
"Free cancellation": "Free cancellation",
"Free for kids aged 12 and under.": "Free for kids aged 12 and under.",
"Free parking": "Free parking",
"Free rebooking": "Free rebooking",
"Free until": "Free until",
@@ -393,6 +397,7 @@
"In order to view your booking, please log in.": "In order to view your booking, please log in.",
"Incl. VAT": "Incl. VAT",
"Included": "Included",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Includes vegan, gluten-free, and other allergy-friendly options.",
"Indoor pool": "Indoor pool",
"Indoor windows and excellent lighting": "Indoor windows and excellent lighting",
"Indoor windows facing the hotel": "Indoor windows facing the hotel",
@@ -593,6 +598,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.",
"Per adult/night": "Per adult/night",
"Per night from": "Per night from",
"Pet room": "Pet room",
"Pet room charge including VAT": "Pet room charge including VAT",

View File

@@ -131,6 +131,8 @@
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Aamiainen ({totalChildren, plural, one {# lapsi} other {# lasta}}) x {totalBreakfasts}",
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Aamiaisbuffet",
"Breakfast can be added after booking for an additional fee.": "Aamiaista voi lisätä varauksen jälkeen lisämaksulla.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Aamiaista voi lisätä varauksen jälkeen lisämaksulla aikuisille ja 4-vuotiaille ja sitä vanhemmille lapsille.",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Aamiainen voidaan lisätä vain koko oleskelun ajaksi ja kaikille asiakkaille.",
"Breakfast charge": "Aamiaismaksu",
"Breakfast deal can be purchased at the hotel.": "Aamiaisdeali voidaan ostaa hotellissa.",
@@ -312,6 +314,7 @@
"Former Scandic Hotel": "Entinen Scandic-hotelli",
"Free": "Ilmainen",
"Free cancellation": "Ilmainen peruutus",
"Free for kids aged 12 and under.": "Ilmainen alle 12-vuotiaille lapsille.",
"Free parking": "Ilmainen pysäköinti",
"Free rebooking": "Ilmainen uudelleenvaraus",
"Free until": "Free until",
@@ -394,6 +397,7 @@
"In order to view your booking, please log in.": "Nähdäksesi varauksesi, ole hyvä ja kirjaudu sisään.",
"Incl. VAT": "Sis. ALV",
"Included": "Sisälly hintaan",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Sisältää vegaanisia, gluteenittomia ja muita allergiaystävällisiä vaihtoehtoja.",
"Indoor pool": "Sisäuima-allas",
"Indoor windows and excellent lighting": "Indoor windows and excellent lighting",
"Indoor windows facing the hotel": "Indoor windows facing the hotel",
@@ -593,6 +597,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Maksu suoritetaan sisäänkirjautumisen yhteydessä. Korttia käytetään vain lisäpalvelun varmistamiseen, jos varausmyyntiä ei tapahdu.",
"Per adult/night": "Aikuista kohden/yö",
"Per night from": "Per yö alkaen",
"Pet room": "Lemmikkihuone",
"Pet room charge including VAT": "Lemmikkihuoneen maksu sis. ALV",

View File

@@ -131,6 +131,8 @@
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Frokost ({totalChildren, plural, one {# barn} other {# barn}}) x {totalBreakfasts}",
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Breakfast buffet",
"Breakfast can be added after booking for an additional fee.": "Frokost kan legges til etter bestilling for en ekstra kostnad.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Frokost kan legges til etter bestilling for en ekstra kostnad for voksne og barn fra 4 år.",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Frokost kan bare legges til for hele oppholdets varighet og for alle gjester.",
"Breakfast charge": "Pris for frokost",
"Breakfast deal can be purchased at the hotel.": "Frokostdeal kan kjøpes på hotellet.",
@@ -311,6 +313,7 @@
"Former Scandic Hotel": "Tidligere Scandic-hotell",
"Free": "Gratis",
"Free cancellation": "Gratis avbestilling",
"Free for kids aged 12 and under.": "Gratis for barn under 12 år.",
"Free parking": "Gratis parkering",
"Free rebooking": "Gratis ombooking",
"Free until": "Free until",
@@ -393,6 +396,7 @@
"In order to view your booking, please log in.": "For å se bestillingen din, vennligst logg inn.",
"Incl. VAT": "Inkl. MVA",
"Included": "Inkludert",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Inkluderer veganske, glutenfrie og andre allergivennlige alternativer.",
"Indoor pool": "Innendørs basseng",
"Indoor windows and excellent lighting": "Indoor windows and excellent lighting",
"Indoor windows facing the hotel": "Indoor windows facing the hotel",
@@ -592,6 +596,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Betaling vil skje ved innsjekking. Kortet vil kun bli brukt til å garantere tillegget i tilfelle av en no-show.",
"Per adult/night": "Per voksen/natt",
"Per night from": "Per nat fra",
"Pet room": "Kjæledyrsrom",
"Pet room charge including VAT": "Kjæledyrromsgebyr inkl. MVA",

View File

@@ -131,6 +131,8 @@
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Frukost ({totalChildren, plural, one {# barn} other {# barn}}) x {totalBreakfasts}",
"Breakfast Restaurant": "Breakfast Restaurant",
"Breakfast buffet": "Frukostbuffé",
"Breakfast can be added after booking for an additional fee.": "Frukost kan läggas till efter bokning för en extra kostnad.",
"Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Frukost kan läggas till efter bokning för en extra kostnad för vuxna och barn från 4 år.",
"Breakfast can only be added for the entire duration of the stay and for all guests.": "Frukost kan endast läggas till för hela vistelsens varaktighet och för alla gäster.",
"Breakfast charge": "Frukostpris",
"Breakfast deal can be purchased at the hotel.": "Frukostdeal kan köpas på hotellet.",
@@ -311,6 +313,7 @@
"Former Scandic Hotel": "Tidigare Scandichotell",
"Free": "Gratis",
"Free cancellation": "Fri avbokning",
"Free for kids aged 12 and under.": "Gratis för barn under 12 år.",
"Free parking": "Gratis parkering",
"Free rebooking": "Fri ombokning",
"Free until": "Free until",
@@ -393,6 +396,7 @@
"In order to view your booking, please log in.": "För att se din bokning, vänligen logga in.",
"Incl. VAT": "Inkl. moms",
"Included": "Inkluderad",
"Includes vegan, gluten-free, and other allergy-friendly options.": "Inkluderar veganska, glutenfria och andra allergivänliga alternativ.",
"Indoor pool": "Inomhuspool",
"Indoor windows and excellent lighting": "Fönster inomhus och utmärkt belysning",
"Indoor windows facing the hotel": "Inomhusfönster mot hotellet",
@@ -592,6 +596,7 @@
"Payment received": "Payment received",
"Payment status": "Payment status",
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.": "Betalning kommer att ske vid incheckning. Kortet kommer endast att användas för att garantera tillägget i händelse av no-show.",
"Per adult/night": "Per vuxen/natt",
"Per night from": "Per natt från",
"Pet room": "Husdjursrum",
"Pet room charge including VAT": "Avgift för husdjursrum inkl. moms",

View File

@@ -14,12 +14,6 @@ export interface AncillaryCardProps {
}
}
export interface BreakfastChoiceCardProps extends AncillaryCardProps {
name: string
id?: string
value: string
}
export interface AncillaryChoiceCardProps extends AncillaryCardProps {
name: string
id?: string