Merged in feat/sw-2873-move-selecthotel-to-booking-flow (pull request #2727)

feat(SW-2873): Move select-hotel to booking flow

* crude setup of select-hotel in partner-sas

* wip

* Fix linting

* restructure tracking files

* Remove dependency on trpc in tracking hooks

* Move pageview tracking to common

* Fix some lint and import issues

* Add AlternativeHotelsPage

* Add SelectHotelMapPage

* Add AlternativeHotelsMapPage

* remove next dependency in tracking store

* Remove dependency on react in tracking hooks

* move isSameBooking to booking-flow

* Inject searchParamsComparator into tracking store

* Move useTrackHardNavigation to common

* Move useTrackSoftNavigation to common

* Add TrackingSDK to partner-sas

* call serverclient in layout

* Remove unused css

* Update types

* Move HotelPin type

* Fix todos

* Merge branch 'master' into feat/sw-2873-move-selecthotel-to-booking-flow

* Merge branch 'master' into feat/sw-2873-move-selecthotel-to-booking-flow

* Fix component


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2025-09-01 08:37:00 +00:00
parent 93a90bef9d
commit 87402a2092
157 changed files with 2026 additions and 1376 deletions

View File

@@ -0,0 +1,28 @@
import { AlternativeHotelsMapPage as AlternativeHotelsMapPagePrimitive } from "@scandic-hotels/booking-flow/pages/AlternativeHotelsMapPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import type { LangParams, PageArgs } from "@/types/params"
export default async function AlternativeHotelsMapPage(
props: PageArgs<LangParams>
) {
const searchParams = await props.searchParams
const lang = await getLang()
return (
<div>
<AlternativeHotelsMapPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
</div>
)
}

View File

@@ -0,0 +1,26 @@
import { AlternativeHotelsPage as AlternativeHotelsPagePrimitive } from "@scandic-hotels/booking-flow/pages/AlternativeHotelsPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import { type LangParams, type PageArgs } from "@/types/params"
export default async function AlternativeHotelsPage(
props: PageArgs<LangParams>
) {
const searchParams = await props.searchParams
const lang = await getLang()
return (
<AlternativeHotelsPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
)
}

View File

@@ -0,0 +1,24 @@
import { SelectHotelMapPage as SelectHotelMapPagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectHotelMapPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import type { LangParams, PageArgs } from "@/types/params"
export default async function SelectHotelMapPage(props: PageArgs<LangParams>) {
const searchParams = await props.searchParams
const lang = await getLang()
return (
<SelectHotelMapPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
)
}

View File

@@ -1,4 +1,24 @@
export default async function SelectHotelPage() {
// eslint-disable-next-line formatjs/no-literal-string-in-jsx
return <div>select-hotel</div>
import { SelectHotelPage as SelectHotelPagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectHotelPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import type { LangParams, PageArgs } from "@/types/params"
export default async function SelectHotelPage(props: PageArgs<LangParams>) {
const searchParams = await props.searchParams
const lang = await getLang()
return (
<SelectHotelPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
)
}

View File

@@ -4,10 +4,13 @@ import "@scandic-hotels/design-system/normalize.css"
import "@scandic-hotels/design-system/design-system-new-deprecated.css"
import "../../globals.css"
import { BookingFlowContextProvider } from "@scandic-hotels/booking-flow/BookingFlowContextProvider"
import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider"
import { Lang } from "@scandic-hotels/common/constants/language"
import { TrpcProvider } from "@scandic-hotels/trpc/Provider"
import { serverClient } from "@/lib/trpc"
import { getMessages } from "@/i18n"
import ClientIntlProvider from "@/i18n/Provider"
import { setLang } from "@/i18n/serverContext"
@@ -15,6 +18,7 @@ import { setLang } from "@/i18n/serverContext"
import {
trackAccordionItemOpen,
trackBookingSearchClick,
trackGenericEvent,
trackOpenSidePeek,
} from "../utils/tracking"
@@ -43,6 +47,10 @@ export default async function RootLayout(props: RootLayoutProps) {
setLang(lang)
const messages = await getMessages(lang)
// TODO we need this import right now to ensure configureServerClient is called,
// but check where we do this
const _caller = await serverClient()
return (
<html lang="en">
<head>{/* TODO */}</head>
@@ -55,28 +63,36 @@ export default async function RootLayout(props: RootLayoutProps) {
>
{/* TODO handle onError */}
<TrpcProvider>
<BookingFlowTrackingProvider
trackingFunctions={{
trackBookingSearchClick,
trackAccordionItemOpen,
trackOpenSidePeek,
<BookingFlowContextProvider
data={{
// TODO
isLoggedIn: false,
}}
>
<header
style={{
height: 64,
backgroundColor: "dodgerblue",
color: "white",
display: "flex",
alignItems: "center",
justifyContent: "center",
<BookingFlowTrackingProvider
trackingFunctions={{
trackBookingSearchClick,
trackAccordionItemOpen,
trackOpenSidePeek,
trackGenericEvent,
}}
>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<h1>SAS</h1>
</header>
<main>{children}</main>
</BookingFlowTrackingProvider>
<header
style={{
height: 64,
backgroundColor: "dodgerblue",
color: "white",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<h1>SAS</h1>
</header>
<main>{children}</main>
</BookingFlowTrackingProvider>
</BookingFlowContextProvider>
</TrpcProvider>
</ClientIntlProvider>
</div>

View File

@@ -1,8 +1,6 @@
import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget"
import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url"
import { serverClient } from "@/lib/trpc"
import { getLang } from "@/i18n/serverContext"
import type { Lang } from "@scandic-hotels/common/constants/language"
@@ -14,9 +12,6 @@ type SearchParams<S = {}> = {
export default async function Home(props: SearchParams<{ lang: Lang }>) {
const searchParams = await props.searchParams
// TODO we need this import right now to ensure configureServerClient is called,
// but we should ensure it's called in a layout instead.
const _caller = await serverClient()
const lang = await getLang()
const booking = parseBookingWidgetSearchParams(searchParams)

View File

@@ -22,3 +22,7 @@ export function trackOpenSidePeek(input: {
}) {
console.warn("TODO: Implement trackOpenSidePeek", { input })
}
export function trackGenericEvent(data: any) {
console.warn("TODO: Implement trackGenericEvent", { data })
}

View File

@@ -0,0 +1,55 @@
"use client"
import { usePathname } from "next/navigation"
import { useTrackHardNavigation } from "@scandic-hotels/common/tracking/useTrackHardNavigation"
import { useTrackSoftNavigation } from "@scandic-hotels/common/tracking/useTrackSoftNavigation"
import { trpc } from "@scandic-hotels/trpc/client"
import useLang from "@/hooks/useLang"
import type {
TrackingSDKAncillaries,
TrackingSDKHotelInfo,
TrackingSDKPageData,
TrackingSDKPaymentInfo,
} from "@scandic-hotels/common/tracking/types"
export default function TrackingSDK({
pageData,
hotelInfo,
paymentInfo,
ancillaries,
}: {
pageData: TrackingSDKPageData
hotelInfo?: TrackingSDKHotelInfo
paymentInfo?: TrackingSDKPaymentInfo
ancillaries?: TrackingSDKAncillaries
}) {
const lang = useLang()
const pathName = usePathname()
const { data, isError } = trpc.user.userTrackingInfo.useQuery({
lang,
})
const userData = isError ? ({ loginStatus: "Error" } as const) : data
useTrackHardNavigation({
pageData,
hotelInfo,
paymentInfo,
ancillaries,
userData,
pathName,
})
useTrackSoftNavigation({
pageData,
hotelInfo,
paymentInfo,
ancillaries,
userData,
pathName,
})
return null
}

View File

@@ -0,0 +1,17 @@
"use client"
import { useParams } from "next/navigation"
import { Lang } from "@scandic-hotels/common/constants/language"
import { languageSchema } from "@scandic-hotels/common/utils/languages"
/**
* A hook to get the current lang from the URL
*/
export default function useLang() {
const { lang } = useParams<{
lang: Lang
}>()
const parsedLang = languageSchema.safeParse(lang)
return parsedLang.success ? parsedLang.data : Lang.en
}

View File

@@ -0,0 +1,19 @@
import type { Lang } from "@scandic-hotels/common/constants/language"
type NextSearchParams = { [key: string]: string | string[] | undefined }
type SearchParams = {
searchParams: Promise<NextSearchParams>
}
type Params<P = {}> = {
params: Promise<P>
}
export type LangParams = {
lang: Lang
}
export type LayoutArgs<P = undefined> = P extends undefined ? {} : Params<P>
export type PageArgs<P = undefined> = LayoutArgs<P> & SearchParams