Merged in fix/SW-2406-update-modal-ancillaries (pull request #1911)

fix(SW-2406): update modal for ancillaries

* fix(SW-2406): update modal for ancillaries

* fix(SW-2406): revert translations


Approved-by: Niclas Edenvin
Approved-by: Erik Tiekstra
This commit is contained in:
Bianca Widstam
2025-04-30 08:20:57 +00:00
parent f4fe2e3a4a
commit 7070770581
9 changed files with 98 additions and 95 deletions

View File

@@ -2,7 +2,7 @@
display: flex;
gap: var(--Spacing-x4);
justify-content: flex-end;
padding: var(--Space-x15) var(--Space-x15) 0;
padding: var(--Space-x2) var(--Space-x15) 0;
}
.confirmButtons {

View File

@@ -26,6 +26,7 @@ export default function ActionButtons({
const {
currentStep,
prevStep,
prevStepMobile,
selectQuantity,
selectDeliveryTime,
selectQuantityAndDeliveryTime,
@@ -33,6 +34,7 @@ export default function ActionButtons({
} = useAddAncillaryStore((state) => ({
currentStep: state.currentStep,
prevStep: state.prevStep,
prevStepMobile: state.prevStepMobile,
selectQuantity: state.selectQuantity,
selectDeliveryTime: state.selectDeliveryTime,
selectQuantityAndDeliveryTime: state.selectQuantityAndDeliveryTime,
@@ -116,7 +118,7 @@ export default function ActionButtons({
variant="Text"
size="Small"
color="Primary"
onPress={prevStep}
onPress={isMobile ? prevStepMobile : prevStep}
>
{intl.formatMessage({
defaultMessage: "Back",

View File

@@ -1,15 +1,15 @@
.selectContainer {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
margin-bottom: var(--Spacing-x2);
gap: var(--Space-x2);
padding: var(--Space-x3);
margin-bottom: var(--Space-x05);
background-color: var(--Base-Background-Primary-Normal);
border-radius: var(--Corner-radius-Medium);
}
.select {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
padding: var(--Spacing-x2) var(--Spacing-x3);
background-color: var(--Base-Background-Primary-Normal);
border-radius: var(--Corner-radius-Medium);
gap: var(--Space-x1);
}

View File

@@ -1,11 +1,10 @@
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { generateDeliveryOptions } from "@/components/HotelReservation/MyStay/utils/ancillaries"
import Input from "@/components/TempDesignSystem/Form/Input"
import Select from "@/components/TempDesignSystem/Form/Select"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./deliveryDetailsStep.module.css"
@@ -16,11 +15,13 @@ export default function DeliveryMethodStep() {
return (
<div className={styles.selectContainer}>
<div className={styles.select}>
<Subtitle type="two">
{intl.formatMessage({
defaultMessage: "Delivered at:",
})}
</Subtitle>
<Typography variant="Body/Supporting text (caption)/smBold">
<h3>
{intl.formatMessage({
defaultMessage: "Delivered at:",
})}
</h3>
</Typography>
<Select
name="deliveryTime"
label={""}
@@ -28,13 +29,15 @@ export default function DeliveryMethodStep() {
registerOptions={{ required: true }}
isNestedInModal
/>
<Body>
</div>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage({
defaultMessage:
"All add-ons are delivered at the same time. Changes to delivery times will affect earlier add-ons.",
})}
</Body>
</div>
</p>
</Typography>
<div className={styles.select}>
<Input
label={intl.formatMessage({
@@ -42,11 +45,13 @@ export default function DeliveryMethodStep() {
})}
name="optionalText"
/>
<Caption>
{intl.formatMessage({
defaultMessage: "Optional",
})}
</Caption>
<Typography variant="Body/Supporting text (caption)/smRegular">
<h3>
{intl.formatMessage({
defaultMessage: "Optional",
})}
</h3>
</Typography>
</div>
</div>
)

View File

@@ -50,20 +50,12 @@ export default function SelectQuantityStep({ user }: SelectQuantityStepProps) {
const insufficientPoints = currentPoints < pointsCost || currentPoints === 0
const pointsLabel = insufficientPoints
? intl.formatMessage({
defaultMessage: "Insufficient points",
})
: intl.formatMessage({
defaultMessage: "Select quantity",
})
return (
<div className={styles.selectContainer}>
{selectedAncillary?.points && user && (
<div className={styles.select}>
<Typography variant="Title/Subtitle/md">
<h2>
<h2 className={styles.selectTitle}>
{intl.formatMessage({
defaultMessage: "Pay with points",
})}
@@ -84,18 +76,29 @@ export default function SelectQuantityStep({ user }: SelectQuantityStepProps) {
<p>{currentPoints}</p>
</Typography>
</div>
<Select
name="quantityWithPoints"
label={pointsLabel}
items={pointsQuantityOptions}
disabled={insufficientPoints}
isNestedInModal
/>
{insufficientPoints ? (
<Typography variant="Body/Supporting text (caption)/smRegular">
<h2 className={styles.insufficientPoints}>
{intl.formatMessage({
defaultMessage: "Insufficient points",
})}
</h2>
</Typography>
) : (
<Select
name="quantityWithPoints"
label={intl.formatMessage({
defaultMessage: "Select quantity",
})}
items={pointsQuantityOptions}
isNestedInModal
/>
)}
</div>
)}
<div className={styles.select}>
<Typography variant="Title/Subtitle/md">
<h2>
<h2 className={styles.selectTitle}>
{
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
" "

View File

@@ -2,7 +2,6 @@
display: flex;
flex-direction: column;
gap: var(--Space-x025);
margin-bottom: var(--Space-x2);
}
.select {
@@ -15,6 +14,14 @@
margin-bottom: var(--Spacing-x1);
}
.selectTitle {
margin-bottom: var(--Space-x1);
}
.insufficientPoints {
color: var(--Text-Tertiary);
}
.totalPointsContainer {
display: flex;
justify-content: space-between;
@@ -73,6 +80,9 @@
display: none;
}
@media screen and (min-width: 768px) {
.select {
margin-bottom: 0;
}
.icon {
display: block;
}

View File

@@ -3,6 +3,7 @@
flex-direction: column;
max-height: 70dvh;
width: 100%;
margin-top: var(--Space-x3);
}
.form {
@@ -19,22 +20,6 @@
.modalScrollable {
display: flex;
flex-direction: column;
margin-bottom: var(--Spacing-x2);
}
.imageContainer {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
border-radius: var(--Corner-radius-Medium);
overflow: hidden;
margin-top: var(--Spacing-x1);
flex-shrink: 0;
margin-bottom: var(--Spacing-x3);
}
.image {
object-fit: cover;
}
.price {
@@ -52,12 +37,10 @@
display: flex;
flex-direction: column;
justify-content: space-between;
position: sticky;
border-radius: var(--Corner-radius-Medium);
bottom: 0;
z-index: 10;
background: var(--Surface-Primary-OnSurface-Default);
padding-bottom: var(--Space-x15);
margin-top: var(--Space-x2);
}
.description {
@@ -65,15 +48,6 @@
margin: var(--Spacing-x2) 0;
}
.actionButtons {
position: sticky;
bottom: 0;
z-index: 10;
background: var(--UI-Opacity-White-100);
border-top: 1px solid var(--Base-Border-Normal);
padding-bottom: var(--Space-x025);
}
.pointsDivider {
display: flex;
gap: var(--Space-x2);

View File

@@ -26,7 +26,6 @@ import {
getAncillarySessionData,
setAncillarySessionData,
} from "@/components/HotelReservation/MyStay/utils/ancillaries"
import Image from "@/components/Image"
import LoadingSpinner from "@/components/LoadingSpinner"
import Modal from "@/components/Modal"
import Divider from "@/components/TempDesignSystem/Divider"
@@ -351,14 +350,6 @@ export default function AddAncillaryFlowModal({
<div className={styles.modalScrollable}>
{selectedAncillary && (
<>
<div className={styles.imageContainer}>
<Image
className={styles.image}
src={selectedAncillary.imageUrl}
alt={selectedAncillary.title}
fill
/>
</div>
{currentStep !== AncillaryStepEnum.confirmation && (
<div className={styles.contentContainer}>
<div className={styles.price}>
@@ -409,24 +400,24 @@ export default function AddAncillaryFlowModal({
</>
)}
<Steps user={user} savedCreditCards={savedCreditCards} />
{currentStep === AncillaryStepEnum.selectAncillary ? null : (
<div
className={
currentStep === AncillaryStepEnum.confirmation
? styles.confirmStep
: ""
}
>
<PriceDetails isPriceDetailsOpen={isPriceDetailsOpen} />
<ActionButtons
isPriceDetailsOpen={isPriceDetailsOpen}
togglePriceDetails={togglePriceDetails}
isSubmitting={addAncillary.isPending || isLoading}
/>
</div>
)}
</div>
</form>
{currentStep === AncillaryStepEnum.selectAncillary ? null : (
<div
className={
currentStep === AncillaryStepEnum.confirmation
? styles.confirmStep
: styles.actionButtons
}
>
<PriceDetails isPriceDetailsOpen={isPriceDetailsOpen} />
<ActionButtons
isPriceDetailsOpen={isPriceDetailsOpen}
togglePriceDetails={togglePriceDetails}
isSubmitting={addAncillary.isPending || isLoading}
/>
</div>
)}
</FormProvider>
</div>
</Modal>

View File

@@ -52,6 +52,7 @@ export interface AddAncillaryState {
openModal: () => void
closeModal: () => void
prevStep: () => void
prevStepMobile: () => void
breakfastData: BreakfastData | null
setBreakfastData: (breakfastData: BreakfastData | null) => void
isBreakfast: boolean
@@ -194,6 +195,23 @@ export const createAddAncillaryStore = (
}
})
),
prevStepMobile: () =>
set(
produce((state: AddAncillaryState) => {
if (state.currentStep === AncillaryStepEnum.selectQuantity) {
state.isOpen = false
clearAncillarySessionData()
state.selectedAncillary = null
state.steps = steps
} else {
if (state.currentStep === AncillaryStepEnum.confirmation) {
state.currentStep = AncillaryStepEnum.selectQuantity
} else {
state.currentStep = state.currentStep - 1
}
}
})
),
selectAncillary: (ancillary) =>
set(
produce((state: AddAncillaryState) => {