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

@@ -0,0 +1,63 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow"
import WrappedAncillaryCard from "../../Card"
import styles from "./selectAncillaryStep.module.css"
export default function SelectAncillaryStep({
onClose,
}: {
onClose: () => void
}) {
const {
ancillariesBySelectedCategory,
selectedCategory,
categories,
selectCategory,
} = useAddAncillaryStore((state) => ({
categories: state.categories,
selectedCategory: state.selectedCategory,
ancillariesBySelectedCategory: state.ancillariesBySelectedCategory,
selectCategory: state.selectCategory,
}))
const intl = useIntl()
return (
<div className={styles.container}>
<div className={styles.tabs}>
{categories.map((categoryName) => (
<button
key={categoryName}
className={`${styles.chip} ${categoryName === selectedCategory ? styles.selected : ""}`}
onClick={() => selectCategory(categoryName)}
>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{categoryName
? categoryName
: intl.formatMessage({
id: "common.other",
defaultMessage: "Other",
})}
</p>
</Typography>
</button>
))}
</div>
<div className={styles.grid}>
{ancillariesBySelectedCategory.map((ancillary) => (
<WrappedAncillaryCard
key={ancillary.id}
ancillary={ancillary}
onClose={onClose}
/>
))}
</div>
</div>
)
}

View File

@@ -0,0 +1,34 @@
.container {
width: 100%;
}
.tabs {
display: flex;
gap: var(--Space-x1);
padding: var(--Space-x3) 0;
flex-wrap: wrap;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(251px, 1fr));
gap: var(--Space-x2);
height: 470px;
overflow-y: auto;
padding-right: var(--Space-x15);
margin-top: var(--Space-x2);
}
.chip {
border-radius: var(--Corner-radius-rounded);
padding: calc(var(--Space-x1) + var(--Space-x025)) var(--Space-x2);
cursor: pointer;
border: 1px solid var(--Border-Interactive-Default);
color: var(--Text-Default);
background-color: var(--Background-Secondary);
}
.chip.selected {
background: var(--Surface-Brand-Primary-3-Default);
color: var(--Text-Inverted);
}

View File

@@ -0,0 +1,19 @@
.modalWrapper {
display: flex;
flex-direction: column;
max-height: 70dvh;
width: 100%;
margin-top: var(--Space-x3);
}
@media screen and (min-width: 768px) {
.modalWrapper {
width: 600px;
}
}
@media screen and (min-width: 1052px) {
.modalWrapper {
width: 833px;
}
}

View File

@@ -0,0 +1,44 @@
"use client"
import { useState } from "react"
import { useIntl } from "react-intl"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Modal from "@scandic-hotels/design-system/Modal"
import SelectAncillaryStep from "./SelectAncillaryStep"
import styles from "./allAncillariesModal.module.css"
export default function AllAncillariesModal() {
const [isOpen, setIsOpen] = useState(false)
const intl = useIntl()
const modalTitle = intl.formatMessage({
id: "ancillaries.upgradeYourStay",
defaultMessage: "Upgrade your stay",
})
return (
<div>
<Button
variant="Text"
size="Small"
color="Primary"
onPress={() => setIsOpen(true)}
>
{intl.formatMessage({
id: "common.seeAll",
defaultMessage: "See all",
})}
<MaterialIcon icon="chevron_right" size={20} color="CurrentColor" />
</Button>
<Modal isOpen={isOpen} onToggle={setIsOpen} title={modalTitle}>
<div className={styles.modalWrapper}>
<SelectAncillaryStep onClose={() => setIsOpen(false)} />
</div>
</Modal>
</div>
)
}