diff --git a/apps/partner-sas/app/[lang]/debug/page.tsx b/apps/partner-sas/app/[lang]/debug/page.tsx new file mode 100644 index 000000000..dd7d3dc9d --- /dev/null +++ b/apps/partner-sas/app/[lang]/debug/page.tsx @@ -0,0 +1,53 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import { serverClient } from "@/lib/trpc" + +import { getIntl } from "@/i18n" +import { getLang } from "@/i18n/serverContext" + +import { ClientComponent } from "../../../components/ClientComponent" + +type SearchParams = { + searchParams: Promise +} + +export default async function Debug(props: SearchParams) { + const searchParams = await props.searchParams + const intl = await getIntl() + const lang = await getLang() + const caller = await serverClient() + const destinations = await caller.autocomplete.destinations({ + lang, + includeTypes: ["hotels"], + query: "Göteborg", + }) + const hotel = destinations.hits.hotels[0].name + + const booking = parseBookingWidgetSearchParams(searchParams) + + return ( +
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

from booking-flow package:

+
+ +
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

hello world with data: {hotel}

+
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

+ translated: + {intl.formatMessage({ defaultMessage: "Map of the city" })} +

+
+
+ +
+ ) +} diff --git a/apps/partner-sas/app/[lang]/layout.tsx b/apps/partner-sas/app/[lang]/layout.tsx index cc501de95..63e8789fa 100644 --- a/apps/partner-sas/app/[lang]/layout.tsx +++ b/apps/partner-sas/app/[lang]/layout.tsx @@ -1,7 +1,9 @@ -import "@scandic-hotels/design-system/style.css" import "@scandic-hotels/design-system/fonts.css" +import "@scandic-hotels/design-system/style.css" import "@/public/_static/css/design-system-new-deprecated.css" +import "../../globals.css" +import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider" import { Lang } from "@scandic-hotels/common/constants/language" import { TrpcProvider } from "@scandic-hotels/trpc/Provider" @@ -9,6 +11,8 @@ import { getMessages } from "@/i18n" import ClientIntlProvider from "@/i18n/Provider" import { setLang } from "@/i18n/serverContext" +import { trackBookingSearchClick } from "../utils/tracking" + import type { Metadata } from "next" export const metadata: Metadata = { @@ -35,21 +39,39 @@ export default async function RootLayout(props: RootLayoutProps) { return ( - - {/* eslint-disable-next-line @next/next/no-css-tags */} - - {/* eslint-disable-next-line @next/next/no-css-tags */} - - + {/* TODO */} - - {/* TODO handle onError */} - {children} - +
+ + {/* TODO handle onError */} + + +
+ {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

SAS

+
+
{children}
+
+
+
+
) diff --git a/apps/partner-sas/app/[lang]/page.module.css b/apps/partner-sas/app/[lang]/page.module.css deleted file mode 100644 index 0c38093bf..000000000 --- a/apps/partner-sas/app/[lang]/page.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.page { - padding-left: 200px; - padding-top: 200px; -} diff --git a/apps/partner-sas/app/[lang]/page.tsx b/apps/partner-sas/app/[lang]/page.tsx index be56c55ef..c42416e12 100644 --- a/apps/partner-sas/app/[lang]/page.tsx +++ b/apps/partner-sas/app/[lang]/page.tsx @@ -1,44 +1,29 @@ -import { Temp } from "@scandic-hotels/booking-flow/test-entry" -import { Lang } from "@scandic-hotels/common/constants/language" -import { Typography } from "@scandic-hotels/design-system/Typography" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" import { serverClient } from "@/lib/trpc" -import { getIntl } from "@/i18n" +import { getLang } from "@/i18n/serverContext" -import { ClientComponent } from "./ClientComponent" +import type { Lang } from "@scandic-hotels/common/constants/language" -import styles from "./page.module.css" +type SearchParams = { + searchParams: Promise +} -export default async function Home() { - const intl = await getIntl() - const caller = await serverClient() - const destinations = await caller.autocomplete.destinations({ - lang: Lang.en, - includeTypes: ["hotels"], - query: "Göteborg", - }) - const hotel = destinations.hits.hotels[0].name +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) return ( -
-
- - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} -

hello world with data: {hotel}

-
- -

{intl.formatMessage({ defaultMessage: "Map of the city" })}

-
-
- -
- - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} -

from booking-flow package:

-
- -
+
+
) } diff --git a/apps/partner-sas/app/favicon.ico b/apps/partner-sas/app/favicon.ico new file mode 100644 index 000000000..a29b7b457 Binary files /dev/null and b/apps/partner-sas/app/favicon.ico differ diff --git a/apps/partner-sas/app/utils/tracking.ts b/apps/partner-sas/app/utils/tracking.ts new file mode 100644 index 000000000..7b9c5918e --- /dev/null +++ b/apps/partner-sas/app/utils/tracking.ts @@ -0,0 +1,11 @@ +"use client" + +export function trackBookingSearchClick( + searchTerm: string, + searchType: "hotel" | "destination" +) { + console.log("TODO: Implement trackBookingSearchClick", { + searchTerm, + searchType, + }) +} diff --git a/apps/partner-sas/app/[lang]/ClientComponent.tsx b/apps/partner-sas/components/ClientComponent.tsx similarity index 100% rename from apps/partner-sas/app/[lang]/ClientComponent.tsx rename to apps/partner-sas/components/ClientComponent.tsx diff --git a/apps/partner-sas/components/IntlProvider.tsx b/apps/partner-sas/components/IntlProvider.tsx new file mode 100644 index 000000000..0189a11ed --- /dev/null +++ b/apps/partner-sas/components/IntlProvider.tsx @@ -0,0 +1,24 @@ +"use client" + +import { type IntlConfig, IntlProvider } from "react-intl" + +type ClientIntlProviderProps = React.PropsWithChildren< + Pick +> + +export default function ClientIntlProvider({ + children, + locale, + defaultLocale, + messages, +}: ClientIntlProviderProps) { + return ( + + {children} + + ) +} diff --git a/apps/partner-sas/globals.css b/apps/partner-sas/globals.css new file mode 100644 index 000000000..4bd623dc1 --- /dev/null +++ b/apps/partner-sas/globals.css @@ -0,0 +1,107 @@ +:root { + --current-max-width: 113.5rem; + + --max-width: 94.5rem; + --max-width-content: min(calc(100dvw - var(--max-width-spacing)), 74.75rem); + --max-width-text-block: 49.5rem; + --current-mobile-site-header-height: 52.41px; + --max-width-navigation: 89.5rem; + + --max-width-single-spacing: var(--Layout-Mobile-Margin-Margin-min); + --max-width-spacing: calc(var(--max-width-single-spacing) * 2); + --max-width-page: min( + calc(100dvw - var(--max-width-spacing)), + var(--max-width-navigation) + ); + + --sitewide-alert-height: 0px; /* Will be overridden when a sitewide alert is visible */ + --main-menu-mobile-height: 75px; + --main-menu-desktop-height: 125px; + --booking-widget-mobile-height: 75px; + --booking-widget-tablet-height: 150px; + --booking-widget-desktop-height: 77px; + --hotel-page-map-desktop-width: 23.75rem; + + /* Z-INDEX */ + --header-z-index: 11; + --menu-overlay-z-index: 11; + --booking-widget-z-index: 10; + --booking-widget-open-z-index: 100; + --dialog-z-index: 9; + --back-to-top-button: 80; + --language-switcher-z-index: 85; + --sidepeek-z-index: 100; + --lightbox-z-index: 150; + --default-modal-overlay-z-index: 100; + --default-modal-z-index: 101; + + --modal-box-shadow: 0px 4px 24px 0px rgba(38, 32, 30, 0.08); + --popup-box-shadow: 0 0 14px 6px rgba(0, 0, 0, 0.1); + + @supports (interpolate-size: allow-keywords) { + interpolate-size: allow-keywords; + } +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + scroll-behavior: smooth; +} + +body { + min-height: 100dvh; + overflow-x: hidden; + display: flex; + flex-direction: column; + color: var(--Text-Default); +} + +body.overflow-hidden { + overflow: hidden; +} + +.root { + isolation: isolate; +} + +/* From Tailwind */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +ul { + padding-inline-start: 0; + margin-block-start: 0; + margin-block-end: 0; +} + +@media screen and (min-width: 768px) { + :root { + --max-width-single-spacing: var(--Layout-Tablet-Margin-Margin-min); + } + + body.overflow-hidden { + overflow: auto; + overflow-x: hidden; + } +} + +@media screen and (min-width: 1367px) { + :root { + --max-width-single-spacing: var(--Layout-Desktop-Margin-Margin-min); + } +} diff --git a/apps/partner-sas/next.config.ts b/apps/partner-sas/next.config.ts index 8f084731f..ff3059491 100644 --- a/apps/partner-sas/next.config.ts +++ b/apps/partner-sas/next.config.ts @@ -12,6 +12,17 @@ const nextConfig: NextConfig = { ], output: "standalone", + experimental: { + swcPlugins: [ + [ + "@swc/plugin-formatjs", + { + ast: true, + }, + ], + ], + }, + webpack: function (config: any) { config.module.rules.push( { @@ -27,17 +38,6 @@ const nextConfig: NextConfig = { return config }, - - experimental: { - swcPlugins: [ - [ - "@swc/plugin-formatjs", - { - ast: true, - }, - ], - ], - }, } export default Sentry.withSentryConfig(nextConfig, { diff --git a/apps/partner-sas/package.json b/apps/partner-sas/package.json index 8a844ca63..5fc0ffabb 100644 --- a/apps/partner-sas/package.json +++ b/apps/partner-sas/package.json @@ -34,6 +34,7 @@ "@playwright/test": "^1.53.1", "@scandic-hotels/common": "workspace:*", "@scandic-hotels/typescript-config": "workspace:*", + "@swc/plugin-formatjs": "^3.2.2", "@types/node": "^20", "@types/react": "19.1.0", "@types/react-dom": "19.1.0", diff --git a/apps/partner-sas/playwright.config.ts b/apps/partner-sas/playwright.config.ts index e3ba29f89..b0f9671f9 100644 --- a/apps/partner-sas/playwright.config.ts +++ b/apps/partner-sas/playwright.config.ts @@ -28,25 +28,37 @@ export default defineConfig({ /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: "http://localhost:3001", + /* How long to wait for actions to complete. */ + actionTimeout: 15 * 1000, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + trace: process.env.CI ? "on-first-retry" : "retain-on-failure", }, /* Configure projects for major browsers */ projects: [ { name: "chromium", - use: { ...devices["Desktop Chrome"] }, + use: { + ...devices["Desktop Chrome"], + viewport: { width: 1400, height: 720 }, + }, }, { name: "firefox", - use: { ...devices["Desktop Firefox"] }, + use: { + ...devices["Desktop Firefox"], + viewport: { width: 1400, height: 720 }, + }, }, { name: "webkit", - use: { ...devices["Desktop Safari"] }, + use: { + ...devices["Desktop Safari"], + viewport: { width: 1400, height: 720 }, + }, }, /* Test against mobile viewports. */ diff --git a/apps/partner-sas/public/_static/icons/cancel.svg b/apps/partner-sas/public/_static/icons/cancel.svg new file mode 100644 index 000000000..9b72e85a0 --- /dev/null +++ b/apps/partner-sas/public/_static/icons/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/partner-sas/tests/booking-widget.spec.ts b/apps/partner-sas/tests/booking-widget.spec.ts new file mode 100644 index 000000000..517042be7 --- /dev/null +++ b/apps/partner-sas/tests/booking-widget.spec.ts @@ -0,0 +1,206 @@ +import { expect, type Page, test } from "@playwright/test" + +import { serializeBookingSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum" + +test("can make a search with city", async ({ page }) => { + await page.goto("/") + + // Search for city + const combobox = page.getByRole("combobox", { name: /where to/i }) + await combobox.click() + await combobox.fill("stockholm") + await page.getByRole("option", { name: /stockholm sweden/i }).click() + + // Open datepicker + // If we had better accessibility for our datepicker this would be so much easier + const today = new Date() + const tomorrow = new Date(today) + tomorrow.setDate(today.getDate() + 1) + + await page + .getByRole("button", { + name: `${formatDate(today)} - ${formatDate(tomorrow)}`, + }) + .click() + + // Select future dates + const twoDaysFromNow = new Date(today) + twoDaysFromNow.setDate(today.getDate() + 2) + await clickDatePickerDate(page, twoDaysFromNow) + + const threeDaysFromNow = new Date(today) + threeDaysFromNow.setDate(today.getDate() + 3) + await clickDatePickerDate(page, threeDaysFromNow) + + await page + .getByRole("button", { + name: /select dates/i, + }) + .click() + + // Select rooms and guests + // Once again, better accessibility would make this so much easier + await page.getByRole("button", { name: /1 room, 1 adult/i }).click() + const roomsDialog = page.getByRole("dialog") + const room1section = roomsDialog.getByText(/room 1/i).locator("..") + + // Add 1 adult + await room1section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click() + + // Add 1 child aged 10 + await room1section + .locator("section") + .filter({ hasText: /children/i }) + .getByRole("button", { name: /add/i }) + .click() + await room1section.getByRole("button", { name: /age/i }).click() + await page.getByRole("option", { name: /10/i }).click() + + await page.getByRole("button", { name: /add room/i }).click() + + const room2section = roomsDialog.getByText(/room 2/i).locator("..") + + // Add 2 adults + await room2section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click({ clickCount: 2 }) + + await roomsDialog.getByRole("button", { name: /done/i }).click() + + await page.getByRole("button", { name: /search/i }).click() + + // Assert that we navigated to the correct URL + const expectedSearchParams = serializeBookingSearchParams({ + rooms: [ + { + adults: 2, + childrenInRoom: [{ age: 10, bed: ChildBedMapEnum.IN_EXTRA_BED }], + }, + { + adults: 3, + childrenInRoom: [], + }, + ], + fromDate: twoDaysFromNow.toISOString().split("T")[0], + toDate: threeDaysFromNow.toISOString().split("T")[0], + city: "STOCKHOLM", + }) + + await expect(page).toHaveURL( + `/en/hotelreservation/select-hotel?${expectedSearchParams}` + ) +}) + +test("can make a search with hotel", async ({ page }) => { + await page.goto("/") + + // Search for hotel + const combobox = page.getByRole("combobox", { name: /where to/i }) + await combobox.click() + await combobox.fill("downtown camper") + await page.getByRole("option", { name: /downtown camper/i }).click() + + // Open datepicker + // If we had better accessibility for our datepicker this would be so much easier + const today = new Date() + const tomorrow = new Date(today) + tomorrow.setDate(today.getDate() + 1) + + await page + .getByRole("button", { + name: `${formatDate(today)} - ${formatDate(tomorrow)}`, + }) + .click() + + // Select future dates + const twoDaysFromNow = new Date(today) + twoDaysFromNow.setDate(today.getDate() + 2) + await clickDatePickerDate(page, twoDaysFromNow) + + const threeDaysFromNow = new Date(today) + threeDaysFromNow.setDate(today.getDate() + 3) + await clickDatePickerDate(page, threeDaysFromNow) + + await page + .getByRole("button", { + name: /select dates/i, + }) + .click() + + // Select rooms and guests + // Once again, better accessibility would make this so much easier + await page.getByRole("button", { name: /1 room, 1 adult/i }).click() + const roomsDialog = page.getByRole("dialog") + const room1section = roomsDialog.getByText(/room 1/i).locator("..") + + // Add 1 adult + await room1section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click() + + // Add 1 child aged 10 + await room1section + .locator("section") + .filter({ hasText: /children/i }) + .getByRole("button", { name: /add/i }) + .click() + await room1section.getByRole("button", { name: /age/i }).click() + await page.getByRole("option", { name: /10/i }).click() + + await page.getByRole("button", { name: /add room/i }).click() + + const room2section = roomsDialog.getByText(/room 2/i).locator("..") + + // Add 2 adults + await room2section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click({ clickCount: 2 }) + + await roomsDialog.getByRole("button", { name: /done/i }).click() + + await page.getByRole("button", { name: /search/i }).click() + + // Assert that we navigated to the correct URL + const expectedSearchParams = serializeBookingSearchParams({ + rooms: [ + { + adults: 2, + childrenInRoom: [{ age: 10, bed: ChildBedMapEnum.IN_EXTRA_BED }], + }, + { + adults: 3, + childrenInRoom: [], + }, + ], + fromDate: twoDaysFromNow.toISOString().split("T")[0], + toDate: threeDaysFromNow.toISOString().split("T")[0], + hotelId: "879", // Downtown Camper + }) + + await expect(page).toHaveURL( + `/en/hotelreservation/select-rate?${expectedSearchParams}` + ) +}) + +const formatDate = (date: Date) => { + const day = date.getDate() + const month = date.toLocaleDateString("en-US", { month: "short" }) + const weekday = date.toLocaleDateString("en-US", { weekday: "short" }) + return `${weekday}, ${day} ${month}` +} + +const clickDatePickerDate = async (page: Page, date: Date) => { + const dateString = date.toISOString().split("T")[0] // YYYY-MM-DD format + await page.locator(`[data-day="${dateString}"]`).getByRole("button").click() +} diff --git a/apps/partner-sas/tests/dummy.spec.ts b/apps/partner-sas/tests/dummy.spec.ts deleted file mode 100644 index 02f5c17ba..000000000 --- a/apps/partner-sas/tests/dummy.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { expect, test } from "@playwright/test" - -test("has text", async ({ page }) => { - await page.goto("/") - - await expect(page.getByText(/hello world/i)).toBeVisible() -}) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx index 3b44d3394..d9764acbe 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx @@ -1,5 +1,6 @@ +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import StartPage from "@/components/ContentType/StartPage" -import { parseBookingWidgetSearchParams } from "@/utils/url" import type { NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx index a9f1764c8..dae04872e 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -1,5 +1,9 @@ import { notFound } from "next/navigation" +import { + bookingConfirmation, + details, +} from "@scandic-hotels/common/constants/routes/hotelReservation" import { logger } from "@scandic-hotels/common/logger" import { getServiceToken } from "@scandic-hotels/common/tokenManager" import { BookingErrorCodeEnum } from "@scandic-hotels/trpc/enums/bookingErrorCode" @@ -8,10 +12,6 @@ import { encrypt } from "@scandic-hotels/trpc/utils/encryption" import { isValidSession } from "@scandic-hotels/trpc/utils/session" import { PaymentCallbackStatusEnum } from "@/constants/booking" -import { - bookingConfirmation, - details, -} from "@/constants/routes/hotelReservation" import { serverClient } from "@/lib/trpc/server" import { auth } from "@/auth" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx index 531888573..76d833824 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx @@ -1,10 +1,11 @@ import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" -import { parseSelectHotelSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx index ca0d50e4c..ef67a2f8d 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx @@ -3,8 +3,10 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { alternativeHotelsMap } from "@scandic-hotels/common/constants/routes/hotelReservation" + import { FamilyAndFriendsCodes } from "@/constants/booking" -import { alternativeHotelsMap } from "@/constants/routes/hotelReservation" import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import SelectHotel from "@/components/HotelReservation/SelectHotel" @@ -13,7 +15,6 @@ import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking" import TrackingSDK from "@/components/TrackingSDK" import { getIntl } from "@/i18n" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" -import { parseSelectHotelSearchParams } from "@/utils/url" import { type LangParams, diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx index 3bbf2990a..5e518c44f 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx @@ -2,6 +2,8 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseDetailsSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { FamilyAndFriendsCodes } from "@/constants/booking" import { getBreakfastPackages, @@ -20,7 +22,6 @@ 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 { parseDetailsSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx index a83533e80..331d11752 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx @@ -2,10 +2,11 @@ import stringify from "json-stable-stringify-without-jsonify" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" -import { parseSelectHotelSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx index d7accb6f0..0eab92eff 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -3,8 +3,10 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { selectHotelMap } from "@scandic-hotels/common/constants/routes/hotelReservation" + import { FamilyAndFriendsCodes } from "@/constants/booking" -import { selectHotelMap } from "@/constants/routes/hotelReservation" import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import SelectHotel from "@/components/HotelReservation/SelectHotel" @@ -12,7 +14,6 @@ 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 { parseSelectHotelSearchParams } from "@/utils/url" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index e4ee94763..45d483e4b 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -1,11 +1,11 @@ import { notFound } from "next/navigation" +import { parseSelectRateSearchParams } from "@scandic-hotels/booking-flow/utils/url" import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking" import { combineRegExps, rateTypeRegex } from "@/constants/booking" import SelectRate from "@/components/HotelReservation/SelectRate" -import { parseSelectRateSearchParams } from "@/utils/url" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx index fdaf11d35..6b64c1b80 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx @@ -1,7 +1,9 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests" -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { getLang } from "@/i18n/serverContext" import type { NextSearchParams, PageArgs } from "@/types/params" @@ -20,5 +22,7 @@ export default async function BookingWidgetDestinationCityPage( const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx index b16b6644d..da4c72fec 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx @@ -1,8 +1,9 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests" -import { BookingWidget } from "@/components/BookingWidget" import { getLang } from "@/i18n/serverContext" -import { parseBookingWidgetSearchParams } from "@/utils/url" import type { NextSearchParams, PageArgs } from "@/types/params" @@ -12,9 +13,10 @@ export default async function BookingWidgetHotelPage( const searchParams = await props.searchParams const hotelPageData = await getHotelPage() + const lang = await getLang() const hotelData = await getHotel({ hotelId: hotelPageData?.hotel_page_id || "", - language: await getLang(), + language: lang, isCardOnlyPayment: false, }) @@ -34,5 +36,5 @@ export default async function BookingWidgetHotelPage( const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams) - return + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx index e49aa6721..59cbf2505 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx @@ -1,4 +1,4 @@ -import { BookingWidgetSkeleton } from "@/components/BookingWidget/Client" +import { BookingWidgetSkeleton } from "@scandic-hotels/booking-flow/BookingWidget/Skeleton" // This file is crucial for displaying a loading // state immediately in the booking flow. diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx index 235081a69..2924e1e15 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx @@ -1,5 +1,7 @@ -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + +import { getLang } from "@/i18n/serverContext" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" @@ -10,5 +12,7 @@ export default async function BookingWidgetPage( const booking = parseBookingWidgetSearchParams(searchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx index 235081a69..2924e1e15 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx @@ -1,5 +1,7 @@ -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + +import { getLang } from "@/i18n/serverContext" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" @@ -10,5 +12,7 @@ export default async function BookingWidgetPage( const booking = parseBookingWidgetSearchParams(searchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/layout.tsx b/apps/scandic-web/app/[lang]/(live)/layout.tsx index 841176a7b..737e8285b 100644 --- a/apps/scandic-web/app/[lang]/(live)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live)/layout.tsx @@ -7,6 +7,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools" import Script from "next/script" import { SessionProvider } from "next-auth/react" +import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider" import { Lang } from "@scandic-hotels/common/constants/language" import TrpcProvider from "@/lib/trpc/Provider" @@ -26,6 +27,7 @@ import { FontPreload } from "@/fonts/font-preloading" import { getMessages } from "@/i18n" import ClientIntlProvider from "@/i18n/Provider" import { setLang } from "@/i18n/serverContext" +import { trackBookingSearchClick } from "@/utils/tracking/booking" import type { LangParams, LayoutArgs } from "@/types/params" @@ -65,17 +67,23 @@ export default async function RootLayout( > - - -
- {bookingwidget} - {children} -