138 lines
3.8 KiB
TypeScript
138 lines
3.8 KiB
TypeScript
"use client"
|
|
|
|
import { usePathname, useRouter } from "next/navigation"
|
|
import { useTransition } from "react"
|
|
import { Form as FormRAC } from "react-aria-components"
|
|
import { useFormContext } from "react-hook-form"
|
|
|
|
import {
|
|
selectHotel,
|
|
selectHotelMap,
|
|
selectRate,
|
|
} from "@scandic-hotels/common/constants/routes/hotelReservation"
|
|
import { trackBookingSearchClick } from "@scandic-hotels/tracking/booking"
|
|
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
|
|
|
|
import { setBookingWidgetState } from "../../../hooks/useBookingWidgetState"
|
|
import useLang from "../../../hooks/useLang"
|
|
import {
|
|
BookingCodeFilterEnum,
|
|
useBookingCodeFilterStore,
|
|
} from "../../../stores/bookingCode-filter"
|
|
import { serializeBookingSearchParams } from "../../../utils/url"
|
|
import FormContent, { BookingWidgetFormContentSkeleton } from "./FormContent"
|
|
import { bookingWidgetVariants } from "./variants"
|
|
|
|
import styles from "./form.module.css"
|
|
|
|
import type { BookingWidgetType } from ".."
|
|
import type { BookingWidgetSchema } from "../Client"
|
|
|
|
const formId = "booking-widget"
|
|
|
|
type BookingWidgetFormProps = {
|
|
type?: BookingWidgetType
|
|
isFloating: boolean
|
|
onClose: () => void
|
|
}
|
|
export default function Form({
|
|
type,
|
|
isFloating,
|
|
onClose,
|
|
}: BookingWidgetFormProps) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
const lang = useLang()
|
|
const [isPending, startTransition] = useTransition()
|
|
const setBookingCodeFilter = useBookingCodeFilterStore(
|
|
(state) => state.setFilter
|
|
)
|
|
|
|
const classNames = bookingWidgetVariants({
|
|
type,
|
|
})
|
|
|
|
const { handleSubmit, setValue, reset } =
|
|
useFormContext<BookingWidgetSchema>()
|
|
|
|
function onSubmit(data: BookingWidgetSchema) {
|
|
trackBookingSearchClick(data.search, data.hotel ? "hotel" : "destination")
|
|
const isMapView = pathname.endsWith("/map")
|
|
const bookingFlowPage = data.hotel
|
|
? selectRate(lang)
|
|
: isMapView
|
|
? selectHotelMap(lang)
|
|
: selectHotel(lang)
|
|
const bookingWidgetParams = serializeBookingSearchParams({
|
|
rooms: data.rooms,
|
|
...data.date,
|
|
...(data.city ? { city: data.city } : {}),
|
|
...(data.hotel ? { hotel: data.hotel } : {}),
|
|
...(data.bookingCode?.value
|
|
? { bookingCode: data.bookingCode.value }
|
|
: {}),
|
|
// Followed current url structure to keep searchtype=redemption param incase of reward night
|
|
...(data.redemption ? { searchType: SEARCH_TYPE_REDEMPTION } : {}),
|
|
})
|
|
setBookingWidgetState({
|
|
fromDate: data.date.fromDate,
|
|
toDate: data.date.toDate,
|
|
rooms: data.rooms,
|
|
})
|
|
onClose()
|
|
startTransition(() => {
|
|
router.push(`${bookingFlowPage}?${bookingWidgetParams.toString()}`)
|
|
})
|
|
|
|
if (data.bookingCode?.value) {
|
|
// Reset the booking code filter if changed by user to "All rates"
|
|
setBookingCodeFilter(BookingCodeFilterEnum.Discounted)
|
|
|
|
if (data.bookingCode.remember) {
|
|
localStorage.setItem("bookingCode", JSON.stringify(data.bookingCode))
|
|
}
|
|
} else {
|
|
setValue("bookingCode.remember", false, {
|
|
shouldDirty: true,
|
|
})
|
|
localStorage.removeItem("bookingCode")
|
|
}
|
|
reset(data)
|
|
}
|
|
|
|
return (
|
|
<section className={classNames}>
|
|
<FormRAC
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
className={styles.form}
|
|
id={formId}
|
|
>
|
|
<FormContent
|
|
formId={formId}
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
isSearching={isPending}
|
|
isFloating={isFloating}
|
|
/>
|
|
</FormRAC>
|
|
</section>
|
|
)
|
|
}
|
|
|
|
export function BookingWidgetFormSkeleton({
|
|
type,
|
|
}: {
|
|
type: BookingWidgetType
|
|
}) {
|
|
const classNames = bookingWidgetVariants({
|
|
type,
|
|
})
|
|
|
|
return (
|
|
<section className={classNames}>
|
|
<form className={styles.form}>
|
|
<BookingWidgetFormContentSkeleton />
|
|
</form>
|
|
</section>
|
|
)
|
|
}
|