feat: new booking confirmation page

This commit is contained in:
Simon Emanuelsson
2024-11-28 14:22:31 +01:00
parent 329d762917
commit ed1574838a
66 changed files with 1127 additions and 825 deletions

View File

@@ -1,5 +1,139 @@
import { dt } from "@/lib/dt"
import {
CheckCircleIcon,
ChevronRightSmallIcon,
CrossCircle,
} from "@/components/Icons"
import Image from "@/components/Image"
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 { getLang } from "@/i18n/serverContext"
import styles from "./room.module.css"
export default function Room() {
return <article className={styles.room}></article>
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/room"
export default async function Room({ booking, img, roomName }: RoomProps) {
const intl = await getIntl()
const lang = getLang()
const fromDate = dt(booking.checkInDate).locale(lang)
const toDate = dt(booking.checkOutDate).locale(lang)
return (
<article className={styles.room}>
<header className={styles.header}>
<div>
{/* <Subtitle color="mainGrey60" type="two">
{intl.formatMessage({ id: "Room" })} 1
</Subtitle> */}
<Subtitle color="uiTextHighContrast" type="two">
{`${intl.formatMessage({ id: "Reservation number" })} ${booking.confirmationNumber}`}
</Subtitle>
</div>
<div className={styles.benefits}>
{booking.rateDefinition.isMemberRate ? (
<>
<CheckCircleIcon color="green" height={20} width={20} />
<Caption>
{intl.formatMessage({ id: "Membership benefits applied" })}
</Caption>
</>
) : (
<>
<CrossCircle color="red" height={20} width={20} />
<Caption>
{intl.formatMessage({ id: "No membership benefits applied" })}
</Caption>
</>
)}
</div>
</header>
<div className={styles.booking}>
<Image
alt={img.metaData.altText}
className={styles.img}
focalPoint={{ x: 50, y: 50 }}
height={204}
src={img.imageSizes.medium}
style={{ borderRadius: "var(--Corner-radius-Medium)" }}
title={img.metaData.title}
width={204}
/>
<div className={styles.roomDetails}>
<div className={styles.roomName}>
<Subtitle color="uiTextHighContrast" type="two">
{roomName}
</Subtitle>
<Link color="burgundy" href="" variant="icon">
{intl.formatMessage({ id: "View room details" })}
<ChevronRightSmallIcon color="burgundy" />
</Link>
</div>
<ul className={styles.details}>
<li className={styles.listItem}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Check-in" })}
</Body>
<Body color="uiTextHighContrast">
{`${fromDate.format("ddd, D MMM")} ${intl.formatMessage({ id: "from" })} ${fromDate.format("HH:mm")}`}
</Body>
</li>
<li className={styles.listItem}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Check-out" })}
</Body>
<Body color="uiTextHighContrast">
{`${toDate.format("ddd, D MMM")} ${intl.formatMessage({ id: "from" })} ${toDate.format("HH:mm")}`}
</Body>
</li>
<li className={styles.listItem}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Breakfast" })}
</Body>
<Body color="uiTextHighContrast">N/A</Body>
</li>
<li className={styles.listItem}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Cancellation policy" })}
</Body>
<Body color="uiTextHighContrast">
{booking.rateDefinition.cancellationText}
</Body>
</li>
<li className={styles.listItem}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Rebooking" })}
</Body>
<Body color="uiTextHighContrast">N/A</Body>
</li>
</ul>
<div className={styles.guest}>
<Body color="uiTextPlaceholder">
{intl.formatMessage({ id: "Main guest" })}
</Body>
<Body color="uiTextHighContrast">
{`${booking.guest.firstName} ${booking.guest.lastName}`}
</Body>
{booking.guest.membershipNumber ? (
<Body color="uiTextHighContrast">
{`${intl.formatMessage({ id: "Friend no." })} ${booking.guest.membershipNumber}`}
</Body>
) : null}
{booking.guest.phoneNumber ? (
<Body color="uiTextHighContrast">
{booking.guest.phoneNumber}
</Body>
) : null}
{booking.guest.email ? (
<Body color="uiTextHighContrast">{booking.guest.email}</Body>
) : null}
</div>
</div>
</div>
</article>
)
}

View File

@@ -0,0 +1,96 @@
.room {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
}
.header {
align-items: flex-end;
display: grid;
gap: var(--Spacing-x2);
grid-template-columns: 1fr;
}
.benefits {
align-items: center;
border: 1px solid var(--Base-Border-Subtle);
border-radius: var(--Corner-radius-Medium);
display: flex;
gap: var(--Spacing-x1);
padding: var(--Spacing-x1) var(--Spacing-x-one-and-half);
width: max-content;
}
.booking {
background-color: var(--Base-Background-Primary-Normal);
border-radius: var(--Corner-radius-Large);
display: grid;
gap: var(--Spacing-x2);
padding: var(--Spacing-x2) var(--Spacing-x2) var(--Spacing-x3)
var(--Spacing-x2);
}
.img {
width: 100%;
}
.roomDetails {
display: grid;
gap: var(--Spacing-x2);
}
.roomName {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-half);
grid-column: 1/-1;
}
.details {
display: grid;
gap: var(--Spacing-x-half) var(--Spacing-x3);
list-style: none;
}
.listItem {
display: flex;
justify-content: space-between;
}
.guest {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-half);
}
@media screen and (max-width: 1366px) {
.details {
padding-bottom: var(--Spacing-x1);
}
.details p:nth-of-type(even) {
text-align: right;
}
}
@media screen and (min-width: 1367px) {
.header {
grid-template-columns: 1fr auto;
}
.booking {
gap: var(--Spacing-x3);
grid-template-columns: auto 1fr;
padding: var(--Spacing-x2) var(--Spacing-x3) var(--Spacing-x2)
var(--Spacing-x2);
}
.roomDetails {
grid-template-columns: 1fr 1fr;
}
.guest {
align-items: flex-end;
align-self: flex-end;
}
}

View File

@@ -1,5 +1,30 @@
import { notFound } from "next/navigation"
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
import { getBookedHotelRoom } from "@/utils/getBookedHotelRoom"
import Room from "./Room"
import styles from "./rooms.module.css"
export default function Rooms() {
return <section className={styles.rooms}></section>
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
export default async function Rooms({
confirmationNumber,
}: BookingConfirmationProps) {
const { booking, hotel } = await getBookingConfirmation(confirmationNumber)
const roomAndBed = getBookedHotelRoom(hotel, booking.roomTypeCode ?? "")
if (!roomAndBed) {
return notFound()
}
return (
<section className={styles.rooms}>
<Room
booking={booking}
img={roomAndBed.images[0]}
roomName={roomAndBed.name}
/>
</section>
)
}

View File

@@ -1,6 +1,5 @@
.rooms {
display: flex;
flex-direction: column;
gap: var(--Spacing-x9);
grid-area: booking;
gap: var(--Spacing-x5);
}