Merged in feat/sw-3472-booking-flow-parameterization (pull request #2811)
feat(SW-3272): Add BookingFlowConfig * Add BookingFlowConfig * Rename "provider" to BookingFlowConfig * Change bookingCode to boolean * Fix error Approved-by: Joakim Jäderberg Approved-by: Linus Flood
This commit is contained in:
@@ -7,6 +7,7 @@ import "../../globals.css"
|
|||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
|
|
||||||
|
import { BookingFlowConfig } from "@scandic-hotels/booking-flow/BookingFlowConfig"
|
||||||
import { BookingFlowContextProvider } from "@scandic-hotels/booking-flow/BookingFlowContextProvider"
|
import { BookingFlowContextProvider } from "@scandic-hotels/booking-flow/BookingFlowContextProvider"
|
||||||
import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider"
|
import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider"
|
||||||
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
||||||
@@ -56,6 +57,8 @@ type RootLayoutProps = {
|
|||||||
bookingwidget: React.ReactNode
|
bookingwidget: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bookingFlowConfig = { bookingCodeEnabled: false } as const
|
||||||
|
|
||||||
export default async function RootLayout(props: RootLayoutProps) {
|
export default async function RootLayout(props: RootLayoutProps) {
|
||||||
const params = await props.params
|
const params = await props.params
|
||||||
const lang = params.lang
|
const lang = params.lang
|
||||||
@@ -87,36 +90,38 @@ export default async function RootLayout(props: RootLayoutProps) {
|
|||||||
<NuqsAdapter>
|
<NuqsAdapter>
|
||||||
<TrpcProvider>
|
<TrpcProvider>
|
||||||
<RACRouterProvider>
|
<RACRouterProvider>
|
||||||
<BookingFlowContextProvider
|
<BookingFlowConfig config={bookingFlowConfig}>
|
||||||
data={{
|
<BookingFlowContextProvider
|
||||||
// TODO
|
data={{
|
||||||
isLoggedIn: false,
|
// TODO
|
||||||
}}
|
isLoggedIn: false,
|
||||||
>
|
|
||||||
<BookingFlowTrackingProvider
|
|
||||||
trackingFunctions={{
|
|
||||||
trackBookingSearchClick,
|
|
||||||
trackAccordionItemOpen,
|
|
||||||
trackOpenSidePeek,
|
|
||||||
trackGenericEvent,
|
|
||||||
trackGlaSaveCardAttempt,
|
|
||||||
trackLoginClick,
|
|
||||||
trackPaymentEvent,
|
|
||||||
trackUpdatePaymentMethod,
|
|
||||||
trackBreakfastSelection,
|
|
||||||
trackBedSelection,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SiteWideAlert />
|
<BookingFlowTrackingProvider
|
||||||
<Header />
|
trackingFunctions={{
|
||||||
{props.bookingwidget}
|
trackBookingSearchClick,
|
||||||
<main>{children}</main>
|
trackAccordionItemOpen,
|
||||||
<Footer />
|
trackOpenSidePeek,
|
||||||
<ToastHandler />
|
trackGenericEvent,
|
||||||
<CookieBotConsent />
|
trackGlaSaveCardAttempt,
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
trackLoginClick,
|
||||||
</BookingFlowTrackingProvider>
|
trackPaymentEvent,
|
||||||
</BookingFlowContextProvider>
|
trackUpdatePaymentMethod,
|
||||||
|
trackBreakfastSelection,
|
||||||
|
trackBedSelection,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SiteWideAlert />
|
||||||
|
<Header />
|
||||||
|
{props.bookingwidget}
|
||||||
|
<main>{children}</main>
|
||||||
|
<Footer />
|
||||||
|
<ToastHandler />
|
||||||
|
<CookieBotConsent />
|
||||||
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
</BookingFlowTrackingProvider>
|
||||||
|
</BookingFlowContextProvider>
|
||||||
|
</BookingFlowConfig>
|
||||||
</RACRouterProvider>
|
</RACRouterProvider>
|
||||||
</TrpcProvider>
|
</TrpcProvider>
|
||||||
</NuqsAdapter>
|
</NuqsAdapter>
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
|||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
import { SessionProvider } from "next-auth/react"
|
import { SessionProvider } from "next-auth/react"
|
||||||
|
|
||||||
|
import { BookingFlowConfig } from "@scandic-hotels/booking-flow/BookingFlowConfig"
|
||||||
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
||||||
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
||||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
||||||
|
|
||||||
|
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
|
||||||
import TrpcProvider from "@/lib/trpc/Provider"
|
import TrpcProvider from "@/lib/trpc/Provider"
|
||||||
|
|
||||||
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
|
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
|
||||||
@@ -72,20 +74,22 @@ export default async function RootLayout(
|
|||||||
<NuqsAdapter>
|
<NuqsAdapter>
|
||||||
<TrpcProvider>
|
<TrpcProvider>
|
||||||
<RACRouterProvider>
|
<RACRouterProvider>
|
||||||
<BookingFlowProviders>
|
<BookingFlowConfig config={bookingFlowConfig}>
|
||||||
<RouteChange />
|
<BookingFlowProviders>
|
||||||
<SitewideAlert />
|
<RouteChange />
|
||||||
<Header />
|
<SitewideAlert />
|
||||||
{bookingwidget}
|
<Header />
|
||||||
{children}
|
{bookingwidget}
|
||||||
<Footer />
|
{children}
|
||||||
<ToastHandler />
|
<Footer />
|
||||||
<SessionRefresher />
|
<ToastHandler />
|
||||||
<StorageCleaner />
|
<SessionRefresher />
|
||||||
<CookieBotConsent />
|
<StorageCleaner />
|
||||||
<UserExists />
|
<CookieBotConsent />
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<UserExists />
|
||||||
</BookingFlowProviders>
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
</BookingFlowProviders>
|
||||||
|
</BookingFlowConfig>
|
||||||
</RACRouterProvider>
|
</RACRouterProvider>
|
||||||
</TrpcProvider>
|
</TrpcProvider>
|
||||||
</NuqsAdapter>
|
</NuqsAdapter>
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
|||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
import { SessionProvider } from "next-auth/react"
|
import { SessionProvider } from "next-auth/react"
|
||||||
|
|
||||||
|
import { BookingFlowConfig } from "@scandic-hotels/booking-flow/BookingFlowConfig"
|
||||||
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
||||||
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
||||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
||||||
|
|
||||||
|
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
|
||||||
import TrpcProvider from "@/lib/trpc/Provider"
|
import TrpcProvider from "@/lib/trpc/Provider"
|
||||||
|
|
||||||
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
|
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
|
||||||
@@ -56,13 +58,15 @@ export default async function RootLayout(
|
|||||||
>
|
>
|
||||||
<NuqsAdapter>
|
<NuqsAdapter>
|
||||||
<TrpcProvider>
|
<TrpcProvider>
|
||||||
<RouteChange />
|
<BookingFlowConfig config={bookingFlowConfig}>
|
||||||
{children}
|
<RouteChange />
|
||||||
<ToastHandler />
|
{children}
|
||||||
<SessionRefresher />
|
<ToastHandler />
|
||||||
<StorageCleaner />
|
<SessionRefresher />
|
||||||
<CookieBotConsent />
|
<StorageCleaner />
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<CookieBotConsent />
|
||||||
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
</BookingFlowConfig>
|
||||||
</TrpcProvider>
|
</TrpcProvider>
|
||||||
</NuqsAdapter>
|
</NuqsAdapter>
|
||||||
</ClientIntlProvider>
|
</ClientIntlProvider>
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import "@scandic-hotels/design-system/style.css"
|
|||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
|
||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
|
|
||||||
|
import { BookingFlowConfig } from "@scandic-hotels/booking-flow/BookingFlowConfig"
|
||||||
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
||||||
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
||||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
||||||
|
|
||||||
|
import { bookingFlowConfig } from "@/constants/bookingFlowConfig"
|
||||||
import TrpcProvider from "@/lib/trpc/Provider"
|
import TrpcProvider from "@/lib/trpc/Provider"
|
||||||
|
|
||||||
import TokenRefresher from "@/components/Auth/TokenRefresher"
|
import TokenRefresher from "@/components/Auth/TokenRefresher"
|
||||||
@@ -56,13 +58,15 @@ export default async function RootLayout(
|
|||||||
>
|
>
|
||||||
<NuqsAdapter>
|
<NuqsAdapter>
|
||||||
<TrpcProvider>
|
<TrpcProvider>
|
||||||
<RouteChange />
|
<BookingFlowConfig config={bookingFlowConfig}>
|
||||||
{children}
|
<RouteChange />
|
||||||
<ToastHandler />
|
{children}
|
||||||
<TokenRefresher />
|
<ToastHandler />
|
||||||
<StorageCleaner />
|
<TokenRefresher />
|
||||||
<CookieBotConsent />
|
<StorageCleaner />
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<CookieBotConsent />
|
||||||
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
</BookingFlowConfig>
|
||||||
</TrpcProvider>
|
</TrpcProvider>
|
||||||
</NuqsAdapter>
|
</NuqsAdapter>
|
||||||
</ClientIntlProvider>
|
</ClientIntlProvider>
|
||||||
|
|||||||
1
apps/scandic-web/constants/bookingFlowConfig.ts
Normal file
1
apps/scandic-web/constants/bookingFlowConfig.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const bookingFlowConfig = { bookingCodeEnabled: true } as const
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import "server-only"
|
||||||
|
|
||||||
|
import { cache } from "react"
|
||||||
|
|
||||||
|
import { BookingFlowConfigContextProvider } from "./bookingFlowConfigContext"
|
||||||
|
|
||||||
|
export type BookingFlowConfig = {
|
||||||
|
bookingCodeEnabled: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRef = cache(() => ({
|
||||||
|
current: undefined as BookingFlowConfig | undefined,
|
||||||
|
}))
|
||||||
|
|
||||||
|
function setBookingFlowConfig(newConfig: BookingFlowConfig) {
|
||||||
|
getRef().current = newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBookingFlowConfig(): BookingFlowConfig {
|
||||||
|
const contextConfig = getRef().current
|
||||||
|
|
||||||
|
if (!contextConfig) {
|
||||||
|
throw new Error("BookingFlowConfig not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return contextConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets up both a server side context and a client side context
|
||||||
|
* for the booking flow config.
|
||||||
|
*/
|
||||||
|
export async function BookingFlowConfig({
|
||||||
|
children,
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
config: BookingFlowConfig
|
||||||
|
}) {
|
||||||
|
setBookingFlowConfig(config)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BookingFlowConfigContextProvider config={config}>
|
||||||
|
{children}
|
||||||
|
</BookingFlowConfigContextProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { createContext, useContext } from "react"
|
||||||
|
|
||||||
|
import type { BookingFlowConfig } from "./bookingFlowConfig"
|
||||||
|
|
||||||
|
type BookingFlowConfigContextData = {
|
||||||
|
config: BookingFlowConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const BookingFlowConfigContext = createContext<
|
||||||
|
BookingFlowConfigContextData | undefined
|
||||||
|
>(undefined)
|
||||||
|
|
||||||
|
export const useBookingFlowConfig = (): BookingFlowConfigContextData => {
|
||||||
|
const context = useContext(BookingFlowConfigContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
"useBookingFlowConfig must be used within a BookingFlowConfigContextProvider. Did you forget to use BookingFlowConfig in the consuming app?"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BookingFlowConfigContextProvider({
|
||||||
|
children,
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
config: BookingFlowConfig
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<BookingFlowConfigContext.Provider value={{ config }}>
|
||||||
|
{children}
|
||||||
|
</BookingFlowConfigContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,15 +5,18 @@ import { useIntl } from "react-intl"
|
|||||||
import Caption from "@scandic-hotels/design-system/Caption"
|
import Caption from "@scandic-hotels/design-system/Caption"
|
||||||
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
|
|
||||||
|
import { useBookingFlowConfig } from "../../../../../bookingFlowConfig/bookingFlowConfigContext"
|
||||||
import BookingCode from "../BookingCode"
|
import BookingCode from "../BookingCode"
|
||||||
import RewardNight from "../RewardNight"
|
import RewardNight from "../RewardNight"
|
||||||
|
|
||||||
import styles from "./voucher.module.css"
|
import styles from "./voucher.module.css"
|
||||||
|
|
||||||
export default function Voucher() {
|
export default function Voucher() {
|
||||||
|
const { config } = useBookingFlowConfig()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.optionsContainer}>
|
<div className={styles.optionsContainer}>
|
||||||
<BookingCode />
|
{config.bookingCodeEnabled && <BookingCode />}
|
||||||
<div className={styles.options}>
|
<div className={styles.options}>
|
||||||
<div className={styles.option}>
|
<div className={styles.option}>
|
||||||
<RewardNight />
|
<RewardNight />
|
||||||
@@ -25,6 +28,7 @@ export default function Voucher() {
|
|||||||
|
|
||||||
export function VoucherSkeleton() {
|
export function VoucherSkeleton() {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
const { config } = useBookingFlowConfig()
|
||||||
|
|
||||||
const vouchers = intl.formatMessage({
|
const vouchers = intl.formatMessage({
|
||||||
defaultMessage: "Code / Voucher",
|
defaultMessage: "Code / Voucher",
|
||||||
@@ -35,14 +39,16 @@ export function VoucherSkeleton() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.optionsContainer}>
|
<div className={styles.optionsContainer}>
|
||||||
<div className={styles.voucherSkeletonContainer}>
|
{config.bookingCodeEnabled && (
|
||||||
<label>
|
<div className={styles.voucherSkeletonContainer}>
|
||||||
<Caption type="bold" color="red" asChild>
|
<label>
|
||||||
<span>{vouchers}</span>
|
<Caption type="bold" color="red" asChild>
|
||||||
</Caption>
|
<span>{vouchers}</span>
|
||||||
</label>
|
</Caption>
|
||||||
<SkeletonShimmer width="100%" display="block" />
|
</label>
|
||||||
</div>
|
<SkeletonShimmer width="100%" display="block" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.options}>
|
<div className={styles.options}>
|
||||||
<div className={cx(styles.option, styles.showOnTablet)}>
|
<div className={cx(styles.option, styles.showOnTablet)}>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"test:watch": "vitest"
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
|
"./BookingFlowConfig": "./lib/bookingFlowConfig/bookingFlowConfig.tsx",
|
||||||
"./BookingFlowContextProvider": "./lib/components/BookingFlowContextProvider.tsx",
|
"./BookingFlowContextProvider": "./lib/components/BookingFlowContextProvider.tsx",
|
||||||
"./BookingFlowTrackingProvider": "./lib/components/BookingFlowTrackingProvider.tsx",
|
"./BookingFlowTrackingProvider": "./lib/components/BookingFlowTrackingProvider.tsx",
|
||||||
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
|
"./BookingWidget": "./lib/components/BookingWidget/index.tsx",
|
||||||
@@ -77,6 +78,7 @@
|
|||||||
"react-hook-form": "^7.56.2",
|
"react-hook-form": "^7.56.2",
|
||||||
"react-intl": "^7.1.11",
|
"react-intl": "^7.1.11",
|
||||||
"react-to-print": "^3.1.0",
|
"react-to-print": "^3.1.0",
|
||||||
|
"server-only": "^0.0.1",
|
||||||
"usehooks-ts": "3.1.1",
|
"usehooks-ts": "3.1.1",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5906,6 +5906,7 @@ __metadata:
|
|||||||
react-hook-form: "npm:^7.56.2"
|
react-hook-form: "npm:^7.56.2"
|
||||||
react-intl: "npm:^7.1.11"
|
react-intl: "npm:^7.1.11"
|
||||||
react-to-print: "npm:^3.1.0"
|
react-to-print: "npm:^3.1.0"
|
||||||
|
server-only: "npm:^0.0.1"
|
||||||
typescript: "npm:5.8.3"
|
typescript: "npm:5.8.3"
|
||||||
usehooks-ts: "npm:3.1.1"
|
usehooks-ts: "npm:3.1.1"
|
||||||
vitest: "npm:^3.2.4"
|
vitest: "npm:^3.2.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user