Refactor booking widget skeleton
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import BookingWidgetSkeleton from "@/components/BookingWidget/BookingWidgetSkeleton"
|
||||
import { BookingWidgetSkeleton } from "@/components/BookingWidget/Client"
|
||||
|
||||
export default function LoadingBookingWidget() {
|
||||
if (env.HIDE_FOR_NEXT_RELEASE) {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { SearchIcon } from "@/components/Icons"
|
||||
|
||||
import { SearchSkeleton } from "../Forms/BookingWidget/FormContent/Search"
|
||||
import { VoucherSkeleton } from "../Forms/BookingWidget/FormContent/Voucher"
|
||||
import { bookingWidgetVariants } from "../Forms/BookingWidget/variants"
|
||||
import SkeletonShimmer from "../SkeletonShimmer"
|
||||
import Button from "../TempDesignSystem/Button"
|
||||
import Caption from "../TempDesignSystem/Text/Caption"
|
||||
|
||||
import formStyles from "../Forms/BookingWidget/form.module.css"
|
||||
import formContentStyles from "../Forms/BookingWidget/FormContent/formContent.module.css"
|
||||
import widgetStyles from "./bookingWidget.module.css"
|
||||
|
||||
export default function BookingWidgetSkeleton() {
|
||||
const intl = useIntl()
|
||||
|
||||
const classNames = bookingWidgetVariants({
|
||||
type: "full",
|
||||
})
|
||||
|
||||
return (
|
||||
<section className={widgetStyles.containerDesktop}>
|
||||
<section className={classNames}>
|
||||
<form className={formStyles.form}>
|
||||
<div className={formContentStyles.input}>
|
||||
<div className={formContentStyles.inputContainer}>
|
||||
<div className={formContentStyles.where}>
|
||||
<SearchSkeleton />
|
||||
</div>
|
||||
<div className={formContentStyles.when}>
|
||||
<Caption color="red" type="bold">
|
||||
{intl.formatMessage(
|
||||
{ id: "booking.nights" },
|
||||
{ totalNights: 0 }
|
||||
)}
|
||||
</Caption>
|
||||
<SkeletonShimmer />
|
||||
</div>
|
||||
<div className={formContentStyles.rooms}>
|
||||
<Caption color="red" type="bold" asChild>
|
||||
<span>{intl.formatMessage({ id: "Guests & Rooms" })}</span>
|
||||
</Caption>
|
||||
<SkeletonShimmer />
|
||||
</div>
|
||||
</div>
|
||||
<div className={formContentStyles.voucherContainer}>
|
||||
<VoucherSkeleton />
|
||||
</div>
|
||||
<div className={formContentStyles.buttonContainer}>
|
||||
<Button
|
||||
className={formContentStyles.button}
|
||||
intent="primary"
|
||||
theme="base"
|
||||
type="submit"
|
||||
disabled
|
||||
>
|
||||
<Caption
|
||||
color="white"
|
||||
type="bold"
|
||||
className={formContentStyles.buttonText}
|
||||
asChild
|
||||
>
|
||||
<span>{intl.formatMessage({ id: "Search" })}</span>
|
||||
</Caption>
|
||||
<span className={formContentStyles.icon}>
|
||||
<SearchIcon color="white" width={28} height={28} />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{/* <section className={styles.containerMobile} data-open={isOpen}>
|
||||
<button
|
||||
className={styles.close}
|
||||
onClick={closeMobileSearch}
|
||||
type="button"
|
||||
>
|
||||
<CloseLargeIcon />
|
||||
</button>
|
||||
<Form locations={locations} type={type} />
|
||||
</section>
|
||||
<div className={styles.backdrop} onClick={closeMobileSearch} />
|
||||
<MobileToggleButton openMobileSearch={openMobileSearch} /> */}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -6,14 +6,18 @@ import { FormProvider, useForm } from "react-hook-form"
|
||||
import { dt } from "@/lib/dt"
|
||||
import { StickyElementNameEnum } from "@/stores/sticky-position"
|
||||
|
||||
import Form from "@/components/Forms/BookingWidget"
|
||||
import Form, {
|
||||
BookingWidgetFormSkeleton,
|
||||
} from "@/components/Forms/BookingWidget"
|
||||
import { bookingWidgetSchema } from "@/components/Forms/BookingWidget/schema"
|
||||
import { CloseLargeIcon } from "@/components/Icons"
|
||||
import useStickyPosition from "@/hooks/useStickyPosition"
|
||||
import { debounce } from "@/utils/debounce"
|
||||
import { getFormattedUrlQueryParams } from "@/utils/url"
|
||||
|
||||
import MobileToggleButton from "./MobileToggleButton"
|
||||
import MobileToggleButton, {
|
||||
MobileToggleButtonSkeleton,
|
||||
} from "./MobileToggleButton"
|
||||
|
||||
import styles from "./bookingWidget.module.css"
|
||||
|
||||
@@ -36,7 +40,6 @@ export default function BookingWidgetClient({
|
||||
name: StickyElementNameEnum.BOOKING_WIDGET,
|
||||
})
|
||||
|
||||
|
||||
const bookingWidgetSearchData: BookingWidgetSearchParams | undefined =
|
||||
searchParams
|
||||
? (getFormattedUrlQueryParams(new URLSearchParams(searchParams), {
|
||||
@@ -79,9 +82,7 @@ export default function BookingWidgetClient({
|
||||
const methods = useForm<BookingWidgetSchema>({
|
||||
defaultValues: {
|
||||
search: selectedLocation?.name ?? "",
|
||||
location: selectedLocation
|
||||
? JSON.stringify(selectedLocation)
|
||||
: undefined,
|
||||
location: selectedLocation ? JSON.stringify(selectedLocation) : undefined,
|
||||
date: {
|
||||
// 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.
|
||||
@@ -147,9 +148,11 @@ export default function BookingWidgetClient({
|
||||
? JSON.parse(sessionStorageSearchData)
|
||||
: undefined
|
||||
|
||||
!(selectedLocation?.name) && initialSelectedLocation?.name &&
|
||||
!selectedLocation?.name &&
|
||||
initialSelectedLocation?.name &&
|
||||
methods.setValue("search", initialSelectedLocation.name)
|
||||
!selectedLocation && sessionStorageSearchData &&
|
||||
!selectedLocation &&
|
||||
sessionStorageSearchData &&
|
||||
methods.setValue("location", encodeURIComponent(sessionStorageSearchData))
|
||||
}, [methods, selectedLocation])
|
||||
|
||||
@@ -173,3 +176,14 @@ export default function BookingWidgetClient({
|
||||
</FormProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export function BookingWidgetSkeleton() {
|
||||
return (
|
||||
<>
|
||||
<section className={styles.containerDesktop}>
|
||||
<BookingWidgetFormSkeleton />
|
||||
</section>
|
||||
<MobileToggleButtonSkeleton />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { dt } from "@/lib/dt"
|
||||
import { StickyElementNameEnum } from "@/stores/sticky-position"
|
||||
|
||||
import { EditIcon, SearchIcon } from "@/components/Icons"
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
@@ -24,7 +25,6 @@ import type { Location } from "@/types/trpc/routers/hotel/locations"
|
||||
export default function MobileToggleButton({
|
||||
openMobileSearch,
|
||||
}: BookingWidgetToggleButtonProps) {
|
||||
const [hasMounted, setHasMounted] = useState(false)
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const d = useWatch({ name: "date" })
|
||||
@@ -46,14 +46,6 @@ export default function MobileToggleButton({
|
||||
const selectedFromDate = dt(d.fromDate).locale(lang).format("D MMM")
|
||||
const selectedToDate = dt(d.toDate).locale(lang).format("D MMM")
|
||||
|
||||
useEffect(() => {
|
||||
setHasMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!hasMounted) {
|
||||
return null
|
||||
}
|
||||
|
||||
const locationAndDateIsSet = parsedLocation && d
|
||||
|
||||
const totalRooms = rooms.length
|
||||
@@ -133,3 +125,33 @@ export default function MobileToggleButton({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function MobileToggleButtonSkeleton() {
|
||||
const intl = useIntl()
|
||||
const bookingWidgetMobileRef = useRef(null)
|
||||
useStickyPosition({
|
||||
ref: bookingWidgetMobileRef,
|
||||
name: StickyElementNameEnum.BOOKING_WIDGET_MOBILE,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.partial} ref={bookingWidgetMobileRef}>
|
||||
<div>
|
||||
<Caption type="bold" color="red">
|
||||
{intl.formatMessage({ id: "Where to" })}
|
||||
</Caption>
|
||||
<SkeletonShimmer height="24px" />
|
||||
</div>
|
||||
<Divider color="baseSurfaceSubtleNormal" variant="vertical" />
|
||||
<div>
|
||||
<Caption type="bold" color="red">
|
||||
{intl.formatMessage({ id: "booking.nights" }, { totalNights: 0 })}
|
||||
</Caption>
|
||||
<SkeletonShimmer height="24px" />
|
||||
</div>
|
||||
<div className={styles.icon}>
|
||||
<SearchIcon color="white" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import { useWatch } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
@@ -9,11 +8,12 @@ import DatePicker from "@/components/DatePicker"
|
||||
import GuestsRoomsPickerForm from "@/components/GuestsRoomsPicker"
|
||||
import GuestsRoomsProvider from "@/components/GuestsRoomsPicker/Provider/GuestsRoomsProvider"
|
||||
import { SearchIcon } from "@/components/Icons"
|
||||
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
|
||||
import Search from "./Search"
|
||||
import Voucher from "./Voucher"
|
||||
import Search, { SearchSkeleton } from "./Search"
|
||||
import Voucher, { VoucherSkeleton } from "./Voucher"
|
||||
|
||||
import styles from "./formContent.module.css"
|
||||
|
||||
@@ -90,3 +90,53 @@ export default function FormContent({
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function BookingWidgetFormContentSkeleton() {
|
||||
const intl = useIntl()
|
||||
|
||||
return (
|
||||
<div className={styles.input}>
|
||||
<div className={styles.inputContainer}>
|
||||
<div className={styles.where}>
|
||||
<SearchSkeleton />
|
||||
</div>
|
||||
<div className={styles.when}>
|
||||
<Caption color="red" type="bold">
|
||||
{intl.formatMessage({ id: "booking.nights" }, { totalNights: 0 })}
|
||||
</Caption>
|
||||
<SkeletonShimmer />
|
||||
</div>
|
||||
<div className={styles.rooms}>
|
||||
<Caption color="red" type="bold" asChild>
|
||||
<span>{intl.formatMessage({ id: "Guests & Rooms" })}</span>
|
||||
</Caption>
|
||||
<SkeletonShimmer />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.voucherContainer}>
|
||||
<VoucherSkeleton />
|
||||
</div>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
intent="primary"
|
||||
theme="base"
|
||||
type="submit"
|
||||
disabled
|
||||
>
|
||||
<Caption
|
||||
color="white"
|
||||
type="bold"
|
||||
className={styles.buttonText}
|
||||
asChild
|
||||
>
|
||||
<span>{intl.formatMessage({ id: "Search" })}</span>
|
||||
</Caption>
|
||||
<span className={styles.icon}>
|
||||
<SearchIcon color="white" width={28} height={28} />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { selectHotel, selectRate } from "@/constants/routes/hotelReservation"
|
||||
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import FormContent from "./FormContent"
|
||||
import FormContent, { BookingWidgetFormContentSkeleton } from "./FormContent"
|
||||
import { bookingWidgetVariants } from "./variants"
|
||||
|
||||
import styles from "./form.module.css"
|
||||
@@ -69,3 +69,17 @@ export default function Form({ locations, type }: BookingWidgetFormProps) {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export function BookingWidgetFormSkeleton() {
|
||||
const classNames = bookingWidgetVariants({
|
||||
type: "full",
|
||||
})
|
||||
|
||||
return (
|
||||
<section className={classNames}>
|
||||
<form className={styles.form}>
|
||||
<BookingWidgetFormContentSkeleton />
|
||||
</form>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user