feat: booking confirmation page with hardcoded data
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./introSection.module.css"
|
||||
|
||||
import { IntroSectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||
|
||||
export default function IntroSection({ email }: IntroSectionProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<section className={styles.section}>
|
||||
<div>
|
||||
<Title textAlign="center" as="h2">
|
||||
{intl.formatMessage({ id: "Thank you" })}
|
||||
</Title>
|
||||
<Subtitle textAlign="center" textTransform="uppercase">
|
||||
{intl.formatMessage({ id: "We look forward to your visit!" })}
|
||||
</Subtitle>
|
||||
</div>
|
||||
<Body color="burgundy" textAlign="center">
|
||||
{intl.formatMessage({
|
||||
id: "We have sent a detailed confirmation of your booking to your email: ",
|
||||
})}
|
||||
{email}
|
||||
</Body>
|
||||
<div className={styles.buttons}>
|
||||
<Button
|
||||
asChild
|
||||
size="small"
|
||||
theme="base"
|
||||
intent="secondary"
|
||||
className={styles.button}
|
||||
>
|
||||
<Link href="#" color="none">
|
||||
{intl.formatMessage({ id: "Download the Scandic app" })}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
asChild
|
||||
size="small"
|
||||
theme="base"
|
||||
intent="secondary"
|
||||
className={styles.button}
|
||||
>
|
||||
<Link href="#" color="none">
|
||||
{intl.formatMessage({ id: "View your booking" })}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x3);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
max-width: 240px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.buttons {
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { ArrowRightIcon, ScandicLogoIcon } from "@/components/Icons"
|
||||
import Image from "@/components/Image"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./staySection.module.css"
|
||||
|
||||
import { StaySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||
|
||||
export default function StaySection({ hotel, stay }: StaySectionProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
const nightsText =
|
||||
stay.nights > 1
|
||||
? intl.formatMessage({ id: "nights" })
|
||||
: intl.formatMessage({ id: "night" })
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={styles.card}>
|
||||
<Image
|
||||
src={hotel.image}
|
||||
alt=""
|
||||
height={400}
|
||||
width={200}
|
||||
className={styles.image}
|
||||
/>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.hotel}>
|
||||
<ScandicLogoIcon color="red" />
|
||||
<Title as="h5" textTransform="capitalize">
|
||||
{hotel.name}
|
||||
</Title>
|
||||
<Caption color="burgundy" className={styles.caption}>
|
||||
<span>{hotel.address}</span>
|
||||
<span>{hotel.phone}</span>
|
||||
</Caption>
|
||||
</div>
|
||||
<Body className={styles.stay}>
|
||||
<span>{`${stay.nights} ${nightsText}`}</span>
|
||||
<span className={styles.dates}>
|
||||
<span>{stay.start}</span>
|
||||
<ArrowRightIcon height={15} width={15} />
|
||||
<span>{stay.end}</span>
|
||||
</span>
|
||||
</Body>
|
||||
</div>
|
||||
</section>
|
||||
<section className={styles.table}>
|
||||
<div className={styles.breakfast}>
|
||||
<Body color="burgundy">
|
||||
{intl.formatMessage({ id: "Breakfast" })}
|
||||
</Body>
|
||||
<Caption className={styles.caption}>
|
||||
<span>{`${intl.formatMessage({ id: "Weekdays" })} ${hotel.breakfast.start}-${hotel.breakfast.end}`}</span>
|
||||
<span>{`${intl.formatMessage({ id: "Weekends" })} ${hotel.breakfast.start}-${hotel.breakfast.end}`}</span>
|
||||
</Caption>
|
||||
</div>
|
||||
<div className={styles.checkIn}>
|
||||
<Body color="burgundy">{intl.formatMessage({ id: "Check in" })}</Body>
|
||||
<Caption className={styles.caption}>
|
||||
<span>{intl.formatMessage({ id: "From" })}</span>
|
||||
<span>{hotel.checkIn}</span>
|
||||
</Caption>
|
||||
</div>
|
||||
<div className={styles.checkOut}>
|
||||
<Body color="burgundy">
|
||||
{intl.formatMessage({ id: "Check out" })}
|
||||
</Body>
|
||||
<Caption className={styles.caption}>
|
||||
<span>{intl.formatMessage({ id: "At latest" })}</span>
|
||||
<span>{hotel.checkOut}</span>
|
||||
</Caption>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
.card {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
border: 1px solid var(--Base-Border-Subtle);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 100%;
|
||||
width: 105px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: var(--Spacing-x1);
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.hotel,
|
||||
.stay {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.caption {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dates {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
.table {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--Spacing-x2);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
background-color: var(--Base-Surface-Primary-dark-Normal);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.breakfast,
|
||||
.checkIn,
|
||||
.checkOut {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-half);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.card {
|
||||
flex-direction: column;
|
||||
}
|
||||
.image {
|
||||
width: 100%;
|
||||
max-height: 195px;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hotel,
|
||||
.stay {
|
||||
width: 100%;
|
||||
max-width: 230px;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./summarySection.module.css"
|
||||
|
||||
import { SummarySectionProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||
|
||||
export default function SummarySection({ summary }: SummarySectionProps) {
|
||||
const intl = useIntl()
|
||||
const roomType = `${intl.formatMessage({ id: "Type of room" })}: ${summary.roomType}`
|
||||
const bedType = `${intl.formatMessage({ id: "Type of bed" })}: ${summary.bedType}`
|
||||
const breakfast = `${intl.formatMessage({ id: "Breakfast" })}: ${summary.breakfast}`
|
||||
const flexibility = `${intl.formatMessage({ id: "Flexibility" })}: ${summary.flexibility}`
|
||||
|
||||
return (
|
||||
<section className={styles.section}>
|
||||
<Title as="h4" textAlign="center">
|
||||
{intl.formatMessage({ id: "Summary" })}
|
||||
</Title>
|
||||
<Caption className={styles.summary}>
|
||||
<span>{roomType}</span>
|
||||
<span>1648 SEK</span>
|
||||
</Caption>
|
||||
<Caption className={styles.summary}>
|
||||
<span>{bedType}</span>
|
||||
<span>0 SEK</span>
|
||||
</Caption>
|
||||
<Caption className={styles.summary}>
|
||||
<span>{breakfast}</span>
|
||||
<span>198 SEK</span>
|
||||
</Caption>
|
||||
<Caption className={styles.summary}>
|
||||
<span>{flexibility}</span>
|
||||
<span>200 SEK</span>
|
||||
</Caption>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
.section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.summary span {
|
||||
padding: var(--Spacing-x2) var(--Spacing-x0);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { BookingConfirmation } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||
|
||||
export const tempConfirmationData: BookingConfirmation = {
|
||||
email: "lisa.andersson@outlook.com",
|
||||
hotel: {
|
||||
name: "Helsinki Hub",
|
||||
address: "Kaisaniemenkatu 7, Helsinki",
|
||||
location: "Helsinki",
|
||||
phone: "+358 300 870680",
|
||||
image:
|
||||
"https://test3.scandichotels.com/imagevault/publishedmedia/i11isd60bh119s9486b7/downtown-camper-by-scandic-lobby-reception-desk-ch.jpg?w=640",
|
||||
checkIn: "15.00",
|
||||
checkOut: "12.00",
|
||||
breakfast: { start: "06:30", end: "10:00" },
|
||||
},
|
||||
stay: {
|
||||
nights: 1,
|
||||
start: "2024.03.09",
|
||||
end: "2024.03.10",
|
||||
},
|
||||
summary: {
|
||||
roomType: "Standard Room",
|
||||
bedType: "King size",
|
||||
breakfast: "Yes",
|
||||
flexibility: "Yes",
|
||||
},
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export default function Payment({
|
||||
resolver: zodResolver(paymentSchema),
|
||||
})
|
||||
|
||||
const initiateBooking = trpc.booking.booking.create.useMutation({
|
||||
const initiateBooking = trpc.booking.create.useMutation({
|
||||
onSuccess: (result) => {
|
||||
if (result?.confirmationNumber) {
|
||||
setConfirmationNumber(result.confirmationNumber)
|
||||
|
||||
40
components/Icons/Download.tsx
Normal file
40
components/Icons/Download.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function DownloadIcon({
|
||||
className,
|
||||
color,
|
||||
...props
|
||||
}: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="21"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
id="mask0_6955_3250"
|
||||
style={{ maskType: "alpha" }}
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="0"
|
||||
y="0"
|
||||
width="21"
|
||||
height="21"
|
||||
>
|
||||
<rect x="0.5" y="0.000244141" width="20" height="20" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_6955_3250)">
|
||||
<path
|
||||
d="M10.5013 12.9065C10.3971 12.9065 10.2982 12.8874 10.2044 12.8492C10.1107 12.811 10.0256 12.7537 9.94922 12.6773L7.05339 9.78145C6.90061 9.62868 6.82595 9.44812 6.82943 9.23979C6.8329 9.03145 6.90755 8.8509 7.05339 8.69812C7.20616 8.54534 7.38846 8.46722 7.60026 8.46375C7.81207 8.46027 7.99436 8.53493 8.14714 8.6877L9.72005 10.2606V4.32312C9.72005 4.10784 9.79644 3.92381 9.94922 3.77104C10.102 3.61826 10.286 3.54187 10.5013 3.54187C10.7166 3.54187 10.9006 3.61826 11.0534 3.77104C11.2062 3.92381 11.2826 4.10784 11.2826 4.32312V10.2606L12.8555 8.6877C13.0082 8.53493 13.1905 8.46027 13.4023 8.46375C13.6142 8.46722 13.7964 8.54534 13.9492 8.69812C14.0951 8.8509 14.1697 9.03145 14.1732 9.23979C14.1767 9.44812 14.102 9.62868 13.9492 9.78145L11.0534 12.6773C10.977 12.7537 10.8919 12.811 10.7982 12.8492C10.7044 12.8874 10.6055 12.9065 10.5013 12.9065ZM5.60547 16.4585C5.17491 16.4585 4.80686 16.3058 4.5013 16.0002C4.19575 15.6946 4.04297 15.3266 4.04297 14.896V13.2294C4.04297 13.0141 4.11936 12.8301 4.27214 12.6773C4.42491 12.5245 4.60894 12.4481 4.82422 12.4481C5.0395 12.4481 5.22352 12.5245 5.3763 12.6773C5.52908 12.8301 5.60547 13.0141 5.60547 13.2294V14.896H15.3971V13.2294C15.3971 13.0141 15.4735 12.8301 15.6263 12.6773C15.7791 12.5245 15.9631 12.4481 16.1784 12.4481C16.3937 12.4481 16.5777 12.5245 16.7305 12.6773C16.8832 12.8301 16.9596 13.0141 16.9596 13.2294V14.896C16.9596 15.3266 16.8069 15.6946 16.5013 16.0002C16.1957 16.3058 15.8277 16.4585 15.3971 16.4585H5.60547Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
36
components/Icons/Printer.tsx
Normal file
36
components/Icons/Printer.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { iconVariants } from "./variants"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export default function PrinterIcon({ className, color, ...props }: IconProps) {
|
||||
const classNames = iconVariants({ className, color })
|
||||
return (
|
||||
<svg
|
||||
className={classNames}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="21"
|
||||
height="20"
|
||||
viewBox="0 0 21 20"
|
||||
fill="none"
|
||||
{...props}
|
||||
>
|
||||
<mask
|
||||
id="mask0_6955_9062"
|
||||
style={{ maskType: "alpha" }}
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="0"
|
||||
y="0"
|
||||
width="21"
|
||||
height="21"
|
||||
>
|
||||
<rect x="0.5" y="0.000244141" width="20" height="20" fill="#D9D9D9" />
|
||||
</mask>
|
||||
<g mask="url(#mask0_6955_9062)">
|
||||
<path
|
||||
d="M7.20964 17.3127C6.77994 17.3127 6.4121 17.1598 6.10611 16.8538C5.80013 16.5478 5.64714 16.1799 5.64714 15.7502V14.0419H3.98047C3.55077 14.0419 3.18293 13.8889 2.87695 13.5829C2.57096 13.2769 2.41797 12.9091 2.41797 12.4794V9.14608C2.41797 8.47941 2.64887 7.91691 3.11068 7.45858C3.57248 7.00024 4.13325 6.77108 4.79297 6.77108H16.2096C16.8763 6.77108 17.4388 7.00024 17.8971 7.45858C18.3555 7.91691 18.5846 8.47941 18.5846 9.14608V12.4794C18.5846 12.9091 18.4316 13.2769 18.1257 13.5829C17.8197 13.8889 17.4518 14.0419 17.0221 14.0419H15.3555V15.7502C15.3555 16.1799 15.2025 16.5478 14.8965 16.8538C14.5905 17.1598 14.2227 17.3127 13.793 17.3127H7.20964ZM3.98047 12.4794H5.64714V12.4169C5.64714 11.9872 5.80013 11.6194 6.10611 11.3134C6.4121 11.0074 6.77994 10.8544 7.20964 10.8544H13.793C14.2227 10.8544 14.5905 11.0074 14.8965 11.3134C15.2025 11.6194 15.3555 11.9872 15.3555 12.4169V12.4794H17.0221V9.14608C17.0221 8.91587 16.944 8.7229 16.7878 8.56718C16.6316 8.41145 16.438 8.33358 16.207 8.33358H4.79564C4.56469 8.33358 4.37109 8.41145 4.21484 8.56718C4.05859 8.7229 3.98047 8.91587 3.98047 9.14608V12.4794ZM13.793 6.77108V4.31274H7.20964V6.77108H5.64714V4.31274C5.64714 3.88305 5.80013 3.51521 6.10611 3.20922C6.4121 2.90324 6.77994 2.75024 7.20964 2.75024H13.793C14.2227 2.75024 14.5905 2.90324 14.8965 3.20922C15.2025 3.51521 15.3555 3.88305 15.3555 4.31274V6.77108H13.793ZM15.3971 10.344C15.6124 10.344 15.7964 10.2676 15.9492 10.1148C16.102 9.96205 16.1784 9.77802 16.1784 9.56274C16.1784 9.34747 16.102 9.16344 15.9492 9.01066C15.7964 8.85788 15.6124 8.78149 15.3971 8.78149C15.1819 8.78149 14.9978 8.85788 14.8451 9.01066C14.6923 9.16344 14.6159 9.34747 14.6159 9.56274C14.6159 9.77802 14.6923 9.96205 14.8451 10.1148C14.9978 10.2676 15.1819 10.344 15.3971 10.344ZM13.793 15.7502V12.4169H7.20964V15.7502H13.793Z"
|
||||
fill="#4D001B"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -28,6 +28,7 @@ export { default as CrossCircle } from "./CrossCircle"
|
||||
export { default as CulturalIcon } from "./Cultural"
|
||||
export { default as DeleteIcon } from "./Delete"
|
||||
export { default as DoorOpenIcon } from "./DoorOpen"
|
||||
export { default as DownloadIcon } from "./Download"
|
||||
export { default as DresserIcon } from "./Dresser"
|
||||
export { default as EditIcon } from "./Edit"
|
||||
export { default as ElectricBikeIcon } from "./ElectricBike"
|
||||
@@ -76,6 +77,7 @@ export { default as PhoneIcon } from "./Phone"
|
||||
export { default as PlusIcon } from "./Plus"
|
||||
export { default as PlusCircleIcon } from "./PlusCircle"
|
||||
export { default as PriceTagIcon } from "./PriceTag"
|
||||
export { default as PrinterIcon } from "./Printer"
|
||||
export { default as RestaurantIcon } from "./Restaurant"
|
||||
export { default as RoomServiceIcon } from "./RoomService"
|
||||
export { default as SaunaIcon } from "./Sauna"
|
||||
|
||||
Reference in New Issue
Block a user