Merged in feat/SW-1943-ancillaries-with-points (pull request #1598)

feat(SW-1943): fix design to pay with points

* feat(SW-1943): fix design to pay with points


Approved-by: Niclas Edenvin
This commit is contained in:
Bianca Widstam
2025-03-21 13:44:14 +00:00
parent 91e26e30af
commit 272c492b76
15 changed files with 160 additions and 78 deletions

View File

@@ -9,7 +9,7 @@
display: flex;
padding: 0 var(--Space-x15);
justify-content: space-between;
align-items: center;
align-items: baseline;
}
.priceButton {

View File

@@ -0,0 +1,38 @@
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">
<p>{`X${quantity}`}</p>
</Typography>
</div>
<div className={styles.column}>
<Typography variant="Body/Paragraph/mdRegular">
<h2>{label}</h2>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<h2>{value}</h2>
</Typography>
</div>
</>
)
}

View File

@@ -5,6 +5,8 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import Divider from "@/components/TempDesignSystem/Divider"
import { formatPrice } from "@/utils/numberFormatting"
import PriceRow from "./PriceRow"
import styles from "./priceSummary.module.css"
import type { Ancillary } from "@/types/components/myPages/myStay/ancillaries"
@@ -12,14 +14,16 @@ import type { Ancillary } from "@/types/components/myPages/myStay/ancillaries"
interface PriceSummaryProps {
totalPrice: number | null
totalPoints: number | null
totalUnits: number
quantityWithPoints: number
quantityWithCard: number
selectedAncillary: NonNullable<Ancillary["ancillaryContent"][number]>
}
export default function PriceSummary({
totalPrice,
totalPoints,
totalUnits,
quantityWithPoints,
quantityWithCard,
selectedAncillary,
}: PriceSummaryProps) {
const intl = useIntl()
@@ -33,61 +37,48 @@ export default function PriceSummary({
</Typography>
<Divider color="subtle" />
<div className={styles.column}>
<Typography variant="Body/Paragraph/mdBold">
<h2>{selectedAncillary.title}</h2>
</Typography>
<Typography variant="Body/Paragraph/mdBold">
<p>{`X${totalUnits}`}</p>
</Typography>
</div>
<div className={styles.column}>
<Typography variant="Body/Paragraph/mdRegular">
<h2>{intl.formatMessage({ id: "Price including VAT" })}</h2>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<h2>
{formatPrice(
intl,
selectedAncillary.price.total,
selectedAncillary.price.currency
)}
</h2>
</Typography>
</div>
{hasTotalPrice && (
<PriceRow
title={selectedAncillary.title}
quantity={quantityWithCard}
label={intl.formatMessage({ id: "Price including VAT" })}
value={formatPrice(
intl,
selectedAncillary.price.total,
selectedAncillary.price.currency
)}
/>
)}
{hasTotalPoints && (
<PriceRow
title={selectedAncillary.title}
quantity={quantityWithPoints}
label={intl.formatMessage({ id: "Points" })}
value={`${selectedAncillary.points} ${intl.formatMessage({ id: "points" })}`}
/>
)}
<Divider color="subtle" />
<div className={styles.column}>
<Typography variant="Body/Paragraph/mdRegular">
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage(
{ id: "<b>Total price</b> (incl VAT)" },
{ b: (str) => <b>{str}</b> }
)}
{hasTotalPrice
? intl.formatMessage({ id: "Total price including VAT" })
: intl.formatMessage({ id: "Total points" })}
</p>
</Typography>
<div className={styles.totalPrice}>
{hasTotalPoints && (
<div>
<div>
<Divider variant="vertical" color="subtle" />
</div>
<Typography variant="Body/Paragraph/mdBold">
<p>
{totalPoints} {intl.formatMessage({ id: "points" })}
{hasTotalPrice && "+"}
</p>
</Typography>
</div>
)}
{hasTotalPrice && (
{(hasTotalPoints || hasTotalPrice) && (
<Typography variant="Body/Paragraph/mdBold">
<p>
{formatPrice(
intl,
totalPrice,
selectedAncillary.price.currency
)}
{hasTotalPrice &&
formatPrice(
intl,
totalPrice,
selectedAncillary.price.currency
)}
{hasTotalPoints && hasTotalPrice && " + "}
{hasTotalPoints &&
`${totalPoints} ${intl.formatMessage({ id: "points" })}`}
</p>
</Typography>
)}

View File

@@ -43,44 +43,59 @@ export default function PriceDetails({
quantityWithPoints && selectedAncillary?.points
? selectedAncillary.points * quantityWithPoints
: null
const totalUnits = (quantityWithCard ?? 0) + (quantityWithPoints ?? 0)
const hasTotalPoints = typeof totalPoints === "number"
const hasTotalPrice = typeof totalPrice === "number"
return (
<>
<div className={styles.totalPrice}>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage(
{ id: "<b>Total price</b> (incl VAT)" },
{ b: (str) => <b>{str}</b> }
)}
</p>
</Typography>
{totalPrice !== null && (
<div className={styles.totalPriceInclVAT}>
<Typography variant="Body/Paragraph/mdBold">
<p>
{formatPrice(intl, totalPrice, selectedAncillary.price.currency)}
</p>
<p>{intl.formatMessage({ id: "Total" })}</p>
</Typography>
)}
{totalPoints !== null && (
<div>
<div>
<Divider variant="vertical" color="subtle" />
</div>
{totalPrice && (
<Typography variant="Body/Paragraph/mdRegular">
<p>({intl.formatMessage({ id: "Incl. VAT" })})</p>
</Typography>
)}
</div>
<div className={styles.totalPriceValue}>
{hasTotalPrice && (
<Typography variant="Body/Paragraph/mdBold">
<p>
{totalPoints} {intl.formatMessage({ id: "points" })}
{formatPrice(
intl,
totalPrice,
selectedAncillary.price.currency
)}
</p>
</Typography>
</div>
)}
)}
{hasTotalPoints && hasTotalPrice && (
<Divider variant="vertical" color="subtle" />
)}
{hasTotalPoints && (
<div>
<div>
<Divider variant="vertical" color="subtle" />
</div>
<Typography variant="Body/Paragraph/mdBold">
<p>
{totalPoints} {intl.formatMessage({ id: "points" })}
</p>
</Typography>
</div>
)}
</div>
</div>
<Divider color="subtle" />
{isPriceDetailsOpen && (
<PriceSummary
totalPrice={totalPrice}
totalPoints={totalPoints}
totalUnits={totalUnits}
quantityWithCard={quantityWithCard ?? 0}
quantityWithPoints={quantityWithPoints ?? 0}
selectedAncillary={selectedAncillary}
/>
)}

View File

@@ -7,3 +7,14 @@
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-Medium);
}
.totalPriceInclVAT {
display: flex;
gap: var(--Space-x05);
}
.totalPriceValue {
display: flex;
gap: var(--Space-x1);
height: 20px;
}

View File

@@ -42,10 +42,9 @@ export default function SelectQuantityStep({ user }: SelectQuantityStepProps) {
const insufficientPoints = currentPoints < pointsCost || currentPoints === 0
const pointsLabel =
insufficientPoints && user
? intl.formatMessage({ id: "Insufficient points" })
: intl.formatMessage({ id: "Select quantity" })
const pointsLabel = insufficientPoints
? intl.formatMessage({ id: "Insufficient points" })
: intl.formatMessage({ id: "Select quantity" })
return (
<div className={styles.selectContainer}>

View File

@@ -57,7 +57,6 @@
bottom: 0;
z-index: 10;
background: var(--Surface-Primary-OnSurface-Default);
border-top: 1px solid var(--Base-Border-Normal);
padding-bottom: var(--Space-x15);
}

View File

@@ -111,6 +111,7 @@ export default function AddAncillaryFlowModal({
{ ancillary: selectedAncillary?.title }
)
)
router.refresh()
} else {
toast.error(ancillaryErrorMessage)
}