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:
@@ -56,7 +56,7 @@ export function mapRoomState(
|
|||||||
formattedRoomCost = formatPrice(
|
formattedRoomCost = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
booking.vouchers,
|
booking.vouchers,
|
||||||
intl.formatMessage({ defaultMessage: "Voucher" })
|
CurrencyEnum.Voucher
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { cx } from "class-variance-authority"
|
import { cx } from "class-variance-authority"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
@@ -16,8 +17,6 @@ import Breakfast from "./Breakfast"
|
|||||||
|
|
||||||
import styles from "./room.module.css"
|
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"
|
import type { Room as RoomType } from "@/types/stores/enter-details"
|
||||||
|
|
||||||
interface RoomProps {
|
interface RoomProps {
|
||||||
@@ -114,14 +113,13 @@ export default function Room({
|
|||||||
)
|
)
|
||||||
|
|
||||||
let currency: string = room.roomPrice.perStay.local.currency
|
let currency: string = room.roomPrice.perStay.local.currency
|
||||||
const voucherCurrency = intl.formatMessage({ defaultMessage: "Voucher" })
|
|
||||||
const isVoucher = "voucher" in room.roomRate
|
const isVoucher = "voucher" in room.roomRate
|
||||||
if (isVoucher) {
|
if (isVoucher) {
|
||||||
currency = voucherCurrency
|
currency = CurrencyEnum.Voucher
|
||||||
price = formatPrice(
|
price = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
room.roomPrice.perStay.local.price,
|
room.roomPrice.perStay.local.price,
|
||||||
voucherCurrency,
|
currency,
|
||||||
room.roomPrice.perStay.local.additionalPrice,
|
room.roomPrice.perStay.local.additionalPrice,
|
||||||
room.roomPrice.perStay.local.additionalPriceCurrency
|
room.roomPrice.perStay.local.additionalPriceCurrency
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -86,15 +86,9 @@ export default function SummaryUI({
|
|||||||
const showDiscounted = containsBookingCodeRate || isMember
|
const showDiscounted = containsBookingCodeRate || isMember
|
||||||
|
|
||||||
const totalCurrency = isVoucherRate
|
const totalCurrency = isVoucherRate
|
||||||
? intl.formatMessage({ defaultMessage: "Voucher" })
|
? CurrencyEnum.Voucher
|
||||||
: totalPrice.local.currency
|
: totalPrice.local.currency
|
||||||
|
|
||||||
if (isVoucherRate && defaultCurrency === CurrencyEnum.Voucher) {
|
|
||||||
defaultCurrency = intl.formatMessage({
|
|
||||||
defaultMessage: "Voucher",
|
|
||||||
}) as CurrencyEnum
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.summary}>
|
<section className={styles.summary}>
|
||||||
<header
|
<header
|
||||||
|
|||||||
@@ -151,24 +151,45 @@ export default function HotelCardListing({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
lang={lang}
|
lang={lang}
|
||||||
prices={{
|
fullPrice={!hotel.availability.bookingCode}
|
||||||
public: hotel.availability.productType?.public
|
prices={
|
||||||
? {
|
hotel.availability.productType && {
|
||||||
...hotel.availability.productType.public,
|
public: hotel.availability.productType?.public
|
||||||
requestedPrice:
|
? {
|
||||||
hotel.availability.productType?.public.requestedPrice ??
|
...hotel.availability.productType.public,
|
||||||
undefined,
|
requestedPrice:
|
||||||
}
|
hotel.availability.productType?.public.requestedPrice ??
|
||||||
: undefined,
|
undefined,
|
||||||
member: hotel.availability.productType?.member
|
}
|
||||||
? {
|
: undefined,
|
||||||
...hotel.availability.productType.member,
|
member: hotel.availability.productType?.member
|
||||||
requestedPrice:
|
? {
|
||||||
hotel.availability.productType?.member.requestedPrice ??
|
...hotel.availability.productType.member,
|
||||||
undefined,
|
requestedPrice:
|
||||||
}
|
hotel.availability.productType?.member.requestedPrice ??
|
||||||
: undefined,
|
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)}
|
onHover={() => engage(hotel.hotel.name)}
|
||||||
onHoverEnd={() => disengage()}
|
onHoverEnd={() => disengage()}
|
||||||
onAddressClick={() => {
|
onAddressClick={() => {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
|
|
||||||
export default function Vouchers({
|
export default function Vouchers({
|
||||||
currencyCode,
|
currencyCode,
|
||||||
isCancelled,
|
isCancelled,
|
||||||
@@ -27,7 +26,7 @@ export default function Vouchers({
|
|||||||
const totalPrice = formatPrice(
|
const totalPrice = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
vouchers,
|
vouchers,
|
||||||
intl.formatMessage({ defaultMessage: "Voucher" }),
|
CurrencyEnum.Voucher,
|
||||||
price,
|
price,
|
||||||
currencyCode
|
currencyCode
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { cx } from "class-variance-authority"
|
import { cx } from "class-variance-authority"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
@@ -21,14 +20,11 @@ export default function LargeRow({
|
|||||||
price,
|
price,
|
||||||
}: RowProps) {
|
}: RowProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const isVoucherRate = price.local.currency === CurrencyEnum.Voucher
|
|
||||||
const currency = isVoucherRate
|
|
||||||
? intl.formatMessage({ defaultMessage: "Voucher" })
|
|
||||||
: price.local.currency
|
|
||||||
const totalPrice = formatPrice(
|
const totalPrice = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
price.local.price,
|
price.local.price,
|
||||||
currency,
|
price.local.currency,
|
||||||
price.local.additionalPrice,
|
price.local.additionalPrice,
|
||||||
price.local.additionalPriceCurrency
|
price.local.additionalPriceCurrency
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
|
|
||||||
import BoldRow from "../Bold"
|
import BoldRow from "../Bold"
|
||||||
@@ -35,19 +36,21 @@ export default function VoucherPrice({
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const voucherCurrency = intl.formatMessage({ defaultMessage: "Voucher" })
|
|
||||||
|
|
||||||
const averagePriceTitle = intl.formatMessage({
|
const averagePriceTitle = intl.formatMessage({
|
||||||
defaultMessage: "Average price per night",
|
defaultMessage: "Average price per night",
|
||||||
})
|
})
|
||||||
|
|
||||||
const averagePricePerNight = `${price.numberOfVouchers / nights} ${voucherCurrency}`
|
const averagePricePerNight = formatPrice(
|
||||||
|
intl,
|
||||||
|
price.numberOfVouchers / nights,
|
||||||
|
CurrencyEnum.Voucher
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BoldRow
|
<BoldRow
|
||||||
label={intl.formatMessage({ defaultMessage: "Room charge" })}
|
label={intl.formatMessage({ defaultMessage: "Room charge" })}
|
||||||
value={formatPrice(intl, price.numberOfVouchers, voucherCurrency)}
|
value={formatPrice(intl, price.numberOfVouchers, CurrencyEnum.Voucher)}
|
||||||
/>
|
/>
|
||||||
{nights > 1 ? (
|
{nights > 1 ? (
|
||||||
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
|
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type {
|
|||||||
Product,
|
Product,
|
||||||
RedemptionProduct,
|
RedemptionProduct,
|
||||||
} from "@scandic-hotels/trpc/types/roomAvailability"
|
} from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
import type { IntlShape } from "react-intl"
|
|
||||||
|
|
||||||
import type { Price } from "@/types/components/hotelReservation/price"
|
import type { Price } from "@/types/components/hotelReservation/price"
|
||||||
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
|
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||||
@@ -214,8 +213,7 @@ export function calculateCorporateChequePrice(selectedRateSummary: Rate[]) {
|
|||||||
export function getTotalPrice(
|
export function getTotalPrice(
|
||||||
mainRoomProduct: Rate | null,
|
mainRoomProduct: Rate | null,
|
||||||
rateSummary: Array<Rate | null>,
|
rateSummary: Array<Rate | null>,
|
||||||
isUserLoggedIn: boolean,
|
isUserLoggedIn: boolean
|
||||||
intl: IntlShape
|
|
||||||
): Price | null {
|
): Price | null {
|
||||||
const summaryArray = rateSummary.filter((rate): rate is Rate => rate !== null)
|
const summaryArray = rateSummary.filter((rate): rate is Rate => rate !== null)
|
||||||
|
|
||||||
@@ -235,9 +233,6 @@ export function getTotalPrice(
|
|||||||
}
|
}
|
||||||
if ("voucher" in product) {
|
if ("voucher" in product) {
|
||||||
const voucherPrice = calculateVoucherPrice(summaryArray)
|
const voucherPrice = calculateVoucherPrice(summaryArray)
|
||||||
voucherPrice.local.currency = intl.formatMessage({
|
|
||||||
defaultMessage: "Voucher",
|
|
||||||
}) as CurrencyEnum
|
|
||||||
return voucherPrice
|
return voucherPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -338,15 +338,25 @@ function VoucherCode({
|
|||||||
|
|
||||||
const rateTermDetails = getRateTermDetails(codeProduct)
|
const rateTermDetails = getRateTermDetails(codeProduct)
|
||||||
|
|
||||||
const voucherMsg = intl
|
const voucherMsg = intl.formatMessage(
|
||||||
.formatMessage({
|
{
|
||||||
defaultMessage: "Voucher",
|
defaultMessage:
|
||||||
})
|
"{numberOfVouchers, plural, one {Voucher} other {Vouchers}}",
|
||||||
.toUpperCase()
|
},
|
||||||
let price = `${numberOfVouchers} ${voucherMsg}`
|
{
|
||||||
if (packagesSum.price) {
|
numberOfVouchers: numberOfVouchers,
|
||||||
price = `${price} + ${packagesSum.price}`
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
|
const { price, currency } = packagesSum.price
|
||||||
|
? {
|
||||||
|
price: `${numberOfVouchers} ${voucherMsg} + ${packagesSum.price}`,
|
||||||
|
currency: packagesSum.currency ?? "",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
price: `${numberOfVouchers} ${voucherMsg}`,
|
||||||
|
currency: "",
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<CodeRateCard
|
<CodeRateCard
|
||||||
key={codeProduct.rate}
|
key={codeProduct.rate}
|
||||||
@@ -358,7 +368,7 @@ function VoucherCode({
|
|||||||
rate={{
|
rate={{
|
||||||
label: codeProduct.rateDefinition?.title,
|
label: codeProduct.rateDefinition?.title,
|
||||||
price,
|
price,
|
||||||
unit: packagesSum.currency ?? "",
|
unit: currency,
|
||||||
}}
|
}}
|
||||||
rateTitle={rateTitles[codeProduct.rate].title}
|
rateTitle={rateTitles[codeProduct.rate].title}
|
||||||
rateTermDetails={rateTermDetails}
|
rateTermDetails={rateTermDetails}
|
||||||
|
|||||||
@@ -232,7 +232,6 @@ export function SelectRateProvider({
|
|||||||
roomConfiguration: roomAvailability[ix]?.[0],
|
roomConfiguration: roomAvailability[ix]?.[0],
|
||||||
})),
|
})),
|
||||||
useMemberPrices: isUserLoggedIn,
|
useMemberPrices: isUserLoggedIn,
|
||||||
intl,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const getPriceForRoom = useCallback(
|
const getPriceForRoom = useCallback(
|
||||||
@@ -252,10 +251,9 @@ export function SelectRateProvider({
|
|||||||
{ rate, roomConfiguration: roomAvailability[roomIndex]?.[0] },
|
{ rate, roomConfiguration: roomAvailability[roomIndex]?.[0] },
|
||||||
],
|
],
|
||||||
useMemberPrices: isUserLoggedIn,
|
useMemberPrices: isUserLoggedIn,
|
||||||
intl,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[selectedRates, roomAvailability, isUserLoggedIn, intl]
|
[selectedRates, roomAvailability, isUserLoggedIn]
|
||||||
)
|
)
|
||||||
|
|
||||||
const setActiveRoomIndex = useCallback(
|
const setActiveRoomIndex = useCallback(
|
||||||
|
|||||||
@@ -2,20 +2,11 @@ import { describe, expect, it } from "vitest"
|
|||||||
|
|
||||||
import { getTotalPrice } from "./getTotalPrice"
|
import { getTotalPrice } from "./getTotalPrice"
|
||||||
|
|
||||||
import type { IntlShape } from "react-intl"
|
|
||||||
|
|
||||||
const mockIntl = {
|
|
||||||
formatMessage: ({ defaultMessage }: { defaultMessage: string }) => {
|
|
||||||
return defaultMessage
|
|
||||||
},
|
|
||||||
} as IntlShape
|
|
||||||
|
|
||||||
describe("getTotalPrice", () => {
|
describe("getTotalPrice", () => {
|
||||||
it("should return null when no rates are selected", () => {
|
it("should return null when no rates are selected", () => {
|
||||||
const result = getTotalPrice({
|
const result = getTotalPrice({
|
||||||
selectedRates: [],
|
selectedRates: [],
|
||||||
useMemberPrices: false,
|
useMemberPrices: false,
|
||||||
intl: mockIntl,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|||||||
import { sumPackages } from "@/components/HotelReservation/utils"
|
import { sumPackages } from "@/components/HotelReservation/utils"
|
||||||
|
|
||||||
import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability"
|
import type { RedemptionProduct } from "@scandic-hotels/trpc/types/roomAvailability"
|
||||||
import type { IntlShape } from "react-intl"
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AvailabilityWithRoomInfo,
|
AvailabilityWithRoomInfo,
|
||||||
@@ -32,11 +31,9 @@ type SelectedRate = {
|
|||||||
export function getTotalPrice({
|
export function getTotalPrice({
|
||||||
selectedRates,
|
selectedRates,
|
||||||
useMemberPrices,
|
useMemberPrices,
|
||||||
intl,
|
|
||||||
}: {
|
}: {
|
||||||
selectedRates: Array<SelectedRate | null>
|
selectedRates: Array<SelectedRate | null>
|
||||||
useMemberPrices: boolean
|
useMemberPrices: boolean
|
||||||
intl: IntlShape
|
|
||||||
}): Price | null {
|
}): Price | null {
|
||||||
const mainRoom = selectedRates[0]
|
const mainRoom = selectedRates[0]
|
||||||
const mainRoomRate = mainRoom?.rate
|
const mainRoomRate = mainRoom?.rate
|
||||||
@@ -63,10 +60,6 @@ export function getTotalPrice({
|
|||||||
}
|
}
|
||||||
if ("voucher" in mainRoomRate) {
|
if ("voucher" in mainRoomRate) {
|
||||||
const voucherPrice = calculateVoucherPrice(summaryArray)
|
const voucherPrice = calculateVoucherPrice(summaryArray)
|
||||||
// TODO: This is a workaround, should be handled where we print the price.
|
|
||||||
voucherPrice.local.currency = intl.formatMessage({
|
|
||||||
defaultMessage: "Voucher",
|
|
||||||
}) as CurrencyEnum
|
|
||||||
return voucherPrice
|
return voucherPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ export default function BookingConfirmationProvider({
|
|||||||
)
|
)
|
||||||
} else if (totalBookingVouchers) {
|
} else if (totalBookingVouchers) {
|
||||||
const room = rooms?.[0]
|
const room = rooms?.[0]
|
||||||
const voucherCurrency = intl.formatMessage({ defaultMessage: "Voucher" })
|
|
||||||
if (room?.packages) {
|
if (room?.packages) {
|
||||||
const pkgsSum = room.packages.reduce(
|
const pkgsSum = room.packages.reduce(
|
||||||
(total, pkg) => total + pkg.totalPrice,
|
(total, pkg) => total + pkg.totalPrice,
|
||||||
@@ -74,7 +73,7 @@ export default function BookingConfirmationProvider({
|
|||||||
formattedTotalCost = formatPrice(
|
formattedTotalCost = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
totalBookingVouchers,
|
totalBookingVouchers,
|
||||||
voucherCurrency,
|
CurrencyEnum.Voucher,
|
||||||
pkgsSum,
|
pkgsSum,
|
||||||
currency
|
currency
|
||||||
)
|
)
|
||||||
@@ -83,7 +82,7 @@ export default function BookingConfirmationProvider({
|
|||||||
formattedTotalCost = formatPrice(
|
formattedTotalCost = formatPrice(
|
||||||
intl,
|
intl,
|
||||||
totalBookingVouchers,
|
totalBookingVouchers,
|
||||||
voucherCurrency
|
CurrencyEnum.Voucher
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,15 @@ export function calculateTotalPrice(
|
|||||||
}
|
}
|
||||||
if (totals.vouchers) {
|
if (totals.vouchers) {
|
||||||
const appendTotalPrice = totalPrice ? `${totalPrice} + ` : ""
|
const appendTotalPrice = totalPrice ? `${totalPrice} + ` : ""
|
||||||
totalPrice = `${appendTotalPrice}${totals.vouchers} ${intl.formatMessage({ defaultMessage: "Voucher" })}`
|
totalPrice = `${appendTotalPrice}${totals.vouchers} ${intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage:
|
||||||
|
"{numberOfVouchers, plural, one {Voucher} other {Vouchers}}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
numberOfVouchers: totals.vouchers,
|
||||||
|
}
|
||||||
|
)}`
|
||||||
}
|
}
|
||||||
if (totals.cash) {
|
if (totals.cash) {
|
||||||
const appendTotalPrice = totalPrice ? `${totalPrice} + ` : ""
|
const appendTotalPrice = totalPrice ? `${totalPrice} + ` : ""
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { CurrencyEnum } from "../constants/currency"
|
||||||
|
|
||||||
import type { IntlShape } from "react-intl"
|
import type { IntlShape } from "react-intl"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +23,7 @@ export function getSingleDecimal(n: Number | string) {
|
|||||||
export function formatPrice(
|
export function formatPrice(
|
||||||
intl: IntlShape,
|
intl: IntlShape,
|
||||||
price: number,
|
price: number,
|
||||||
currency: string,
|
currency: string | CurrencyEnum,
|
||||||
additionalPrice?: number,
|
additionalPrice?: number,
|
||||||
additionalPriceCurrency?: string
|
additionalPriceCurrency?: string
|
||||||
) {
|
) {
|
||||||
@@ -37,5 +39,18 @@ export function formatPrice(
|
|||||||
formattedAdditionalPrice = ` + ${localizedAdditionalPrice} ${additionalPriceCurrency}`
|
formattedAdditionalPrice = ` + ${localizedAdditionalPrice} ${additionalPriceCurrency}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${localizedPrice} ${currency}${formattedAdditionalPrice}`
|
const currencyText =
|
||||||
|
currency === CurrencyEnum.Voucher
|
||||||
|
? intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage:
|
||||||
|
"{numberOfVouchers, plural, one {Voucher} other {Vouchers}}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
numberOfVouchers: price,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
: currency
|
||||||
|
|
||||||
|
return `${localizedPrice} ${currencyText}${formattedAdditionalPrice}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl'
|
||||||
|
|
||||||
import { CurrencyEnum } from '@scandic-hotels/common/constants/currency'
|
|
||||||
import Caption from '../../Caption'
|
import Caption from '../../Caption'
|
||||||
import Subtitle from '../../Subtitle'
|
import Subtitle from '../../Subtitle'
|
||||||
|
|
||||||
@@ -29,7 +28,15 @@ export default function HotelVoucherCard({
|
|||||||
{productTypeVoucher.numberOfVouchers}
|
{productTypeVoucher.numberOfVouchers}
|
||||||
</Subtitle>
|
</Subtitle>
|
||||||
<Caption color="uiTextHighContrast" className={styles.currency}>
|
<Caption color="uiTextHighContrast" className={styles.currency}>
|
||||||
{CurrencyEnum.Voucher}
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage:
|
||||||
|
'{numberOfVouchers, plural, one {Voucher} other {Vouchers}}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
numberOfVouchers: productTypeVoucher.numberOfVouchers,
|
||||||
|
}
|
||||||
|
)}
|
||||||
</Caption>
|
</Caption>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ import styles from './hotelCard.module.css'
|
|||||||
import type { Lang } from '@scandic-hotels/common/constants/language'
|
import type { Lang } from '@scandic-hotels/common/constants/language'
|
||||||
import { FacilityEnum } from '@scandic-hotels/common/constants/facilities'
|
import { FacilityEnum } from '@scandic-hotels/common/constants/facilities'
|
||||||
import { RateTypeEnum } from '@scandic-hotels/common/constants/rateType'
|
import { RateTypeEnum } from '@scandic-hotels/common/constants/rateType'
|
||||||
import { CurrencyEnum } from '@scandic-hotels/common/constants/currency'
|
|
||||||
import { BookingCodeChip } from '../BookingCodeChip'
|
import { BookingCodeChip } from '../BookingCodeChip'
|
||||||
import { HotelType } from '@scandic-hotels/common/constants/hotelType'
|
import { HotelType } from '@scandic-hotels/common/constants/hotelType'
|
||||||
import { TripAdvisorChip } from '../TripAdvisorChip'
|
import { TripAdvisorChip } from '../TripAdvisorChip'
|
||||||
|
import { CurrencyEnum } from '@scandic-hotels/common/constants/currency'
|
||||||
|
|
||||||
type Price = {
|
type Price = {
|
||||||
pricePerStay: number
|
pricePerStay: number
|
||||||
@@ -57,47 +57,48 @@ export type HotelCardProps = {
|
|||||||
tripAdvisor?: number
|
tripAdvisor?: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prices: {
|
prices:
|
||||||
public?: {
|
| {
|
||||||
rateType: RateTypeEnum
|
public?: {
|
||||||
localPrice: Price
|
rateType: RateTypeEnum
|
||||||
requestedPrice?: Price
|
localPrice: Price
|
||||||
}
|
requestedPrice?: Price
|
||||||
member?: {
|
}
|
||||||
rateType: RateTypeEnum
|
member?: {
|
||||||
localPrice: Price
|
rateType: RateTypeEnum
|
||||||
requestedPrice?: Price
|
localPrice: Price
|
||||||
}
|
requestedPrice?: Price
|
||||||
voucher?: {
|
}
|
||||||
numberOfVouchers: number
|
voucher?: {
|
||||||
rateCode: string
|
numberOfVouchers: number
|
||||||
rateType: RateTypeEnum
|
rateCode: string
|
||||||
}
|
rateType: RateTypeEnum
|
||||||
bonusCheque?: {
|
}
|
||||||
rateCode: string
|
bonusCheque?: {
|
||||||
rateType: RateTypeEnum
|
rateCode: string
|
||||||
localPrice: {
|
rateType: RateTypeEnum
|
||||||
additionalPricePerStay: number
|
localPrice: {
|
||||||
currency: CurrencyEnum | null | undefined
|
additionalPricePerStay: number
|
||||||
numberOfCheques: number
|
currency: CurrencyEnum | null | undefined
|
||||||
|
numberOfCheques: number
|
||||||
|
}
|
||||||
|
requestedPrice?: {
|
||||||
|
additionalPricePerStay: number
|
||||||
|
currency: CurrencyEnum | null | undefined
|
||||||
|
numberOfCheques: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
redemptions?: {
|
||||||
|
rateCode: string
|
||||||
|
hasEnoughPoints: boolean
|
||||||
|
localPrice: {
|
||||||
|
additionalPricePerStay: number
|
||||||
|
pointsPerStay: number
|
||||||
|
currency: CurrencyEnum | null | undefined
|
||||||
|
}
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
requestedPrice?: {
|
| undefined
|
||||||
additionalPricePerStay: number
|
|
||||||
currency: CurrencyEnum | null | undefined
|
|
||||||
numberOfCheques: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redemptions?: {
|
|
||||||
rateCode: string
|
|
||||||
hasEnoughPoints: boolean
|
|
||||||
localPrice: {
|
|
||||||
additionalPricePerStay: number
|
|
||||||
pointsPerStay: number
|
|
||||||
currency: string
|
|
||||||
}
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
images: GalleryImage[]
|
images: GalleryImage[]
|
||||||
distanceToCityCenter: number
|
distanceToCityCenter: number
|
||||||
isUserLoggedIn: boolean
|
isUserLoggedIn: boolean
|
||||||
@@ -105,6 +106,7 @@ export type HotelCardProps = {
|
|||||||
state?: 'default' | 'active'
|
state?: 'default' | 'active'
|
||||||
bookingCode?: string | null
|
bookingCode?: string | null
|
||||||
isAlternative?: boolean
|
isAlternative?: boolean
|
||||||
|
fullPrice: boolean
|
||||||
|
|
||||||
lang: Lang
|
lang: Lang
|
||||||
|
|
||||||
@@ -128,6 +130,7 @@ export const HotelCard = memo(
|
|||||||
images,
|
images,
|
||||||
lang,
|
lang,
|
||||||
belowInfoSlot,
|
belowInfoSlot,
|
||||||
|
fullPrice,
|
||||||
onAddressClick,
|
onAddressClick,
|
||||||
onHover,
|
onHover,
|
||||||
onHoverEnd,
|
onHoverEnd,
|
||||||
@@ -151,16 +154,15 @@ export const HotelCard = memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
||||||
const fullPrice = !bookingCode
|
|
||||||
|
|
||||||
const hasInsufficientPoints = !prices.redemptions?.some(
|
const hasInsufficientPoints = !prices?.redemptions?.some(
|
||||||
(r) => r.hasEnoughPoints
|
(r) => r.hasEnoughPoints
|
||||||
)
|
)
|
||||||
const notEnoughPointsLabel = intl.formatMessage({
|
const notEnoughPointsLabel = intl.formatMessage({
|
||||||
defaultMessage: 'Not enough points',
|
defaultMessage: 'Not enough points',
|
||||||
})
|
})
|
||||||
|
|
||||||
const isDisabled = prices.redemptions?.length && hasInsufficientPoints
|
const isDisabled = prices?.redemptions?.length && hasInsufficientPoints
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
|
|||||||
Reference in New Issue
Block a user