feat: move room charge to top in price details modal

This commit is contained in:
Simon Emanuelsson
2025-05-08 11:28:22 +02:00
committed by Michael Zetterberg
parent 194a401a56
commit a99e434d84
28 changed files with 264 additions and 136 deletions

View File

@@ -53,13 +53,62 @@ export default function PriceDetails() {
total.local.price = total.local.price + room.totalPrice
}
if (
(room.cheques || room.roomPoints || room.vouchers) &&
room.roomPrice
) {
// Corporate Cheque
if (room.cheques) {
if (room.roomPrice) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + room.totalPrice
total.local.additionalPriceCurrency = currency
} else {
const pkgsSum = room.packages.reduce(
(total, pkg) => total + pkg.totalPrice,
0
)
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum
const pkgsCurrency = room.packages.find(
(pkg) => pkg.currency
)?.currency
if (!total.local.additionalPriceCurrency) {
total.local.additionalPriceCurrency = pkgsCurrency ?? currency
}
}
}
// Redemption
if (room.roomPoints) {
if (room.roomPrice) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + room.totalPrice
total.local.additionalPriceCurrency = currency
} else {
const pkgsSum = room.packages.reduce(
(total, pkg) => total + pkg.totalPrice,
0
)
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum
const pkgsCurrency = room.packages.find(
(pkg) => pkg.currency
)?.currency
if (!total.local.additionalPriceCurrency) {
total.local.additionalPriceCurrency = pkgsCurrency ?? currency
}
}
}
// Voucher
if (room.vouchers && room.packages) {
const pkgsSum = room.packages.reduce(
(total, pkg) => total + pkg.totalPrice,
0
)
total.local.additionalPrice =
(total.local.additionalPrice || 0) + room.totalPrice
total.local.additionalPriceCurrency = currency
(total.local.additionalPrice || 0) + pkgsSum
const pkgsCurrency = room.packages.find((pkg) => pkg.currency)?.currency
if (!total.local.additionalPriceCurrency) {
total.local.additionalPriceCurrency = pkgsCurrency ?? currency
}
}
return total

View File

@@ -17,20 +17,16 @@ export function mapToPrice(rooms: (Room | null)[], nights: number) {
if (room.cheques) {
price = {
corporateCheque: {
additionalPricePerStay: room.totalPrice
? room.totalPrice
: undefined,
currency: room.totalPrice ? room.currencyCode : undefined,
additionalPricePerStay: room.roomPrice ? room.roomPrice : undefined,
currency: room.roomPrice ? room.currencyCode : undefined,
numberOfCheques: room.cheques,
},
}
} else if (room.roomPoints) {
price = {
redemption: {
additionalPricePerStay: room.totalPrice
? room.totalPrice
: undefined,
currency: room.totalPrice ? room.currencyCode : undefined,
additionalPricePerStay: room.roomPrice ? room.roomPrice : undefined,
currency: room.roomPrice ? room.currencyCode : undefined,
pointsPerNight: room.roomPoints / nights,
pointsPerStay: room.roomPoints,
},
@@ -46,7 +42,7 @@ export function mapToPrice(rooms: (Room | null)[], nights: number) {
regular: {
currency: room.currencyCode,
pricePerNight: room.roomPrice / nights,
pricePerStay: room.totalPrice,
pricePerStay: room.roomPrice,
},
}
}

View File

@@ -29,7 +29,7 @@ export function mapRoomState(
intl,
booking.roomPoints,
CurrencyEnum.POINTS,
booking.totalPrice,
booking.roomPrice,
booking.currencyCode
)
} else if (booking.cheques) {
@@ -37,7 +37,7 @@ export function mapRoomState(
intl,
booking.cheques,
CurrencyEnum.CC,
booking.totalPrice,
booking.roomPrice,
booking.currencyCode
)
} else if (booking.vouchers) {

View File

@@ -9,14 +9,16 @@ import SummaryUI from "./UI"
import type { SummaryProps } from "@/types/components/hotelReservation/summary"
export default function DesktopSummary({ isMember }: SummaryProps) {
const {
booking,
actions: { toggleSummaryOpen },
totalPrice,
vat,
} = useEnterDetailsStore((state) => state)
const toggleSummaryOpen = useEnterDetailsStore(
(state) => state.actions.toggleSummaryOpen
)
const rooms = useEnterDetailsStore((state) => state.rooms)
const { booking, rooms, totalPrice, vat } = useEnterDetailsStore((state) => ({
booking: state.booking,
rooms: state.rooms,
totalPrice: state.totalPrice,
vat: state.vat,
}))
return (
<SidePanel variant="summary">

View File

@@ -12,14 +12,16 @@ import styles from "./mobile.module.css"
import type { SummaryProps } from "@/types/components/hotelReservation/summary"
export default function MobileSummary({ isMember }: SummaryProps) {
const {
booking,
actions: { toggleSummaryOpen },
totalPrice,
vat,
} = useEnterDetailsStore((state) => state)
const toggleSummaryOpen = useEnterDetailsStore(
(state) => state.actions.toggleSummaryOpen
)
const rooms = useEnterDetailsStore((state) => state.rooms)
const { booking, rooms, totalPrice, vat } = useEnterDetailsStore((state) => ({
booking: state.booking,
rooms: state.rooms,
totalPrice: state.totalPrice,
vat: state.vat,
}))
const showPromo =
!isMember &&

View File

@@ -94,7 +94,7 @@ export default function SummaryUI({
? totalPrice.requested.currency === totalPrice.local.currency
: false
const priceDetailsRooms = mapToPrice(rooms, isMember, nights)
const priceDetailsRooms = mapToPrice(rooms, isMember)
const isAllCampaignRate = rooms.every(
(room) => room.room.roomRate.rateDefinition.isCampaignRate
)
@@ -378,7 +378,12 @@ export default function SummaryUI({
<div className={styles.entry}>
<Body color="uiTextHighContrast">
{intl.formatMessage({
defaultMessage: "Breakfast included",
defaultMessage: "Breakfast buffet",
})}
</Body>
<Body color="red">
{intl.formatMessage({
defaultMessage: "Included",
})}
</Body>
</div>

View File

@@ -2,11 +2,7 @@ import { sumPackages } from "@/components/HotelReservation/utils"
import type { RoomState } from "@/types/stores/enter-details"
export function mapToPrice(
rooms: RoomState[],
isMember: boolean,
nights: number
) {
export function mapToPrice(rooms: RoomState[], isMember: boolean) {
return rooms
.filter((room) => room && room.room.roomRate)
.map(({ room }, idx) => {
@@ -26,8 +22,8 @@ export function mapToPrice(
corporateCheque: {
...room.roomRate.corporateCheque.localPrice,
additionalPricePerStay:
(room.roomRate.corporateCheque.localPrice
.additionalPricePerStay || 0) + pkgsSum.price,
room.roomRate.corporateCheque.localPrice
.additionalPricePerStay || 0,
},
},
}
@@ -53,8 +49,8 @@ export function mapToPrice(
redemption: {
...room.roomRate.redemption.localPrice,
additionalPricePerStay:
(room.roomRate.redemption.localPrice.additionalPricePerStay ||
0) + pkgsSum.price,
room.roomRate.redemption.localPrice.additionalPricePerStay ||
0,
},
},
}
@@ -88,12 +84,8 @@ export function mapToPrice(
price: {
regular: {
...room.roomRate.member.localPrice,
pricePerNight:
room.roomRate.member.localPrice.pricePerNight +
pkgsSum.price / nights,
pricePerStay:
room.roomRate.member.localPrice.pricePerStay +
pkgsSum.price,
pricePerNight: room.roomRate.member.localPrice.pricePerNight,
pricePerStay: room.roomRate.member.localPrice.pricePerStay,
},
},
}
@@ -116,11 +108,8 @@ export function mapToPrice(
price: {
regular: {
...room.roomRate.public.localPrice,
pricePerNight:
room.roomRate.public.localPrice.pricePerNight +
pkgsSum.price / nights,
pricePerStay:
room.roomRate.public.localPrice.pricePerStay + pkgsSum.price,
pricePerNight: room.roomRate.public.localPrice.pricePerNight,
pricePerStay: room.roomRate.public.localPrice.pricePerStay,
},
},
}

View File

@@ -1,5 +1,7 @@
import { dt } from "@/lib/dt"
import { sumPackages } from "../../utils"
import { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
import type { Price } from "@/types/components/hotelReservation/price"
import { CurrencyEnum } from "@/types/enums/currency"
@@ -10,7 +12,7 @@ export function mapToPrice(room: Room) {
case PriceTypeEnum.cheque:
return {
corporateCheque: {
additionalPricePerStay: room.totalPrice,
additionalPricePerStay: room.roomPrice.perStay.local.price,
currency: room.roomPrice.perStay.local.currency,
numberOfCheques: room.cheques,
},
@@ -20,7 +22,7 @@ export function mapToPrice(room: Room) {
regular: {
currency: room.currencyCode,
pricePerNight: room.roomPrice.perNight.local.price,
pricePerStay: room.totalPrice,
pricePerStay: room.roomPrice.perStay.local.price,
},
}
case PriceTypeEnum.points:
@@ -29,7 +31,7 @@ export function mapToPrice(room: Room) {
.diff(dt(room.checkInDate).startOf("day"), "days")
return {
redemption: {
additionalPricePerStay: room.totalPrice,
additionalPricePerStay: room.roomPrice.perStay.local.price,
currency: room.currencyCode,
pointsPerNight: room.roomPoints / nights,
pointsPerStay: room.roomPoints,
@@ -80,7 +82,6 @@ export function calculateTotalPrice(rooms: Room[], currency: CurrencyEnum) {
switch (room.priceType) {
case PriceTypeEnum.cheque:
case PriceTypeEnum.points:
case PriceTypeEnum.voucher:
{
if (room.totalPrice) {
total.local.additionalPrice =
@@ -88,8 +89,19 @@ export function calculateTotalPrice(rooms: Room[], currency: CurrencyEnum) {
}
if (!total.local.additionalPriceCurrency) {
if (room.currencyCode) {
total.local.additionalPriceCurrency = room.currencyCode
total.local.additionalPriceCurrency = currency
}
}
break
case PriceTypeEnum.voucher:
{
if (room.packages) {
const pkgsSum = sumPackages(room.packages)
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum.price
if (pkgsSum.currency) {
total.local.additionalPriceCurrency = pkgsSum.currency
} else {
total.local.additionalPriceCurrency = currency
}

View File

@@ -3,8 +3,6 @@ import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import { formatPrice } from "@/utils/numberFormatting"
@@ -12,15 +10,16 @@ import { CurrencyEnum } from "@/types/enums/currency"
export default function Cheques({
cheques,
currencyCode,
isCancelled,
price,
}: {
cheques: number
currencyCode: CurrencyEnum
isCancelled: boolean
price: number
}) {
const intl = useIntl()
const currency = useMyStayStore((state) => state.bookedRoom.currencyCode)
if (!cheques) {
return <SkeletonShimmer width="100px" />
@@ -31,7 +30,7 @@ export default function Cheques({
cheques,
CurrencyEnum.CC,
price,
currency
currencyCode
)
return (

View File

@@ -3,24 +3,23 @@ import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import { formatPrice } from "@/utils/numberFormatting"
import { CurrencyEnum } from "@/types/enums/currency"
export default function Vouchers({
currencyCode,
isCancelled,
price,
vouchers,
}: {
currencyCode: CurrencyEnum
isCancelled: boolean
price?: number
vouchers: number
}) {
const intl = useIntl()
const currency = useMyStayStore((state) => state.bookedRoom.currencyCode)
if (!vouchers) {
return <SkeletonShimmer width="100px" />
@@ -31,7 +30,7 @@ export default function Vouchers({
vouchers,
CurrencyEnum.Voucher,
price,
currency
currencyCode
)
return (

View File

@@ -39,6 +39,7 @@ export default function PriceType({
return (
<Cheques
cheques={cheques}
currencyCode={currencyCode}
isCancelled={isCancelled}
price={totalPrice}
/>
@@ -63,6 +64,7 @@ export default function PriceType({
case PriceTypeEnum.voucher:
return (
<Vouchers
currencyCode={currencyCode}
isCancelled={isCancelled}
price={totalPrice}
vouchers={vouchers}

View File

@@ -6,6 +6,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { useMyStayStore } from "@/stores/my-stay"
import PriceType from "@/components/HotelReservation/MyStay/PriceType"
import { sumPackages } from "@/components/HotelReservation/utils"
import styles from "./details.module.css"
@@ -17,6 +18,7 @@ export default function PriceDetails() {
formattedTotalPrice: state.totalPrice,
isCancelled: state.bookedRoom.isCancelled,
currencyCode: state.bookedRoom.currencyCode,
packages: state.bookedRoom.packages,
priceType: state.bookedRoom.priceType,
rateDefinition: state.bookedRoom.rateDefinition,
roomPoints: state.bookedRoom.roomPoints,
@@ -24,6 +26,14 @@ export default function PriceDetails() {
vouchers: state.bookedRoom.vouchers,
}))
let totalPrice = pricing.totalPrice
// API returns negative values for totalPrice
// on voucher bookings (╯°□°)╯︵ ┻━┻
if (pricing.vouchers && totalPrice < 0) {
const pkgsSum = sumPackages(pricing.packages)
totalPrice = pkgsSum.price
}
return (
<div className={styles.priceDetails}>
<div className={styles.price}>
@@ -34,7 +44,7 @@ export default function PriceDetails() {
})}
</p>
</Typography>
<PriceType {...pricing} />
<PriceType {...pricing} totalPrice={totalPrice} />
</div>
</div>
)

View File

@@ -1,26 +1,39 @@
"use client"
import { useMyStayStore } from "@/stores/my-stay"
import { sumPackages } from "../../utils"
import PriceType from "../PriceType"
import type { PriceType as _PriceType } from "@/types/components/hotelReservation/myStay/myStay"
export default function TotalPrice() {
const { bookedRoom, formattedTotalPrice } = useMyStayStore((state) => ({
bookedRoom: state.bookedRoom,
formattedTotalPrice: state.totalPrice,
}))
const { bookedRoom, formattedTotalPrice, rooms } = useMyStayStore(
(state) => ({
bookedRoom: state.bookedRoom,
formattedTotalPrice: state.totalPrice,
rooms: state.rooms,
})
)
const totalCheques = rooms.reduce((total, room) => total + room.cheques, 0)
const totalPoints = rooms.reduce((total, room) => total + room.roomPoints, 0)
let totalPrice = rooms.reduce((total, room) => total + room.totalPrice, 0)
if (rooms.some((room) => room.vouchers)) {
const pkgsSum = sumPackages(rooms.flatMap((r) => r.packages || []))
totalPrice = pkgsSum.price
}
return (
<PriceType
cheques={bookedRoom.cheques}
cheques={totalCheques}
formattedTotalPrice={formattedTotalPrice}
isCancelled={bookedRoom.isCancelled}
currencyCode={bookedRoom.currencyCode}
priceType={bookedRoom.priceType}
rateDefinition={bookedRoom.rateDefinition}
roomPoints={bookedRoom.roomPoints}
totalPrice={bookedRoom.totalPrice}
roomPoints={totalPoints}
totalPrice={totalPrice}
vouchers={bookedRoom.vouchers}
/>
)

View File

@@ -21,7 +21,6 @@ export interface CorporateChequePriceType {
interface CorporateChequePriceProps extends SharedPriceRowProps {
currency: string
nights: number
price: CorporateChequePriceType["corporateCheque"]
}
@@ -57,9 +56,6 @@ export default function CorporateChequePrice({
return (
<>
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
<BoldRow
label={intl.formatMessage({ defaultMessage: "Room charge" })}
value={formatPrice(
@@ -70,6 +66,11 @@ export default function CorporateChequePrice({
additionalCurrency
)}
/>
{nights > 1 ? (
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
) : null}
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
</>
)
}

View File

@@ -57,9 +57,6 @@ export default function RedemptionPrice({
return (
<>
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
<BoldRow
label={intl.formatMessage({ defaultMessage: "Room charge" })}
value={formatPrice(
@@ -70,6 +67,11 @@ export default function RedemptionPrice({
additionalCurrency
)}
/>
{nights > 1 ? (
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
) : null}
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
</>
)
}

View File

@@ -25,6 +25,7 @@ interface RegularPriceProps extends SharedPriceRowProps {
export default function RegularPrice({
bedType,
nights,
packages,
price,
}: RegularPriceProps) {
@@ -48,13 +49,15 @@ export default function RegularPrice({
return (
<>
<RegularRow label={averagePriceTitle} value={avgeragePricePerNight} />
<BedTypeRow bedType={bedType} currency={price.currency} />
<PackagesRow packages={packages} />
<BoldRow
label={intl.formatMessage({ defaultMessage: "Room charge" })}
value={roomCharge}
/>
{nights > 1 ? (
<RegularRow label={averagePriceTitle} value={avgeragePricePerNight} />
) : null}
<BedTypeRow bedType={bedType} currency={price.currency} />
<PackagesRow packages={packages} />
</>
)
}

View File

@@ -1,7 +1,6 @@
"use client"
import { useIntl } from "react-intl"
import { sumPackages } from "@/components/HotelReservation/utils"
import { formatPrice } from "@/utils/numberFormatting"
import BoldRow from "../Bold"
@@ -40,37 +39,20 @@ export default function VoucherPrice({
const averagePriceTitle = intl.formatMessage({
defaultMessage: "Average price per night",
})
const pkgsSum = sumPackages(packages)
let additionalPricePerStay
if (pkgsSum.price) {
additionalPricePerStay = pkgsSum.price
}
const averageAdditionalPricePerNight = additionalPricePerStay
? Math.ceil(additionalPricePerStay / nights)
: null
let averagePricePerNight = `${price.numberOfVouchers} ${CurrencyEnum.Voucher}`
if (averageAdditionalPricePerNight) {
averagePricePerNight = `${averagePricePerNight} + ${averageAdditionalPricePerNight} ${pkgsSum.currency ?? currency}`
}
const averagePricePerNight = `${price.numberOfVouchers / nights} ${CurrencyEnum.Voucher}`
return (
<>
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
<BoldRow
label={intl.formatMessage({ defaultMessage: "Room charge" })}
value={formatPrice(
intl,
price.numberOfVouchers,
CurrencyEnum.Voucher,
additionalPricePerStay,
pkgsSum.currency ?? currency
)}
value={formatPrice(intl, price.numberOfVouchers, CurrencyEnum.Voucher)}
/>
{nights > 1 ? (
<RegularRow label={averagePriceTitle} value={averagePricePerNight} />
) : null}
<BedTypeRow bedType={bedType} currency={currency} />
<PackagesRow packages={packages} />
</>
)
}

View File

@@ -3,5 +3,6 @@ import type { Packages } from "@/types/requests/packages"
export interface SharedPriceRowProps {
bedType: BedTypeSchema | undefined
nights: number
packages: Packages | null
}

View File

@@ -17,6 +17,7 @@ const noVatCurrencies = [
CurrencyEnum.CC,
CurrencyEnum.POINTS,
CurrencyEnum.Voucher,
CurrencyEnum.Unknown,
]
export default function VatRow({ totalPrice, vat }: VatProps) {

View File

@@ -72,15 +72,15 @@ export default function PriceDetailsTable({
const intl = useIntl()
const lang = useLang()
const diff = dt(toDate).diff(fromDate, "days")
const nights = intl.formatMessage(
const nights = dt(toDate).diff(fromDate, "days")
const nightsMsg = intl.formatMessage(
{ defaultMessage: "{totalNights, plural, one {# night} other {# nights}}" },
{ totalNights: diff }
{ totalNights: nights }
)
const arrival = dt(fromDate).locale(lang).format("ddd, D MMM")
const departue = dt(toDate).locale(lang).format("ddd, D MMM")
const duration = ` ${arrival} - ${departue} (${nights})`
const duration = ` ${arrival} - ${departue} (${nightsMsg})`
const allRoomsPackages: Package[] = rooms
.flatMap((r) => r.packages)
@@ -153,26 +153,27 @@ export default function PriceDetailsTable({
<RegularPrice
bedType={room.bedType}
packages={room.packages}
nights={nights}
price={price}
/>
<CorporateChequePrice
bedType={room.bedType}
currency={currency}
nights={diff}
nights={nights}
packages={room.packages}
price={chequePrice}
/>
<RedemptionPrice
bedType={room.bedType}
currency={currency}
nights={diff}
nights={nights}
packages={room.packages}
price={redemptionPrice}
/>
<VoucherPrice
bedType={room.bedType}
currency={currency}
nights={diff}
nights={nights}
packages={room.packages}
price={voucherPrice}
/>
@@ -184,7 +185,7 @@ export default function PriceDetailsTable({
breakfastIncluded={room.breakfastIncluded}
childrenInRoom={room.childrenInRoom}
currency={currency}
nights={diff}
nights={nights}
/>
</Fragment>
)

View File

@@ -128,6 +128,13 @@ export function calculateVoucherPrice(selectedRateSummary: Rate[]) {
total.local.price = total.local.price + rate.numberOfVouchers
const pkgsSum = sumPackages(room.packages)
if (pkgsSum.price && pkgsSum.currency) {
total.local.additionalPrice =
(total.local.additionalPrice || 0) + pkgsSum.price
total.local.additionalPriceCurrency = pkgsSum.currency
}
return total
},
{

View File

@@ -80,6 +80,9 @@ export default function SelectedRoomPanel() {
return null
}
const selectedPackagesCurrency = selectedPackages.find(
(pkg) => pkg.localPrice.currency
)
const selectedPackagesPrice = selectedPackages.reduce(
(total, pkg) => total + pkg.localPrice.totalPrice,
0
@@ -104,11 +107,17 @@ export default function SelectedRoomPanel() {
} else if ("corporateCheque" in selectedRate.product) {
const { localPrice } = selectedRate.product.corporateCheque
selectedProduct = `${localPrice.numberOfCheques} ${CurrencyEnum.CC}`
if (localPrice.additionalPricePerStay && localPrice.currency) {
selectedProduct = `${selectedProduct} + ${localPrice.additionalPricePerStay} ${localPrice.currency}`
if (
(localPrice.additionalPricePerStay || selectedPackagesPrice) &&
localPrice.currency
) {
selectedProduct = `${selectedProduct} + ${localPrice.additionalPricePerStay + selectedPackagesPrice} ${localPrice.currency}`
}
} else if ("voucher" in selectedRate.product) {
selectedProduct = `${selectedRate.product.voucher.numberOfVouchers} ${CurrencyEnum.Voucher}`
if (selectedPackagesPrice && selectedPackagesCurrency) {
selectedProduct = `${selectedProduct} + ${selectedPackagesPrice} ${selectedPackagesCurrency}`
}
}
if (!selectedProduct) {

View File

@@ -115,6 +115,16 @@ export default function Code({
if ("voucher" in product) {
const { numberOfVouchers, rateCode } = product.voucher
const isSelected = isSelectedVoucher(product, selectedRate, roomTypeCode)
const voucherMsg = intl
.formatMessage({
defaultMessage: "Voucher",
})
.toUpperCase()
let price = `${numberOfVouchers} ${voucherMsg}`
if (pkgsSum.price) {
price = `${price} + ${pkgsSum.price}`
}
return (
<CodeRateCard
key={product.rate}
@@ -125,12 +135,8 @@ export default function Code({
paymentTerm={rateTitles[product.rate].paymentTerm}
rate={{
label: product.rateDefinition?.title,
price: numberOfVouchers.toString(),
unit: intl
.formatMessage({
defaultMessage: "Voucher",
})
.toUpperCase(),
price,
unit: pkgsSum.currency ?? "",
}}
rateTitle={rateTitles[product.rate].title}
rateTermDetails={rateTermDetails}

View File

@@ -9,6 +9,7 @@ import { dt } from "@/lib/dt"
import GuestDetails from "@/components/HotelReservation/MyStay/GuestDetails"
import PriceType from "@/components/HotelReservation/MyStay/PriceType"
import { hasModifiableRate } from "@/components/HotelReservation/MyStay/utils"
import { sumPackages } from "@/components/HotelReservation/utils"
import ImageGallery from "@/components/ImageGallery"
import Accordion from "@/components/TempDesignSystem/Accordion"
import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem"
@@ -103,6 +104,14 @@ export default function BookedRoomSidePeek({
vouchers,
} = room
let totalRoomPrice = totalPrice
// API returns negative values for totalPrice
// on voucher bookings (╯°□°)╯︵ ┻━┻
if (vouchers && totalRoomPrice < 0) {
const pkgsSum = sumPackages(packages)
totalRoomPrice = pkgsSum.price
}
const fromDate = dt(checkInDate).locale(lang)
const galleryImages = hotelRoom
@@ -382,7 +391,7 @@ export default function BookedRoomSidePeek({
currencyCode={currencyCode}
rateDefinition={rateDefinition}
roomPoints={roomPoints}
totalPrice={totalPrice}
totalPrice={totalRoomPrice}
vouchers={vouchers}
/>
</div>

View File

@@ -61,12 +61,29 @@ export default function BookingConfirmationProvider({
currencyCode
)
} else if (totalBookingVouchers) {
isVatCurrency = false
formattedTotalCost = formatPrice(
intl,
totalBookingVouchers,
CurrencyEnum.Voucher
)
const room = rooms?.[0]
if (room?.packages) {
const pkgsSum = room.packages.reduce(
(total, pkg) => total + pkg.totalPrice,
0
)
const currency = room.packages.find((pkg) => pkg.currency)?.currency
isVatCurrency = false
formattedTotalCost = formatPrice(
intl,
totalBookingVouchers,
CurrencyEnum.Voucher,
pkgsSum,
currency
)
} else {
isVatCurrency = false
formattedTotalCost = formatPrice(
intl,
totalBookingVouchers,
CurrencyEnum.Voucher
)
}
}
const initialData = {
bookingCode,

View File

@@ -12,6 +12,7 @@ import type { Price } from "@/types/components/hotelReservation/price"
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { CurrencyEnum } from "@/types/enums/currency"
import { StepEnum } from "@/types/enums/step"
import type { Package } from "@/types/requests/packages"
import type { PersistedState, RoomState } from "@/types/stores/enter-details"
import type { SafeUser } from "@/types/user"
@@ -368,15 +369,22 @@ export function getTotalPrice(roomRates: RoomRate[], isMember: boolean) {
return totalPrice
}
export function calculateVoucherPrice(roomRates: RoomRate[]) {
export function calculateVoucherPrice(
roomRates: RoomRate[],
packages: Package[]
) {
return roomRates.reduce<Price>(
(total, room) => {
if (!("voucher" in room)) {
return total
}
const pkgsSum = sumPackages(packages)
return {
local: {
additionalPrice: pkgsSum.price,
additionalPriceCurrency: pkgsSum.currency,
currency: total.local.currency,
price: total.local.price + room.voucher.numberOfVouchers,
},

View File

@@ -85,7 +85,8 @@ export function createDetailsStore(
roomOneRoomRate.redemption.localPrice.additionalPricePerStay
}
} else if (isVoucher) {
initialTotalPrice = calculateVoucherPrice(initialRoomRates)
const pkgs = initialState.rooms.flatMap((room) => room.roomFeatures || [])
initialTotalPrice = calculateVoucherPrice(initialRoomRates, pkgs)
} else if (isCorpChq) {
initialTotalPrice = calculateCorporateChequePrice(initialRoomRates)
} else {

View File

@@ -26,7 +26,9 @@ export function calculateTotalPrice(
if (room.totalPoints) {
total.points = total.points + room.totalPoints
}
if (room.totalPrice) {
// room.totalPrice is a negative value when
// its a vouchers booking (╯°□°)╯︵ ┻━┻
if (room.totalPrice && !room.vouchers) {
total.cash = total.cash + room.totalPrice
}
return total