Merged in feat/sw-1602-preliminary-receipt (pull request #1595)
feat/sw-1602 preliminary receipt * feat(sw-1602): create page for preliminary receipt * Add link to my stay page Approved-by: Pontus Dreij
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
.dl {
|
||||
padding: 0 var(--Spacing-x2);
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dl > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
}
|
||||
|
||||
.dl dt {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
|
||||
.rightColumn {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { getNumberOfNights } from "@/utils/dateFormatting"
|
||||
|
||||
import styles from "./footer.module.css"
|
||||
|
||||
import type { FooterProps } from "@/types/components/hotelReservation/myStay/receipt"
|
||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
|
||||
export default async function Footer({ booking, room }: FooterProps) {
|
||||
const intl = await getIntl()
|
||||
const lang = getLang()
|
||||
|
||||
const petRoomPackage = booking.packages.find(
|
||||
(p) => p.code === RoomPackageCodeEnum.PET_ROOM
|
||||
)
|
||||
|
||||
return (
|
||||
<dl className={styles.dl}>
|
||||
<div>
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Reference number" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{booking.confirmationNumber}</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Room" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{room?.name}</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Rate" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{booking.rateDefinition.title}</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Check-in" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{dt(booking.checkInDate).locale(lang).format("ddd, D MMM YYYY")}
|
||||
</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Check-out" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{dt(booking.checkOutDate).locale(lang).format("ddd, D MMM YYYY")}
|
||||
</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.rightColumn}>
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Number of nights" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{getNumberOfNights(booking.checkInDate, booking.checkOutDate)}
|
||||
</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Number of guests" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{intl.formatMessage(
|
||||
{ id: "{adults, plural, one {# adult} other {# adults}}" },
|
||||
{ adults: booking.adults }
|
||||
)}
|
||||
{booking.childrenAges.length > 0 && (
|
||||
<>
|
||||
{", "}
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "{children, plural, one {# child} other {# children}}",
|
||||
},
|
||||
{ children: booking.childrenAges.length }
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Bed type" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{room?.bedType.mainBed.description}</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
{petRoomPackage && (
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Room classification" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{intl.formatMessage({ id: "Pet-friendly" })}</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Breakfast" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{booking.rateDefinition.breakfastIncluded
|
||||
? intl.formatMessage({ id: "Included" })
|
||||
: intl.formatMessage({ id: "Not included" })}
|
||||
</dd>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</dl>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./specification.module.css"
|
||||
|
||||
import type { SpecificationProps } from "@/types/components/hotelReservation/myStay/receipt"
|
||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
|
||||
export default async function Specification({
|
||||
ancillaryPackages,
|
||||
booking,
|
||||
currency,
|
||||
}: SpecificationProps) {
|
||||
const intl = await getIntl()
|
||||
|
||||
const breakfastPackages = booking.packages.filter(
|
||||
(p) => p.type === "Breakfast"
|
||||
)
|
||||
const breakfastTotalPriceInMoney = breakfastPackages
|
||||
.filter((p) => p.currency !== "Points")
|
||||
.reduce((acc, curr) => acc + curr.totalPrice, 0)
|
||||
const breakfastTotalPriceInPoints = breakfastPackages
|
||||
.filter((p) => p.currency === "Points")
|
||||
.reduce((acc, curr) => acc + curr.totalPrice, 0)
|
||||
|
||||
const breakfastCount = breakfastPackages.reduce(
|
||||
(acc, curr) => acc + curr.unit,
|
||||
0
|
||||
)
|
||||
|
||||
const breakfastMoneyString =
|
||||
breakfastTotalPriceInMoney > 0
|
||||
? `${breakfastTotalPriceInMoney} ${currency}`
|
||||
: ""
|
||||
const breakfastPointsString =
|
||||
breakfastTotalPriceInPoints > 0
|
||||
? `${breakfastTotalPriceInPoints} ${intl.formatMessage({ id: "Points" })}`
|
||||
: ""
|
||||
const breakfastPlusString =
|
||||
breakfastMoneyString && breakfastPointsString ? " + " : ""
|
||||
|
||||
const petRoomPackage = booking.packages.find(
|
||||
(p) => p.code === RoomPackageCodeEnum.PET_ROOM
|
||||
)
|
||||
|
||||
const roomPriceExclVat =
|
||||
booking.roomPrice - (booking.roomPrice * booking.vatPercentage) / 100
|
||||
const roomPriceVat = booking.roomPrice - roomPriceExclVat
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div>
|
||||
{/****** The room ********/}
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>
|
||||
{intl.formatMessage({ id: "Accommodation" })}
|
||||
{!booking.rateDefinition.mustBeGuaranteed && (
|
||||
<>
|
||||
{" - "}
|
||||
{intl.formatMessage({ id: "Room is prepaid" })}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</Typography>
|
||||
<dl className={styles.dl}>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>{intl.formatMessage({ id: "Price including VAT" })}</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>
|
||||
{!booking.rateDefinition.mustBeGuaranteed &&
|
||||
`(${intl.formatMessage({ id: "PREPAID" })}) `}
|
||||
{`${booking.roomPrice} ${currency}`}
|
||||
</dd>
|
||||
</Typography>
|
||||
|
||||
{petRoomPackage && (
|
||||
<>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>
|
||||
{intl.formatMessage({ id: "Pet room charge including VAT" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{`${petRoomPackage.totalPrice} ${petRoomPackage.currency}`}</dd>
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt className={styles.tertiary}>
|
||||
{intl.formatMessage({ id: "Price excluding VAT" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd
|
||||
className={styles.tertiary}
|
||||
>{`${roomPriceExclVat.toFixed(2)} ${currency}`}</dd>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt className={styles.tertiary}>
|
||||
{intl.formatMessage({ id: "VAT" })} {booking.vatPercentage} %
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd
|
||||
className={styles.tertiary}
|
||||
>{`${roomPriceVat.toFixed(2)} ${currency}`}</dd>
|
||||
</Typography>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
{/****** Ancillaries ********/}
|
||||
{booking.ancillaries.map((ancillary) => (
|
||||
<>
|
||||
<Divider color="subtle" />
|
||||
<div>
|
||||
<div className={styles.quantifyingHeader}>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>
|
||||
{ancillaryPackages?.flatMap((a) =>
|
||||
a.ancillaryContent.filter(
|
||||
(aa) =>
|
||||
aa.id === ancillary.code ||
|
||||
aa.loyaltyCode === ancillary.code
|
||||
)
|
||||
)[0]?.title ?? intl.formatMessage({ id: "Unknown item" })}
|
||||
</span>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>{`x ${ancillary.unit}`}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<dl className={styles.dl}>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>
|
||||
{ancillary.currency !== "Points"
|
||||
? intl.formatMessage({ id: "Price including VAT" })
|
||||
: intl.formatMessage({ id: "Price" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{`${ancillary.totalPrice} ${ancillary.currency}`}</dd>
|
||||
</Typography>
|
||||
</dl>
|
||||
</div>
|
||||
</>
|
||||
))}
|
||||
|
||||
{/****** Breakfast ********/}
|
||||
{breakfastCount > 0 && (
|
||||
<>
|
||||
<Divider color="subtle" />
|
||||
<div>
|
||||
<div className={styles.quantifyingHeader}>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>{intl.formatMessage({ id: "Breakfast" })}</span>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span>{`x ${breakfastCount}`}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<dl className={styles.dl}>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dt>
|
||||
{breakfastTotalPriceInMoney > 0
|
||||
? intl.formatMessage({ id: "Price including VAT" })
|
||||
: intl.formatMessage({ id: "Price" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<dd>{`${breakfastMoneyString}${breakfastPlusString}${breakfastPointsString}`}</dd>
|
||||
</Typography>
|
||||
</dl>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
.container {
|
||||
display: flex;
|
||||
padding: 0 var(--Spacing-x2);
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.tertiary {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
|
||||
.dl {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.dl dd {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.quantifyingHeader {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import styles from "./total.module.css"
|
||||
|
||||
import type { TotalProps } from "@/types/components/hotelReservation/myStay/receipt"
|
||||
|
||||
export default async function Total({ booking, currency }: TotalProps) {
|
||||
const intl = await getIntl()
|
||||
|
||||
const totalPriceInMoney = booking.totalPrice
|
||||
const totalPriceInMoneyExclVat = booking.totalPriceExVat
|
||||
const totalVat = booking.vatAmount
|
||||
const totalPriceInPoints = booking.ancillaries
|
||||
.filter((a) => a.currency === "Points")
|
||||
.reduce((acc, curr) => acc + curr.totalPrice, 0)
|
||||
|
||||
const moneyString =
|
||||
totalPriceInMoney > 0 ? `${totalPriceInMoney} ${currency}` : ""
|
||||
const pointsString =
|
||||
totalPriceInPoints > 0
|
||||
? `${totalPriceInPoints} ${intl.formatMessage({ id: "Points" })}`
|
||||
: ""
|
||||
const plusString = moneyString && pointsString ? " + " : ""
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/****** Total ********/}
|
||||
<div className={styles.totalContainer}>
|
||||
<Typography>
|
||||
<div>
|
||||
<span className={styles.title}>
|
||||
{intl.formatMessage({ id: "Preliminary receipt" })}
|
||||
</span>
|
||||
<span className={styles.titleSubtext}>
|
||||
{intl.formatMessage({
|
||||
id: "Final VAT breakdown will be provided at check-out.",
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</Typography>
|
||||
|
||||
<Divider color="subtle" />
|
||||
<dl className={styles.dl}>
|
||||
<Typography>
|
||||
<dt>{intl.formatMessage({ id: "Total including VAT" })}</dt>
|
||||
</Typography>
|
||||
<Typography>
|
||||
<dd>{`${moneyString}${plusString}${pointsString}`}</dd>
|
||||
</Typography>
|
||||
|
||||
{totalPriceInMoney > 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
<dt className={styles.tertiary}>
|
||||
{intl.formatMessage({ id: "Total excluding VAT" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography>
|
||||
<dd
|
||||
className={styles.tertiary}
|
||||
>{`${totalPriceInMoneyExclVat} ${currency}`}</dd>
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
|
||||
{totalPriceInMoney > 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
<dt className={styles.tertiary}>
|
||||
{intl.formatMessage({ id: "VAT" })}
|
||||
</dt>
|
||||
</Typography>
|
||||
<Typography>
|
||||
<dd className={styles.tertiary}>{`${totalVat} ${currency}`}</dd>
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
.tertiary {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--Text-Tertiary);
|
||||
font-weight: var(--Body-Supporting-text-Font-weight-2);
|
||||
font-size: var(--Body-Supporting-text-Size);
|
||||
margin-right: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.titleSubtext {
|
||||
color: var(--Text-Tertiary);
|
||||
font-size: var(--Body-Supporting-text-Size);
|
||||
}
|
||||
|
||||
.totalContainer {
|
||||
border: 1px solid var(--Border-Divider-Subtle);
|
||||
border-radius: var(--Spacing-x1);
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2) var(--Spacing-x2)
|
||||
var(--Spacing-x2);
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: var(--Spacing-x-one-and-half);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dl {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
gap: var(--Spacing-x-half);
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.dl dd {
|
||||
text-align: right;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import { cookies } from "next/headers"
|
||||
import { notFound } from "next/navigation"
|
||||
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import {
|
||||
getAncillaryPackages,
|
||||
getBookingConfirmation,
|
||||
getProfileSafely,
|
||||
} from "@/lib/trpc/memoizedRequests"
|
||||
import { decrypt } from "@/server/routers/utils/encryption"
|
||||
|
||||
import { ScandicLogoIcon } from "@/components/Icons"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import AdditionalInfoForm from "../../FindMyBooking/AdditionalInfoForm"
|
||||
import accessBooking, {
|
||||
ACCESS_GRANTED,
|
||||
ERROR_BAD_REQUEST,
|
||||
ERROR_UNAUTHORIZED,
|
||||
} from "../accessBooking"
|
||||
import Footer from "./Footer"
|
||||
import Specification from "./Specification"
|
||||
import Total from "./Total"
|
||||
|
||||
import styles from "./receipt.module.css"
|
||||
|
||||
export async function Receipt({ refId }: { refId: string }) {
|
||||
const value = decrypt(refId)
|
||||
if (!value) {
|
||||
return notFound()
|
||||
}
|
||||
const [confirmationNumber, lastName] = value.split(",")
|
||||
const bookingConfirmation = await getBookingConfirmation(confirmationNumber)
|
||||
if (!bookingConfirmation) {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
const { booking, hotel, room } = bookingConfirmation
|
||||
const user = await getProfileSafely()
|
||||
const bv = cookies().get("bv")?.value
|
||||
const intl = await getIntl()
|
||||
|
||||
const access = accessBooking(booking.guest, lastName, user, bv)
|
||||
|
||||
if (access === ACCESS_GRANTED) {
|
||||
const ancillaryPackages = await getAncillaryPackages({
|
||||
fromDate: dt(booking.checkInDate).format("YYYY-MM-DD"),
|
||||
hotelId: hotel.operaId,
|
||||
toDate: dt(booking.checkOutDate).format("YYYY-MM-DD"),
|
||||
})
|
||||
|
||||
const currency =
|
||||
booking.currencyCode !== "Points"
|
||||
? booking.currencyCode
|
||||
: (booking.ancillaries.find((a) => a.currency !== "Points")?.currency ??
|
||||
booking.packages.find((p) => p.currency !== "Points")?.currency)
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div>
|
||||
<ScandicLogoIcon width="89px" height="19px" color="red" />
|
||||
<div className={styles.addresses}>
|
||||
<div>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div>{hotel.name}</div>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div>
|
||||
{`${hotel.address.streetAddress}, ${hotel.address.zipCode} ${hotel.address.city}`}
|
||||
</div>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div className={`${styles.tertiary} ${styles.addressMargin}`}>
|
||||
{hotel.contactInformation.email}
|
||||
</div>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div className={styles.tertiary}>
|
||||
{hotel.contactInformation.phoneNumber}
|
||||
</div>
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={styles.rightColumn}>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div>{`${booking.guest.firstName} ${booking.guest.lastName}`}</div>
|
||||
</Typography>
|
||||
{booking.guest.membershipNumber && (
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div>{`${intl.formatMessage({ id: "Member" })} ${booking.guest.membershipNumber}`}</div>
|
||||
</Typography>
|
||||
)}
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div className={`${styles.tertiary} ${styles.addressMargin}`}>
|
||||
{booking.guest.email}
|
||||
</div>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<div className={styles.tertiary}>
|
||||
{booking.guest.phoneNumber}
|
||||
</div>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Total booking={booking} currency={currency} />
|
||||
<Specification
|
||||
ancillaryPackages={ancillaryPackages}
|
||||
booking={booking}
|
||||
currency={currency}
|
||||
/>
|
||||
|
||||
<hr className={styles.divider} />
|
||||
|
||||
<Footer booking={booking} room={room} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
if (access === ERROR_BAD_REQUEST) {
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div className={styles.form}>
|
||||
<AdditionalInfoForm
|
||||
confirmationNumber={confirmationNumber}
|
||||
lastName={lastName}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
if (access === ERROR_UNAUTHORIZED) {
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div className={styles.logIn}>
|
||||
<Body textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "In order to view your booking, please log in.",
|
||||
})}
|
||||
</Body>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
return notFound()
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
.main {
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
display: flex;
|
||||
padding: var(--Spacing-x5) var(--Spacing-x4);
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x5);
|
||||
}
|
||||
|
||||
.addresses {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.rightColumn {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.addressMargin {
|
||||
margin-top: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.tertiary {
|
||||
color: var(--Text-Tertiary);
|
||||
}
|
||||
|
||||
.divider {
|
||||
color: var(--Border-Divider-Accent);
|
||||
}
|
||||
|
||||
.form {
|
||||
max-width: 640px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: var(--Spacing-x5) 0;
|
||||
}
|
||||
|
||||
.logIn {
|
||||
padding: var(--Spacing-x5) var(--Spacing-x2);
|
||||
}
|
||||
Reference in New Issue
Block a user