Merged in fix/SW-3021-vouchers (pull request #2719)

fix(SW-3021): add pluralization support for vouchers

* fix(SW-3021): add pluralization support for vouchers


Approved-by: Anton Gunnarsson
This commit is contained in:
Bianca Widstam
2025-08-28 08:27:03 +00:00
parent 997f928f2b
commit 0e00e8eaf1
17 changed files with 160 additions and 131 deletions

View File

@@ -56,7 +56,7 @@ export function mapRoomState(
formattedRoomCost = formatPrice(
intl,
booking.vouchers,
intl.formatMessage({ defaultMessage: "Voucher" })
CurrencyEnum.Voucher
)
}

View File

@@ -1,6 +1,7 @@
import { cx } from "class-variance-authority"
import { useIntl } from "react-intl"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import { Button } from "@scandic-hotels/design-system/Button"
import { Divider } from "@scandic-hotels/design-system/Divider"
@@ -16,8 +17,6 @@ import Breakfast from "./Breakfast"
import styles from "./room.module.css"
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import type { Room as RoomType } from "@/types/stores/enter-details"
interface RoomProps {
@@ -114,14 +113,13 @@ export default function Room({
)
let currency: string = room.roomPrice.perStay.local.currency
const voucherCurrency = intl.formatMessage({ defaultMessage: "Voucher" })
const isVoucher = "voucher" in room.roomRate
if (isVoucher) {
currency = voucherCurrency
currency = CurrencyEnum.Voucher
price = formatPrice(
intl,
room.roomPrice.perStay.local.price,
voucherCurrency,
currency,
room.roomPrice.perStay.local.additionalPrice,
room.roomPrice.perStay.local.additionalPriceCurrency
)

View File

@@ -86,15 +86,9 @@ export default function SummaryUI({
const showDiscounted = containsBookingCodeRate || isMember
const totalCurrency = isVoucherRate
? intl.formatMessage({ defaultMessage: "Voucher" })
? CurrencyEnum.Voucher
: totalPrice.local.currency
if (isVoucherRate && defaultCurrency === CurrencyEnum.Voucher) {
defaultCurrency = intl.formatMessage({
defaultMessage: "Voucher",
}) as CurrencyEnum
}
return (
<section className={styles.summary}>
<header

View File

@@ -151,24 +151,45 @@ export default function HotelCardListing({
},
}}
lang={lang}
prices={{
public: hotel.availability.productType?.public
? {
...hotel.availability.productType.public,
requestedPrice:
hotel.availability.productType?.public.requestedPrice ??
undefined,
}
: undefined,
member: hotel.availability.productType?.member
? {
...hotel.availability.productType.member,
requestedPrice:
hotel.availability.productType?.member.requestedPrice ??
undefined,
}
: undefined,
}}
fullPrice={!hotel.availability.bookingCode}
prices={
hotel.availability.productType && {
public: hotel.availability.productType?.public
? {
...hotel.availability.productType.public,
requestedPrice:
hotel.availability.productType?.public.requestedPrice ??
undefined,
}
: undefined,
member: hotel.availability.productType?.member
? {
...hotel.availability.productType.member,
requestedPrice:
hotel.availability.productType?.member.requestedPrice ??
undefined,
}
: undefined,
voucher: hotel.availability.productType?.voucher,
bonusCheque: hotel.availability.productType?.bonusCheque
? {
...hotel.availability.productType.bonusCheque,
requestedPrice:
hotel.availability.productType.bonusCheque
.requestedPrice ?? undefined,
}
: undefined,
redemptions: hotel.availability.productType?.redemptions?.map(
(redemption) => ({
...redemption,
localPrice: {
...redemption.localPrice,
currency: redemption.localPrice.currency,
},
})
),
}
}
onHover={() => engage(hotel.hotel.name)}
onHoverEnd={() => disengage()}
onAddressClick={() => {

View File

@@ -1,12 +1,11 @@
"use client"
import { useIntl } from "react-intl"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
import { Typography } from "@scandic-hotels/design-system/Typography"
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
export default function Vouchers({
currencyCode,
isCancelled,
@@ -27,7 +26,7 @@ export default function Vouchers({
const totalPrice = formatPrice(
intl,
vouchers,
intl.formatMessage({ defaultMessage: "Voucher" }),
CurrencyEnum.Voucher,
price,
currencyCode
)

View File

@@ -1,7 +1,6 @@
import { cx } from "class-variance-authority"
import { useIntl } from "react-intl"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import { Typography } from "@scandic-hotels/design-system/Typography"
@@ -21,14 +20,11 @@ export default function LargeRow({
price,
}: RowProps) {
const intl = useIntl()
const isVoucherRate = price.local.currency === CurrencyEnum.Voucher
const currency = isVoucherRate
? intl.formatMessage({ defaultMessage: "Voucher" })
: price.local.currency
const totalPrice = formatPrice(
intl,
price.local.price,
currency,
price.local.currency,
price.local.additionalPrice,
price.local.additionalPriceCurrency
)

View File

@@ -1,6 +1,7 @@
"use client"
import { useIntl } from "react-intl"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import BoldRow from "../Bold"
@@ -35,19 +36,21 @@ export default function VoucherPrice({
return null
}
const voucherCurrency = intl.formatMessage({ defaultMessage: "Voucher" })
const averagePriceTitle = intl.formatMessage({
defaultMessage: "Average price per night",
})
const averagePricePerNight = `${price.numberOfVouchers / nights} ${voucherCurrency}`
const averagePricePerNight = formatPrice(
intl,
price.numberOfVouchers / nights,
CurrencyEnum.Voucher
)
return (
<>
<BoldRow
label={intl.formatMessage({ defaultMessage: "Room charge" })}
value={formatPrice(intl, price.numberOfVouchers, voucherCurrency)}
value={formatPrice(intl, price.numberOfVouchers, CurrencyEnum.Voucher)}
/>
{nights > 1 ? (
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />

View File

@@ -8,7 +8,6 @@ import type {
Product,
RedemptionProduct,
} from "@scandic-hotels/trpc/types/roomAvailability"
import type { IntlShape } from "react-intl"
import type { Price } from "@/types/components/hotelReservation/price"
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
@@ -214,8 +213,7 @@ export function calculateCorporateChequePrice(selectedRateSummary: Rate[]) {
export function getTotalPrice(
mainRoomProduct: Rate | null,
rateSummary: Array<Rate | null>,
isUserLoggedIn: boolean,
intl: IntlShape
isUserLoggedIn: boolean
): Price | null {
const summaryArray = rateSummary.filter((rate): rate is Rate => rate !== null)
@@ -235,9 +233,6 @@ export function getTotalPrice(
}
if ("voucher" in product) {
const voucherPrice = calculateVoucherPrice(summaryArray)
voucherPrice.local.currency = intl.formatMessage({
defaultMessage: "Voucher",
}) as CurrencyEnum
return voucherPrice
}

View File

@@ -338,15 +338,25 @@ function VoucherCode({
const rateTermDetails = getRateTermDetails(codeProduct)
const voucherMsg = intl
.formatMessage({
defaultMessage: "Voucher",
})
.toUpperCase()
let price = `${numberOfVouchers} ${voucherMsg}`
if (packagesSum.price) {
price = `${price} + ${packagesSum.price}`
}
const voucherMsg = intl.formatMessage(
{
defaultMessage:
"{numberOfVouchers, plural, one {Voucher} other {Vouchers}}",
},
{
numberOfVouchers: numberOfVouchers,
}
)
const { price, currency } = packagesSum.price
? {
price: `${numberOfVouchers} ${voucherMsg} + ${packagesSum.price}`,
currency: packagesSum.currency ?? "",
}
: {
price: `${numberOfVouchers} ${voucherMsg}`,
currency: "",
}
return (
<CodeRateCard
key={codeProduct.rate}
@@ -358,7 +368,7 @@ function VoucherCode({
rate={{
label: codeProduct.rateDefinition?.title,
price,
unit: packagesSum.currency ?? "",
unit: currency,
}}
rateTitle={rateTitles[codeProduct.rate].title}
rateTermDetails={rateTermDetails}