196 lines
5.4 KiB
TypeScript
196 lines
5.4 KiB
TypeScript
"use client"
|
|
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { dt } from "@/lib/dt"
|
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
|
|
|
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 PriceDetailsTableProps } from "@/types/components/hotelReservation/enterDetails/priceDetailsTable"
|
|
import type { DetailsState } 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 function storeSelector(state: DetailsState) {
|
|
return {
|
|
bedType: state.bedType,
|
|
booking: state.booking,
|
|
breakfast: state.breakfast,
|
|
packages: state.packages,
|
|
roomRate: state.roomRate,
|
|
roomPrice: state.roomPrice,
|
|
totalPrice: state.totalPrice,
|
|
vat: state.vat,
|
|
}
|
|
}
|
|
|
|
export default function PriceDetailsTable({
|
|
roomType,
|
|
}: PriceDetailsTableProps) {
|
|
const intl = useIntl()
|
|
const lang = useLang()
|
|
|
|
const { bedType, booking, breakfast, roomPrice, totalPrice, vat } =
|
|
useEnterDetailsStore(storeSelector)
|
|
|
|
// TODO: Update for Multiroom later
|
|
const { adults, childrenInRoom } = booking.rooms[0]
|
|
|
|
const diff = dt(booking.toDate).diff(booking.fromDate, "days")
|
|
const nights = intl.formatMessage(
|
|
{ id: "booking.nights" },
|
|
{ totalNights: diff }
|
|
)
|
|
const vatPercentage = vat / 100
|
|
const vatAmount = totalPrice.local.price * vatPercentage
|
|
|
|
const priceExclVat = totalPrice.local.price - vatAmount
|
|
|
|
const duration = ` ${dt(booking.fromDate).locale(lang).format("ddd, D MMM")}
|
|
-
|
|
${dt(booking.toDate).locale(lang).format("ddd, D MMM")} (${nights})`
|
|
return (
|
|
<table className={styles.priceDetailsTable}>
|
|
<TableSection>
|
|
<TableSectionHeader title={roomType} subtitle={duration} />
|
|
<Row
|
|
label={intl.formatMessage({ id: "Average price per night" })}
|
|
value={formatPrice(
|
|
intl,
|
|
roomPrice.perNight.local.price,
|
|
roomPrice.perNight.local.currency
|
|
)}
|
|
/>
|
|
{bedType ? (
|
|
<Row
|
|
label={bedType.description}
|
|
value={formatPrice(intl, 0, roomPrice.perStay.local.currency)}
|
|
/>
|
|
) : null}
|
|
<Row
|
|
bold
|
|
label={intl.formatMessage({ id: "Room charge" })}
|
|
value={formatPrice(
|
|
intl,
|
|
roomPrice.perStay.local.price,
|
|
roomPrice.perStay.local.currency
|
|
)}
|
|
/>
|
|
</TableSection>
|
|
|
|
{breakfast ? (
|
|
<TableSection>
|
|
<Row
|
|
label={intl.formatMessage(
|
|
{
|
|
id: "Breakfast ({totalAdults, plural, one {# adult} other {# adults}}) x {totalBreakfasts}",
|
|
},
|
|
{ totalAdults: adults, totalBreakfasts: diff }
|
|
)}
|
|
value={formatPrice(
|
|
intl,
|
|
parseInt(breakfast.localPrice.totalPrice),
|
|
breakfast.localPrice.currency
|
|
)}
|
|
/>
|
|
{childrenInRoom?.length ? (
|
|
<Row
|
|
label={intl.formatMessage(
|
|
{
|
|
id: "Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}",
|
|
},
|
|
{ totalChildren: childrenInRoom.length, totalBreakfasts: diff }
|
|
)}
|
|
value={formatPrice(intl, 0, breakfast.localPrice.currency)}
|
|
/>
|
|
) : null}
|
|
<Row
|
|
bold
|
|
label={intl.formatMessage({
|
|
id: "Breakfast charge",
|
|
})}
|
|
value={formatPrice(
|
|
intl,
|
|
parseInt(breakfast.localPrice.totalPrice),
|
|
breakfast.localPrice.currency
|
|
)}
|
|
/>
|
|
</TableSection>
|
|
) : null}
|
|
<TableSection>
|
|
<TableSectionHeader title={intl.formatMessage({ id: "Total" })} />
|
|
<Row
|
|
label={intl.formatMessage({ id: "Price excluding VAT" })}
|
|
value={formatPrice(intl, priceExclVat, totalPrice.local.currency)}
|
|
/>
|
|
<Row
|
|
label={intl.formatMessage({ id: "VAT {vat}%" }, { vat })}
|
|
value={formatPrice(intl, vatAmount, totalPrice.local.currency)}
|
|
/>
|
|
<tr className={styles.row}>
|
|
<td>
|
|
<Body textTransform="bold">
|
|
{intl.formatMessage({ id: "Price including VAT" })}
|
|
</Body>
|
|
</td>
|
|
<td className={styles.price}>
|
|
<Body textTransform="bold">
|
|
{formatPrice(
|
|
intl,
|
|
totalPrice.local.price,
|
|
totalPrice.local.currency
|
|
)}
|
|
</Body>
|
|
</td>
|
|
</tr>
|
|
</TableSection>
|
|
</table>
|
|
)
|
|
}
|