Merged in chore/move-enter-details (pull request #2778)

Chore/move enter details

Approved-by: Anton Gunnarsson
This commit is contained in:
Joakim Jäderberg
2025-09-11 07:16:24 +00:00
parent 15711cb3a4
commit 7dee6d5083
238 changed files with 1656 additions and 1602 deletions

View File

@@ -1,6 +1,5 @@
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"
@@ -16,12 +15,6 @@ export default async function AlternativeHotelsMapPage(
<AlternativeHotelsMapPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
</div>
)

View File

@@ -1,6 +1,5 @@
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"
@@ -12,15 +11,6 @@ export default async function AlternativeHotelsPage(
const lang = await getLang()
return (
<AlternativeHotelsPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
<AlternativeHotelsPagePrimitive lang={lang} searchParams={searchParams} />
)
}

View File

@@ -1,6 +1,5 @@
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"
@@ -9,16 +8,5 @@ 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}
/>
)}
/>
)
return <SelectHotelMapPagePrimitive lang={lang} searchParams={searchParams} />
}

View File

@@ -1,6 +1,5 @@
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"
@@ -9,16 +8,5 @@ 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}
/>
)}
/>
)
return <SelectHotelPagePrimitive lang={lang} searchParams={searchParams} />
}

View File

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

View File

@@ -22,9 +22,15 @@ import { Footer } from "../components/Footer/Footer"
import { Header } from "../components/Header/Header"
import {
trackAccordionItemOpen,
trackBedSelection,
trackBookingSearchClick,
trackBreakfastSelection,
trackGenericEvent,
trackGlaSaveCardAttempt,
trackLoginClick,
trackOpenSidePeek,
trackPaymentEvent,
trackUpdatePaymentMethod,
} from "../utils/tracking"
import type { Metadata } from "next"
@@ -82,6 +88,12 @@ export default async function RootLayout(props: RootLayoutProps) {
trackAccordionItemOpen,
trackOpenSidePeek,
trackGenericEvent,
trackGlaSaveCardAttempt,
trackLoginClick,
trackPaymentEvent,
trackUpdatePaymentMethod,
trackBreakfastSelection,
trackBedSelection,
}}
>
<SiteWideAlert />

View File

@@ -1,5 +1,11 @@
"use client"
import type {
PaymentEvent,
PaymentFailEvent,
} from "@scandic-hotels/tracking/types"
import type { BreakfastPackages } from "@scandic-hotels/trpc/routers/hotels/output"
export function trackBookingSearchClick(
searchTerm: string,
searchType: "hotel" | "destination"
@@ -26,3 +32,120 @@ export function trackOpenSidePeek(input: {
export function trackGenericEvent(data: any) {
console.warn("TODO: Implement trackGenericEvent", { data })
}
export function trackGlaSaveCardAttempt({
hotelId,
hasSavedCreditCard,
creditCardType,
lateArrivalGuarantee,
}: {
hotelId: string
hasSavedCreditCard: boolean
creditCardType?: string
lateArrivalGuarantee: "mandatory" | "yes" | "no" | "na"
}) {
console.warn("TODO: Implement trackGlaSaveCardAttempt", {
event: "glaCardSaveAttempt",
hotelInfo: {
hotelId,
lateArrivalGuarantee,
guaranteedProduct: "room",
},
paymentInfo: {
status: "glacardsaveattempt",
isSavedCreditCard: hasSavedCreditCard,
type: creditCardType,
},
})
}
export function trackLoginClick(
position:
| "top menu"
| "hamburger menu"
| "join scandic friends sidebar"
| "enter details"
| "my stay"
) {
console.warn("TODO: Implement trackLoginClick", {
event: "loginStart",
login: {
position,
action: "login start",
ctaName: "login",
},
})
}
export function trackPaymentEvent(paymentEvent: PaymentEvent) {
console.warn("TODO: Implement trackPaymentEvent", {
event: paymentEvent.event,
hotelInfo: {
hotelId: paymentEvent.hotelId,
},
paymentInfo: {
isSavedCard: paymentEvent.isSavedCreditCard,
status: paymentEvent.status,
type: paymentEvent.method,
smsEnable: paymentEvent.smsEnable,
errorMessage: isPaymentFailEvent(paymentEvent)
? paymentEvent.errorMessage
: undefined,
},
})
}
export function trackUpdatePaymentMethod({ method }: { method: string }) {
console.warn("TODO: Implement trackUpdatePaymentMethod", {
event: "paymentSelection",
hotelInfo: {
hotelId: "", // TODO: Needs to be verified with analytics if this should even be here
},
cta: {
name: method,
},
})
}
export function trackBreakfastSelection({
breakfastPackage,
hotelId,
units,
}: {
breakfastPackage: BreakfastPackages[number]
hotelId: string
units: number
}) {
console.warn("TODO: Implement trackBreakfastSelection", {
event: "breakfastSelection",
selection: {
name: "breakfast options selection click",
},
...(units > 0 && {
ancillaries: [
{
hotelId,
productCategory: "",
productId: breakfastPackage.code,
productUnits: units,
productPrice: breakfastPackage.localPrice.price * units,
productPoints: 0,
productType: "food",
productName: breakfastPackage.packageType,
},
],
}),
})
}
export function trackBedSelection(bedType: string) {
console.warn("TODO: Implement trackBedSelection", {
event: "bedSelection",
selection: {
name: "bed options selection click",
bedType: bedType,
},
})
}
function isPaymentFailEvent(event: PaymentEvent): event is PaymentFailEvent {
return "errorMessage" in event
}

View File

@@ -21,6 +21,7 @@
"@netlify/plugin-nextjs": "^5.11.2",
"@scandic-hotels/booking-flow": "workspace:*",
"@scandic-hotels/design-system": "workspace:*",
"@scandic-hotels/tracking": "workspace:*",
"@scandic-hotels/trpc": "workspace:*",
"@sentry/nextjs": "^8.41.0",
"@swc/plugin-formatjs": "^3.2.2",

View File

@@ -1,11 +1,11 @@
import Image from "@scandic-hotels/design-system/Image"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { serverClient } from "@/lib/trpc/server"
import Blocks from "@/components/Blocks"
import SectionHeader from "@/components/Section/Header"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
import styles from "./page.module.css"

View File

@@ -1,8 +1,9 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getProfile } from "@/lib/trpc/memoizedRequests"
import { serverClient } from "@/lib/trpc/server"
import Form from "@/components/Forms/Edit/Profile"
import TrackingSDK from "@/components/TrackingSDK"
import styles from "./page.module.css"

View File

@@ -1,7 +1,8 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { serverClient } from "@/lib/trpc/server"
import Profile from "@/components/MyPages/Profile"
import TrackingSDK from "@/components/TrackingSDK"
import type { LangParams, PageArgs } from "@/types/params"

View File

@@ -1,6 +1,6 @@
import { notFound } from "next/navigation"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/booking"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/paymentCallbackStatusEnum"
import { myStay } from "@scandic-hotels/common/constants/routes/myStay"
import { logger } from "@scandic-hotels/common/logger"
import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner"

View File

@@ -1,6 +1,8 @@
import { notFound } from "next/navigation"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/booking"
import { HandleErrorCallback } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/PaymentCallback/HandleErrorCallback"
import { HandleSuccessCallback } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/paymentCallbackStatusEnum"
import {
bookingConfirmation,
details,
@@ -15,8 +17,6 @@ import { isValidSession } from "@scandic-hotels/trpc/utils/session"
import { serverClient } from "@/lib/trpc/server"
import { auth } from "@/auth"
import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback"
import HandleSuccessCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback"
import type { LangParams, PageArgs } from "@/types/params"

View File

@@ -1,6 +1,5 @@
import { AlternativeHotelsMapPage as AlternativeHotelsMapPagePrimitive } from "@scandic-hotels/booking-flow/pages/AlternativeHotelsMapPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import styles from "./page.module.css"
@@ -18,12 +17,6 @@ export default async function AlternativeHotelsMapPage(
<AlternativeHotelsMapPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
</div>
)

View File

@@ -1,6 +1,5 @@
import { AlternativeHotelsPage as AlternativeHotelsPagePrimitive } from "@scandic-hotels/booking-flow/pages/AlternativeHotelsPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import {
@@ -14,17 +13,7 @@ export default async function AlternativeHotelsPage(
) {
const searchParams = await props.searchParams
const lang = await getLang()
return (
<AlternativeHotelsPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
<AlternativeHotelsPagePrimitive lang={lang} searchParams={searchParams} />
)
}

View File

@@ -1,167 +1,12 @@
import { cookies } from "next/headers"
import { notFound } from "next/navigation"
import { Suspense } from "react"
import FnFNotAllowedAlert from "@scandic-hotels/booking-flow/components/FnFNotAllowedAlert"
import { parseDetailsSearchParams } from "@scandic-hotels/booking-flow/utils/url"
import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAndFriends"
import {
getBreakfastPackages,
getHotel,
getProfileSafely,
getSelectedRoomsAvailabilityEnterDetails,
} from "@/lib/trpc/memoizedRequests"
import HotelHeader from "@/components/HotelReservation/EnterDetails/Header"
import Payment from "@/components/HotelReservation/EnterDetails/Payment"
import Multiroom from "@/components/HotelReservation/EnterDetails/Room/Multiroom"
import RoomOne from "@/components/HotelReservation/EnterDetails/Room/One"
import DesktopSummary from "@/components/HotelReservation/EnterDetails/Summary/Desktop"
import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mobile"
import EnterDetailsTrackingWrapper from "@/components/HotelReservation/EnterDetails/Tracking"
import RoomProvider from "@/providers/Details/RoomProvider"
import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
import styles from "./page.module.css"
import { EnterDetailsPage as EnterDetailsPagePrimitive } from "@scandic-hotels/booking-flow/pages/EnterDetailsPage"
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
export default async function DetailsPage(
props: PageArgs<LangParams, NextSearchParams>
) {
const { lang } = await props.params
const searchParams = await props.searchParams
const params = await props.params
const { lang } = params
const selectRoomParams = new URLSearchParams(searchParams)
const booking = parseDetailsSearchParams(searchParams)
if (!booking) return notFound()
if (selectRoomParams.has("activeRoomIndex")) {
selectRoomParams.delete("activeRoomIndex")
}
if (
booking.bookingCode &&
FamilyAndFriendsCodes.includes(booking.bookingCode)
) {
const cookieStore = await cookies()
const isInValidFNF = cookieStore.get("sc")?.value !== "1"
if (isInValidFNF) {
return <FnFNotAllowedAlert />
}
}
const breakfastInput = {
adults: 1,
fromDate: booking.fromDate,
hotelId: booking.hotelId,
toDate: booking.toDate,
}
const hotelInput = {
hotelId: booking.hotelId,
// TODO: Remove this from input since it forces
// waterfalls for no other reason than to
// set merchantInformationData.alternatePaymentOptions
// to an empty array
isCardOnlyPayment: false,
language: lang,
}
void getHotel(hotelInput)
void getBreakfastPackages(breakfastInput)
void getProfileSafely()
const rooms = await getSelectedRoomsAvailabilityEnterDetails({
booking,
lang,
})
const hotelData = await getHotel(hotelInput)
if (!hotelData || !rooms.length) {
return notFound()
}
const breakfastPackages = await getBreakfastPackages(breakfastInput)
const user = await getProfileSafely()
const isCardOnlyPayment = rooms.some((room) => room.mustBeGuaranteed)
const { hotel } = hotelData
// TODO: Temp fix to avoid waterfall fetch and moving this
// logic from the route here for now
if (isCardOnlyPayment) {
hotel.merchantInformationData.alternatePaymentOptions = []
}
const firstRoom = rooms[0]
const multirooms = rooms.slice(1)
const { rateDefinition, rateDefinitionMember } = firstRoom.roomRate
if (user && rateDefinitionMember) {
const rateCode = selectRoomParams.get("room[0].ratecode")
if (rateDefinitionMember.rateCode !== rateCode) {
booking.rooms[0].rateCode = rateDefinitionMember.rateCode
selectRoomParams.set("room[0].ratecode", rateDefinitionMember.rateCode)
booking.rooms[0].counterRateCode = rateDefinition.rateCode
selectRoomParams.set("room[0].counterratecode", rateDefinition.rateCode)
}
}
// attribute data-footer-spacing used to add spacing
// beneath footer to be able to show entire footer upon
// scrolling down to the bottom of the page
return (
<main data-footer-spacing>
<EnterDetailsProvider
booking={booking}
breakfastPackages={breakfastPackages}
lang={lang}
rooms={rooms}
searchParamsStr={selectRoomParams.toString()}
user={user}
vat={hotel.vat}
roomCategories={hotelData.roomCategories}
>
<HotelHeader hotelData={hotelData} />
<div className={styles.container}>
<div className={styles.content}>
<RoomProvider idx={0} room={firstRoom}>
<RoomOne user={user} />
</RoomProvider>
{multirooms.map((room, idx) => (
// Need to start idx from 1 since first room is
// rendered above
<RoomProvider key={idx + 1} idx={idx + 1} room={room}>
<Multiroom />
</RoomProvider>
))}
<Suspense>
<Payment
otherPaymentOptions={
hotel.merchantInformationData.alternatePaymentOptions
}
supportedCards={hotel.merchantInformationData.cards}
/>
</Suspense>
</div>
<aside className={styles.summary}>
<MobileSummary isUserLoggedIn={!!user} />
<DesktopSummary isUserLoggedIn={!!user} />
</aside>
</div>
<EnterDetailsTrackingWrapper
booking={booking}
hotel={hotel}
isMember={!!user}
lang={lang}
rooms={rooms}
/>
</EnterDetailsProvider>
</main>
)
return <EnterDetailsPagePrimitive lang={lang} searchParams={searchParams} />
}

View File

@@ -1,9 +1,8 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@scandic-hotels/common/tracking/types"
import TrackingSDK from "@/components/TrackingSDK"
} from "@scandic-hotels/tracking/types"
import styles from "./page.module.css"

View File

@@ -1,6 +1,5 @@
import { SelectHotelMapPage as SelectHotelMapPagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectHotelMapPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import styles from "./page.module.css"
@@ -15,16 +14,7 @@ export default async function SelectHotelMapPage(
return (
<div className={styles.main}>
<SelectHotelMapPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
<SelectHotelMapPagePrimitive lang={lang} searchParams={searchParams} />
</div>
)
}

View File

@@ -1,6 +1,5 @@
import { SelectHotelPage as SelectHotelPagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectHotelPage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import type { LangParams, NextSearchParams, PageArgs } from "@/types/params"
@@ -11,16 +10,5 @@ export default async function SelectHotelPage(
const searchParams = await props.searchParams
const lang = await getLang()
return (
<SelectHotelPagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
)
return <SelectHotelPagePrimitive lang={lang} searchParams={searchParams} />
}

View File

@@ -1,6 +1,5 @@
import { SelectRatePage as SelectRatePagePrimitive } from "@scandic-hotels/booking-flow/pages/SelectRatePage"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import {
@@ -15,16 +14,5 @@ export default async function SelectRatePage(
const searchParams = await props.searchParams
const lang = await getLang()
return (
<SelectRatePagePrimitive
lang={lang}
searchParams={searchParams}
renderTracking={(props) => (
<TrackingSDK
hotelInfo={props.hotelsTrackingData}
pageData={props.pageTrackingData}
/>
)}
/>
)
return <SelectRatePagePrimitive lang={lang} searchParams={searchParams} />
}

View File

@@ -1,9 +1,9 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
export default async function Tracking() {

View File

@@ -8,6 +8,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import { SessionProvider } from "next-auth/react"
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
import { Lang } from "@scandic-hotels/common/constants/language"
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
@@ -19,7 +20,6 @@ import { BookingFlowProviders } from "@/components/BookingFlowProviders"
import CookieBotConsent from "@/components/CookieBot"
import Footer from "@/components/Footer"
import Header from "@/components/Header"
import StorageCleaner from "@/components/HotelReservation/EnterDetails/StorageCleaner"
import { RACRouterProvider } from "@/components/RACRouterProvider"
import RouteChange from "@/components/RouteChange"
import SitewideAlert from "@/components/SitewideAlert"

View File

@@ -8,6 +8,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import { SessionProvider } from "next-auth/react"
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
import { Lang } from "@scandic-hotels/common/constants/language"
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
@@ -16,7 +17,6 @@ import TrpcProvider from "@/lib/trpc/Provider"
import { SessionRefresher } from "@/components/Auth/TokenRefresher"
import CookieBotConsent from "@/components/CookieBot"
import StorageCleaner from "@/components/HotelReservation/EnterDetails/StorageCleaner"
import RouteChange from "@/components/RouteChange"
import AdobeSDKScript from "@/components/TrackingSDK/AdobeSDKScript"
import GTMScript from "@/components/TrackingSDK/GTMScript"

View File

@@ -7,6 +7,7 @@ import "@scandic-hotels/design-system/style.css"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
import Script from "next/script"
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
import { Lang } from "@scandic-hotels/common/constants/language"
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
@@ -15,7 +16,6 @@ import TrpcProvider from "@/lib/trpc/Provider"
import TokenRefresher from "@/components/Auth/TokenRefresher"
import CookieBotConsent from "@/components/CookieBot"
import StorageCleaner from "@/components/HotelReservation/EnterDetails/StorageCleaner"
import RouteChange from "@/components/RouteChange"
import AdobeSDKScript from "@/components/TrackingSDK/AdobeSDKScript"
import GTMScript from "@/components/TrackingSDK/GTMScript"

View File

@@ -1,9 +1,9 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
export default async function Tracking() {

View File

@@ -2,11 +2,22 @@
import { BookingFlowContextProvider } from "@scandic-hotels/booking-flow/BookingFlowContextProvider"
import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
import { useIsUserLoggedIn } from "@/hooks/useIsUserLoggedIn"
import { trackAccordionClick, trackOpenSidePeekEvent } from "@/utils/tracking"
import { trackBookingSearchClick } from "@/utils/tracking/booking"
import {
trackAccordionClick,
trackLoginClick,
trackOpenSidePeekEvent,
trackPaymentEvent,
trackUpdatePaymentMethod,
} from "@/utils/tracking"
import {
trackBedSelection,
trackBookingSearchClick,
trackBreakfastSelection,
} from "@/utils/tracking/booking"
import { trackGlaSaveCardAttempt } from "@/utils/tracking/myStay"
import type { ReactNode } from "react"
@@ -21,6 +32,12 @@ export function BookingFlowProviders({ children }: { children: ReactNode }) {
trackAccordionItemOpen: trackAccordionClick,
trackOpenSidePeek: trackOpenSidePeekEvent,
trackGenericEvent: trackEvent,
trackGlaSaveCardAttempt,
trackLoginClick,
trackPaymentEvent,
trackUpdatePaymentMethod,
trackBreakfastSelection,
trackBedSelection,
}}
>
{children}

View File

@@ -2,12 +2,12 @@ import { notFound } from "next/navigation"
import { Suspense } from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getCampaignOverviewPage } from "@/lib/trpc/memoizedRequests"
import TopCampaign from "@/components/ContentType/CampaignOverviewPage/TopCampaign"
import LinkChips from "@/components/TempDesignSystem/LinkChips"
import TrackingSDK from "@/components/TrackingSDK"
import Blocks from "./Blocks"
import CampaignOverviewPageSkeleton from "./CampaignOverviewPageSkeleton"

View File

@@ -3,11 +3,10 @@ import { notFound } from "next/navigation"
import { Suspense } from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getCampaignPage } from "@/lib/trpc/memoizedRequests"
import TrackingSDK from "@/components/TrackingSDK"
import Blocks from "./Blocks"
import CampaignPageSkeleton from "./CampaignPageSkeleton"
import CampaignHero from "./Hero"

View File

@@ -2,11 +2,11 @@ import { Suspense } from "react"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getDestinationOverviewPage } from "@/lib/trpc/memoizedRequests"
import Blocks from "@/components/Blocks"
import TrackingSDK from "@/components/TrackingSDK"
import { DestinationSearch } from "./DestinationSearch"
import HotelsSection from "./HotelsSection"

View File

@@ -3,10 +3,11 @@
import { useSearchParams } from "next/navigation"
import { useEffect } from "react"
import TrackingSDK from "@/components/TrackingSDK"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { trackOpenMapView } from "@/utils/tracking/destinationPage"
import type { TrackingSDKPageData } from "@scandic-hotels/common/tracking/types"
import type { TrackingSDKPageData } from "@scandic-hotels/tracking/types"
interface DestinationTrackingProps {
pageData: TrackingSDKPageData

View File

@@ -5,6 +5,7 @@ import { dt } from "@scandic-hotels/common/dt"
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
import { Alert } from "@scandic-hotels/design-system/Alert"
import Link from "@scandic-hotels/design-system/Link"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import {
getHotel,
@@ -16,7 +17,6 @@ import AccordionSection from "@/components/Blocks/Accordion"
import Breadcrumbs from "@/components/Breadcrumbs"
import HotelCampaigns from "@/components/ContentType/HotelPage/Campaigns"
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
import TrackingSDK from "@/components/TrackingSDK"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { setFacilityCards } from "@/utils/facilityCards"

View File

@@ -3,7 +3,7 @@ import {
TrackingChannelEnum,
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
import { PointOfInterestGroupEnum } from "@scandic-hotels/trpc/enums/pointOfInterest"
import type { Lang } from "@scandic-hotels/common/constants/language"

View File

@@ -3,6 +3,7 @@ import { Suspense } from "react"
import Preamble from "@scandic-hotels/design-system/Preamble"
import Title from "@scandic-hotels/design-system/Title"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { serverClient } from "@/lib/trpc/server"
@@ -11,7 +12,6 @@ import Hero from "@/components/Hero"
import MaxWidth from "@/components/MaxWidth"
import Sidebar from "@/components/Sidebar"
import SidebarSkeleton from "@/components/Sidebar/SidebarSkeleton"
import TrackingSDK from "@/components/TrackingSDK"
import { isLoggedInUser } from "@/utils/isLoggedInUser"
import styles from "./loyaltyPage.module.css"

View File

@@ -1,13 +1,13 @@
import { FloatingBookingWidget } from "@scandic-hotels/booking-flow/BookingWidget/FloatingBookingWidget"
import Image from "@scandic-hotels/design-system/Image"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { BlocksEnums } from "@scandic-hotels/trpc/types/blocksEnum"
import { getStartPage } from "@/lib/trpc/memoizedRequests"
import Blocks from "@/components/Blocks"
import FullWidthCampaign from "@/components/Blocks/FullWidthCampaign"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
import styles from "./startPage.module.css"

View File

@@ -2,6 +2,7 @@ import { Suspense } from "react"
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import Blocks from "@/components/Blocks"
import HeaderDynamicContent from "@/components/Headers/DynamicContent"
@@ -10,7 +11,6 @@ import MeetingPackageWidget from "@/components/MeetingPackageWidget"
import Sidebar from "@/components/Sidebar"
import SidebarSkeleton from "@/components/Sidebar/SidebarSkeleton"
import LinkChips from "@/components/TempDesignSystem/LinkChips"
import TrackingSDK from "@/components/TrackingSDK"
import { staticPageVariants } from "./variants"

View File

@@ -1,4 +1,4 @@
import type { TrackingSDKPageData } from "@scandic-hotels/common/tracking/types"
import type { TrackingSDKPageData } from "@scandic-hotels/tracking/types"
import type { CollectionPage } from "@scandic-hotels/trpc/types/collectionPage"
import type { ContentPage } from "@scandic-hotels/trpc/types/contentPage"
import type { VariantProps } from "class-variance-authority"

View File

@@ -4,9 +4,10 @@
import { usePathname } from "next/navigation"
import { useIntl } from "react-intl"
import { findMyBookingCurrentWebPath } from "@scandic-hotels/common/constants/routes/findMyBooking"
import { findMyBookingCurrentWebPath } from "@scandic-hotels/common/constants/routes/findMyBookingRoutes"
import { logout } from "@scandic-hotels/common/constants/routes/handleAuth"
import { myPages } from "@scandic-hotels/common/constants/routes/myPages"
import { useLazyPathname } from "@scandic-hotels/common/hooks/useLazyPathname"
import { getCurrentWebUrl } from "@scandic-hotels/common/utils/url"
import Image from "@scandic-hotels/design-system/Image"
import Link from "@scandic-hotels/design-system/Link"
@@ -18,7 +19,6 @@ import useDropdownStore from "@/stores/main-menu"
import Avatar from "@/components/MyPages/Avatar"
import useLang from "@/hooks/useLang"
import { useLazyPathname } from "@/hooks/useLazyPathname"
import { trackClick, trackLoginClick } from "@/utils/tracking"
import BookingButton from "../BookingButton"
@@ -152,7 +152,7 @@ export function MainMenu({
<li className={styles.mobileLinkRow}>
<LoginButton
lang={lang}
pathName={loginPathname}
redirectTo={loginPathname}
trackingId="loginStartHamburgerMenu"
className={styles.mobileLinkButton}
onClick={() => {

View File

@@ -75,7 +75,7 @@ export default async function TopMenu({
) : (
<LoginButton
lang={lang}
pathName={pathname}
redirectTo={pathname}
trackingId="loginStartTopMenu"
className={`${styles.sessionLink} ${styles.loginLink}`}
size="small"
@@ -112,7 +112,7 @@ export async function TopMenuSkeleton() {
<li className={styles.sessionContainer}>
<LoginButton
lang={lang}
pathName={pathname}
redirectTo={pathname}
trackingId="loginStartTopMenu"
className={`${styles.sessionLink} ${styles.loginLink}`}
size="small"

View File

@@ -9,7 +9,7 @@ import type {
SiteSectionObject,
TrackingData,
TrackingProps,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
function createPageObject(trackingData: TrackingData) {
const englishSegments = trackingData.englishUrl

View File

@@ -7,6 +7,7 @@ import { useIntl } from "react-intl"
import { logout } from "@scandic-hotels/common/constants/routes/handleAuth"
import { profile } from "@scandic-hotels/common/constants/routes/myPages"
import { usePhoneNumberParsing } from "@scandic-hotels/common/hooks/usePhoneNumberParsing"
import { logger } from "@scandic-hotels/common/logger"
import {
formatPhoneNumber,
@@ -21,7 +22,6 @@ import { langToApiLang } from "@scandic-hotels/trpc/constants/apiLang"
import { editProfile } from "@/actions/editProfile"
import Dialog from "@/components/Dialog"
import ChangeNameDisclaimer from "@/components/MyPages/Profile/ChangeNameDisclaimer"
import usePhoneNumberParsing from "@/hooks/usePhoneNumberParsing"
import FormContent from "./FormContent"
import { type EditProfileSchema, editProfileSchema } from "./schema"

View File

@@ -6,8 +6,9 @@ import { useRouter } from "next/navigation"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { membershipTermsAndConditions } from "@scandic-hotels/common/constants/routes/membershipTermsAndConditions"
import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes"
import { logger } from "@scandic-hotels/common/logger"
import { useFormTracking } from "@scandic-hotels/common/tracking/useFormTracking"
import {
formatPhoneNumber,
getDefaultCountryFromLang,
@@ -20,6 +21,7 @@ import Phone from "@scandic-hotels/design-system/Form/Phone"
import Link from "@scandic-hotels/design-system/Link"
import { toast } from "@scandic-hotels/design-system/Toast"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useFormTracking } from "@scandic-hotels/tracking/useFormTracking"
import { trpc } from "@scandic-hotels/trpc/client"
import {
signupErrors,
@@ -27,11 +29,6 @@ import {
signUpSchema,
} from "@scandic-hotels/trpc/routers/user/schemas"
import {
membershipTermsAndConditions,
privacyPolicy,
} from "@/constants/webHrefs"
import Input from "@/components/TempDesignSystem/Form/Input"
import PasswordInput from "@/components/TempDesignSystem/Form/PasswordInput"
import useLang from "@/hooks/useLang"
@@ -290,7 +287,7 @@ export default function SignupForm({ title }: SignUpFormProps) {
textDecoration="underline"
color="Text/Interactive/Secondary"
target="_blank"
href={privacyPolicy[lang]}
href={privacyPolicyRoutes[lang]}
>
{str}
</Link>

View File

@@ -5,10 +5,10 @@ import { Dialog, Modal } from "react-aria-components"
import { useIntl } from "react-intl"
import { useMediaQuery } from "usehooks-ts"
import { findMyBooking } from "@scandic-hotels/common/constants/routes/findMyBooking"
import { customerService } from "@scandic-hotels/common/constants/routes/customerService"
import { findMyBookingRoutes } from "@scandic-hotels/common/constants/routes/findMyBookingRoutes"
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
import { customerService } from "@/constants/webHrefs"
import useDropdownStore from "@/stores/main-menu"
import LanguageSwitcher from "@/components/LanguageSwitcher"
@@ -71,7 +71,7 @@ export default function MobileMenu({
defaultMessage: "Open menu",
})
const findMyBookingUrl = findMyBooking[lang]
const findMyBookingUrl = findMyBookingRoutes[lang]
return (
<>

View File

@@ -4,13 +4,13 @@ import { useSession } from "next-auth/react"
import { useIntl } from "react-intl"
import { MembershipLevelEnum } from "@scandic-hotels/common/constants/membershipLevels"
import { useLazyPathname } from "@scandic-hotels/common/hooks/useLazyPathname"
import { Avatar } from "@scandic-hotels/design-system/Avatar"
import { LoginButton } from "@scandic-hotels/design-system/LoginButton"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trpc } from "@scandic-hotels/trpc/client"
import useLang from "@/hooks/useLang"
import { useLazyPathname } from "@/hooks/useLazyPathname"
import { isValidClientSession } from "@/utils/clientSession"
import { trackLoginClick } from "@/utils/tracking"
@@ -73,7 +73,7 @@ export default function MyPagesMenuWrapper() {
onClick={() => {
trackLoginClick("top menu")
}}
pathName={loginPathname}
redirectTo={loginPathname}
trackingId="loginStartNewTopMenu"
>
<Avatar />

View File

@@ -1,4 +1,4 @@
import { findMyBooking } from "@scandic-hotels/common/constants/routes/findMyBooking"
import { findMyBookingRoutes } from "@scandic-hotels/common/constants/routes/findMyBookingRoutes"
import { IconName } from "@scandic-hotels/design-system/Icons/iconName"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
@@ -26,7 +26,7 @@ export default async function TopMenu() {
}
const lang = await getLang()
const findMyBookingUrl = findMyBooking[lang]
const findMyBookingUrl = findMyBookingRoutes[lang]
return (
<div className={styles.topMenu}>

View File

@@ -2,13 +2,13 @@
import { useEffect, useState } from "react"
import { clearPaymentInfoSessionStorage } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/helpers"
import { useSearchHistory } from "@scandic-hotels/booking-flow/hooks/useSearchHistory"
import { useBookingConfirmationStore } from "@scandic-hotels/booking-flow/stores/booking-confirmation"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import TrackingSDK from "@/components/TrackingSDK"
import useLang from "@/hooks/useLang"
import { clearPaymentInfoSessionStorage } from "../../EnterDetails/Payment/helpers"
import { getTracking } from "./tracking"
import type { Room } from "@scandic-hotels/booking-flow/types/stores/booking-confirmation"

View File

@@ -1,7 +1,9 @@
import { createHash } from "crypto"
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { readPaymentInfoFromSessionStorage } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/helpers"
import { invertedBedTypeMap } from "@scandic-hotels/booking-flow/utils/SelectRate"
import { getSpecialRoomType } from "@scandic-hotels/booking-flow/utils/specialRoomType"
import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { RateEnum } from "@scandic-hotels/common/constants/rate"
@@ -11,13 +13,10 @@ import {
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
type TrackingSDKPaymentInfo,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import { readPaymentInfoFromSessionStorage } from "@/components/HotelReservation/EnterDetails/Payment/helpers"
import { getSpecialRoomType } from "@/utils/specialRoomType"
import type { Room } from "@scandic-hotels/booking-flow/types/stores/booking-confirmation"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"

View File

@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { customerService } from "@scandic-hotels/common/constants/routes/customerService"
import { myStay } from "@scandic-hotels/common/constants/routes/myStay"
import { logger } from "@scandic-hotels/common/logger"
import Body from "@scandic-hotels/design-system/Body"
@@ -15,8 +16,6 @@ import Title from "@scandic-hotels/design-system/Title"
import { toast } from "@scandic-hotels/design-system/Toast"
import { trpc } from "@scandic-hotels/trpc/client"
import { customerService } from "@/constants/webHrefs"
import Input from "@/components/TempDesignSystem/Form/Input"
import useLang from "@/hooks/useLang"

View File

@@ -3,6 +3,8 @@ import { useIntl } from "react-intl"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes"
import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes"
import { dt } from "@scandic-hotels/common/dt"
import { Alert } from "@scandic-hotels/design-system/Alert"
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
@@ -13,7 +15,6 @@ import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Link from "@scandic-hotels/design-system/Link"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { bookingTermsAndConditions, privacyPolicy } from "@/constants/webHrefs"
import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow"
import useLang from "@/hooks/useLang"
@@ -182,7 +183,7 @@ export default function ConfirmationStep({
textDecoration="underline"
color="Text/Interactive/Secondary"
target="_blank"
href={bookingTermsAndConditions[lang]}
href={bookingTermsAndConditionsRoutes[lang]}
>
{str}
</Link>
@@ -192,7 +193,7 @@ export default function ConfirmationStep({
textDecoration="underline"
color="Text/Interactive/Secondary"
target="_blank"
href={privacyPolicy[lang]}
href={privacyPolicyRoutes[lang]}
>
{str}
</Link>

View File

@@ -1,9 +1,9 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
import TrackingSDK from "@/components/TrackingSDK"
import { getLang } from "@/i18n/serverContext"
export default async function Tracking() {

View File

@@ -3,8 +3,11 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { writeGlaToSessionStorage } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/PaymentCallback/helpers"
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes"
import { guaranteeCallback } from "@scandic-hotels/common/constants/routes/hotelReservation"
import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import { Divider } from "@scandic-hotels/design-system/Divider"
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
@@ -16,11 +19,9 @@ import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner"
import { toast } from "@scandic-hotels/design-system/Toast"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { bookingTermsAndConditions, privacyPolicy } from "@/constants/webHrefs"
import { env } from "@/env/client"
import { useMyStayStore } from "@/stores/my-stay"
import { writeGlaToSessionStorage } from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers"
import { useGuaranteeBooking } from "@/hooks/booking/useGuaranteeBooking"
import useLang from "@/hooks/useLang"
import { trackUpdatePaymentMethod } from "@/utils/tracking"
@@ -72,7 +73,11 @@ export default function Form() {
const savedCreditCard = savedCreditCards?.find(
(card) => card.id === data.paymentMethod
)
trackGlaSaveCardAttempt(hotelId, savedCreditCard, "yes")
trackGlaSaveCardAttempt({
hotelId,
hasSavedCreditCard: !!savedCreditCard,
lateArrivalGuarantee: "yes",
})
if (confirmationNumber) {
const card = savedCreditCard
? {
@@ -117,7 +122,7 @@ export default function Form() {
textDecoration="underline"
color="Text/Interactive/Secondary"
target="_blank"
href={bookingTermsAndConditions[lang]}
href={bookingTermsAndConditionsRoutes[lang]}
onClick={(e) => e.stopPropagation()}
>
{str}
@@ -128,7 +133,7 @@ export default function Form() {
textDecoration="underline"
color="Text/Interactive/Secondary"
target="_blank"
href={privacyPolicy[lang]}
href={privacyPolicyRoutes[lang]}
onClick={(e) => e.stopPropagation()}
>
{str}

View File

@@ -1,6 +1,6 @@
import { useIntl } from "react-intl"
import { getFeatureDescription } from "@scandic-hotels/booking-flow/utils/getRoomFeatureDescription"
import { getRoomFeatureDescription } from "@scandic-hotels/booking-flow/utils/getRoomFeatureDescription"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import { useMyStayStore } from "@/stores/my-stay"
@@ -19,7 +19,7 @@ export default function Packages() {
)
)
.map((item) =>
getFeatureDescription(item.code, item.description, intl)
getRoomFeatureDescription(item.code, item.description, intl)
) || []
)

View File

@@ -3,14 +3,14 @@
import { useRouter } from "next/navigation"
import { useEffect } from "react"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/booking"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner"
import {
clearGlaSessionStorage,
readGlaFromSessionStorage,
} from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/helpers"
} from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/PaymentCallback/helpers"
import { PaymentCallbackStatusEnum } from "@scandic-hotels/common/constants/paymentCallbackStatusEnum"
import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner"
import { trackEvent } from "@scandic-hotels/tracking/base"
import { getAncillarySessionData } from "@/components/HotelReservation/MyStay/utils/ancillaries"
import {
buildAncillariesTracking,

View File

@@ -6,6 +6,7 @@ import React, { useState } from "react"
import { Dialog, Modal, ModalOverlay } from "react-aria-components"
import { useIntl } from "react-intl"
import { customerService } from "@scandic-hotels/common/constants/routes/customerService"
import { benefits } from "@scandic-hotels/common/constants/routes/myPages"
import { logger } from "@scandic-hotels/common/logger"
import Link from "@scandic-hotels/design-system/Link"
@@ -17,7 +18,6 @@ import {
benefits as webviewBenefits,
myPagesWebviews,
} from "@/constants/routes/webviews"
import { customerService } from "@/constants/webHrefs"
import useLang from "@/hooks/useLang"

View File

@@ -1,6 +1,6 @@
import { useIntl } from "react-intl"
import { getFeatureDescription } from "@scandic-hotels/booking-flow/utils/getRoomFeatureDescription"
import { getRoomFeatureDescription } from "@scandic-hotels/booking-flow/utils/getRoomFeatureDescription"
import { sumPackages } from "@scandic-hotels/booking-flow/utils/SelectRate"
import { changeOrCancelDateFormat } from "@scandic-hotels/common/constants/dateFormats"
import { dt } from "@scandic-hotels/common/dt"
@@ -25,13 +25,13 @@ import RoomDetails from "./RoomDetails"
import styles from "./bookedRoomSidePeek.module.css"
import type { BedTypeSchema } from "@scandic-hotels/booking-flow/stores/enter-details/types"
import type { BreakfastPackage } from "@scandic-hotels/trpc/routers/hotels/schemas/packages"
import type { BookingConfirmationSchema } from "@scandic-hotels/trpc/types/bookingConfirmation"
import type { Child } from "@scandic-hotels/trpc/types/child"
import type { Room as HotelRoom } from "@scandic-hotels/trpc/types/hotel"
import type { Packages } from "@scandic-hotels/trpc/types/packages"
import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
import type { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
import type { SafeUser } from "@/types/user"
@@ -353,7 +353,7 @@ export default function BookedRoomSidePeek({
)
)
.map((item) =>
getFeatureDescription(
getRoomFeatureDescription(
item.code,
item.description,
intl

View File

@@ -2,12 +2,12 @@
import { useIntl } from "react-intl"
import { useLazyPathname } from "@scandic-hotels/common/hooks/useLazyPathname"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { LoginButton } from "@scandic-hotels/design-system/LoginButton"
import { Typography } from "@scandic-hotels/design-system/Typography"
import useLang from "@/hooks/useLang"
import { useLazyPathname } from "@/hooks/useLazyPathname"
import { trackLoginClick } from "@/utils/tracking"
export function LoyaltyLoginButton() {
@@ -21,7 +21,7 @@ export function LoyaltyLoginButton() {
onClick={() => {
trackLoginClick("join scandic friends sidebar")
}}
pathName={loginPathname}
redirectTo={loginPathname}
trackingId="loginJoinLoyalty"
>
<MaterialIcon icon="arrow_forward" color="CurrentColor" size={20} />

View File

@@ -1,8 +1,9 @@
import { membershipTermsAndConditions } from "@scandic-hotels/common/constants/routes/membershipTermsAndConditions"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Link from "@scandic-hotels/design-system/Link"
import Subtitle from "@scandic-hotels/design-system/Subtitle"
import { faq, membershipTermsAndConditions } from "@/constants/webHrefs"
import { faq } from "@/constants/webHrefs"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"

View File

@@ -1,55 +0,0 @@
"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

@@ -1,9 +1,10 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { overview } from "@/constants/routes/webviews"
import { serverClient } from "@/lib/trpc/server"
import MaxWidth from "@/components/MaxWidth"
import Surprises from "@/components/MyPages/Surprises"
import TrackingSDK from "@/components/TrackingSDK"
import Blocks from "@/components/Webviews/AccountPage/Blocks"
import LinkToOverview from "@/components/Webviews/LinkToOverview"
import { getLang } from "@/i18n/serverContext"

View File

@@ -1,9 +1,9 @@
import Title from "@scandic-hotels/design-system/Title"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { serverClient } from "@/lib/trpc/server"
import MaxWidth from "@/components/MaxWidth"
import TrackingSDK from "@/components/TrackingSDK"
import LinkToOverview from "@/components/Webviews/LinkToOverview"
import Blocks from "./Blocks"

View File

@@ -2,24 +2,6 @@ import { Lang } from "@scandic-hotels/common/constants/language"
import type { LangRoute } from "@scandic-hotels/common/constants/routes/langRoute"
export const bookingTermsAndConditions: LangRoute = {
da: `/${Lang.da}/kundeservice/politikker/bookingsvilkar`,
de: `/${Lang.de}/kundenbetreuung/richtlinien/reservierungsbedingungen`,
en: `/${Lang.en}/customer-service/policies/booking-terms`,
fi: `/${Lang.fi}/asiakaspalvelu/ehdot/varausehdot`,
no: `/${Lang.no}/kundeservice/betingelser/reservasjonsbetingelser`,
sv: `/${Lang.sv}/kundservice/villkor/bokningsvillkor`,
}
export const membershipTermsAndConditions: LangRoute = {
da: `/${Lang.da}/kundeservice/politikker/scandic-friends-betingelser`,
de: `/${Lang.de}/kundenbetreuung/richtlinien/scandic-friends-allgemeine-geschaeftsbedingungen`,
en: `/${Lang.en}/customer-service/policies/scandic-friends`,
fi: `/${Lang.fi}/asiakaspalvelu/ehdot/scandic-friends`,
no: `/${Lang.no}/kundeservice/betingelser/scandic-friends-betingelser`,
sv: `/${Lang.sv}/kundservice/villkor/scandic-friends`,
}
export const sasPartnershipTermsAndConditions: LangRoute = {
da: `/${Lang.da}/kundeservice/politikker/scandic-friends-betingelser/sas-eurobonus`,
de: `/${Lang.de}/kundenbetreuung/richtlinien/scandic-friends-allgemeine-geschaeftsbedingungen/sas-eurobonus`,
@@ -46,21 +28,3 @@ export const partners: LangRoute = {
no: `/${Lang.no}/scandic-friends/partnere`,
sv: `/${Lang.sv}/scandic-friends/partners`,
}
export const privacyPolicy: LangRoute = {
da: `/${Lang.da}/kundeservice/politikker/privatliv`,
de: `/${Lang.de}/kundenbetreuung/richtlinien/datenschutz`,
en: `/${Lang.en}/customer-service/policies/privacy`,
fi: `/${Lang.fi}/asiakaspalvelu/ehdot/tietosuojaseloste`,
no: `/${Lang.no}/kundeservice/personvernpolicy`,
sv: `/${Lang.sv}/kundservice/villkor/integritetspolicy`,
}
export const customerService: LangRoute = {
da: `/${Lang.da}/kundeservice`,
de: `/${Lang.de}/kundenbetreuung`,
en: `/${Lang.en}/customer-service`,
fi: `/${Lang.fi}/asiakaspalvelu`,
no: `/${Lang.no}/kundeservice`,
sv: `/${Lang.sv}/kundservice`,
}

View File

@@ -1,5 +0,0 @@
import { createContext } from "react"
import type { DetailsStore } from "@/types/contexts/enter-details"
export const DetailsContext = createContext<DetailsStore | null>(null)

View File

@@ -1,13 +0,0 @@
import { createContext, useContext } from "react"
import type { RoomContextValue } from "@/types/contexts/details/room"
export const RoomContext = createContext<RoomContextValue | null>(null)
export function useRoomContext() {
const ctx = useContext(RoomContext)
if (!ctx) {
throw new Error("Missing context value [RoomContext]")
}
return ctx
}

View File

@@ -2,13 +2,12 @@ import { useRouter } from "next/navigation"
import { useCallback, useEffect, useState } from "react"
import { useIntl } from "react-intl"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { useHandleBookingStatus } from "@scandic-hotels/booking-flow/hooks/useHandleBookingStatus"
import { toast } from "@scandic-hotels/design-system/Toast"
import { trackEvent } from "@scandic-hotels/tracking/base"
import { trpc } from "@scandic-hotels/trpc/client"
import { BookingStatusEnum } from "@scandic-hotels/trpc/enums/bookingStatus"
import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
const maxRetries = 15
const retryInterval = 2000

View File

@@ -12,7 +12,6 @@ import type { Country } from "@scandic-hotels/trpc/types/country"
import type { HotelInput } from "@scandic-hotels/trpc/types/hotel"
import type {
AncillaryPackagesInput,
BreackfastPackagesInput,
PackagesInput,
} from "@scandic-hotels/trpc/types/packages"
@@ -123,13 +122,6 @@ export const getSiteConfig = cache(async function getMemoizedSiteConfig(
return caller.contentstack.base.siteConfig({ lang })
})
export const getBreakfastPackages = cache(
async function getMemoizedBreakfastPackages(input: BreackfastPackagesInput) {
const caller = await serverClient()
return caller.hotel.packages.breakfast(input)
}
)
export const getAncillaryPackages = cache(
async function getMemoizedAncillaryPackages(input: AncillaryPackagesInput) {
const caller = await serverClient()

View File

@@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url"
import * as Sentry from "@sentry/nextjs"
import createJiti from "jiti"
import { findMyBooking } from "@scandic-hotels/common/constants/routes/findMyBooking"
import { findMyBookingRoutes } from "@scandic-hotels/common/constants/routes/findMyBookingRoutes"
import {
login,
logout,
@@ -313,27 +313,27 @@ const nextConfig = {
},
// Find my booking
{
source: findMyBooking.en,
source: findMyBookingRoutes.en,
destination: "/en/hotelreservation/get-booking",
},
{
source: findMyBooking.da,
source: findMyBookingRoutes.da,
destination: "/da/hotelreservation/get-booking",
},
{
source: findMyBooking.de,
source: findMyBookingRoutes.de,
destination: "/de/hotelreservation/get-booking",
},
{
source: findMyBooking.fi,
source: findMyBookingRoutes.fi,
destination: "/fi/hotelreservation/get-booking",
},
{
source: findMyBooking.no,
source: findMyBookingRoutes.no,
destination: "/no/hotelreservation/get-booking",
},
{
source: findMyBooking.sv,
source: findMyBookingRoutes.sv,
destination: "/sv/hotelreservation/get-booking",
},
// My stay

View File

@@ -41,6 +41,7 @@
"@scandic-hotels/booking-flow": "workspace:*",
"@scandic-hotels/common": "workspace:*",
"@scandic-hotels/design-system": "workspace:*",
"@scandic-hotels/tracking": "workspace:*",
"@scandic-hotels/trpc": "workspace:*",
"@sentry/nextjs": "^8.41.0",
"@swc/plugin-formatjs": "^3.2.2",

View File

@@ -1,33 +0,0 @@
"use client"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { RoomContext } from "@/contexts/Details/Room"
import type { RoomProviderProps } from "@/types/providers/details/room"
export default function RoomProvider({ children, idx }: RoomProviderProps) {
const { actions, isComplete, room, steps } = useEnterDetailsStore(
(state) => ({
actions: state.rooms[idx].actions,
isComplete: state.rooms[idx].isComplete,
room: state.rooms[idx].room,
steps: state.rooms[idx].steps,
})
)
return (
<RoomContext.Provider
value={{
actions,
idx,
isComplete,
room,
roomNr: idx + 1,
steps,
}}
>
{children}
</RoomContext.Provider>
)
}

View File

@@ -1,6 +0,0 @@
import type { z } from "zod"
import type { breakfastFormSchema } from "@/components/HotelReservation/EnterDetails/Breakfast/schema"
export interface BreakfastFormSchema
extends z.output<typeof breakfastFormSchema> {}

View File

@@ -1,14 +1,3 @@
import type { z } from "zod"
import type { bedTypeFormSchema } from "@/components/HotelReservation/EnterDetails/BedType/schema"
export interface BedTypeFormSchema extends z.output<typeof bedTypeFormSchema> {}
export type BedTypeSchema = {
description: string
type: string
roomTypeCode: string
}
export type BedTypeInfoProps = {
hasMultipleBedTypes: boolean
}

View File

@@ -1,38 +1,15 @@
import type { BookingSearchType } from "@scandic-hotels/booking-flow/searchType"
import type { productTypePointsSchema } from "@scandic-hotels/trpc/routers/hotels/schemas/productTypePrice"
import type { Child } from "@scandic-hotels/trpc/types/child"
import type { PackageEnum } from "@scandic-hotels/trpc/types/packages"
import type { Product } from "@scandic-hotels/trpc/types/roomAvailability"
import type { z } from "zod"
import type { SafeUser } from "@/types/user"
import type { getMultiroomDetailsSchema } from "@/components/HotelReservation/EnterDetails/Details/Multiroom/schema"
import type {
guestDetailsSchema,
signedInDetailsSchema,
} from "@/components/HotelReservation/EnterDetails/Details/RoomOne/schema"
import type { Price } from "../price"
export type DetailsSchema = z.output<typeof guestDetailsSchema>
export type MultiroomDetailsSchema = z.output<
ReturnType<typeof getMultiroomDetailsSchema>
>
export type SignedInDetailsSchema = z.output<typeof signedInDetailsSchema>
export type ProductTypePointsSchema = z.output<typeof productTypePointsSchema>
export interface RoomPrice {
perNight: Price
perStay: Price
}
export interface DetailsProps {
user: SafeUser
}
export type JoinScandicFriendsCardProps = {
name?: string
}
export type RoomRate = Product
export type DetailsBooking = {

View File

@@ -1,5 +0,0 @@
import type { HotelData } from "@scandic-hotels/trpc/types/hotel"
export interface HotelHeaderProps {
hotelData: HotelData & { url: string | null }
}

View File

@@ -1,23 +0,0 @@
import type { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
import type { CreditCard } from "@scandic-hotels/trpc/types/user"
export interface PaymentProps {
otherPaymentOptions: PaymentMethodEnum[]
supportedCards: PaymentMethodEnum[]
}
export interface PaymentClientProps
extends Omit<PaymentProps, "supportedCards"> {
savedCreditCards: CreditCard[] | null
isUserLoggedIn: boolean
}
export type PriceChangeData = Array<{
roomPrice: number
totalPrice: number
packagePrice?: number
} | null>
export interface TermsAndConditionsProps {
isFlexBookingTerms: boolean
}

View File

@@ -1,9 +0,0 @@
import type { StepEnum } from "@/types/enums/step"
export interface SectionProps {
header: string
label: string
additionalInfo?: string | null
step: StepEnum
disabled?: boolean
}

View File

@@ -1,14 +1,8 @@
import type { SelectRateBooking } from "@scandic-hotels/booking-flow/types/components/selectRate/selectRate"
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import type { Child } from "@scandic-hotels/trpc/types/child"
import type { Packages } from "@scandic-hotels/trpc/types/packages"
import type { RoomState } from "@/types/stores/enter-details"
import type {
DetailsBooking,
RoomPrice,
RoomRate,
} from "./enterDetails/details"
import type { RoomPrice, RoomRate } from "./enterDetails/details"
import type { Price } from "./price"
export type RoomsData = {
@@ -21,20 +15,6 @@ export type RoomsData = {
packages: Packages | null
}
export interface SummaryProps {
isUserLoggedIn: boolean
}
export interface EnterDetailsSummaryProps {
booking: DetailsBooking
isUserLoggedIn: boolean
totalPrice: Price
vat: number
rooms: RoomState[]
toggleSummaryOpen: () => void
defaultCurrency: CurrencyEnum
}
export interface SelectRateSummaryProps {
booking: SelectRateBooking
isMember: boolean

View File

@@ -1,10 +0,0 @@
import type { RoomState } from "@/types/stores/enter-details"
export interface RoomContextValue {
actions: RoomState["actions"]
isComplete: RoomState["isComplete"]
idx: number
room: RoomState["room"]
roomNr: number
steps: RoomState["steps"]
}

View File

@@ -1,3 +0,0 @@
import type { createDetailsStore } from "@/stores/enter-details"
export type DetailsStore = ReturnType<typeof createDetailsStore>

View File

@@ -1,6 +0,0 @@
import type { Room } from "@scandic-hotels/trpc/types/room"
export interface RoomProviderProps extends React.PropsWithChildren {
idx: number
room: Room
}

View File

@@ -5,14 +5,3 @@ import type { Room } from "@scandic-hotels/trpc/types/room"
import type { SafeUser } from "@/types/user"
import type { DetailsBooking } from "../components/hotelReservation/enterDetails/details"
export interface DetailsProviderProps extends React.PropsWithChildren {
booking: DetailsBooking
breakfastPackages: BreakfastPackages
lang: Lang
rooms: Room[]
searchParamsStr: string
user: SafeUser
vat: number
roomCategories: RoomCategories
}

View File

@@ -1,3 +1,4 @@
import type { BedTypeSchema } from "@scandic-hotels/booking-flow/stores/enter-details/types"
import type { BreakfastPackage } from "@scandic-hotels/trpc/routers/hotels/schemas/packages"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
import type { Child } from "@scandic-hotels/trpc/types/child"
@@ -9,7 +10,6 @@ import type {
import type { CreditCard } from "@scandic-hotels/trpc/types/user"
import type { IntlShape } from "react-intl"
import type { BedTypeSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
import type { RoomPrice } from "@/types/components/hotelReservation/enterDetails/details"
import type { PriceTypeEnum } from "@/types/components/hotelReservation/myStay/myStay"
import type { Packages } from "@/types/components/myPages/myStay/ancillaries"

View File

@@ -1,10 +1,12 @@
import {
multiroomErrors,
roomOneErrors,
} from "@scandic-hotels/booking-flow/components/EnterDetails/enterDetailsErrors"
import { logger } from "@scandic-hotels/common/logger"
import { phoneErrors } from "@scandic-hotels/common/utils/zod/phoneValidator"
import { signupErrors } from "@scandic-hotels/trpc/routers/user/schemas"
import { editProfileErrors } from "@/components/Forms/Edit/Profile/schema"
import { multiroomErrors } from "@/components/HotelReservation/EnterDetails/Details/Multiroom/schema"
import { roomOneErrors } from "@/components/HotelReservation/EnterDetails/Details/RoomOne/schema"
import { findMyBookingErrors } from "@/components/HotelReservation/FindMyBooking/schema"
import type { IntlShape } from "react-intl"

View File

@@ -1,8 +1,8 @@
"use client"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
import type { LowestRoomPriceEvent } from "@scandic-hotels/common/tracking/types"
import type { LowestRoomPriceEvent } from "@scandic-hotels/tracking/types"
import type { BreakfastPackages } from "@scandic-hotels/trpc/routers/hotels/output"
export function trackLowestRoomPrice(event: LowestRoomPriceEvent) {

View File

@@ -1,5 +1,5 @@
"use client"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
export function trackAccordionClick(option: string) {
trackEvent({

View File

@@ -1,4 +1,4 @@
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
export function trackSortingChangeEvent(sortOption: string) {
trackEvent({

View File

@@ -1,4 +1,4 @@
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
export function trackHotelMapClick() {
trackEvent({

View File

@@ -12,9 +12,9 @@ export {
trackSocialMediaClick,
} from "./navigation"
export { trackPaymentEvent, trackUpdatePaymentMethod } from "./payment"
export { trackClick } from "@scandic-hotels/common/tracking/base"
export { trackClick } from "@scandic-hotels/tracking/base"
export {
createSDKPageObject,
trackPageView,
trackPageViewStart,
} from "@scandic-hotels/common/tracking/pageview"
} from "@scandic-hotels/tracking/pageview"

View File

@@ -1,5 +1,5 @@
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import type { PackageSchema } from "@scandic-hotels/trpc/types/bookingConfirmation"
@@ -35,13 +35,17 @@ export function trackMyStayPageLink(ctaName: string) {
})
}
type LateArrivalGuarantee = "mandatory" | "yes" | "no" | "na"
export function trackGlaSaveCardAttempt(
hotelId: string,
savedCreditCard: CreditCard | undefined,
lateArrivalGuarantee: LateArrivalGuarantee
) {
export function trackGlaSaveCardAttempt({
hotelId,
hasSavedCreditCard,
creditCardType,
lateArrivalGuarantee,
}: {
hotelId: string
hasSavedCreditCard: boolean
creditCardType?: string
lateArrivalGuarantee: "mandatory" | "yes" | "no" | "na"
}) {
trackEvent({
event: "glaCardSaveAttempt",
hotelInfo: {
@@ -51,8 +55,8 @@ export function trackGlaSaveCardAttempt(
},
paymentInfo: {
status: "glacardsaveattempt",
isSavedCreditCard: !!savedCreditCard,
type: savedCreditCard?.cardType,
isSavedCreditCard: hasSavedCreditCard,
type: creditCardType,
},
})
}

View File

@@ -1,6 +1,6 @@
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
import type { TrackingPosition } from "@scandic-hotels/common/tracking/types"
import type { TrackingPosition } from "@scandic-hotels/tracking/types"
export function trackFooterClick(group: string, name: string) {
trackEvent({

View File

@@ -1,9 +1,9 @@
import { trackEvent } from "@scandic-hotels/common/tracking/base"
import { trackEvent } from "@scandic-hotels/tracking/base"
import type {
PaymentEvent,
PaymentFailEvent,
} from "@scandic-hotels/common/tracking/types"
} from "@scandic-hotels/tracking/types"
function isPaymentFailEvent(event: PaymentEvent): event is PaymentFailEvent {
return "errorMessage" in event

21
packages/booking-flow/env/client.ts vendored Normal file
View File

@@ -0,0 +1,21 @@
import { createEnv } from "@t3-oss/env-nextjs"
import { z } from "zod"
export const env = createEnv({
client: {
NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]),
NEXT_PUBLIC_PORT: z.string().default("3000"),
// NEXT_PUBLIC_SENTRY_ENVIRONMENT: z.string().default("development"),
// NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE: z.coerce.number().default(0.001),
// NEXT_PUBLIC_PUBLIC_URL: z.string().optional(),
},
emptyStringAsUndefined: true,
runtimeEnv: {
NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV,
NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT,
// NEXT_PUBLIC_SENTRY_ENVIRONMENT: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT,
// NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE:
// process.env.NEXT_PUBLIC_SENTRY_CLIENT_SAMPLERATE,
// NEXT_PUBLIC_PUBLIC_URL: process.env.NEXT_PUBLIC_PUBLIC_URL,
},
})

View File

@@ -2,3 +2,9 @@ import "@scandic-hotels/common/global.d.ts"
import "@scandic-hotels/trpc/types.d.ts"
import "@scandic-hotels/trpc/auth.d.ts"
import "@scandic-hotels/trpc/jwt.d.ts"
declare global {
interface Window {
ApplePaySession: (() => void) | undefined
}
}

View File

@@ -13,7 +13,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
import { ChildBedTypeEnum } from "@scandic-hotels/trpc/enums/childBedTypeEnum"
import { useBookingConfirmationStore } from "../../../../stores/booking-confirmation"
import { getFeatureDescription } from "../../../../utils/getRoomFeatureDescription"
import { getRoomFeatureDescription } from "../../../../utils/getRoomFeatureDescription"
import Breakfast from "./Breakfast"
import RoomSkeletonLoader from "./RoomSkeletonLoader"
@@ -183,7 +183,7 @@ export function ReceiptRoom({
<div>
<Typography variant="Body/Paragraph/mdRegular">
<p className={styles.uiTextHighContrast}>
{getFeatureDescription(
{getRoomFeatureDescription(
feature.code,
feature.description,
intl

View File

@@ -4,26 +4,22 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { useCallback, useEffect, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { BED_TYPE_ICONS } from "@scandic-hotels/booking-flow/bedTypeIcons"
import RadioCard from "@scandic-hotels/design-system/Form/RadioCard"
import {
BedTypeEnum,
type ExtraBedTypeEnum,
} from "@scandic-hotels/trpc/enums/bedType"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { useRoomContext } from "@/contexts/Details/Room"
import { trackBedSelection } from "@/utils/tracking"
import { bedTypeFormSchema } from "./schema"
import { useRoomContext } from "../../../contexts/EnterDetails/RoomContext"
import { BED_TYPE_ICONS } from "../../../misc/bedTypeIcons"
import { useEnterDetailsStore } from "../../../stores/enter-details"
import { useTrackingContext } from "../../../trackingContext"
import { type BedTypeFormSchema, bedTypeFormSchema } from "./schema"
import styles from "./bedOptions.module.css"
import type { IconProps } from "@scandic-hotels/design-system/Icons"
import type { BedTypeFormSchema } from "@/types/components/hotelReservation/enterDetails/bedType"
export default function BedType() {
const availableBeds = useEnterDetailsStore((state) => state.availableBeds)
const {
@@ -33,6 +29,8 @@ export default function BedType() {
const initialBedType = bedType?.roomTypeCode
const [previousBedType, setPreviousBedType] = useState("")
const { trackBedSelection } = useTrackingContext()
const methods = useForm<BedTypeFormSchema>({
criteriaMode: "all",
mode: "all",
@@ -53,10 +51,11 @@ export default function BedType() {
type: matchingRoom.type,
}
updateBedType(bedType)
trackBedSelection(bedType.description)
}
},
[bedTypes, updateBedType]
[bedTypes, updateBedType, trackBedSelection]
)
const selectedBedType = methods.watch("bedType")

View File

@@ -1,5 +1,6 @@
import { z } from "zod"
export type BedTypeFormSchema = z.infer<typeof bedTypeFormSchema>
export const bedTypeFormSchema = z.object({
bedType: z.string(),
})

View File

@@ -12,17 +12,13 @@ import BreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/BreakfastBu
import NoBreakfastBuffetIcon from "@scandic-hotels/design-system/Icons/NoBreakfastBuffetIcon"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { useRoomContext } from "@/contexts/Details/Room"
import { trackBreakfastSelection } from "@/utils/tracking"
import { breakfastFormSchema } from "./schema"
import { useRoomContext } from "../../../contexts/EnterDetails/RoomContext"
import { useEnterDetailsStore } from "../../../stores/enter-details"
import { useTrackingContext } from "../../../trackingContext"
import { type BreakfastFormSchema, breakfastFormSchema } from "./schema"
import styles from "./breakfast.module.css"
import type { BreakfastFormSchema } from "@/types/components/hotelReservation/breakfast"
export default function Breakfast() {
const intl = useIntl()
const packages = useEnterDetailsStore((state) => state.breakfastPackages)
@@ -32,6 +28,8 @@ export default function Breakfast() {
room,
} = useRoomContext()
const { trackBreakfastSelection } = useTrackingContext()
const hasChildrenInRoom = !!room.childrenInRoom?.length
const totalPriceForNoBreakfast = 0
@@ -57,12 +55,14 @@ export default function Breakfast() {
} else {
updateBreakfast(false)
}
trackBreakfastSelection({
breakfastPackage: pkg ?? packages[0],
hotelId,
units: pkg ? room.adults : 0,
})
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[packages, hotelId, room.adults, updateBreakfast]
)

View File

@@ -1,5 +1,6 @@
import { z } from "zod"
export type BreakfastFormSchema = z.infer<typeof breakfastFormSchema>
export const breakfastFormSchema = z.object({
breakfast: z.string().or(z.literal("false")),
})

View File

@@ -19,7 +19,7 @@ import { SelectPaymentMethod } from "@scandic-hotels/design-system/Form/SelectPa
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { trackUpdatePaymentMethod } from "@/utils/tracking"
import { useTrackingContext } from "../../../../trackingContext"
import styles from "./guarantee.module.css"
@@ -32,6 +32,8 @@ interface GuaranteeProps {
export default function Guarantee({ savedCreditCards }: GuaranteeProps) {
const intl = useIntl()
const guarantee = useWatch({ name: "guarantee" })
const { trackUpdatePaymentMethod } = useTrackingContext()
return (
<div className={styles.guarantee}>
<Checkbox name="guarantee">
@@ -106,18 +108,19 @@ export default function Guarantee({ savedCreditCards }: GuaranteeProps) {
</Checkbox>
{savedCreditCards?.length && guarantee ? (
<SelectPaymentMethod
formName="paymentMethod"
onChange={(method) => trackUpdatePaymentMethod({ method })}
paymentMethods={savedCreditCards.map((x) => ({
...x,
cardType: x.cardType as PaymentMethodEnum,
paymentMethods={savedCreditCards.map((card) => ({
...card,
cardType: card.cardType as PaymentMethodEnum,
}))}
onChange={(method) => {
trackUpdatePaymentMethod({ method })
}}
formName={"paymentMethod"}
/>
) : null}
{guarantee ? (
<PaymentOptionsGroup
name="paymentMethod"
onChange={(method) => trackUpdatePaymentMethod({ method })}
label={
savedCreditCards?.length
? intl.formatMessage({

Some files were not shown because too many files have changed in this diff Show More