Merged in fix/handle-single-ancillaries (pull request #3231)

Fix(STAY-128): Handle single ancillaries

* fix: refactor ancillaries flow

* fix: add logic to determine if an ancillary requires quantity

* fix: breakout ancillary description to its own component

* fix: cleanup

* fix: cleanup


Approved-by: Bianca Widstam
Approved-by: Erik Tiekstra
This commit is contained in:
Christel Westerberg
2025-11-28 15:02:45 +00:00
parent 4eee1cff64
commit 69f194f7bf
40 changed files with 1310 additions and 1197 deletions

View File

@@ -1,28 +1,23 @@
"use client"
import { use } from "react"
import { useIntl } from "react-intl"
import Title from "@scandic-hotels/design-system/Title"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import { Carousel } from "@/components/Carousel"
import { useAncillaries } from "@/hooks/useAncillaries"
import { AddAncillaryProvider } from "@/providers/AddAncillaryProvider"
import AddAncillaryFlowModal from "./AddAncillaryFlow/AddAncillaryFlowModal"
import AncillaryFlowModalWrapper from "./AddAncillaryFlow/AncillaryFlowModalWrapper"
import WrappedAncillaryCard from "./AddAncillaryFlow/WrappedAncillaryCard"
import AllAncillariesModal from "./AllAncillariesModal/input"
import { AddedAncillaries } from "./AddedAncillaries"
import { generateUniqueAncillaries, mapAncillaries } from "./utils"
import ViewAllAncillaries from "./ViewAllAncillaries"
import WrappedAncillaryCard from "./Card"
import styles from "./ancillaries.module.css"
import type {
AncillariesProps,
SelectedAncillary,
} from "@/types/components/myPages/myStay/ancillaries"
import type { AncillariesProps } from "@/types/components/myPages/myStay/ancillaries"
export function Ancillaries({
ancillariesPromise,
@@ -31,91 +26,35 @@ export function Ancillaries({
user,
}: AncillariesProps) {
const intl = useIntl()
const ancillaries = use(ancillariesPromise)
const bookedRoom = useMyStayStore((state) => state.bookedRoom)
if (!bookedRoom || bookedRoom.isCancelled || !bookedRoom.showAncillaries) {
const ancillaries = useAncillaries(ancillariesPromise, packages, user)
if (!ancillaries || !bookedRoom) {
return null
}
const alreadyHasBreakfast =
bookedRoom.rateDefinition.breakfastIncluded || bookedRoom.breakfast
const breakfastPackageAdults = alreadyHasBreakfast
? undefined
: packages?.find(
(p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
)
/**
* A constructed ancillary for breakfast
*
* This is a "fake" ancillary for breakfast, since breakfast isn't really an
* ancillary in the system. This makes it play nicely with the add ancillary
* flow. If the user shouldn't be able to add breakfast this will be `undefined`.
*/
const breakfastAncillary: SelectedAncillary | undefined =
breakfastPackageAdults
? {
description: intl.formatMessage({
id: "common.buffet",
defaultMessage: "Buffet",
}),
id: breakfastPackageAdults.code,
title: intl.formatMessage({
id: "common.breakfast",
defaultMessage: "Breakfast",
}),
price: {
currency: breakfastPackageAdults.localPrice.currency,
total: breakfastPackageAdults.localPrice.totalPrice,
},
imageUrl:
"https://images.scandichotels.com/publishedmedia/inyre69evkpzgtygjnvp/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg",
requiresDeliveryTime: false,
loyaltyCode: undefined,
points: undefined,
hotelId: Number(bookedRoom.hotelId),
internalCategoryName: "Food",
translatedCategoryName: intl.formatMessage({
id: "common.food",
defaultMessage: "Food",
}),
}
: undefined
const allAncillaries = mapAncillaries(
intl,
ancillaries,
breakfastAncillary,
user
)
if (!allAncillaries.length) {
return null
}
const uniqueAncillaries = generateUniqueAncillaries(allAncillaries)
return (
<AddAncillaryProvider booking={bookedRoom} ancillaries={allAncillaries}>
<AddAncillaryProvider booking={bookedRoom} ancillaries={ancillaries.all}>
<div className={styles.container}>
{uniqueAncillaries.length > 0 && bookedRoom.canModifyAncillaries && (
{ancillaries.unique.length > 0 && bookedRoom.canModifyAncillaries && (
<>
<div className={styles.title}>
<Title as="h5">
{intl.formatMessage({
id: "ancillaries.upgradeYourStay",
defaultMessage: "Upgrade your stay",
})}
</Title>
<Typography variant="Title/Subtitle/lg">
<h2>
{intl.formatMessage({
id: "ancillaries.upgradeYourStay",
defaultMessage: "Upgrade your stay",
})}
</h2>
</Typography>
<div className={styles.viewAllLink}>
<ViewAllAncillaries />
<AllAncillariesModal />
</div>
</div>
<div className={styles.ancillaries}>
{uniqueAncillaries.slice(0, 4).map((ancillary) => (
{ancillaries.unique.slice(0, 4).map((ancillary) => (
<WrappedAncillaryCard
ancillary={ancillary}
key={ancillary.id}
@@ -126,7 +65,7 @@ export function Ancillaries({
<div className={styles.mobileAncillaries}>
<Carousel>
<Carousel.Content>
{uniqueAncillaries.map((ancillary) => {
{ancillaries.unique.map((ancillary) => {
return (
<Carousel.Item key={ancillary.id}>
<WrappedAncillaryCard ancillary={ancillary} />
@@ -142,7 +81,7 @@ export function Ancillaries({
<AddedAncillaries
booking={bookedRoom}
ancillaries={uniqueAncillaries}
ancillaries={ancillaries.unique}
/>
<AncillaryFlowModalWrapper>