Merged in fix/STAY-133 (pull request #3313)
Fix/STAY-133 * fix: Add static summary buttons row on add ancillary flow * fix: refactor handling of modals * fix: refactor file structure for add ancillary flow * Merged in chore/replace-deprecated-body (pull request #3300) Replace deprecated <Body> with <Typography> * chore: replace deprecated body component * refactor: replace Body component with Typography across various components * merge Approved-by: Bianca Widstam Approved-by: Matilda Landström Approved-by: Bianca Widstam Approved-by: Matilda Landström
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow"
|
||||
|
||||
import styles from "./priceDetails.module.css"
|
||||
|
||||
import type { SelectedAncillary } from "@/types/components/myPages/myStay/ancillaries"
|
||||
|
||||
export default function PriceDetails({
|
||||
totalPoints,
|
||||
totalPrice,
|
||||
selectedAncillary,
|
||||
}: {
|
||||
totalPoints: number | null
|
||||
totalPrice: number | null
|
||||
selectedAncillary: SelectedAncillary
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
|
||||
const { isBreakfast, breakfastData } = useAddAncillaryStore((state) => ({
|
||||
isBreakfast: state.isBreakfast,
|
||||
breakfastData: state.breakfastData,
|
||||
}))
|
||||
|
||||
if (isBreakfast && !breakfastData) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.totalPrice}>
|
||||
<div className={styles.totalPriceInclVAT}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "common.total",
|
||||
defaultMessage: "Total",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
{totalPrice && (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p className={styles.vatText}>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{`(${intl.formatMessage({
|
||||
id: "common.inclVAT",
|
||||
defaultMessage: "Incl. VAT",
|
||||
})})`}
|
||||
</p>
|
||||
</Typography>
|
||||
)}
|
||||
{isBreakfast && breakfastData ? (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p className={styles.hideOnDesktop}>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "booking.numberOfNights",
|
||||
defaultMessage:
|
||||
"{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{
|
||||
totalNights: breakfastData.nrOfNights,
|
||||
}
|
||||
) +
|
||||
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
|
||||
" / " +
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: "common.numberOfGuests",
|
||||
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(
|
||||
{
|
||||
id: "booking.numberOfNights",
|
||||
defaultMessage:
|
||||
"{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{
|
||||
totalNights: breakfastData.nrOfNights,
|
||||
}
|
||||
) +
|
||||
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
|
||||
" / " +
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: "common.numberOfGuests",
|
||||
defaultMessage:
|
||||
"{value, plural, one {# guest} other {# guests}}",
|
||||
},
|
||||
{
|
||||
value:
|
||||
breakfastData.nrOfAdults +
|
||||
breakfastData.nrOfPayingChildren +
|
||||
breakfastData.nrOfFreeChildren,
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
<Divider variant="vertical" />
|
||||
</>
|
||||
) : null}
|
||||
{totalPrice && (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{formatPrice(
|
||||
intl,
|
||||
totalPrice,
|
||||
selectedAncillary.price.currency
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
)}
|
||||
{totalPoints && totalPrice && <Divider variant="vertical" />}
|
||||
{totalPoints && (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "common.numberOfPoints",
|
||||
defaultMessage:
|
||||
"{points, plural, one {# point} other {# points}}",
|
||||
},
|
||||
{ points: totalPoints }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
.totalPrice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--Space-x1);
|
||||
border-radius: var(--Corner-radius-md);
|
||||
}
|
||||
|
||||
.showOnDesktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.totalPriceInclVAT {
|
||||
display: flex;
|
||||
gap: var(--Space-x15);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.totalPriceValue {
|
||||
display: flex;
|
||||
gap: var(--Space-x1);
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.vatText {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.showOnDesktop {
|
||||
display: block;
|
||||
}
|
||||
.hideOnDesktop {
|
||||
display: none;
|
||||
}
|
||||
.totalPrice {
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import styles from "./priceRow.module.css"
|
||||
|
||||
interface PriceRowProps {
|
||||
title: string
|
||||
quantity: number
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export default function PriceRow({
|
||||
title,
|
||||
quantity,
|
||||
label,
|
||||
value,
|
||||
}: PriceRowProps) {
|
||||
return (
|
||||
<>
|
||||
<div className={styles.column}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<h2>{title}</h2>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
<p>{`×${quantity}`}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.column}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<h2 className={styles.priceText}>{label}</h2>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<h2 className={styles.priceText}>{value}</h2>
|
||||
</Typography>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.column {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.priceText {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import { Fragment } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import PriceRow from "./PriceRow"
|
||||
|
||||
import styles from "./priceSummary.module.css"
|
||||
|
||||
interface PriceSummaryProps {
|
||||
totalPrice: number | null
|
||||
totalPoints: number | null
|
||||
|
||||
items: {
|
||||
title: string
|
||||
totalPrice: number
|
||||
currency: string
|
||||
points?: number
|
||||
quantityWithCard?: number
|
||||
quantityWithPoints?: number
|
||||
}[]
|
||||
}
|
||||
|
||||
export function PriceSummary({
|
||||
totalPrice,
|
||||
totalPoints,
|
||||
items,
|
||||
}: PriceSummaryProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<h2>
|
||||
{intl.formatMessage({
|
||||
id: "common.summary",
|
||||
defaultMessage: "Summary",
|
||||
})}
|
||||
</h2>
|
||||
</Typography>
|
||||
<Divider />
|
||||
|
||||
{items.map((item) => (
|
||||
<Fragment key={item.title}>
|
||||
{!!item.quantityWithCard && (
|
||||
<PriceRow
|
||||
title={item.title}
|
||||
quantity={item.quantityWithCard}
|
||||
label={intl.formatMessage({
|
||||
id: "common.price",
|
||||
defaultMessage: "Price",
|
||||
})}
|
||||
value={formatPrice(intl, item.totalPrice, item.currency)}
|
||||
/>
|
||||
)}
|
||||
{!!item.quantityWithPoints && (
|
||||
<PriceRow
|
||||
title={item.title}
|
||||
quantity={item.quantityWithPoints}
|
||||
label={intl.formatMessage({
|
||||
id: "common.points",
|
||||
defaultMessage: "Points",
|
||||
})}
|
||||
value={intl.formatMessage(
|
||||
{
|
||||
id: "common.numberOfPoints",
|
||||
defaultMessage:
|
||||
"{points, plural, one {# point} other {# points}}",
|
||||
},
|
||||
{ points: item.points }
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<Divider />
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
<div className={styles.column}>
|
||||
{totalPrice ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "booking.totalPriceInclVat",
|
||||
defaultMessage: "<b>Total price</b> (incl VAT)",
|
||||
},
|
||||
{
|
||||
b: (str) => (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<span>{str}</span>
|
||||
</Typography>
|
||||
),
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "common.totalPoints",
|
||||
defaultMessage: "Total points",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<div className={styles.totalPrice}>
|
||||
{(totalPoints || totalPrice) && (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{totalPrice
|
||||
? formatPrice(intl, totalPrice, items[0]?.currency)
|
||||
: null}
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{totalPoints && totalPrice ? " + " : null}
|
||||
{totalPoints
|
||||
? intl.formatMessage(
|
||||
{
|
||||
id: "common.numberOfPoints",
|
||||
defaultMessage:
|
||||
"{points, plural, one {# point} other {# points}}",
|
||||
},
|
||||
{ points: totalPoints }
|
||||
)
|
||||
: null}
|
||||
</p>
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
.container {
|
||||
display: flex;
|
||||
padding: var(--Space-x3);
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x2);
|
||||
align-self: stretch;
|
||||
border-radius: var(--Corner-radius-lg);
|
||||
border: 1px solid var(--Border-Divider-Default);
|
||||
background: var(--Surface-Primary-Default);
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.totalPrice {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
import { cx } from "class-variance-authority"
|
||||
import { useState } from "react"
|
||||
import { useFormContext } from "react-hook-form"
|
||||
import { type IntlShape, useIntl } from "react-intl"
|
||||
import { useMediaQuery } from "usehooks-ts"
|
||||
|
||||
import { Button, type ButtonProps } from "@scandic-hotels/design-system/Button"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
|
||||
import {
|
||||
AncillaryStepEnum,
|
||||
type BreakfastData,
|
||||
useAddAncillaryStore,
|
||||
} from "@/stores/my-stay/add-ancillary-flow"
|
||||
|
||||
import { trackAddAncillary } from "@/utils/tracking/myStay"
|
||||
|
||||
import PriceDetails from "./PriceDetails"
|
||||
import { PriceSummary } from "./PriceSummary"
|
||||
|
||||
import styles from "./summary.module.css"
|
||||
|
||||
import type { SelectedAncillary } from "@/types/components/myPages/myStay/ancillaries"
|
||||
|
||||
export default function Summary({
|
||||
isConfirmation = false,
|
||||
}: {
|
||||
isConfirmation?: boolean
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||
const [isPriceDetailsOpen, setIsPriceDetailsOpen] = useState(false)
|
||||
function togglePriceDetails() {
|
||||
setIsPriceDetailsOpen((isOpen) => !isOpen)
|
||||
}
|
||||
const {
|
||||
prevStep,
|
||||
selectedAncillary,
|
||||
isBreakfast,
|
||||
breakfastData,
|
||||
currentStep,
|
||||
selectQuantityAndDeliveryTime,
|
||||
selectDeliveryTime,
|
||||
selectQuantity,
|
||||
} = useAddAncillaryStore((state) => ({
|
||||
prevStep: state.prevStep,
|
||||
currentStep: state.currentStep,
|
||||
selectedAncillary: state.selectedAncillary,
|
||||
isBreakfast: state.isBreakfast,
|
||||
breakfastData: state.breakfastData,
|
||||
selectQuantityAndDeliveryTime: state.selectQuantityAndDeliveryTime,
|
||||
selectQuantity: state.selectQuantity,
|
||||
selectDeliveryTime: state.selectDeliveryTime,
|
||||
}))
|
||||
|
||||
const {
|
||||
watch,
|
||||
trigger,
|
||||
formState: { isSubmitting },
|
||||
} = useFormContext()
|
||||
|
||||
const quantityWithCard = watch("quantityWithCard") as number
|
||||
const quantityWithPoints = watch("quantityWithPoints") as number
|
||||
|
||||
async function handleNextStep() {
|
||||
if (currentStep === AncillaryStepEnum.selectQuantity) {
|
||||
const isValid = await trigger(["quantityWithCard", "quantityWithPoints"])
|
||||
if (isValid) {
|
||||
trackAddAncillary(
|
||||
selectedAncillary,
|
||||
quantityWithCard,
|
||||
quantityWithPoints,
|
||||
breakfastData
|
||||
)
|
||||
if (isMobile) {
|
||||
selectQuantityAndDeliveryTime()
|
||||
} else {
|
||||
selectQuantity()
|
||||
}
|
||||
}
|
||||
} else if (currentStep === AncillaryStepEnum.selectDelivery) {
|
||||
selectDeliveryTime()
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedAncillary || (!breakfastData && isBreakfast)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isSingleItem = !selectedAncillary.requiresQuantity
|
||||
|
||||
const buttonProps: ButtonProps = isConfirmation
|
||||
? {
|
||||
type: "submit",
|
||||
form: "add-ancillary-form-id",
|
||||
variant: "Primary",
|
||||
}
|
||||
: {
|
||||
type: "button",
|
||||
onPress: handleNextStep,
|
||||
variant: isSingleItem ? "Primary" : "Secondary",
|
||||
}
|
||||
|
||||
const buttonLabel = isConfirmation
|
||||
? intl.formatMessage({
|
||||
id: "common.confirm",
|
||||
defaultMessage: "Confirm",
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: "common.continue",
|
||||
defaultMessage: "Continue",
|
||||
})
|
||||
|
||||
const items = isBreakfast
|
||||
? getBreakfastItems(intl, selectedAncillary, breakfastData)
|
||||
: [
|
||||
{
|
||||
title: selectedAncillary.title,
|
||||
totalPrice: selectedAncillary.price.total,
|
||||
currency: selectedAncillary.price.currency,
|
||||
points: selectedAncillary.points,
|
||||
quantityWithCard,
|
||||
quantityWithPoints,
|
||||
},
|
||||
]
|
||||
|
||||
const totalPrice = isBreakfast
|
||||
? breakfastData!.totalPrice
|
||||
: quantityWithCard && selectedAncillary
|
||||
? selectedAncillary.price.total * quantityWithCard
|
||||
: null
|
||||
|
||||
const totalPoints =
|
||||
quantityWithPoints && selectedAncillary?.points
|
||||
? selectedAncillary.points * quantityWithPoints
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className={styles.summary}>
|
||||
<div
|
||||
className={cx({
|
||||
[styles.backgroundBox]: isConfirmation || isSingleItem,
|
||||
})}
|
||||
>
|
||||
{(isSingleItem || isConfirmation) && (
|
||||
<PriceDetails
|
||||
totalPrice={totalPrice}
|
||||
totalPoints={totalPoints}
|
||||
selectedAncillary={selectedAncillary}
|
||||
/>
|
||||
)}
|
||||
{isConfirmation && isPriceDetailsOpen && (
|
||||
<PriceSummary
|
||||
totalPrice={totalPrice}
|
||||
totalPoints={totalPoints}
|
||||
items={items}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className={cx({
|
||||
[styles.confirmButtons]: isConfirmation,
|
||||
})}
|
||||
>
|
||||
{isConfirmation && (
|
||||
<Button
|
||||
type="button"
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
size="Small"
|
||||
variant="Text"
|
||||
onPress={togglePriceDetails}
|
||||
className={styles.priceButton}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "commonpriceDetails",
|
||||
defaultMessage: "Price details",
|
||||
})}
|
||||
<MaterialIcon
|
||||
icon={
|
||||
isPriceDetailsOpen
|
||||
? "keyboard_arrow_up"
|
||||
: "keyboard_arrow_down"
|
||||
}
|
||||
size={20}
|
||||
color="CurrentColor"
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
type="button"
|
||||
variant="Text"
|
||||
size="Small"
|
||||
color="Primary"
|
||||
onPress={() => prevStep(isMobile)}
|
||||
>
|
||||
{intl.formatMessage({
|
||||
id: "common.back",
|
||||
defaultMessage: "Back",
|
||||
})}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
typography="Body/Supporting text (caption)/smBold"
|
||||
size="Small"
|
||||
isDisabled={isSubmitting}
|
||||
isPending={isSubmitting}
|
||||
{...buttonProps}
|
||||
>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function getBreakfastItems(
|
||||
intl: IntlShape,
|
||||
selectedAncillary: SelectedAncillary,
|
||||
breakfastData: BreakfastData | null
|
||||
) {
|
||||
if (!breakfastData) {
|
||||
return []
|
||||
}
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: `${selectedAncillary.title} / ${intl.formatMessage({
|
||||
id: "common.adult",
|
||||
defaultMessage: "adult",
|
||||
})}`,
|
||||
totalPrice: breakfastData.priceAdult,
|
||||
currency: breakfastData.currency,
|
||||
quantityWithCard: breakfastData.nrOfAdults * breakfastData.nrOfNights,
|
||||
},
|
||||
]
|
||||
|
||||
if (breakfastData.nrOfPayingChildren > 0) {
|
||||
items.push({
|
||||
title: `${selectedAncillary.title} / ${intl.formatMessage({
|
||||
id: "common.children",
|
||||
defaultMessage: "Children",
|
||||
})} 4-12`,
|
||||
totalPrice: breakfastData.priceChild,
|
||||
currency: breakfastData.currency,
|
||||
quantityWithCard:
|
||||
breakfastData.nrOfPayingChildren * breakfastData.nrOfNights,
|
||||
})
|
||||
}
|
||||
|
||||
if (breakfastData.nrOfFreeChildren > 0) {
|
||||
items.push({
|
||||
title: `${selectedAncillary.title} / ${intl.formatMessage(
|
||||
{
|
||||
id: "common.childrenUnderAge",
|
||||
defaultMessage: "Children under {age}",
|
||||
},
|
||||
{ age: 4 }
|
||||
)}`,
|
||||
totalPrice: 0,
|
||||
currency: breakfastData.currency,
|
||||
quantityWithCard:
|
||||
breakfastData.nrOfFreeChildren * breakfastData.nrOfNights,
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
.summary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: var(--Space-x2) var(--Space-x2) var(--Space-x3);
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--Border-Default);
|
||||
}
|
||||
|
||||
.backgroundBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--Surface-Primary-OnSurface-Default);
|
||||
padding: var(--Space-x15);
|
||||
gap: var(--Space-x2);
|
||||
border-radius: var(--Corner-radius-md);
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: var(--Space-x4);
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.confirmButtons {
|
||||
display: flex;
|
||||
padding-left: var(--Space-x15);
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.priceButton {
|
||||
display: flex;
|
||||
gap: var(--Space-x05);
|
||||
}
|
||||
Reference in New Issue
Block a user