Merged in fix/refactor-booking-flow-search-params (pull request #2148)
Fix: refactor booking flow search params * wip: apply codemod and upgrade swc plugin * wip: design-system to react 19, fix issues from async (search)params * Prepare new parse function for booking flow search params * Prepare serialize function for booking flow search params * Improve handling of comma separated arrays * Slightly refactor for readability * Next abstracts URLSearchParams so handle the abstraction instead * Refactor booking widget to use new search params parsing * Rename search param functions * Refactor select-hotel to use new search param parser * Use new search params parser in select-rate and details * Fix hotelId type * Avoid passing down search params into BookingWidget components * More updates to use new types instead of SearchParams<T> * Remove types SelectHotelSearchParams and AlternativeSelectHotelSearchParams * Fix parseBookingWidgetSearchParams return type * Add error handling to booking search param parsers * Fix modifyRateIndex handling in details page * Clean up * Refactor booking widget search param serializing to util function * Move start page booking widget search param parsing to page * Use new search param serializer in HandleErrorCallback * Delete convertSearchParamsToObj & convertObjToSearchParams Approved-by: Michael Zetterberg
This commit is contained in:
@@ -3,19 +3,21 @@ import { notFound } from "next/navigation"
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import StartPage from "@/components/ContentType/StartPage"
|
||||
import { parseBookingWidgetSearchParams } from "@/utils/url"
|
||||
|
||||
import type { BookingWidgetSearchData } from "@/types/components/bookingWidget"
|
||||
import type { PageArgs } from "@/types/params"
|
||||
import type { NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export { generateMetadata } from "@/utils/generateMetadata"
|
||||
|
||||
export default async function StartPagePage(
|
||||
props: PageArgs<{}, BookingWidgetSearchData>
|
||||
props: PageArgs<{}, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
return <StartPage searchParams={searchParams} />
|
||||
const booking = parseBookingWidgetSearchParams(searchParams)
|
||||
|
||||
return <StartPage booking={booking} />
|
||||
}
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import { notFound } from "next/navigation"
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer"
|
||||
import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton"
|
||||
import { MapContainer } from "@/components/MapContainer"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseSelectHotelSearchParams } from "@/utils/url"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { AlternativeHotelsSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectHotelMapPage(
|
||||
props: PageArgs<LangParams, AlternativeHotelsSearchParams>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
|
||||
const booking =
|
||||
convertSearchParamsToObj<AlternativeHotelsSearchParams>(searchParams)
|
||||
const booking = parseSelectHotelSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
return (
|
||||
<div className={styles.main}>
|
||||
|
||||
@@ -13,23 +13,19 @@ import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getHotelSearchDetails } from "@/utils/hotelSearchDetails"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseSelectHotelSearchParams } from "@/utils/url"
|
||||
|
||||
import type {
|
||||
AlternativeHotelsSearchParams,
|
||||
SelectHotelSearchParams,
|
||||
} from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function AlternativeHotelsPage(
|
||||
props: PageArgs<LangParams, AlternativeHotelsSearchParams>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
const params = await props.params
|
||||
|
||||
const booking =
|
||||
convertSearchParamsToObj<AlternativeHotelsSearchParams>(searchParams)
|
||||
const booking = parseSelectHotelSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
const searchDetails = await getHotelSearchDetails(booking, true)
|
||||
|
||||
@@ -42,10 +38,10 @@ export default async function AlternativeHotelsPage(
|
||||
bookingCode,
|
||||
childrenInRoom,
|
||||
city,
|
||||
cityName,
|
||||
hotel: isAlternativeFor,
|
||||
noOfRooms,
|
||||
redemption,
|
||||
selectHotelParams,
|
||||
} = searchDetails
|
||||
|
||||
if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) {
|
||||
@@ -59,16 +55,18 @@ export default async function AlternativeHotelsPage(
|
||||
|
||||
// TODO: This needs to be refactored into its
|
||||
// own functions
|
||||
const hotels = await getHotels(
|
||||
selectHotelParams,
|
||||
const hotels = await getHotels({
|
||||
fromDate: booking.fromDate,
|
||||
toDate: booking.toDate,
|
||||
rooms: booking.rooms,
|
||||
isAlternativeFor,
|
||||
bookingCode,
|
||||
city,
|
||||
!!redemption
|
||||
)
|
||||
redemption: !!redemption,
|
||||
})
|
||||
|
||||
const arrivalDate = new Date(selectHotelParams.fromDate)
|
||||
const departureDate = new Date(selectHotelParams.toDate)
|
||||
const arrivalDate = new Date(booking.fromDate)
|
||||
const departureDate = new Date(booking.toDate)
|
||||
|
||||
const isRedemptionAvailability = redemption
|
||||
? hotels.some(
|
||||
@@ -92,11 +90,11 @@ export default async function AlternativeHotelsPage(
|
||||
adultsInRoom,
|
||||
childrenInRoom,
|
||||
hotels?.length ?? 0,
|
||||
selectHotelParams.hotelId,
|
||||
booking.hotelId,
|
||||
noOfRooms,
|
||||
hotels?.[0]?.hotel.address.country,
|
||||
hotels?.[0]?.hotel.address.city,
|
||||
selectHotelParams.city,
|
||||
cityName,
|
||||
bookingCode,
|
||||
isBookingCodeRateAvailable,
|
||||
redemption,
|
||||
|
||||
@@ -20,15 +20,14 @@ import EnterDetailsTrackingWrapper from "@/components/HotelReservation/EnterDeta
|
||||
import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert"
|
||||
import RoomProvider from "@/providers/Details/RoomProvider"
|
||||
import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseDetailsSearchParams } from "@/utils/url"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function DetailsPage(
|
||||
props: PageArgs<LangParams, SelectRateSearchParams>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
const params = await props.params
|
||||
@@ -37,11 +36,12 @@ export default async function DetailsPage(
|
||||
|
||||
const selectRoomParams = new URLSearchParams(searchParams)
|
||||
|
||||
const { errorCode, ...booking } =
|
||||
convertSearchParamsToObj<SelectRateSearchParams>(searchParams)
|
||||
if ("modifyRateIndex" in booking) {
|
||||
const booking = parseDetailsSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
if (selectRoomParams.has("modifyRateIndex")) {
|
||||
selectRoomParams.delete("modifyRateIndex")
|
||||
delete booking.modifyRateIndex
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import stringify from "json-stable-stringify-without-jsonify"
|
||||
import { notFound } from "next/navigation"
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer"
|
||||
import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton"
|
||||
import { MapContainer } from "@/components/MapContainer"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseSelectHotelSearchParams } from "@/utils/url"
|
||||
|
||||
import styles from "./page.module.css"
|
||||
|
||||
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectHotelMapPage(
|
||||
props: PageArgs<LangParams, SelectHotelSearchParams>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
const suspenseKey = stringify(searchParams)
|
||||
|
||||
const booking =
|
||||
convertSearchParamsToObj<SelectHotelSearchParams>(searchParams)
|
||||
const booking = parseSelectHotelSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
return (
|
||||
<div className={styles.main}>
|
||||
|
||||
@@ -12,19 +12,19 @@ import { getHotels } from "@/components/HotelReservation/SelectHotel/helpers"
|
||||
import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { getHotelSearchDetails } from "@/utils/hotelSearchDetails"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseSelectHotelSearchParams } from "@/utils/url"
|
||||
|
||||
import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function SelectHotelPage(
|
||||
props: PageArgs<LangParams, SelectHotelSearchParams>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
const params = await props.params
|
||||
|
||||
const booking =
|
||||
convertSearchParamsToObj<SelectHotelSearchParams>(searchParams)
|
||||
const booking = parseSelectHotelSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
const searchDetails = await getHotelSearchDetails(booking)
|
||||
|
||||
@@ -35,9 +35,9 @@ export default async function SelectHotelPage(
|
||||
bookingCode,
|
||||
childrenInRoom,
|
||||
city,
|
||||
cityName,
|
||||
noOfRooms,
|
||||
redemption,
|
||||
selectHotelParams,
|
||||
} = searchDetails
|
||||
|
||||
if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) {
|
||||
@@ -49,16 +49,18 @@ export default async function SelectHotelPage(
|
||||
}
|
||||
}
|
||||
|
||||
const hotels = await getHotels(
|
||||
selectHotelParams,
|
||||
null,
|
||||
const hotels = await getHotels({
|
||||
fromDate: booking.fromDate,
|
||||
toDate: booking.toDate,
|
||||
rooms: booking.rooms,
|
||||
isAlternativeFor: null,
|
||||
bookingCode,
|
||||
city,
|
||||
!!redemption
|
||||
)
|
||||
redemption: !!redemption,
|
||||
})
|
||||
|
||||
const arrivalDate = new Date(selectHotelParams.fromDate)
|
||||
const departureDate = new Date(selectHotelParams.toDate)
|
||||
const arrivalDate = new Date(booking.fromDate)
|
||||
const departureDate = new Date(booking.toDate)
|
||||
|
||||
const isRedemptionAvailability = redemption
|
||||
? hotels.some(
|
||||
@@ -82,11 +84,11 @@ export default async function SelectHotelPage(
|
||||
adultsInRoom,
|
||||
childrenInRoom,
|
||||
hotels?.length ?? 0,
|
||||
selectHotelParams.hotelId,
|
||||
booking.hotelId,
|
||||
noOfRooms,
|
||||
hotels?.[0]?.hotel.address.country,
|
||||
hotels?.[0]?.hotel.address.city,
|
||||
selectHotelParams.city,
|
||||
cityName,
|
||||
bookingCode,
|
||||
isBookingCodeRateAvailable,
|
||||
redemption,
|
||||
|
||||
@@ -3,10 +3,9 @@ import { notFound } from "next/navigation"
|
||||
import { combineRegExps, rateTypeRegex, REDEMPTION } from "@/constants/booking"
|
||||
|
||||
import SelectRate from "@/components/HotelReservation/SelectRate"
|
||||
import { convertSearchParamsToObj } from "@/utils/url"
|
||||
import { parseSelectRateSearchParams } from "@/utils/url"
|
||||
|
||||
import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
const singleRoomRateTypes = combineRegExps(
|
||||
[rateTypeRegex.ARB, rateTypeRegex.VOUCHER],
|
||||
@@ -14,11 +13,13 @@ const singleRoomRateTypes = combineRegExps(
|
||||
)
|
||||
|
||||
export default async function SelectRatePage(
|
||||
props: PageArgs<LangParams & { section: string }, SelectRateSearchParams>
|
||||
props: PageArgs<LangParams & { section: string }, NextSearchParams>
|
||||
) {
|
||||
const params = await props.params
|
||||
const searchParams = await props.searchParams
|
||||
const booking = convertSearchParamsToObj<SelectRateSearchParams>(searchParams)
|
||||
const booking = parseSelectRateSearchParams(searchParams)
|
||||
|
||||
if (!booking) return notFound()
|
||||
|
||||
const isMultiRoom = booking.rooms.length > 1
|
||||
const isRedemption = booking.searchType === REDEMPTION
|
||||
|
||||
@@ -2,12 +2,14 @@ import { env } from "@/env/server"
|
||||
import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import { BookingWidget } from "@/components/BookingWidget"
|
||||
import { parseBookingWidgetSearchParams } from "@/utils/url"
|
||||
|
||||
import type { BookingWidgetSearchData } from "@/types/components/bookingWidget"
|
||||
import type { PageArgs } from "@/types/params"
|
||||
import type { NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function BookingWidgetDestinationCityPage(props: PageArgs<{}, BookingWidgetSearchData>) {
|
||||
const searchParams = await props.searchParams;
|
||||
export default async function BookingWidgetDestinationCityPage(
|
||||
props: PageArgs<{}, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") {
|
||||
return null
|
||||
}
|
||||
@@ -20,5 +22,7 @@ export default async function BookingWidgetDestinationCityPage(props: PageArgs<{
|
||||
city: pageData?.city.name ?? "",
|
||||
}
|
||||
|
||||
return <BookingWidget bookingWidgetSearchParams={bookingWidgetSearchParams} />
|
||||
const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams)
|
||||
|
||||
return <BookingWidget booking={booking} />
|
||||
}
|
||||
|
||||
@@ -3,20 +3,18 @@ import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import { BookingWidget } from "@/components/BookingWidget"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
import { parseBookingWidgetSearchParams } from "@/utils/url"
|
||||
|
||||
import type { BookingWidgetSearchData } from "@/types/components/bookingWidget"
|
||||
import type { PageArgs } from "@/types/params"
|
||||
import type { NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function BookingWidgetHotelPage(
|
||||
props: PageArgs<{}, BookingWidgetSearchData & { subpage?: string }>
|
||||
props: PageArgs<{}, NextSearchParams & { subpage?: string }>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") {
|
||||
return null
|
||||
}
|
||||
|
||||
const { bookingCode, subpage } = searchParams
|
||||
|
||||
const hotelPageData = await getHotelPage()
|
||||
const hotelData = await getHotel({
|
||||
hotelId: hotelPageData?.hotel_page_id || "",
|
||||
@@ -24,6 +22,7 @@ export default async function BookingWidgetHotelPage(
|
||||
isCardOnlyPayment: false,
|
||||
})
|
||||
|
||||
const subpage = searchParams.subpage
|
||||
const isMeetingSubpage =
|
||||
subpage && hotelData?.additionalData.meetingRooms.nameInUrl === subpage
|
||||
|
||||
@@ -32,10 +31,12 @@ export default async function BookingWidgetHotelPage(
|
||||
}
|
||||
|
||||
const bookingWidgetSearchParams = {
|
||||
bookingCode: bookingCode ?? "",
|
||||
bookingCode: searchParams.bookingCode ?? "",
|
||||
hotel: hotelData?.hotel.id ?? "",
|
||||
city: hotelData?.hotel.cityName ?? "",
|
||||
}
|
||||
|
||||
return <BookingWidget bookingWidgetSearchParams={bookingWidgetSearchParams} />
|
||||
const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams)
|
||||
|
||||
return <BookingWidget booking={booking} />
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { BookingWidget } from "@/components/BookingWidget"
|
||||
import { parseBookingWidgetSearchParams } from "@/utils/url"
|
||||
|
||||
import type { BookingWidgetSearchData } from "@/types/components/bookingWidget"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function BookingWidgetPage(
|
||||
props: PageArgs<LangParams, BookingWidgetSearchData>
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const searchParams = await props.searchParams
|
||||
|
||||
return <BookingWidget bookingWidgetSearchParams={searchParams} />
|
||||
const booking = parseBookingWidgetSearchParams(searchParams)
|
||||
|
||||
return <BookingWidget booking={booking} />
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { env } from "@/env/server"
|
||||
|
||||
import { BookingWidget } from "@/components/BookingWidget"
|
||||
import { parseBookingWidgetSearchParams } from "@/utils/url"
|
||||
|
||||
import type { BookingWidgetSearchData } from "@/types/components/bookingWidget"
|
||||
import type { LangParams, PageArgs } from "@/types/params"
|
||||
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function BookingWidgetPage(props: PageArgs<LangParams, BookingWidgetSearchData>) {
|
||||
const params = await props.params;
|
||||
const searchParams = await props.searchParams;
|
||||
export default async function BookingWidgetPage(
|
||||
props: PageArgs<LangParams, NextSearchParams>
|
||||
) {
|
||||
const params = await props.params
|
||||
const searchParams = await props.searchParams
|
||||
if (!env.isLangLive(params.lang)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <BookingWidget bookingWidgetSearchParams={searchParams} />
|
||||
const booking = parseBookingWidgetSearchParams(searchParams)
|
||||
|
||||
return <BookingWidget booking={booking} />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user