feat(SW-240): refactor booking widget
This commit is contained in:
@@ -1,63 +1,8 @@
|
|||||||
.container {
|
.container {
|
||||||
border-top: 1px solid var(--Base-Border-Subtle);
|
border-top: 1px solid var(--Base-Border-Subtle);
|
||||||
|
box-shadow: 0px 16px 24px 0px #00000014;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
max-width: 1432px;
|
|
||||||
padding: var(--Spacing-x2) var(--Spacing-x5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--Spacing-x2);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: 118px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bodyFontSize {
|
|
||||||
font-size: var(--typography-Caption-Bold-Desktop-fontSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
.border {
|
|
||||||
border-right: 1px solid var(--Base-Surface-Subtle-Normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
.where {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 280px;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 46px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.when,
|
|
||||||
.rooms {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 240px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vouchers {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 158px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the styles after mobile UX is ready
|
|
||||||
*/
|
|
||||||
|
|
||||||
@media screen and (max-width: 1367px) {
|
@media screen and (max-width: 1367px) {
|
||||||
.container {
|
.container {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -1,131 +1,11 @@
|
|||||||
"use client"
|
import Form from "../Forms/BookingWidget"
|
||||||
import { zodResolver } from "@hookform/resolvers/zod"
|
|
||||||
import { FormProvider, useForm } from "react-hook-form"
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import { dt } from "@/lib/dt"
|
|
||||||
|
|
||||||
import Button from "../TempDesignSystem/Button"
|
|
||||||
import Body from "../TempDesignSystem/Text/Body"
|
|
||||||
import { bookingWidgetSchema } from "./schema"
|
|
||||||
|
|
||||||
import styles from "./bookingWidget.module.css"
|
import styles from "./bookingWidget.module.css"
|
||||||
|
|
||||||
import { type BookingWidgetSchema } from "@/types/components/bookingWidget"
|
|
||||||
|
|
||||||
export function BookingWidget() {
|
export function BookingWidget() {
|
||||||
const intl = useIntl()
|
|
||||||
|
|
||||||
const methods = useForm<BookingWidgetSchema>({
|
|
||||||
defaultValues: {
|
|
||||||
search: {
|
|
||||||
stayType: "",
|
|
||||||
stayValue: "",
|
|
||||||
},
|
|
||||||
nights: {
|
|
||||||
// UTC is required to handle requests from far away timezones https://scandichotels.atlassian.net/browse/SWAP-6375 & PET-507
|
|
||||||
// This is specifically to handle timezones falling in different dates.
|
|
||||||
fromDate: dt().utc().format("DD/MM/YYYY"),
|
|
||||||
toDate: dt().utc().add(1, "day").format("DD/MM/YYYY"),
|
|
||||||
},
|
|
||||||
bookingCode: "",
|
|
||||||
redemption: false,
|
|
||||||
voucher: false,
|
|
||||||
rooms: [
|
|
||||||
{
|
|
||||||
adults: 1,
|
|
||||||
childs: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
mode: "all",
|
|
||||||
resolver: zodResolver(bookingWidgetSchema),
|
|
||||||
reValidateMode: "onChange",
|
|
||||||
})
|
|
||||||
|
|
||||||
function onSubmit(data: BookingWidgetSchema) {
|
|
||||||
console.log(data)
|
|
||||||
// Parse data and route accordignly to Select hotel or select room-rate page
|
|
||||||
console.log("to be routing")
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="booking-widget" className={styles.container}>
|
<section className={styles.container}>
|
||||||
<form onSubmit={methods.handleSubmit(onSubmit)} className={styles.form}>
|
<Form />
|
||||||
<FormProvider {...methods}>
|
</section>
|
||||||
<div className={styles.input}>
|
|
||||||
<div className={`${styles.where} ${styles.border}`}>
|
|
||||||
<Body
|
|
||||||
color="red"
|
|
||||||
textTransform="bold"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Where to" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
<div className={`${styles.when} ${styles.border}`}>
|
|
||||||
<Body
|
|
||||||
color="red"
|
|
||||||
textTransform="bold"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "When" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
<div className={`${styles.rooms} ${styles.border}`}>
|
|
||||||
<Body
|
|
||||||
color="red"
|
|
||||||
textTransform="bold"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Rooms & Guests" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
<div className={`${styles.vouchers} ${styles.border}`}>
|
|
||||||
<Body
|
|
||||||
color="textMediumContrast"
|
|
||||||
textTransform="bold"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Booking codes and vouchers" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
<div className={styles.options}>
|
|
||||||
<div>
|
|
||||||
<Body
|
|
||||||
color="textMediumContrast"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Use bonus cheque" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Body
|
|
||||||
color="textMediumContrast"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Book reward night" })}
|
|
||||||
</Body>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
size="small"
|
|
||||||
theme="base"
|
|
||||||
intent="primary"
|
|
||||||
className={styles.button}
|
|
||||||
>
|
|
||||||
<Body
|
|
||||||
color="white"
|
|
||||||
textTransform="bold"
|
|
||||||
className={styles.bodyFontSize}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: "Find hotels" })}
|
|
||||||
</Body>
|
|
||||||
</Button>
|
|
||||||
</FormProvider>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Spacing-x2);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
width: 118px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodyFontSize {
|
||||||
|
font-size: var(--typography-Caption-Bold-Desktop-fontSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
.border {
|
||||||
|
border-right: 1px solid var(--Base-Surface-Subtle-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.where {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Spacing-x-quarter);
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.when,
|
||||||
|
.rooms {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vouchers {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 158px;
|
||||||
|
}
|
||||||
90
components/Forms/BookingWidget/FormContent/index.tsx
Normal file
90
components/Forms/BookingWidget/FormContent/index.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
|
|
||||||
|
import styles from "./formContent.module.css"
|
||||||
|
|
||||||
|
export default function FormContent() {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
const where = intl.formatMessage({ id: "Where to" })
|
||||||
|
const when = intl.formatMessage({ id: "When" })
|
||||||
|
const rooms = intl.formatMessage({ id: "Rooms & Guests" })
|
||||||
|
const vouchers = intl.formatMessage({ id: "Booking codes and vouchers" })
|
||||||
|
const bonus = intl.formatMessage({ id: "Use bonus cheque" })
|
||||||
|
const reward = intl.formatMessage({ id: "Book reward night" })
|
||||||
|
const search = intl.formatMessage({ id: "Find hotels" })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.input}>
|
||||||
|
<div className={`${styles.where} ${styles.border}`}>
|
||||||
|
<Body
|
||||||
|
color="red"
|
||||||
|
textTransform="bold"
|
||||||
|
className={styles.bodyFontSize}
|
||||||
|
>
|
||||||
|
{where}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.when} ${styles.border}`}>
|
||||||
|
<Body
|
||||||
|
color="red"
|
||||||
|
textTransform="bold"
|
||||||
|
className={styles.bodyFontSize}
|
||||||
|
>
|
||||||
|
{when}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.rooms} ${styles.border}`}>
|
||||||
|
<Body
|
||||||
|
color="red"
|
||||||
|
textTransform="bold"
|
||||||
|
className={styles.bodyFontSize}
|
||||||
|
>
|
||||||
|
{rooms}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.vouchers} ${styles.border}`}>
|
||||||
|
<Body
|
||||||
|
color="textMediumContrast"
|
||||||
|
textTransform="bold"
|
||||||
|
className={styles.bodyFontSize}
|
||||||
|
>
|
||||||
|
{vouchers}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
<div className={styles.options}>
|
||||||
|
<div>
|
||||||
|
<Body color="textMediumContrast" className={styles.bodyFontSize}>
|
||||||
|
{bonus}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Body color="textMediumContrast" className={styles.bodyFontSize}>
|
||||||
|
{reward}
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
size="small"
|
||||||
|
theme="base"
|
||||||
|
intent="primary"
|
||||||
|
className={styles.button}
|
||||||
|
>
|
||||||
|
<Body
|
||||||
|
color="white"
|
||||||
|
textTransform="bold"
|
||||||
|
className={styles.bodyFontSize}
|
||||||
|
>
|
||||||
|
{search}
|
||||||
|
</Body>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
7
components/Forms/BookingWidget/form.module.css
Normal file
7
components/Forms/BookingWidget/form.module.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1432px;
|
||||||
|
padding: var(--Spacing-x2) var(--Spacing-x5);
|
||||||
|
}
|
||||||
61
components/Forms/BookingWidget/index.tsx
Normal file
61
components/Forms/BookingWidget/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"use client"
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
|
import { FormProvider, useForm } from "react-hook-form"
|
||||||
|
|
||||||
|
import { dt } from "@/lib/dt"
|
||||||
|
|
||||||
|
import FormContent from "./FormContent"
|
||||||
|
import { bookingWidgetSchema } from "./schema"
|
||||||
|
|
||||||
|
import styles from "./form.module.css"
|
||||||
|
|
||||||
|
import { BookingWidgetSchema } from "@/types/components/bookingWidget"
|
||||||
|
|
||||||
|
const formId = "booking-widget"
|
||||||
|
|
||||||
|
export default function Form() {
|
||||||
|
const methods = useForm<BookingWidgetSchema>({
|
||||||
|
defaultValues: {
|
||||||
|
search: {
|
||||||
|
stayType: "",
|
||||||
|
stayValue: "",
|
||||||
|
},
|
||||||
|
nights: {
|
||||||
|
// UTC is required to handle requests from far away timezones https://scandichotels.atlassian.net/browse/SWAP-6375 & PET-507
|
||||||
|
// This is specifically to handle timezones falling in different dates.
|
||||||
|
fromDate: dt().utc().format("DD/MM/YYYY"),
|
||||||
|
toDate: dt().utc().add(1, "day").format("DD/MM/YYYY"),
|
||||||
|
},
|
||||||
|
bookingCode: "",
|
||||||
|
redemption: false,
|
||||||
|
voucher: false,
|
||||||
|
rooms: [
|
||||||
|
{
|
||||||
|
adults: 1,
|
||||||
|
childs: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
mode: "all",
|
||||||
|
resolver: zodResolver(bookingWidgetSchema),
|
||||||
|
reValidateMode: "onChange",
|
||||||
|
})
|
||||||
|
|
||||||
|
function onSubmit(data: BookingWidgetSchema) {
|
||||||
|
console.log(data)
|
||||||
|
// Parse data and route accordignly to Select hotel or select room-rate page
|
||||||
|
console.log("to be routing")
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={methods.handleSubmit(onSubmit)}
|
||||||
|
className={styles.form}
|
||||||
|
id={formId}
|
||||||
|
>
|
||||||
|
<FormProvider {...methods}>
|
||||||
|
<FormContent />
|
||||||
|
</FormProvider>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import { bookingWidgetSchema } from "@/components/BookingWidget/schema"
|
import { bookingWidgetSchema } from "@/components/Forms/BookingWidget/schema"
|
||||||
|
|
||||||
export type BookingWidgetSchema = z.output<typeof bookingWidgetSchema>
|
export type BookingWidgetSchema = z.output<typeof bookingWidgetSchema>
|
||||||
|
|||||||
Reference in New Issue
Block a user