Merged in feat/SW-2612-mystay-breakfast-buffet-u (pull request #2059)

Feat: SW-2612 Updated breakfast ancillary UI and Optimised code

* Feat: SW-2612 Updated breakfast ancillary UI and Optimised code

* feat: SW-2612 Updated UI as per figma

* feat: SW-2612 Optimised code

* feat: SW-2612 Optimised code


Approved-by: Tobias Johansson
This commit is contained in:
Hrishikesh Vaipurkar
2025-05-16 08:32:54 +00:00
parent d489bc7aed
commit fa7d94093e
9 changed files with 113 additions and 38 deletions

View File

@@ -2,12 +2,12 @@
display: flex;
gap: var(--Spacing-x4);
justify-content: flex-end;
padding: var(--Space-x2) var(--Space-x15) 0;
padding: var(--Space-x2) var(--Space-x15) 0 0;
}
.confirmButtons {
display: flex;
padding: 0 var(--Space-x15);
padding-left: var(--Space-x15);
justify-content: space-between;
align-items: baseline;
}

View File

@@ -25,6 +25,7 @@ export default function ActionButtons({
}: ActionButtonsProps) {
const {
currentStep,
isBreakfast,
prevStep,
prevStepMobile,
selectQuantity,
@@ -33,6 +34,7 @@ export default function ActionButtons({
selectedAncillary,
} = useAddAncillaryStore((state) => ({
currentStep: state.currentStep,
isBreakfast: state.isBreakfast,
prevStep: state.prevStep,
prevStepMobile: state.prevStepMobile,
selectQuantity: state.selectQuantity,
@@ -96,19 +98,13 @@ export default function ActionButtons({
{intl.formatMessage({
defaultMessage: "Price details",
})}
{isPriceDetailsOpen ? (
<MaterialIcon
icon="keyboard_arrow_up"
size={20}
color="Icon/Interactive/Accent"
/>
) : (
<MaterialIcon
icon="keyboard_arrow_down"
size={20}
color="Icon/Interactive/Accent"
/>
)}
<MaterialIcon
icon={
isPriceDetailsOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"
}
size={20}
color="Icon/Interactive/Accent"
/>
</Button>
)}
<div className={styles.buttons}>
@@ -140,7 +136,7 @@ export default function ActionButtons({
<Button
type="button"
typography="Body/Supporting text (caption)/smBold"
variant="Secondary"
variant={isBreakfast ? "Primary" : "Secondary"}
size="Small"
isDisabled={isSubmitting}
onPress={handleNextStep}

View File

@@ -1,3 +1,4 @@
import { Fragment } from "react"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
@@ -44,7 +45,7 @@ export default function PriceSummary({
<Divider color="subtle" />
{items.map((item) => (
<>
<Fragment key={item.title}>
{!!item.quantityWithCard && (
<PriceRow
title={item.title}
@@ -68,7 +69,7 @@ export default function PriceSummary({
/>
)}
<Divider color="subtle" />
</>
</Fragment>
))}
<div className={styles.column}>

View File

@@ -37,7 +37,10 @@ export default function PriceDetails({
const quantityWithPoints = useWatch({ name: "quantityWithPoints" })
const quantityWithCard = useWatch({ name: "quantityWithCard" })
if (!selectedAncillary || currentStep !== AncillaryStepEnum.confirmation) {
if (
!selectedAncillary ||
(currentStep !== AncillaryStepEnum.confirmation && !isBreakfast)
) {
return null
}
@@ -147,8 +150,69 @@ export default function PriceDetails({
</p>
</Typography>
)}
{isBreakfast && breakfastData ? (
<Typography variant="Body/Paragraph/mdBold">
<p className={styles.hideOnDesktop}>
{intl.formatMessage(
{
defaultMessage:
"{totalNights, plural, one {# night} other {# nights}}",
},
{
totalNights: breakfastData.nrOfNights,
}
) +
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
" / " +
intl.formatMessage(
{
defaultMessage:
"{value, plural, one {# guest} other {# guests}}",
},
{
value:
breakfastData.nrOfAdults +
breakfastData.nrOfPayingChildren +
breakfastData.nrOfFreeChildren,
}
)}
</p>
</Typography>
) : null}
</div>
<div className={styles.totalPriceValue}>
{isBreakfast && breakfastData ? (
<>
<Typography variant="Body/Paragraph/mdBold">
<p className={styles.showOnDesktop}>
{intl.formatMessage(
{
defaultMessage:
"{totalNights, plural, one {# night} other {# nights}}",
},
{
totalNights: breakfastData.nrOfNights,
}
) +
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
" / " +
intl.formatMessage(
{
defaultMessage:
"{value, plural, one {# guest} other {# guests}}",
},
{
value:
breakfastData.nrOfAdults +
breakfastData.nrOfPayingChildren +
breakfastData.nrOfFreeChildren,
}
)}
</p>
</Typography>
<Divider variant="vertical" color="subtle" />
</>
) : null}
{hasTotalPrice && (
<Typography variant="Body/Paragraph/mdBold">
<p>
@@ -185,7 +249,7 @@ export default function PriceDetails({
</div>
</div>
<Divider color="subtle" />
{isPriceDetailsOpen && (
{isPriceDetailsOpen && currentStep === AncillaryStepEnum.confirmation && (
<PriceSummary
totalPrice={totalPrice}
totalPoints={totalPoints}

View File

@@ -1,16 +1,20 @@
.totalPrice {
display: flex;
align-items: baseline;
align-items: center;
justify-content: space-between;
gap: var(--Spacing-x1);
padding: var(--Spacing-x-one-and-half);
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-md);
}
.showOnDesktop {
display: none;
}
.totalPriceInclVAT {
display: flex;
gap: var(--Space-x15);
flex-wrap: wrap;
}
.totalPriceValue {
@@ -22,3 +26,15 @@
.vatText {
color: var(--Text-Tertiary);
}
@media screen and (min-width: 768px) {
.showOnDesktop {
display: block;
}
.hideOnDesktop {
display: none;
}
.totalPrice {
align-items: baseline;
}
}

View File

@@ -126,10 +126,6 @@ function BreakfastInfo() {
const intl = useIntl()
const breakfastData = useAddAncillaryStore((state) => state.breakfastData)
const { setValue } = useFormContext()
setValue("quantityWithCard", 1)
if (!breakfastData) {
return intl.formatMessage({
defaultMessage: "Can not show breakfast prices.",

View File

@@ -91,7 +91,8 @@ export default function AddAncillaryFlowModal({
const formMethods = useForm<AncillaryFormData>({
defaultValues: {
quantityWithPoints: null,
quantityWithCard: !user || hasInsufficientPoints ? 1 : null,
quantityWithCard:
!user || hasInsufficientPoints || isBreakfast ? 1 : null,
deliveryTime: defaultDeliveryTime,
optionalText: "",
termsAndConditions: false,
@@ -357,17 +358,17 @@ export default function AddAncillaryFlowModal({
<div className={styles.contentContainer}>
<div className={styles.price}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{isBreakfast ? (
<BreakfastPriceList />
) : (
formatPrice(
{isBreakfast ? (
<BreakfastPriceList />
) : (
<p>
{formatPrice(
intl,
selectedAncillary.price.total,
selectedAncillary.price.currency
)
)}
</p>
)}
</p>
)}
</Typography>
{selectedAncillary.points && (
<div className={styles.pointsDivider}>
@@ -406,7 +407,8 @@ export default function AddAncillaryFlowModal({
{currentStep === AncillaryStepEnum.selectAncillary ? null : (
<div
className={
currentStep === AncillaryStepEnum.confirmation
currentStep === AncillaryStepEnum.confirmation ||
isBreakfast
? styles.confirmStep
: ""
}

View File

@@ -2,7 +2,6 @@
display: flex;
flex-direction: column;
gap: var(--Spacing-x-half);
padding: 0 var(--Spacing-x2);
}
.header {

View File

@@ -1,3 +1,4 @@
import { Fragment } from "react"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
@@ -71,7 +72,7 @@ export function AddedAncillaries({
} X${ancillary.totalUnit}`
return (
<>
<Fragment key={ancillary.code}>
<Accordion className={styles.ancillaryMobile}>
<AccordionItem
title={ancillaryTitle}
@@ -209,7 +210,7 @@ export function AddedAncillaries({
) : null}
</div>
</div>
</>
</Fragment>
)
})}
</div>