fix: improve handling of booking widget params from search params
now we are defensive in parsing the location if parsing fails the not found is now displayed
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
"use client"
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { FormProvider, useForm } from "react-hook-form"
|
||||
@@ -30,6 +31,25 @@ import type {
|
||||
} from "@/types/components/bookingWidget"
|
||||
import type { Location } from "@/types/trpc/routers/hotel/locations"
|
||||
|
||||
function getLocationObj(locations: Location[], destination: string) {
|
||||
try {
|
||||
const location = locations.find((location) => {
|
||||
if (location.type === "hotels") {
|
||||
return location.operaId === destination
|
||||
} else if (location.type === "cities") {
|
||||
return location.name.toLowerCase() === destination.toLowerCase()
|
||||
}
|
||||
})
|
||||
|
||||
if (location) {
|
||||
return location
|
||||
}
|
||||
} catch (_) {
|
||||
// ignore any errors
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default function BookingWidgetClient({
|
||||
locations,
|
||||
type,
|
||||
@@ -37,80 +57,62 @@ export default function BookingWidgetClient({
|
||||
}: BookingWidgetClientProps) {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const bookingWidgetRef = useRef(null)
|
||||
|
||||
useStickyPosition({
|
||||
ref: bookingWidgetRef,
|
||||
name: StickyElementNameEnum.BOOKING_WIDGET,
|
||||
})
|
||||
|
||||
const bookingWidgetSearchData = bookingWidgetSearchParams
|
||||
? convertSearchParamsToObj<BookingWidgetSearchData>(
|
||||
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 parsedFromDate = reqFromDate ? dt(reqFromDate) : undefined
|
||||
const parsedToDate = reqToDate ? dt(reqToDate) : undefined
|
||||
const params = convertSearchParamsToObj<BookingWidgetSearchData>(
|
||||
bookingWidgetSearchParams
|
||||
)
|
||||
|
||||
const now = dt()
|
||||
// if fromDate or toDate is undefined, dt will return value that represents the same as 'now' above.
|
||||
// this is fine as isDateParamValid will catch this and default the values accordingly.
|
||||
let fromDate = dt(params.fromDate)
|
||||
let toDate = dt(params.toDate)
|
||||
|
||||
const isDateParamValid =
|
||||
parsedFromDate &&
|
||||
parsedToDate &&
|
||||
parsedFromDate.isSameOrAfter(now, "day") &&
|
||||
parsedToDate.isAfter(parsedFromDate)
|
||||
fromDate.isValid() &&
|
||||
toDate.isValid() &&
|
||||
fromDate.isSameOrAfter(now, "day") &&
|
||||
toDate.isAfter(fromDate)
|
||||
|
||||
const selectedLocation = bookingWidgetSearchData
|
||||
? getLocationObj(
|
||||
(bookingWidgetSearchData.hotelId ??
|
||||
bookingWidgetSearchData.city) as string
|
||||
)
|
||||
: undefined
|
||||
if (!isDateParamValid) {
|
||||
fromDate = now
|
||||
toDate = now.add(1, "day")
|
||||
}
|
||||
|
||||
const selectedBookingCode = bookingWidgetSearchData
|
||||
? bookingWidgetSearchData.bookingCode
|
||||
: ""
|
||||
let selectedLocation: Location | null = null
|
||||
|
||||
const defaultRoomsData: BookingWidgetSchema["rooms"] =
|
||||
bookingWidgetSearchData?.rooms?.map((room) => ({
|
||||
if (params.hotelId) {
|
||||
selectedLocation = getLocationObj(locations, params.hotelId)
|
||||
} else if (params.city) {
|
||||
selectedLocation = getLocationObj(locations, params.city)
|
||||
}
|
||||
|
||||
const selectedBookingCode = params.bookingCode ?? ""
|
||||
|
||||
const defaultRoomsData: BookingWidgetSchema["rooms"] = params.rooms?.map(
|
||||
(room) => ({
|
||||
adults: room.adults,
|
||||
childrenInRoom: room.childrenInRoom ?? [],
|
||||
})) ?? [
|
||||
{
|
||||
adults: 1,
|
||||
childrenInRoom: [],
|
||||
},
|
||||
]
|
||||
})
|
||||
) ?? [
|
||||
{
|
||||
adults: 1,
|
||||
childrenInRoom: [],
|
||||
},
|
||||
]
|
||||
|
||||
const methods = useForm<BookingWidgetSchema>({
|
||||
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
|
||||
? parsedFromDate.format("YYYY-MM-DD")
|
||||
: now.utc().format("YYYY-MM-DD"),
|
||||
toDate: isDateParamValid
|
||||
? parsedToDate.format("YYYY-MM-DD")
|
||||
: now.utc().add(1, "day").format("YYYY-MM-DD"),
|
||||
fromDate: fromDate.format("YYYY-MM-DD"),
|
||||
toDate: toDate.format("YYYY-MM-DD"),
|
||||
},
|
||||
bookingCode: {
|
||||
value: selectedBookingCode,
|
||||
|
||||
@@ -317,12 +317,21 @@ export const locationsSchema = z.object({
|
||||
},
|
||||
},
|
||||
type: location.type,
|
||||
operaId: location.attributes.operaId ?? "",
|
||||
}
|
||||
})
|
||||
)
|
||||
.transform((data) =>
|
||||
data
|
||||
.filter((node) => !!node)
|
||||
.filter((node) => {
|
||||
if (node.type === "hotels") {
|
||||
if (!node.operaId) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (a.type === b.type) {
|
||||
return a.name.localeCompare(b.name)
|
||||
|
||||
@@ -13,7 +13,7 @@ export const locationHotelSchema = z.object({
|
||||
.optional(),
|
||||
keyWords: z.array(z.string()).optional(),
|
||||
name: z.string().optional().default(""),
|
||||
operaId: z.string().optional(),
|
||||
operaId: z.coerce.string().optional(),
|
||||
}),
|
||||
id: z.string().optional().default(""),
|
||||
relationships: z
|
||||
|
||||
Reference in New Issue
Block a user