"use client" import { zodResolver } from "@hookform/resolvers/zod" import { useEffect, useRef, useState } from "react" 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 { 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 styles from "./bookingWidget.module.css" import type { BookingWidgetClientProps, BookingWidgetSchema, BookingWidgetSearchParams, } from "@/types/components/bookingWidget" import type { Location } from "@/types/trpc/routers/hotel/locations" export default function BookingWidgetClient({ locations, type, searchParams, }: BookingWidgetClientProps) { const [isOpen, setIsOpen] = useState(false) const bookingWidgetRef = useRef(null) useStickyPosition({ ref: bookingWidgetRef, name: StickyElementNameEnum.BOOKING_WIDGET, }) const bookingWidgetSearchData: BookingWidgetSearchParams | undefined = searchParams ? (getFormattedUrlQueryParams(new URLSearchParams(searchParams), { adults: "number", age: "number", bed: "number", }) as BookingWidgetSearchParams) : undefined const getLocationObj = (destination: string): Location | undefined => { if (destination) { const location: Location | undefined = locations.find((location) => { return ( location.name.toLowerCase() === destination.toLowerCase() || //@ts-ignore (due to operaId not property error) (location.operaId && location.operaId == destination) ) }) return location } return undefined } const reqFromDate = bookingWidgetSearchData?.fromDate?.toString() const reqToDate = bookingWidgetSearchData?.toDate?.toString() const isDateParamValid = reqFromDate && reqToDate && dt(reqFromDate).isAfter(dt().subtract(1, "day")) && dt(reqToDate).isAfter(dt(reqFromDate)) const selectedLocation = bookingWidgetSearchData ? getLocationObj( (bookingWidgetSearchData.city ?? bookingWidgetSearchData.hotel) as string ) : undefined const methods = useForm({ defaultValues: { search: selectedLocation?.name ?? "", 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. fromDate: isDateParamValid ? bookingWidgetSearchData?.fromDate?.toString() : dt().utc().format("YYYY-MM-DD"), toDate: isDateParamValid ? bookingWidgetSearchData?.toDate?.toString() : dt().utc().add(1, "day").format("YYYY-MM-DD"), }, bookingCode: "", redemption: false, voucher: false, rooms: bookingWidgetSearchData?.room ?? [ { adults: 1, child: [], }, ], }, shouldFocusError: false, mode: "all", resolver: zodResolver(bookingWidgetSchema), reValidateMode: "onChange", }) function closeMobileSearch() { setIsOpen(false) document.body.style.overflowY = "visible" } function openMobileSearch() { setIsOpen(true) document.body.style.overflowY = "hidden" } useEffect(() => { const debouncedResizeHandler = debounce(function ([ entry, ]: ResizeObserverEntry[]) { if (entry.contentRect.width > 1366) { closeMobileSearch() } }) const observer = new ResizeObserver(debouncedResizeHandler) observer.observe(document.body) return () => { if (observer) { observer.unobserve(document.body) } } }, []) useEffect(() => { const sessionStorageSearchData = typeof window !== "undefined" ? sessionStorage.getItem("searchData") : undefined const initialSelectedLocation: Location | undefined = sessionStorageSearchData ? JSON.parse(sessionStorageSearchData) : undefined !(selectedLocation?.name) && initialSelectedLocation?.name && methods.setValue("search", initialSelectedLocation.name) !selectedLocation && sessionStorageSearchData && methods.setValue("location", encodeURIComponent(sessionStorageSearchData)) }, [methods, selectedLocation]) return (
) }