Merged in feat/sw-2879-booking-widget-to-booking-flow-package (pull request #2532)
feat(SW-2879): Move BookingWidget to booking-flow package * Fix lockfile * Fix styling * a tiny little booking widget test * Tiny fixes * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Remove unused scripts * lint:fix * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Tiny lint fixes * update test * Update Input in booking-flow * Clean up comments etc * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Setup tracking context for booking-flow * Add missing use client * Fix temp tracking function * Pass booking to booking-widget * Remove comment * Add use client to booking widget tracking provider * Add use client to tracking functions * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Move debug page * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package Approved-by: Bianca Widstam
This commit is contained in:
287
packages/booking-flow/lib/utils/url.ts
Normal file
287
packages/booking-flow/lib/utils/url.ts
Normal file
@@ -0,0 +1,287 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { logger } from "@scandic-hotels/common/logger"
|
||||
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
|
||||
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
|
||||
|
||||
import { type BookingWidgetSearchData } from "../components/BookingWidget"
|
||||
import { type BookingSearchType, bookingSearchTypes } from "../misc/searchType"
|
||||
import { parseSearchParams, serializeSearchParams } from "./searchParams"
|
||||
|
||||
import type { Child } from "@scandic-hotels/trpc/types/child"
|
||||
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
|
||||
|
||||
import type { NextSearchParams } from "../types"
|
||||
|
||||
type PartialRoom = { rooms?: Partial<Room>[] }
|
||||
|
||||
export type SelectHotelParams<T> = Omit<T, "hotel"> & {
|
||||
hotelId: string
|
||||
} & PartialRoom
|
||||
|
||||
export function searchParamsToRecord(searchParams: URLSearchParams) {
|
||||
return Object.fromEntries(searchParams.entries())
|
||||
}
|
||||
|
||||
const keyRenameMap = {
|
||||
room: "rooms",
|
||||
ratecode: "rateCode",
|
||||
counterratecode: "counterRateCode",
|
||||
roomtype: "roomTypeCode",
|
||||
fromdate: "fromDate",
|
||||
todate: "toDate",
|
||||
hotel: "hotelId",
|
||||
child: "childrenInRoom",
|
||||
searchtype: "searchType",
|
||||
}
|
||||
const typeHints = {
|
||||
filters: "COMMA_SEPARATED_ARRAY",
|
||||
packages: "COMMA_SEPARATED_ARRAY",
|
||||
} as const
|
||||
const adultsSchema = z.coerce.number().min(1).max(6).catch(0)
|
||||
const childAgeSchema = z.coerce.number().catch(-1)
|
||||
const childBedSchema = z.coerce.number().catch(-1)
|
||||
const searchTypeSchema = z.enum(bookingSearchTypes).optional().catch(undefined)
|
||||
|
||||
export function parseBookingWidgetSearchParams(
|
||||
searchParams: NextSearchParams
|
||||
): BookingWidgetSearchData {
|
||||
try {
|
||||
const result = parseSearchParams(searchParams, {
|
||||
keyRenameMap,
|
||||
typeHints,
|
||||
schema: z.object({
|
||||
city: z.string().optional(),
|
||||
hotelId: z.string().optional(),
|
||||
fromDate: z.string().optional(),
|
||||
toDate: z.string().optional(),
|
||||
bookingCode: z.string().optional(),
|
||||
searchType: searchTypeSchema,
|
||||
rooms: z
|
||||
.array(
|
||||
z.object({
|
||||
adults: adultsSchema,
|
||||
childrenInRoom: z
|
||||
.array(
|
||||
z.object({
|
||||
bed: childBedSchema,
|
||||
age: childAgeSchema,
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
.default([]),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
logger.error("[URL] Error parsing search params for booking widget:", error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export function parseSelectHotelSearchParams(
|
||||
searchParams: NextSearchParams
|
||||
): SelectHotelBooking | null {
|
||||
try {
|
||||
const result = parseSearchParams(searchParams, {
|
||||
keyRenameMap,
|
||||
typeHints,
|
||||
schema: z.object({
|
||||
city: z.string().optional(),
|
||||
hotelId: z.string().optional(),
|
||||
fromDate: z.string(),
|
||||
toDate: z.string(),
|
||||
bookingCode: z.string().optional(),
|
||||
searchType: searchTypeSchema,
|
||||
rooms: z.array(
|
||||
z.object({
|
||||
adults: adultsSchema,
|
||||
childrenInRoom: z
|
||||
.array(
|
||||
z.object({
|
||||
bed: childBedSchema,
|
||||
age: childAgeSchema,
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
logger.error("[URL] Error parsing search params for select hotel:", error)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function parseSelectRateSearchParams(
|
||||
searchParams: NextSearchParams
|
||||
): SelectRateBooking | null {
|
||||
try {
|
||||
const result = parseSearchParams(searchParams, {
|
||||
keyRenameMap,
|
||||
typeHints,
|
||||
schema: z.object({
|
||||
city: z.string().optional(),
|
||||
hotelId: z.string(),
|
||||
fromDate: z.string(),
|
||||
toDate: z.string(),
|
||||
searchType: searchTypeSchema,
|
||||
bookingCode: z.string().optional(),
|
||||
rooms: z.array(
|
||||
z.object({
|
||||
adults: adultsSchema,
|
||||
bookingCode: z.string().optional(),
|
||||
counterRateCode: z.string().optional(),
|
||||
rateCode: z.string().optional(),
|
||||
roomTypeCode: z.string().optional(),
|
||||
packages: z
|
||||
.array(
|
||||
z.nativeEnum({
|
||||
...BreakfastPackageEnum,
|
||||
...RoomPackageCodeEnum,
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
childrenInRoom: z
|
||||
.array(
|
||||
z.object({
|
||||
bed: childBedSchema,
|
||||
age: childAgeSchema,
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
logger.error("[URL] Error parsing search params for select rate:", error)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function parseDetailsSearchParams(
|
||||
searchParams: NextSearchParams
|
||||
): DetailsBooking | null {
|
||||
const packageEnum = {
|
||||
...BreakfastPackageEnum,
|
||||
...RoomPackageCodeEnum,
|
||||
} as const
|
||||
|
||||
try {
|
||||
const result = parseSearchParams(searchParams, {
|
||||
keyRenameMap,
|
||||
typeHints,
|
||||
schema: z.object({
|
||||
city: z.string().optional(),
|
||||
hotelId: z.string(),
|
||||
fromDate: z.string(),
|
||||
toDate: z.string(),
|
||||
searchType: searchTypeSchema,
|
||||
bookingCode: z.string().optional(),
|
||||
rooms: z.array(
|
||||
z.object({
|
||||
adults: adultsSchema,
|
||||
bookingCode: z.string().optional(),
|
||||
counterRateCode: z.string().optional(),
|
||||
rateCode: z.string(),
|
||||
roomTypeCode: z.string(),
|
||||
packages: z.array(z.nativeEnum(packageEnum)).optional(),
|
||||
childrenInRoom: z
|
||||
.array(
|
||||
z.object({
|
||||
bed: childBedSchema,
|
||||
age: childAgeSchema,
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
logger.error("[URL] Error parsing search params for details:", error)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const reversedKeyRenameMap = Object.fromEntries(
|
||||
Object.entries(keyRenameMap).map(([key, value]) => [value, key])
|
||||
)
|
||||
export function serializeBookingSearchParams(
|
||||
obj:
|
||||
| BookingWidgetSearchData
|
||||
| SelectHotelBooking
|
||||
| SelectRateBooking
|
||||
| DetailsBooking,
|
||||
{ initialSearchParams }: { initialSearchParams?: URLSearchParams } = {}
|
||||
) {
|
||||
return serializeSearchParams(obj, {
|
||||
keyRenameMap: reversedKeyRenameMap,
|
||||
initialSearchParams,
|
||||
typeHints,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO duplicated until full booking flow is migrated to booking-flow package
|
||||
export type DetailsBooking = {
|
||||
hotelId: string
|
||||
fromDate: string
|
||||
toDate: string
|
||||
city?: string
|
||||
bookingCode?: string
|
||||
searchType?: BookingSearchType
|
||||
rooms: {
|
||||
adults: number
|
||||
rateCode: string
|
||||
roomTypeCode: string
|
||||
bookingCode?: string
|
||||
childrenInRoom?: Child[]
|
||||
counterRateCode?: string
|
||||
packages?: PackageEnum[]
|
||||
}[]
|
||||
}
|
||||
export type SelectHotelBooking = {
|
||||
hotelId?: string
|
||||
city?: string
|
||||
fromDate: string
|
||||
toDate: string
|
||||
rooms: {
|
||||
adults: number
|
||||
childrenInRoom?: Child[]
|
||||
}[]
|
||||
bookingCode?: string
|
||||
searchType?: BookingSearchType
|
||||
}
|
||||
export type SelectRateBooking = {
|
||||
bookingCode?: string
|
||||
city?: string
|
||||
fromDate: string
|
||||
hotelId: string
|
||||
rooms: Room[]
|
||||
searchType?: BookingSearchType
|
||||
toDate: string
|
||||
}
|
||||
export interface Room {
|
||||
adults: number
|
||||
childrenInRoom?: Child[]
|
||||
bookingCode?: string | null
|
||||
counterRateCode?: string | null
|
||||
packages?: PackageEnum[] | null
|
||||
rateCode?: string | null
|
||||
roomTypeCode?: string | null
|
||||
}
|
||||
Reference in New Issue
Block a user