feat: new booking confirmation page
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import { ChevronRightSmallIcon, InfoCircleIcon } from "@/components/Icons"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getBookedHotelRoom } from "@/utils/getBookedHotelRoom"
|
||||
|
||||
import styles from "./receipt.module.css"
|
||||
|
||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
|
||||
export default async function Receipt({
|
||||
confirmationNumber,
|
||||
}: BookingConfirmationProps) {
|
||||
const intl = await getIntl()
|
||||
const { booking, hotel } = await getBookingConfirmation(confirmationNumber)
|
||||
const roomAndBed = getBookedHotelRoom(hotel, booking.roomTypeCode ?? "")
|
||||
if (!roomAndBed) {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
const breakfastPkgSelected = booking.packages.find(
|
||||
(pkg) => pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST
|
||||
)
|
||||
const breakfastPkgIncluded = booking.packages.find(
|
||||
(pkg) => pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST
|
||||
)
|
||||
return (
|
||||
<section className={styles.receipt}>
|
||||
<Subtitle type="two">{intl.formatMessage({ id: "Summary" })}</Subtitle>
|
||||
<article className={styles.room}>
|
||||
<header className={styles.roomHeader}>
|
||||
<Body color="uiTextHighContrast">{roomAndBed.name}</Body>
|
||||
{booking.rateDefinition.isMemberRate ? (
|
||||
<div className={styles.memberPrice}>
|
||||
<Body color="uiTextPlaceholder">
|
||||
<s>N/A</s>
|
||||
</Body>
|
||||
<Body color="red">
|
||||
{intl.formatNumber(booking.roomPrice, {
|
||||
currency: booking.currencyCode,
|
||||
style: "currency",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
) : (
|
||||
<Body color="uiTextHighContrast">
|
||||
{intl.formatNumber(booking.roomPrice, {
|
||||
currency: booking.currencyCode,
|
||||
style: "currency",
|
||||
})}
|
||||
</Body>
|
||||
)}
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.adults" },
|
||||
{
|
||||
totalAdults: booking.adults,
|
||||
}
|
||||
)}
|
||||
</Caption>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{booking.rateDefinition.cancellationText}
|
||||
</Caption>
|
||||
<Link
|
||||
color="peach80"
|
||||
href=""
|
||||
size="small"
|
||||
textDecoration="underline"
|
||||
variant="icon"
|
||||
>
|
||||
{intl.formatMessage({ id: "Reservation policy" })}
|
||||
<InfoCircleIcon color="peach80" />
|
||||
</Link>
|
||||
</header>
|
||||
<div className={styles.entry}>
|
||||
<Body color="uiTextHighContrast">
|
||||
{roomAndBed.bedType.description}
|
||||
</Body>
|
||||
<Body color="uiTextHighContrast">
|
||||
{intl.formatNumber(0, {
|
||||
currency: booking.currencyCode,
|
||||
style: "currency",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.entry}>
|
||||
<Body>{intl.formatMessage({ id: "Breakfast buffet" })}</Body>
|
||||
{booking.rateDefinition.breakfastIncluded ?? breakfastPkgIncluded ? (
|
||||
<Body color="red">{intl.formatMessage({ id: "Included" })}</Body>
|
||||
) : null}
|
||||
|
||||
{breakfastPkgSelected ? (
|
||||
<Body color="uiTextHighContrast">
|
||||
{intl.formatNumber(breakfastPkgSelected.totalPrice, {
|
||||
currency: breakfastPkgSelected.currency,
|
||||
style: "currency",
|
||||
})}
|
||||
</Body>
|
||||
) : null}
|
||||
</div>
|
||||
</article>
|
||||
<Divider color="primaryLightSubtle" />
|
||||
<div className={styles.price}>
|
||||
<div className={styles.entry}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Total price" })}
|
||||
</Body>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatNumber(booking.totalPrice, {
|
||||
currency: booking.currencyCode,
|
||||
style: "currency",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.entry}>
|
||||
<Button
|
||||
className={styles.btn}
|
||||
intent="text"
|
||||
size="small"
|
||||
theme="base"
|
||||
variant="icon"
|
||||
wrapping
|
||||
>
|
||||
{intl.formatMessage({ id: "Price details" })}
|
||||
<ChevronRightSmallIcon />
|
||||
</Button>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Approx." })} N/A EUR
|
||||
</Caption>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
.receipt {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
}
|
||||
|
||||
.room {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
}
|
||||
|
||||
.roomHeader {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
.roomHeader :nth-child(n + 3) {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
|
||||
.memberPrice {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.receipt .price button.btn {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.receipt {
|
||||
padding: var(--Spacing-x3);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user