fix: always use totalPrice to display roomCharge
This commit is contained in:
@@ -36,10 +36,6 @@ export default function PriceDetails() {
|
||||
return total
|
||||
}
|
||||
|
||||
const pkgsSum =
|
||||
room.roomFeatures?.reduce((total, pkg) => total + pkg.totalPrice, 0) ??
|
||||
0
|
||||
|
||||
if (room.cheques) {
|
||||
// CorporateCheque Booking
|
||||
total.local.currency = CurrencyEnum.CC
|
||||
@@ -54,7 +50,7 @@ export default function PriceDetails() {
|
||||
total.local.price = total.local.price + room.vouchers
|
||||
} else {
|
||||
// Price Booking
|
||||
total.local.price = total.local.price + room.roomPrice + pkgsSum
|
||||
total.local.price = total.local.price + room.totalPrice
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -62,7 +58,7 @@ export default function PriceDetails() {
|
||||
room.roomPrice
|
||||
) {
|
||||
total.local.additionalPrice =
|
||||
(total.local.additionalPrice || 0) + room.roomPrice + pkgsSum
|
||||
(total.local.additionalPrice || 0) + room.totalPrice
|
||||
total.local.additionalPriceCurrency = currency
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
} from "@/server/routers/hotels/schemas/packages"
|
||||
|
||||
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
import { PackageTypeEnum } from "@/types/enums/packages"
|
||||
import type { Package } from "@/types/requests/packages"
|
||||
import type { Room } from "@/types/stores/booking-confirmation"
|
||||
|
||||
@@ -15,16 +17,20 @@ export function mapToPrice(rooms: (Room | null)[], nights: number) {
|
||||
if (room.cheques) {
|
||||
price = {
|
||||
corporateCheque: {
|
||||
additionalPricePerStay: room.roomPrice ? room.roomPrice : undefined,
|
||||
currency: room.roomPrice ? room.currencyCode : undefined,
|
||||
additionalPricePerStay: room.totalPrice
|
||||
? room.totalPrice
|
||||
: undefined,
|
||||
currency: room.totalPrice ? room.currencyCode : undefined,
|
||||
numberOfCheques: room.cheques,
|
||||
},
|
||||
}
|
||||
} else if (room.roomPoints) {
|
||||
price = {
|
||||
redemption: {
|
||||
additionalPricePerStay: room.roomPrice ? room.roomPrice : undefined,
|
||||
currency: room.roomPrice ? room.currencyCode : undefined,
|
||||
additionalPricePerStay: room.totalPrice
|
||||
? room.totalPrice
|
||||
: undefined,
|
||||
currency: room.totalPrice ? room.currencyCode : undefined,
|
||||
pointsPerNight: room.roomPoints / nights,
|
||||
pointsPerStay: room.roomPoints,
|
||||
},
|
||||
@@ -40,7 +46,7 @@ export function mapToPrice(rooms: (Room | null)[], nights: number) {
|
||||
regular: {
|
||||
currency: room.currencyCode,
|
||||
pricePerNight: room.roomPrice / nights,
|
||||
pricePerStay: room.roomPrice,
|
||||
pricePerStay: room.totalPrice,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -53,7 +59,10 @@ export function mapToPrice(rooms: (Room | null)[], nights: number) {
|
||||
price: room.breakfast?.unitPrice,
|
||||
totalPrice: room.breakfast?.totalPrice,
|
||||
},
|
||||
packageType: room.breakfast?.type,
|
||||
packageType:
|
||||
room.breakfast?.code === BreakfastPackageEnum.REGULAR_BREAKFAST
|
||||
? PackageTypeEnum.BreakfastAdult
|
||||
: "",
|
||||
requestedPrice: {
|
||||
currency: room.breakfast?.currency,
|
||||
price: room.breakfast?.unitPrice,
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Fragment } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import DiscountIcon from "@scandic-hotels/design-system/Icons/DiscountIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import IconChip from "@/components/TempDesignSystem/IconChip"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
|
||||
import styles from "./priceDetailsTable.module.css"
|
||||
|
||||
import type { Price } from "@/types/components/hotelReservation/price"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
import type { RoomState } from "@/types/stores/enter-details"
|
||||
|
||||
function Row({
|
||||
label,
|
||||
value,
|
||||
bold,
|
||||
}: {
|
||||
label: string
|
||||
value: string
|
||||
bold?: boolean
|
||||
}) {
|
||||
return (
|
||||
<tr className={styles.row}>
|
||||
<td>
|
||||
<Caption type={bold ? "bold" : undefined}>{label}</Caption>
|
||||
</td>
|
||||
<td className={styles.price}>
|
||||
<Caption type={bold ? "bold" : undefined}>{value}</Caption>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
function TableSection({ children }: React.PropsWithChildren) {
|
||||
return <tbody className={styles.tableSection}>{children}</tbody>
|
||||
}
|
||||
|
||||
function TableSectionHeader({
|
||||
title,
|
||||
subtitle,
|
||||
}: {
|
||||
title: string
|
||||
subtitle?: string
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<Body>{title}</Body>
|
||||
{subtitle ? <Body>{subtitle}</Body> : null}
|
||||
</th>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
export type Room = Pick<
|
||||
RoomState["room"],
|
||||
| "adults"
|
||||
| "bedType"
|
||||
| "breakfast"
|
||||
| "childrenInRoom"
|
||||
| "roomFeatures"
|
||||
| "roomRate"
|
||||
| "roomType"
|
||||
> & {
|
||||
guest?: RoomState["room"]["guest"]
|
||||
}
|
||||
|
||||
export interface PriceDetailsTableProps {
|
||||
bookingCode?: string
|
||||
fromDate: string
|
||||
isMember: boolean
|
||||
rooms: Room[]
|
||||
toDate: string
|
||||
totalPrice: Price
|
||||
vat: number
|
||||
}
|
||||
|
||||
export default function PriceDetailsTable({
|
||||
bookingCode,
|
||||
fromDate,
|
||||
isMember,
|
||||
rooms,
|
||||
toDate,
|
||||
totalPrice,
|
||||
vat,
|
||||
}: PriceDetailsTableProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const diff = dt(toDate).diff(fromDate, "days")
|
||||
const nights = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{ totalNights: diff }
|
||||
)
|
||||
const vatPercentage = vat / 100
|
||||
const vatAmount = totalPrice.local.price * vatPercentage
|
||||
|
||||
const priceExclVat = totalPrice.local.price - vatAmount
|
||||
|
||||
const duration = ` ${dt(fromDate).locale(lang).format("ddd, D MMM")}
|
||||
-
|
||||
${dt(toDate).locale(lang).format("ddd, D MMM")} (${nights})`
|
||||
const noVatCurrencies = [
|
||||
CurrencyEnum.CC,
|
||||
CurrencyEnum.POINTS,
|
||||
CurrencyEnum.Voucher,
|
||||
]
|
||||
return (
|
||||
<table className={styles.priceDetailsTable}>
|
||||
{rooms.map((room, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
const getMemberRate =
|
||||
room.guest?.join ||
|
||||
room.guest?.membershipNo ||
|
||||
(isMainRoom && isMember)
|
||||
|
||||
let price
|
||||
if (
|
||||
getMemberRate &&
|
||||
"member" in room.roomRate &&
|
||||
room.roomRate.member
|
||||
) {
|
||||
price = room.roomRate.member
|
||||
} else if ("public" in room.roomRate && room.roomRate.public) {
|
||||
price = room.roomRate.public
|
||||
}
|
||||
const voucherPrice =
|
||||
"voucher" in room.roomRate ? room.roomRate.voucher : undefined
|
||||
const chequePrice =
|
||||
"corporateCheque" in room.roomRate
|
||||
? room.roomRate.corporateCheque
|
||||
: undefined
|
||||
const redemptionPrice =
|
||||
"redemption" in room.roomRate ? room.roomRate.redemption : undefined
|
||||
if (!price && !voucherPrice && !chequePrice && !redemptionPrice) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<Fragment key={idx}>
|
||||
<TableSection>
|
||||
{rooms.length > 1 && (
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Room",
|
||||
})}
|
||||
{
|
||||
/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */
|
||||
" "
|
||||
}
|
||||
{idx + 1}
|
||||
</Body>
|
||||
</th>
|
||||
</tr>
|
||||
)}
|
||||
<TableSectionHeader title={room.roomType} subtitle={duration} />
|
||||
{price && (
|
||||
<>
|
||||
<Row
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Average price per night",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
price.localPrice.pricePerNight,
|
||||
price.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
{room.roomFeatures
|
||||
? room.roomFeatures.map((feature) => (
|
||||
<Row
|
||||
key={feature.code}
|
||||
label={feature.description}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
+feature.localPrice.totalPrice,
|
||||
feature.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
{room.bedType ? (
|
||||
<Row
|
||||
label={room.bedType.description}
|
||||
value={formatPrice(intl, 0, price.localPrice.currency)}
|
||||
/>
|
||||
) : null}
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Room charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
price.localPrice.pricePerStay,
|
||||
price.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{voucherPrice && (
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Room charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
voucherPrice.numberOfVouchers,
|
||||
CurrencyEnum.Voucher
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{chequePrice && (
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Room charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
chequePrice.localPrice.numberOfCheques,
|
||||
CurrencyEnum.CC,
|
||||
chequePrice.localPrice.additionalPricePerStay,
|
||||
chequePrice.localPrice.currency ?? undefined
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{redemptionPrice && (
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Room charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
redemptionPrice.localPrice.pointsPerStay,
|
||||
CurrencyEnum.POINTS,
|
||||
redemptionPrice.localPrice.additionalPricePerStay,
|
||||
redemptionPrice.localPrice.currency ?? undefined
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</TableSection>
|
||||
|
||||
{room.breakfast ? (
|
||||
<TableSection>
|
||||
<Row
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"Breakfast ({totalAdults, plural, one {# adult} other {# adults}}) x {totalBreakfasts}",
|
||||
},
|
||||
{ totalAdults: room.adults, totalBreakfasts: diff }
|
||||
)}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.breakfast.localPrice.price * room.adults,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
{room.childrenInRoom?.length ? (
|
||||
<Row
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}",
|
||||
},
|
||||
{
|
||||
totalChildren: room.childrenInRoom.length,
|
||||
totalBreakfasts: diff,
|
||||
}
|
||||
)}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
0,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Breakfast charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.breakfast.localPrice.price * room.adults * diff,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
</TableSection>
|
||||
) : null}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
<TableSection>
|
||||
<TableSectionHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Total",
|
||||
})}
|
||||
/>
|
||||
{!noVatCurrencies.includes(totalPrice.local.currency) ? (
|
||||
<>
|
||||
<Row
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Price excluding VAT",
|
||||
})}
|
||||
value={formatPrice(intl, priceExclVat, totalPrice.local.currency)}
|
||||
/>
|
||||
<Row
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "VAT {vat}%",
|
||||
},
|
||||
{ vat }
|
||||
)}
|
||||
value={formatPrice(intl, vatAmount, totalPrice.local.currency)}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
<tr className={styles.row}>
|
||||
<td>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Price including VAT",
|
||||
})}
|
||||
</Body>
|
||||
</td>
|
||||
<td className={styles.price}>
|
||||
<Body textTransform="bold">
|
||||
{formatPrice(
|
||||
intl,
|
||||
totalPrice.local.price,
|
||||
totalPrice.local.currency,
|
||||
totalPrice.local.additionalPrice,
|
||||
totalPrice.local.additionalPriceCurrency
|
||||
)}
|
||||
</Body>
|
||||
</td>
|
||||
</tr>
|
||||
{totalPrice.local.regularPrice ? (
|
||||
<tr className={styles.row}>
|
||||
<td></td>
|
||||
<td className={styles.price}>
|
||||
<Caption color="uiTextMediumContrast" striked={true}>
|
||||
{formatPrice(
|
||||
intl,
|
||||
totalPrice.local.regularPrice,
|
||||
totalPrice.local.currency
|
||||
)}
|
||||
</Caption>
|
||||
</td>
|
||||
</tr>
|
||||
) : null}
|
||||
{bookingCode && (
|
||||
<tr className={styles.row}>
|
||||
<td colSpan={2} align="left">
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<IconChip
|
||||
color="blue"
|
||||
icon={<DiscountIcon color="Icon/Feedback/Information" />}
|
||||
>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "<strong>Booking code</strong>: {value}",
|
||||
},
|
||||
{
|
||||
value: bookingCode,
|
||||
strong: (text) => (
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<strong>{text}</strong>
|
||||
</Typography>
|
||||
),
|
||||
}
|
||||
)}
|
||||
</IconChip>
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</TableSection>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
@@ -48,13 +48,13 @@ export default function SummaryUI({
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const diff = dt(booking.toDate).diff(booking.fromDate, "days")
|
||||
const nights = dt(booking.toDate).diff(booking.fromDate, "days")
|
||||
|
||||
const nights = intl.formatMessage(
|
||||
const nightsMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{ totalNights: diff }
|
||||
{ totalNights: nights }
|
||||
)
|
||||
|
||||
function handleToggleSummary() {
|
||||
@@ -95,7 +95,7 @@ export default function SummaryUI({
|
||||
? totalPrice.requested.currency === totalPrice.local.currency
|
||||
: false
|
||||
|
||||
const priceDetailsRooms = mapToPrice(rooms, isMember)
|
||||
const priceDetailsRooms = mapToPrice(rooms, isMember, nights)
|
||||
|
||||
return (
|
||||
<section className={styles.summary}>
|
||||
@@ -113,7 +113,7 @@ export default function SummaryUI({
|
||||
size={15}
|
||||
/>
|
||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||
{dt(booking.toDate).locale(lang).format("ddd, D MMM")} ({nights})
|
||||
{dt(booking.toDate).locale(lang).format("ddd, D MMM")} ({nightsMsg})
|
||||
</Body>
|
||||
<Button
|
||||
onPress={handleToggleSummary}
|
||||
@@ -399,7 +399,7 @@ export default function SummaryUI({
|
||||
<Body color="uiTextHighContrast">
|
||||
{formatPrice(
|
||||
intl,
|
||||
room.breakfast.localPrice.price * adults * diff,
|
||||
room.breakfast.localPrice.price * adults * nights,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
</Body>
|
||||
|
||||
@@ -1,12 +1,37 @@
|
||||
import { sumPackages } from "@/components/HotelReservation/utils"
|
||||
|
||||
import type { RoomState } from "@/types/stores/enter-details"
|
||||
|
||||
export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
||||
export function mapToPrice(
|
||||
rooms: RoomState[],
|
||||
isMember: boolean,
|
||||
nights: number
|
||||
) {
|
||||
return rooms
|
||||
.filter((room) => room && room.room.roomRate)
|
||||
.map(({ room }, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
|
||||
const pkgsSum = sumPackages(room.roomFeatures)
|
||||
|
||||
if ("corporateCheque" in room.roomRate) {
|
||||
if (
|
||||
room.roomRate.corporateCheque.localPrice.additionalPricePerStay ||
|
||||
pkgsSum.price
|
||||
) {
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
price: {
|
||||
corporateCheque: {
|
||||
...room.roomRate.corporateCheque.localPrice,
|
||||
additionalPricePerStay:
|
||||
(room.roomRate.corporateCheque.localPrice
|
||||
.additionalPricePerStay || 0) + pkgsSum.price,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
@@ -17,6 +42,23 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
||||
}
|
||||
|
||||
if ("redemption" in room.roomRate) {
|
||||
if (
|
||||
room.roomRate.redemption.localPrice.additionalPricePerStay ||
|
||||
pkgsSum.price
|
||||
) {
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
price: {
|
||||
redemption: {
|
||||
...room.roomRate.redemption.localPrice,
|
||||
additionalPricePerStay:
|
||||
(room.roomRate.redemption.localPrice.additionalPricePerStay ||
|
||||
0) + pkgsSum.price,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
@@ -39,6 +81,23 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
||||
const isMemberRate = !!(room.guest.join || room.guest.membershipNo)
|
||||
if ((isMember && isMainRoom) || isMemberRate) {
|
||||
if ("member" in room.roomRate && room.roomRate.member) {
|
||||
if (pkgsSum.price) {
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
price: {
|
||||
regular: {
|
||||
...room.roomRate.member.localPrice,
|
||||
pricePerNight:
|
||||
room.roomRate.member.localPrice.pricePerNight +
|
||||
pkgsSum.price / nights,
|
||||
pricePerStay:
|
||||
room.roomRate.member.localPrice.pricePerStay +
|
||||
pkgsSum.price,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
@@ -50,6 +109,22 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
||||
}
|
||||
|
||||
if ("public" in room.roomRate && room.roomRate.public) {
|
||||
if (pkgsSum.price) {
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
price: {
|
||||
regular: {
|
||||
...room.roomRate.public.localPrice,
|
||||
pricePerNight:
|
||||
room.roomRate.public.localPrice.pricePerNight +
|
||||
pkgsSum.price / nights,
|
||||
pricePerStay:
|
||||
room.roomRate.public.localPrice.pricePerStay + pkgsSum.price,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
...room,
|
||||
packages: room.roomFeatures,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useMyStayTotalPriceStore } from "@/stores/my-stay/myStayTotalPrice"
|
||||
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
|
||||
export default function Cheques({
|
||||
cheques,
|
||||
price,
|
||||
}: {
|
||||
cheques: number
|
||||
price: number
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
const currencyCode = useMyStayTotalPriceStore((state) => state.currencyCode)
|
||||
|
||||
if (!cheques) {
|
||||
return <SkeletonShimmer width={"100px"} />
|
||||
}
|
||||
|
||||
const totalPrice = formatPrice(
|
||||
intl,
|
||||
cheques,
|
||||
CurrencyEnum.CC,
|
||||
price,
|
||||
currencyCode
|
||||
)
|
||||
|
||||
return (
|
||||
<Typography variant="Title/Subtitle/lg">
|
||||
<p>{totalPrice}</p>
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
@@ -16,8 +16,7 @@ import IconChip from "@/components/TempDesignSystem/IconChip"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import { IconForFeatureCode } from "../../utils"
|
||||
import Points from "../Points"
|
||||
import Price from "../Price"
|
||||
import PriceType from "../PriceType"
|
||||
import { hasModifiableRate } from "../utils"
|
||||
import { hasBreakfastPackageFromBookingFlow } from "../utils/hasBreakfastPackage"
|
||||
import { mapRoomDetails } from "../utils/mapRoomDetails"
|
||||
@@ -119,17 +118,18 @@ export default function MultiRoom({
|
||||
const {
|
||||
adults,
|
||||
checkInDate,
|
||||
cheques,
|
||||
childrenAges,
|
||||
confirmationNumber,
|
||||
cancellationNumber,
|
||||
hotelId,
|
||||
roomPoints,
|
||||
roomPrice,
|
||||
packages,
|
||||
rateDefinition,
|
||||
isCancelled,
|
||||
priceType,
|
||||
vouchers,
|
||||
totalPrice,
|
||||
} = multiRoom
|
||||
|
||||
const fromDate = dt(checkInDate).locale(lang)
|
||||
@@ -349,26 +349,15 @@ export default function MultiRoom({
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
{priceType === "points" ? (
|
||||
<Points points={roomPoints} variant="Body/Paragraph/mdBold" />
|
||||
) : priceType === "voucher" ? (
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{count} voucher",
|
||||
},
|
||||
{ count: vouchers }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
) : (
|
||||
<Price
|
||||
price={isCancelled ? 0 : roomPrice.perStay.local.price}
|
||||
variant="Body/Paragraph/mdBold"
|
||||
isMember={rateDefinition.isMemberRate}
|
||||
/>
|
||||
)}
|
||||
<PriceType
|
||||
cheques={cheques}
|
||||
isCancelled={isCancelled}
|
||||
priceType={priceType}
|
||||
rateDefinition={rateDefinition}
|
||||
roomPoints={roomPoints}
|
||||
totalPrice={totalPrice}
|
||||
vouchers={vouchers}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Fragment } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
|
||||
import styles from "./priceDetailsTable.module.css"
|
||||
|
||||
import type { Price } from "@/types/components/hotelReservation/price"
|
||||
import type { Room } from "@/stores/my-stay/myStayRoomDetailsStore"
|
||||
|
||||
function Row({
|
||||
label,
|
||||
value,
|
||||
bold,
|
||||
}: {
|
||||
label: string
|
||||
value: string
|
||||
bold?: boolean
|
||||
}) {
|
||||
return (
|
||||
<tr className={styles.row}>
|
||||
<td>
|
||||
<Typography
|
||||
variant={
|
||||
bold
|
||||
? "Body/Supporting text (caption)/smBold"
|
||||
: "Body/Supporting text (caption)/smRegular"
|
||||
}
|
||||
>
|
||||
<span>{label}</span>
|
||||
</Typography>
|
||||
</td>
|
||||
<td className={styles.price}>
|
||||
<Typography
|
||||
variant={
|
||||
bold
|
||||
? "Body/Supporting text (caption)/smBold"
|
||||
: "Body/Supporting text (caption)/smRegular"
|
||||
}
|
||||
>
|
||||
<span>{value}</span>
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
function TableSection({ children }: React.PropsWithChildren) {
|
||||
return <tbody className={styles.tableSection}>{children}</tbody>
|
||||
}
|
||||
|
||||
function TableSectionHeader({
|
||||
title,
|
||||
subtitle,
|
||||
}: {
|
||||
title: string
|
||||
subtitle?: string
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{title}</span>
|
||||
</Typography>
|
||||
</th>
|
||||
</tr>
|
||||
{subtitle && (
|
||||
<tr>
|
||||
<th colSpan={2}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{subtitle}</span>
|
||||
</Typography>
|
||||
</th>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export type RoomPriceDetails = Pick<
|
||||
Room,
|
||||
| "adults"
|
||||
| "bedType"
|
||||
| "breakfast"
|
||||
| "childrenInRoom"
|
||||
| "roomPrice"
|
||||
| "roomName"
|
||||
| "packages"
|
||||
| "isCancelled"
|
||||
> & {
|
||||
guest?: Room["guest"]
|
||||
}
|
||||
|
||||
export interface PriceDetailsTableProps {
|
||||
bookingCode?: string | null
|
||||
fromDate: string
|
||||
bookedRoom: RoomPriceDetails
|
||||
linkedReservationRooms: RoomPriceDetails[]
|
||||
toDate: string
|
||||
totalPrice: Price
|
||||
vat: number
|
||||
}
|
||||
|
||||
export default function PriceDetailsTable({
|
||||
bookingCode,
|
||||
fromDate,
|
||||
bookedRoom,
|
||||
linkedReservationRooms,
|
||||
toDate,
|
||||
totalPrice,
|
||||
vat,
|
||||
}: PriceDetailsTableProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const rooms = [bookedRoom, ...linkedReservationRooms].filter(
|
||||
(room) => !room.isCancelled
|
||||
)
|
||||
|
||||
const diff = dt(toDate).diff(fromDate, "days")
|
||||
const nights = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{totalNights, plural, one {# night} other {# nights}}",
|
||||
},
|
||||
{ totalNights: diff }
|
||||
)
|
||||
const vatPercentage = vat / 100
|
||||
const vatAmount = totalPrice.local.price * vatPercentage
|
||||
|
||||
const priceExclVat = totalPrice.local.price - vatAmount
|
||||
|
||||
const duration = ` ${dt(fromDate).locale(lang).format("ddd, D MMM")}
|
||||
-
|
||||
${dt(toDate).locale(lang).format("ddd, D MMM")} (${nights})`
|
||||
|
||||
return (
|
||||
<table className={styles.priceDetailsTable}>
|
||||
{rooms.map((room, idx) => {
|
||||
const totalAdultsMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"{totalAdults, plural, one {# adult} other {# adults}}",
|
||||
},
|
||||
{
|
||||
totalAdults: room.adults,
|
||||
}
|
||||
)
|
||||
|
||||
const totalChildrenMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"{totalChildren, plural, one {# child} other {# children}}",
|
||||
},
|
||||
{
|
||||
totalChildren: room.childrenInRoom.length,
|
||||
}
|
||||
)
|
||||
|
||||
const guestsCountMsg = [totalAdultsMsg]
|
||||
if (room.childrenInRoom.length) {
|
||||
guestsCountMsg.push(totalChildrenMsg)
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment key={idx}>
|
||||
<TableSection>
|
||||
{rooms.length > 1 && (
|
||||
<tr>
|
||||
<td>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<span>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Room {roomIndex}",
|
||||
},
|
||||
{ roomIndex: idx + 1 }
|
||||
)}
|
||||
</span>
|
||||
</Typography>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
<TableSectionHeader title={room.roomName} subtitle={duration} />
|
||||
<Row
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Average price per night",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.roomPrice.perNight.local.price,
|
||||
room.roomPrice.perNight.local.currency
|
||||
)}
|
||||
/>
|
||||
{room.packages
|
||||
? room.packages.map((feature) => (
|
||||
<Row
|
||||
key={feature.code}
|
||||
label={feature.description}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
+feature.localPrice.totalPrice,
|
||||
feature.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Room charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.roomPrice.perStay.local.price,
|
||||
room.roomPrice.perStay.local.currency
|
||||
)}
|
||||
/>
|
||||
</TableSection>
|
||||
{room.breakfast ? (
|
||||
<TableSection>
|
||||
<Row
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage:
|
||||
"Breakfast ({guestsCount}) x {totalBreakfasts}",
|
||||
},
|
||||
{
|
||||
guestsCount: guestsCountMsg.join(", "),
|
||||
totalBreakfasts: diff,
|
||||
}
|
||||
)}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.breakfast.localPrice.totalPrice,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
<Row
|
||||
bold
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Breakfast charge",
|
||||
})}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
room.breakfast.localPrice.totalPrice,
|
||||
room.breakfast.localPrice.currency
|
||||
)}
|
||||
/>
|
||||
</TableSection>
|
||||
) : null}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
<TableSection>
|
||||
<TableSectionHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Total",
|
||||
})}
|
||||
/>
|
||||
<Row
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Price excluding VAT",
|
||||
})}
|
||||
value={formatPrice(intl, priceExclVat, totalPrice.local.currency)}
|
||||
/>
|
||||
<Row
|
||||
label={intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "VAT {vat}%",
|
||||
},
|
||||
{ vat }
|
||||
)}
|
||||
value={formatPrice(intl, vatAmount, totalPrice.local.currency)}
|
||||
/>
|
||||
<tr className={styles.row}>
|
||||
<td>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Price including VAT",
|
||||
})}
|
||||
</Body>
|
||||
</td>
|
||||
<td className={styles.price}>
|
||||
<Body textTransform="bold">
|
||||
{formatPrice(
|
||||
intl,
|
||||
totalPrice.local.price,
|
||||
totalPrice.local.currency
|
||||
)}
|
||||
</Body>
|
||||
</td>
|
||||
</tr>
|
||||
{totalPrice.local.regularPrice && (
|
||||
<tr className={styles.row}>
|
||||
<td></td>
|
||||
<td className={styles.price}>
|
||||
<Caption color="uiTextMediumContrast" striked={true}>
|
||||
{formatPrice(
|
||||
intl,
|
||||
totalPrice.local.regularPrice,
|
||||
totalPrice.local.currency
|
||||
)}
|
||||
</Caption>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{bookingCode && totalPrice.local.regularPrice && (
|
||||
<tr className={styles.row}>
|
||||
<td>
|
||||
<MaterialIcon icon="sell" />
|
||||
{bookingCode}
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
)}
|
||||
</TableSection>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import { sumPackages } from "@/components/HotelReservation/utils"
|
||||
|
||||
import { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
import type { Price } from "@/types/components/hotelReservation/price"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
@@ -12,7 +10,7 @@ export function mapToPrice(room: Room) {
|
||||
case PriceTypeEnum.cheque:
|
||||
return {
|
||||
corporateCheque: {
|
||||
additionalPricePerStay: room.roomPrice.perStay.local.price,
|
||||
additionalPricePerStay: room.totalPrice,
|
||||
currency: room.roomPrice.perStay.local.currency,
|
||||
numberOfCheques: room.cheques,
|
||||
},
|
||||
@@ -21,8 +19,8 @@ export function mapToPrice(room: Room) {
|
||||
return {
|
||||
regular: {
|
||||
currency: room.currencyCode,
|
||||
pricePerNight: room.roomPrice.perNight,
|
||||
pricePerStay: room.roomPrice.perStay,
|
||||
pricePerNight: room.roomPrice.perNight.local.price,
|
||||
pricePerStay: room.totalPrice,
|
||||
},
|
||||
}
|
||||
case PriceTypeEnum.points:
|
||||
@@ -31,8 +29,8 @@ export function mapToPrice(room: Room) {
|
||||
.diff(dt(room.checkInDate).startOf("day"), "days")
|
||||
return {
|
||||
redemption: {
|
||||
additionalPricePerStay: room.roomPrice.perStay.local.price,
|
||||
currency: room.roomPrice.perStay.local.currency,
|
||||
additionalPricePerStay: room.totalPrice,
|
||||
currency: room.currencyCode,
|
||||
pointsPerNight: room.roomPoints / nights,
|
||||
pointsPerStay: room.roomPoints,
|
||||
},
|
||||
@@ -51,11 +49,6 @@ export function mapToPrice(room: Room) {
|
||||
export function calculateTotalPrice(rooms: Room[], currency: CurrencyEnum) {
|
||||
return rooms.reduce<Price>(
|
||||
(total, room) => {
|
||||
const pkgsSum = sumPackages(room.packages)
|
||||
let breakfastPrice = 0
|
||||
if (room.breakfast && !room.rateDefinition.breakfastIncluded) {
|
||||
breakfastPrice = room.breakfast.localPrice.totalPrice
|
||||
}
|
||||
switch (room.priceType) {
|
||||
case PriceTypeEnum.cheque:
|
||||
{
|
||||
@@ -65,11 +58,7 @@ export function calculateTotalPrice(rooms: Room[], currency: CurrencyEnum) {
|
||||
break
|
||||
case PriceTypeEnum.money:
|
||||
{
|
||||
total.local.price =
|
||||
total.local.price +
|
||||
room.roomPrice.perStay.local.price +
|
||||
pkgsSum.price +
|
||||
breakfastPrice
|
||||
total.local.price = total.local.price + room.totalPrice
|
||||
|
||||
if (!total.local.currency) {
|
||||
total.local.currency = room.currencyCode
|
||||
@@ -93,17 +82,14 @@ export function calculateTotalPrice(rooms: Room[], currency: CurrencyEnum) {
|
||||
case PriceTypeEnum.points:
|
||||
case PriceTypeEnum.voucher:
|
||||
{
|
||||
if (room.roomPrice.perStay.local.price || pkgsSum) {
|
||||
if (room.totalPrice) {
|
||||
total.local.additionalPrice =
|
||||
room.roomPrice.perStay.local.price +
|
||||
pkgsSum.price +
|
||||
breakfastPrice
|
||||
(total.local.additionalPrice || 0) + room.totalPrice
|
||||
}
|
||||
|
||||
if (!total.local.additionalPriceCurrency) {
|
||||
if (room.roomPrice.perStay.local.currency) {
|
||||
total.local.additionalPriceCurrency =
|
||||
room.roomPrice.perStay.local.currency
|
||||
if (room.currencyCode) {
|
||||
total.local.additionalPriceCurrency = room.currencyCode
|
||||
} else {
|
||||
total.local.additionalPriceCurrency = currency
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import Cheques from "./Cheques"
|
||||
import Points from "./Points"
|
||||
import Price from "./Price"
|
||||
|
||||
import { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||
|
||||
interface PriceTypeProps
|
||||
extends Pick<
|
||||
BookingConfirmation["booking"],
|
||||
"cheques" | "rateDefinition" | "roomPoints" | "totalPrice" | "vouchers"
|
||||
> {
|
||||
isCancelled: boolean
|
||||
priceType: PriceTypeEnum
|
||||
}
|
||||
|
||||
export default function PriceType({
|
||||
cheques,
|
||||
isCancelled,
|
||||
priceType,
|
||||
rateDefinition,
|
||||
roomPoints,
|
||||
totalPrice,
|
||||
vouchers,
|
||||
}: PriceTypeProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
switch (priceType) {
|
||||
case PriceTypeEnum.cheque:
|
||||
return <Cheques cheques={cheques} price={isCancelled ? 0 : totalPrice} />
|
||||
case PriceTypeEnum.money:
|
||||
return (
|
||||
<Price
|
||||
isMember={rateDefinition.isMemberRate}
|
||||
price={isCancelled ? 0 : totalPrice}
|
||||
variant="Title/Subtitle/lg"
|
||||
/>
|
||||
)
|
||||
case PriceTypeEnum.points:
|
||||
return <Points points={roomPoints} variant="Title/Subtitle/lg" />
|
||||
case PriceTypeEnum.voucher:
|
||||
return (
|
||||
<Typography variant="Title/Subtitle/lg">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{count} voucher",
|
||||
},
|
||||
{ count: vouchers }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,8 @@ import useLang from "@/hooks/useLang"
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
|
||||
import GuestDetails from "../GuestDetails"
|
||||
import Points from "../Points"
|
||||
import Price from "../Price"
|
||||
import PriceDetails from "../PriceDetails"
|
||||
import PriceType from "../PriceType"
|
||||
import { hasModifiableRate } from "../utils"
|
||||
import ToggleSidePeek from "./ToggleSidePeek"
|
||||
|
||||
@@ -58,16 +57,17 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
|
||||
|
||||
const {
|
||||
adults,
|
||||
bookingCode,
|
||||
breakfast,
|
||||
cheques,
|
||||
childrenAges,
|
||||
confirmationNumber,
|
||||
bookingCode,
|
||||
roomPrice,
|
||||
roomPoints,
|
||||
breakfast,
|
||||
packages,
|
||||
rateDefinition,
|
||||
isCancelled,
|
||||
packages,
|
||||
priceType,
|
||||
rateDefinition,
|
||||
roomPoints,
|
||||
totalPrice,
|
||||
vouchers,
|
||||
} = bookedRoom
|
||||
|
||||
@@ -419,26 +419,15 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
{priceType === "points" ? (
|
||||
<Points points={roomPoints} variant="Title/Subtitle/lg" />
|
||||
) : priceType === "voucher" ? (
|
||||
<Typography variant="Title/Subtitle/lg">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{count} voucher",
|
||||
},
|
||||
{ count: vouchers }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
) : (
|
||||
<Price
|
||||
price={isCancelled ? 0 : roomPrice.perStay.local.price}
|
||||
variant="Title/Subtitle/lg"
|
||||
isMember={rateDefinition.isMemberRate}
|
||||
/>
|
||||
)}
|
||||
<PriceType
|
||||
cheques={cheques}
|
||||
isCancelled={isCancelled}
|
||||
priceType={priceType}
|
||||
rateDefinition={rateDefinition}
|
||||
roomPoints={roomPoints}
|
||||
totalPrice={totalPrice}
|
||||
vouchers={vouchers}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { PriceType } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
import { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
|
||||
export function getPriceType(
|
||||
cheques: number,
|
||||
points: number,
|
||||
vouchers: number
|
||||
): PriceType {
|
||||
if (points > 0) return "points"
|
||||
if (vouchers > 0) return "voucher"
|
||||
if (cheques > 0) return "cheque"
|
||||
return "money"
|
||||
): PriceTypeEnum {
|
||||
if (points > 0) return PriceTypeEnum.points
|
||||
if (vouchers > 0) return PriceTypeEnum.voucher
|
||||
if (cheques > 0) return PriceTypeEnum.cheque
|
||||
return PriceTypeEnum.money
|
||||
}
|
||||
|
||||
@@ -153,6 +153,9 @@ export function mapRoomDetails({
|
||||
requested: undefined,
|
||||
},
|
||||
},
|
||||
totalPriceExVat: booking.totalPriceExVat,
|
||||
totalPrice: booking.totalPrice,
|
||||
vatAmount: booking.vatAmount,
|
||||
breakfast,
|
||||
priceType,
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -43,21 +42,14 @@ export default function CorporateChequePrice({
|
||||
defaultMessage: "Average price per night",
|
||||
})
|
||||
|
||||
const pkgsSum = sumPackages(packages)
|
||||
const roomAdditionalPrice = price.additionalPricePerStay
|
||||
let additionalPricePerStay
|
||||
if (roomAdditionalPrice) {
|
||||
additionalPricePerStay = roomAdditionalPrice + pkgsSum.price
|
||||
} else if (pkgsSum.price) {
|
||||
additionalPricePerStay = pkgsSum.price
|
||||
}
|
||||
const additionalPricePerStay = price.additionalPricePerStay
|
||||
|
||||
const averageChequesPerNight = price.numberOfCheques / nights
|
||||
const averageAdditionalPricePerNight = roomAdditionalPrice
|
||||
? Math.ceil(roomAdditionalPrice / nights)
|
||||
const averageAdditionalPricePerNight = additionalPricePerStay
|
||||
? Math.ceil(additionalPricePerStay / nights)
|
||||
: null
|
||||
|
||||
const additionalCurrency = price.currency ?? pkgsSum.currency
|
||||
const additionalCurrency = price.currency ?? currency
|
||||
let averagePricePerNight = `${averageChequesPerNight} ${CurrencyEnum.CC}`
|
||||
if (averageAdditionalPricePerNight) {
|
||||
averagePricePerNight = `${averagePricePerNight} + ${averageAdditionalPricePerNight} ${additionalCurrency}`
|
||||
|
||||
@@ -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"
|
||||
@@ -43,21 +42,14 @@ export default function RedemptionPrice({
|
||||
const averagePriceTitle = intl.formatMessage({
|
||||
defaultMessage: "Average price per night",
|
||||
})
|
||||
const pkgsSum = sumPackages(packages)
|
||||
|
||||
const roomAdditionalPrice = price.additionalPricePerStay
|
||||
let additionalPricePerStay
|
||||
if (roomAdditionalPrice) {
|
||||
additionalPricePerStay = roomAdditionalPrice + pkgsSum.price
|
||||
} else if (pkgsSum.price) {
|
||||
additionalPricePerStay = pkgsSum.price
|
||||
}
|
||||
const additionalPricePerStay = price.additionalPricePerStay
|
||||
|
||||
const averageAdditionalPricePerNight = roomAdditionalPrice
|
||||
? Math.ceil(roomAdditionalPrice / nights)
|
||||
const averageAdditionalPricePerNight = additionalPricePerStay
|
||||
? Math.ceil(additionalPricePerStay / nights)
|
||||
: null
|
||||
|
||||
const additionalCurrency = price.currency ?? pkgsSum.currency
|
||||
const additionalCurrency = price.currency ?? currency
|
||||
let averagePricePerNight = `${price.pointsPerNight} ${CurrencyEnum.POINTS}`
|
||||
if (averageAdditionalPricePerNight) {
|
||||
averagePricePerNight = `${averagePricePerNight} + ${averageAdditionalPricePerNight} ${additionalCurrency}`
|
||||
|
||||
@@ -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"
|
||||
@@ -45,13 +44,7 @@ export default function RegularPrice({
|
||||
price.currency
|
||||
)
|
||||
|
||||
const pkgs = sumPackages(packages)
|
||||
|
||||
const roomCharge = formatPrice(
|
||||
intl,
|
||||
price.pricePerStay + pkgs.price,
|
||||
price.currency
|
||||
)
|
||||
const roomCharge = formatPrice(intl, price.pricePerStay, price.currency)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -273,7 +273,7 @@ export function getRoomPrice(roomRate: RoomRate, isMember: boolean) {
|
||||
}
|
||||
|
||||
export function getTotalPrice(roomRates: RoomRate[], isMember: boolean) {
|
||||
return roomRates.reduce<Price>(
|
||||
const totalPrice = roomRates.reduce<Price>(
|
||||
(total, roomRate, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
let rate
|
||||
@@ -320,6 +320,52 @@ export function getTotalPrice(roomRates: RoomRate[], isMember: boolean) {
|
||||
requested: undefined,
|
||||
}
|
||||
)
|
||||
|
||||
if (totalPrice.local.regularPrice) {
|
||||
const totalPriceWithRegularPrice = roomRates.reduce(
|
||||
(total, roomRate, idx) => {
|
||||
const isMainRoom = idx === 0
|
||||
let rate
|
||||
if (isMainRoom && isMember && "member" in roomRate && roomRate.member) {
|
||||
rate = roomRate.member
|
||||
} else if ("public" in roomRate && roomRate.public) {
|
||||
rate = roomRate.public
|
||||
}
|
||||
|
||||
if (!rate) {
|
||||
return total
|
||||
}
|
||||
|
||||
if (rate.localPrice.regularPricePerStay) {
|
||||
total.local.regularPrice =
|
||||
total.local.regularPrice + rate.localPrice.regularPricePerStay
|
||||
} else {
|
||||
total.local.regularPrice =
|
||||
total.local.regularPrice + rate.localPrice.pricePerStay
|
||||
}
|
||||
|
||||
return total
|
||||
},
|
||||
{
|
||||
...totalPrice,
|
||||
local: {
|
||||
...totalPrice.local,
|
||||
regularPrice: 0,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (
|
||||
totalPriceWithRegularPrice.local.price ===
|
||||
totalPriceWithRegularPrice.local.regularPrice
|
||||
) {
|
||||
totalPriceWithRegularPrice.local.regularPrice = 0
|
||||
}
|
||||
|
||||
return totalPriceWithRegularPrice
|
||||
}
|
||||
|
||||
return totalPrice
|
||||
}
|
||||
|
||||
export function calculateVoucherPrice(roomRates: RoomRate[]) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { create } from "zustand"
|
||||
import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
|
||||
import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
|
||||
import type { RoomPrice } from "@/types/components/hotelReservation/enterDetails/details"
|
||||
import type { PriceType } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
import { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
|
||||
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
import type { Packages } from "@/types/requests/packages"
|
||||
@@ -33,6 +33,9 @@ export type Room = Pick<
|
||||
| "currencyCode"
|
||||
| "vatPercentage"
|
||||
| "roomPoints"
|
||||
| "totalPrice"
|
||||
| "totalPriceExVat"
|
||||
| "vatAmount"
|
||||
> & {
|
||||
roomName: string
|
||||
roomNumber: number | null
|
||||
@@ -45,7 +48,7 @@ export type Room = Pick<
|
||||
roomPrice: RoomPrice
|
||||
breakfast: BreakfastPackage | null
|
||||
mainRoom: boolean
|
||||
priceType: PriceType
|
||||
priceType: PriceTypeEnum
|
||||
}
|
||||
|
||||
interface MyStayRoomDetailsState {
|
||||
@@ -118,6 +121,7 @@ export const useMyStayRoomDetailsStore = create<MyStayRoomDetailsState>(
|
||||
vatPercentage: 0,
|
||||
vatAmount: 0,
|
||||
totalPriceExVat: 0,
|
||||
totalPrice: 0,
|
||||
createDateTime: new Date(),
|
||||
canChangeDate: false,
|
||||
multiRoom: false,
|
||||
@@ -136,7 +140,7 @@ export const useMyStayRoomDetailsStore = create<MyStayRoomDetailsState>(
|
||||
breakfast: null,
|
||||
linkedReservations: [],
|
||||
isCancelable: false,
|
||||
priceType: "money",
|
||||
priceType: PriceTypeEnum.money,
|
||||
},
|
||||
linkedReservationRooms: [],
|
||||
actions: {
|
||||
|
||||
Reference in New Issue
Block a user