Files
web/apps/scandic-web/components/HotelReservation/PriceDetailsModal/PriceDetailsTable/index.tsx
Simon.Emanuelsson 85acd3453d Merged in feat/SW-1719-strikethrough-rates (pull request #2266)
Feat/SW-1719 strikethrough rates

* feat(SW-1719): Strikethrough rate if logged in on regular rate cards

* feat(SW-1719): Strikethrough rate if logged in on rate summary

* feat(SW-1719): Strikethrough rate if logged in on mobile rate summary

* feat(SW-1719): Strikethrough rate if logged in on enter details

* feat(SW-1719): Strikethrough rate support for multiple rooms

* feat(SW-1719): booking receipt fixes on confirmation page

* feat(SW-1719): improve initial total price calculation

* feat: harmonize enter details total price to use one and the same function


Approved-by: Michael Zetterberg
2025-06-13 12:01:16 +00:00

228 lines
7.0 KiB
TypeScript

"use client"
import { Fragment } from "react"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { dt } from "@/lib/dt"
import useLang from "@/hooks/useLang"
import BookingCodeRow from "./Row/BookingCode"
import HeaderRow from "./Row/Header"
import LargeRow from "./Row/Large"
import CorporateChequePrice, {
type CorporateChequePriceType,
} from "./Row/Price/CorporateCheque"
import RedemptionPrice, {
type RedemptionPriceType,
} from "./Row/Price/Redemption"
import RegularPrice, { type RegularPriceType } from "./Row/Price/Regular"
import VoucherPrice, { type VoucherPriceType } from "./Row/Price/Voucher"
import VatRow from "./Row/Vat"
import Breakfast from "./Breakfast"
import Tbody from "./Tbody"
import styles from "./priceDetailsTable.module.css"
import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
import type { Price } from "@/types/components/hotelReservation/price"
import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { CurrencyEnum } from "@/types/enums/currency"
import type { Packages } from "@/types/requests/packages"
import type { RateDefinition } from "@/types/trpc/routers/hotel/roomAvailability"
type RoomPrice =
| CorporateChequePriceType
| RegularPriceType
| RedemptionPriceType
| VoucherPriceType
export interface Room {
adults: number
bedType: BedTypeSchema | undefined
breakfast: Omit<BreakfastPackage, "requestedPrice"> | false | undefined | null
breakfastChildren?: Omit<BreakfastPackage, "requestedPrice"> | null
breakfastIncluded: boolean
childrenInRoom: Child[] | undefined
packages: Packages | null
price: RoomPrice
rateDefinition: Pick<RateDefinition, "isMemberRate">
roomType: string
}
export interface PriceDetailsTableProps {
bookingCode?: string
fromDate: string
isCampaignRate?: boolean
rooms: Room[]
toDate: string
totalPrice: Price
vat: number
defaultCurrency: CurrencyEnum
}
export default function PriceDetailsTable({
bookingCode,
fromDate,
isCampaignRate,
rooms,
toDate,
totalPrice,
vat,
defaultCurrency,
}: PriceDetailsTableProps) {
const intl = useIntl()
const lang = useLang()
const nights = dt(toDate).diff(fromDate, "days")
const nightsMsg = intl.formatMessage(
{ defaultMessage: "{totalNights, plural, one {# night} other {# nights}}" },
{ 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} (${nightsMsg})`
const isAllBreakfastIncluded = rooms.every((room) => room.breakfastIncluded)
const allPricesIsDiscounted = rooms.every((room) => {
if (!("regular" in room.price)) {
return false
}
if (room.rateDefinition.isMemberRate) {
return true
}
if (!room.price.regular) {
return false
}
return room.price.regular.pricePerStay > room.price.regular.pricePerStay
})
return (
<table className={styles.priceDetailsTable}>
{rooms.map((room, idx) => {
let currency = ""
let chequePrice: CorporateChequePriceType["corporateCheque"] | undefined
if ("corporateCheque" in room.price && room.price.corporateCheque) {
chequePrice = room.price.corporateCheque
if (room.price.corporateCheque.currency) {
currency = room.price.corporateCheque.currency
}
}
let isMemberRate = false
let price: RegularPriceType["regular"] | undefined
if ("regular" in room.price && room.price.regular) {
price = room.price.regular
currency = room.price.regular.currency
isMemberRate = room.rateDefinition.isMemberRate
}
let redemptionPrice: RedemptionPriceType["redemption"] | undefined
if ("redemption" in room.price && room.price.redemption) {
redemptionPrice = room.price.redemption
if (room.price.redemption.currency) {
currency = room.price.redemption.currency
}
}
let voucherPrice: VoucherPriceType["voucher"] | undefined
if ("voucher" in room.price && room.price.voucher) {
voucherPrice = room.price.voucher
}
if (!currency) {
currency = defaultCurrency
}
if (!price && !voucherPrice && !chequePrice && !redemptionPrice) {
return null
}
return (
<Fragment key={idx}>
<Tbody>
{rooms.length > 1 && (
<tr>
<th colSpan={2}>
<Typography variant="Body/Paragraph/mdBold">
<span>
{intl.formatMessage(
{ defaultMessage: "Room {roomIndex}" },
{ roomIndex: idx + 1 }
)}
</span>
</Typography>
</th>
</tr>
)}
<HeaderRow title={room.roomType} subtitle={duration} />
<RegularPrice
bedType={room.bedType}
packages={room.packages}
isMemberRate={isMemberRate}
nights={nights}
price={price}
/>
<CorporateChequePrice
bedType={room.bedType}
currency={currency}
nights={nights}
packages={room.packages}
price={chequePrice}
/>
<RedemptionPrice
bedType={room.bedType}
currency={currency}
nights={nights}
packages={room.packages}
price={redemptionPrice}
/>
<VoucherPrice
bedType={room.bedType}
currency={currency}
nights={nights}
packages={room.packages}
price={voucherPrice}
/>
</Tbody>
<Breakfast
adults={room.adults}
breakfast={room.breakfast}
breakfastChildren={room.breakfastChildren}
breakfastIncluded={room.breakfastIncluded}
childrenInRoom={room.childrenInRoom}
currency={currency}
nights={nights}
/>
</Fragment>
)
})}
<Tbody>
<HeaderRow title={intl.formatMessage({ defaultMessage: "Total" })} />
<VatRow totalPrice={totalPrice} vat={vat} />
<LargeRow
allPricesIsDiscounted={allPricesIsDiscounted}
label={intl.formatMessage({ defaultMessage: "Price including VAT" })}
price={totalPrice}
/>
<BookingCodeRow
isCampaignRate={isCampaignRate}
isBreakfastIncluded={isAllBreakfastIncluded}
bookingCode={bookingCode}
/>
</Tbody>
</table>
)
}