diff --git a/components/Current/Header/LoginButton.tsx b/components/Current/Header/LoginButton.tsx
index d74d63e80..7ddbe427f 100644
--- a/components/Current/Header/LoginButton.tsx
+++ b/components/Current/Header/LoginButton.tsx
@@ -1,6 +1,6 @@
"use client"
-import { PropsWithChildren, useEffect } from "react"
+import { PropsWithChildren } from "react"
import { login } from "@/constants/routes/handleAuth"
@@ -31,17 +31,6 @@ export default function LoginButton({
? `${login[lang]}?redirectTo=${encodeURIComponent(pathName)}`
: login[lang]
- useEffect(() => {
- document
- .getElementById(trackingId)
- ?.addEventListener("click", () => trackLoginClick(position))
- return () => {
- document
- .getElementById(trackingId)
- ?.removeEventListener("click", () => trackLoginClick(position))
- }
- }, [position, trackingId])
-
return (
trackLoginClick(position)}
>
{children}
diff --git a/components/TempDesignSystem/Link/index.tsx b/components/TempDesignSystem/Link/index.tsx
index 23cf15e46..e45d08954 100644
--- a/components/TempDesignSystem/Link/index.tsx
+++ b/components/TempDesignSystem/Link/index.tsx
@@ -4,6 +4,7 @@ import { usePathname, useRouter } from "next/navigation"
import { startTransition, useCallback } from "react"
import useRouterTransitionStore from "@/stores/router-transition"
+import useTrackingStore from "@/stores/tracking"
import { trackClick, trackPageViewStart } from "@/utils/tracking"
@@ -27,6 +28,7 @@ export default function Link({
...props
}: LinkProps) {
const currentPageSlug = usePathname()
+ const { setInitialPageLoadTime } = useTrackingStore()
let isActive = active || currentPageSlug === href
if (partialMatch && !isActive) {
@@ -72,6 +74,7 @@ export default function Link({
return
}
e.preventDefault()
+ setInitialPageLoadTime(Date.now())
trackPageViewStart()
startTransition(() => {
startRouterTransition()
diff --git a/components/TrackingSDK/Client.tsx b/components/TrackingSDK/Client.tsx
index 37933ba96..9239c9e70 100644
--- a/components/TrackingSDK/Client.tsx
+++ b/components/TrackingSDK/Client.tsx
@@ -1,7 +1,7 @@
"use client"
import { usePathname } from "next/navigation"
-import { useCallback, useEffect } from "react"
+import { useCallback, useEffect, useRef } from "react"
import { webviews } from "@/constants/routes/webviews"
import useTrackingStore from "@/stores/tracking"
@@ -10,11 +10,15 @@ import { createSDKPageObject } from "@/utils/tracking"
import { TrackingSDKProps } from "@/types/components/tracking"
-export default function TrackingSDK({ pageData, userData }: TrackingSDKProps) {
+export default function TrackingSDK({
+ pageData,
+ userData,
+ hotelInfo,
+}: TrackingSDKProps) {
const pathName = usePathname()
const isWebview = webviews.includes(pathName)
- const { hasRun, setHasRun } = useTrackingStore()
-
+ const { hasRun, setHasRun, getPageLoadTime } = useTrackingStore()
+ const hasRunLocal = useRef(false)
const CookiebotCallbackOnAccept = useCallback(() => {
const cookie = window._satellite.cookie.get("CookieConsent")
@@ -40,31 +44,36 @@ export default function TrackingSDK({ pageData, userData }: TrackingSDKProps) {
}
useEffect(() => {
- if (!hasRun) {
- const perfObserver = new PerformanceObserver((observedEntries) => {
- const entry = observedEntries.getEntriesByType("navigation")[0]
-
- if (entry && window.adobeDataLayer) {
- const trackingData = { ...pageData, pathName }
- const pageObject = createSDKPageObject(trackingData)
-
- window.adobeDataLayer.push({
- event: "pageView",
- pageInfo: pageObject,
- userInfo: userData,
- })
- perfObserver.disconnect()
- }
- })
-
- perfObserver.observe({
- type: "navigation",
- buffered: true,
- })
-
+ if (!hasRun && !hasRunLocal.current) {
+ hasRunLocal.current = true
setHasRun()
+
+ if (window.adobeDataLayer) {
+ const trackingData = {
+ ...pageData,
+ pathName,
+ pageLoadTime: getPageLoadTime(),
+ }
+
+ const pageObject = createSDKPageObject(trackingData)
+ console.log("TRACKING: Tracking pageView", pageObject, userData)
+ window.adobeDataLayer.push({
+ event: "pageView",
+ pageInfo: pageObject,
+ userInfo: userData,
+ hotelInfo: hotelInfo,
+ })
+ }
}
- }, [pathName, pageData, userData, hasRun, setHasRun])
+ }, [
+ pathName,
+ pageData,
+ userData,
+ hasRun,
+ setHasRun,
+ hotelInfo,
+ getPageLoadTime,
+ ])
useEffect(() => {
// handle consent
diff --git a/components/TrackingSDK/RouterTransition.tsx b/components/TrackingSDK/RouterTransition.tsx
index cb2597c20..a664e8677 100644
--- a/components/TrackingSDK/RouterTransition.tsx
+++ b/components/TrackingSDK/RouterTransition.tsx
@@ -4,8 +4,9 @@ import { usePathname } from "next/navigation"
import { startTransition, useEffect, useOptimistic, useState } from "react"
import useRouterTransitionStore from "@/stores/router-transition"
+import useTrackingStore from "@/stores/tracking"
-import { createSDKPageObject } from "@/utils/tracking"
+import { createSDKPageObject, trackPageViewStart } from "@/utils/tracking"
import { TrackingSDKProps } from "@/types/components/tracking"
@@ -20,15 +21,28 @@ type TransitionStatus = keyof typeof TransitionStatusEnum
export default function RouterTransition({
pageData,
userData,
+ hotelInfo,
}: TrackingSDKProps) {
const [loading, setLoading] = useOptimistic(false)
const [status, setStatus] = useState(
TransitionStatusEnum.NotRun
)
+ const { getPageLoadTime } = useTrackingStore()
const pathName = usePathname()
const { isTransitioning, stopRouterTransition } = useRouterTransitionStore()
+ // useEffect(() => {
+ // const handleStart = () => {
+ // trackPageViewStart()
+ // setInitialPageLoadTime(Date.now())
+ // }
+
+ // return () => {
+ // handleStart()
+ // }
+ // }, [pathName])
+
useEffect(() => {
if (isTransitioning && status === TransitionStatusEnum.NotRun) {
startTransition(() => {
@@ -48,13 +62,21 @@ export default function RouterTransition({
status === TransitionStatusEnum.Done
) {
if (window.adobeDataLayer) {
- const trackingData = { ...pageData, pathName }
+ const trackingData = {
+ ...pageData,
+ pathName,
+ pageLoadTime: getPageLoadTime(),
+ }
const pageObject = createSDKPageObject(trackingData)
-
+ console.log(
+ "TRACKING: Tracking RouterTransition pageViewEnd",
+ pageObject
+ )
window.adobeDataLayer.push({
event: "pageViewEnd",
pageInfo: pageObject,
userInfo: userData,
+ hotelInfo: hotelInfo,
})
}
}
@@ -67,6 +89,8 @@ export default function RouterTransition({
pageData,
pathName,
userData,
+ hotelInfo,
+ getPageLoadTime,
])
return null
diff --git a/components/TrackingSDK/index.tsx b/components/TrackingSDK/index.tsx
index d267341b6..f38c2bd0e 100644
--- a/components/TrackingSDK/index.tsx
+++ b/components/TrackingSDK/index.tsx
@@ -4,7 +4,10 @@ import RouterTransition from "@/components/TrackingSDK/RouterTransition"
import TrackingSDKClient from "./Client"
-import { TrackingSDKPageData } from "@/types/components/tracking"
+import {
+ TrackingSDKHotelInfo,
+ TrackingSDKPageData,
+} from "@/types/components/tracking"
export const preloadUserTracking = () => {
void serverClient().user.tracking()
@@ -12,15 +15,25 @@ export const preloadUserTracking = () => {
export default async function TrackingSDK({
pageData,
+ hotelInfo,
}: {
pageData: TrackingSDKPageData
+ hotelInfo?: TrackingSDKHotelInfo
}) {
const userTrackingData = await serverClient().user.tracking()
return (
<>
-
-
+
+
>
)
}
diff --git a/lib/graphql/Query/AccountPage/AccountPage.graphql b/lib/graphql/Query/AccountPage/AccountPage.graphql
index d18f69bff..f94b5bf61 100644
--- a/lib/graphql/Query/AccountPage/AccountPage.graphql
+++ b/lib/graphql/Query/AccountPage/AccountPage.graphql
@@ -20,6 +20,9 @@ query GetAccountPage($locale: String!, $uid: String!) {
created_at
updated_at
}
+ page_settings {
+ tracking_page_name
+ }
}
}
diff --git a/lib/graphql/Query/ContentPage/ContentPage.graphql b/lib/graphql/Query/ContentPage/ContentPage.graphql
index 150429ee0..ea2d311a6 100644
--- a/lib/graphql/Query/ContentPage/ContentPage.graphql
+++ b/lib/graphql/Query/ContentPage/ContentPage.graphql
@@ -37,6 +37,9 @@ query GetContentPage($locale: String!, $uid: String!) {
created_at
updated_at
}
+ page_settings {
+ tracking_page_name
+ }
}
}
diff --git a/lib/graphql/Query/HotelPage/HotelPage.graphql b/lib/graphql/Query/HotelPage/HotelPage.graphql
index dee41c6a8..b1713133d 100644
--- a/lib/graphql/Query/HotelPage/HotelPage.graphql
+++ b/lib/graphql/Query/HotelPage/HotelPage.graphql
@@ -31,6 +31,9 @@ query GetHotelPage($locale: String!, $uid: String!) {
}
}
}
+ page_settings {
+ tracking_page_name
+ }
}
}
diff --git a/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql b/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql
index 7a0d8650a..40aed7835 100644
--- a/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql
+++ b/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql
@@ -33,6 +33,9 @@ query GetLoyaltyPage($locale: String!, $uid: String!) {
created_at
updated_at
}
+ page_settings {
+ tracking_page_name
+ }
}
}
diff --git a/server/routers/contentstack/accountPage/output.ts b/server/routers/contentstack/accountPage/output.ts
index b0703784f..8f5e0e6ba 100644
--- a/server/routers/contentstack/accountPage/output.ts
+++ b/server/routers/contentstack/accountPage/output.ts
@@ -46,6 +46,9 @@ export const accountPageSchema = z.object({
heading: z.string().nullable(),
title: z.string(),
url: z.string(),
+ page_settings: z.object({
+ tracking_page_name: z.string().nullable(),
+ }),
system: systemSchema.merge(
z.object({
created_at: z.string(),
diff --git a/server/routers/contentstack/accountPage/query.ts b/server/routers/contentstack/accountPage/query.ts
index 612dd37c2..9100f888f 100644
--- a/server/routers/contentstack/accountPage/query.ts
+++ b/server/routers/contentstack/accountPage/query.ts
@@ -191,11 +191,16 @@ export const accountPageQueryRouter = router({
const tracking: TrackingSDKPageData = {
pageId: validatedAccountPage.data.account_page.system.uid,
- lang: validatedAccountPage.data.account_page.system.locale as Lang,
+ domainLanguage: validatedAccountPage.data.account_page.system
+ .locale as Lang,
publishedDate: validatedAccountPage.data.account_page.system.updated_at,
createdDate: validatedAccountPage.data.account_page.system.created_at,
channel: TrackingChannelEnum["scandic-friends"],
pageType: `member${parsedtitle}page`,
+ pageName:
+ validatedAccountPage.data.account_page.page_settings.tracking_page_name,
+ siteSections:
+ validatedAccountPage.data.account_page.page_settings.tracking_page_name, // Always the same as pageName for this page
}
return {
diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts
index 2be699b43..bf45d9631 100644
--- a/server/routers/contentstack/contentPage/output.ts
+++ b/server/routers/contentstack/contentPage/output.ts
@@ -18,6 +18,7 @@ import {
shortcutsRefsSchema,
shortcutsSchema,
} from "../schemas/blocks/shortcuts"
+import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
import {
contentRefsSchema as sidebarContentRefsSchema,
@@ -31,7 +32,6 @@ import {
import { systemSchema } from "../schemas/system"
import { ContentPageEnum } from "@/types/enums/contentPage"
-import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
// Block schemas
export const contentPageCards = z
@@ -58,9 +58,11 @@ export const contentPageShortcuts = z
})
.merge(shortcutsSchema)
-export const contentPageTextCols = z.object({
- __typename: z.literal(ContentPageEnum.ContentStack.blocks.TextCols),
-}).merge(textColsSchema)
+export const contentPageTextCols = z
+ .object({
+ __typename: z.literal(ContentPageEnum.ContentStack.blocks.TextCols),
+ })
+ .merge(textColsSchema)
export const blocksSchema = z.discriminatedUnion("__typename", [
contentPageCards,
@@ -113,6 +115,9 @@ export const contentPageSchema = z.object({
updated_at: z.string(),
})
),
+ page_settings: z.object({
+ tracking_page_name: z.string().nullable(),
+ }),
}),
})
diff --git a/server/routers/contentstack/contentPage/query.ts b/server/routers/contentstack/contentPage/query.ts
index 79ef83a4e..5414dbe6b 100644
--- a/server/routers/contentstack/contentPage/query.ts
+++ b/server/routers/contentstack/contentPage/query.ts
@@ -63,11 +63,14 @@ export const contentPageQueryRouter = router({
const tracking: TrackingSDKPageData = {
pageId: contentPage.data.content_page.system.uid,
- lang: contentPage.data.content_page.system.locale as Lang,
+ domainLanguage: contentPage.data.content_page.system.locale as Lang,
publishedDate: contentPage.data.content_page.system.updated_at,
createdDate: contentPage.data.content_page.system.created_at,
channel: TrackingChannelEnum["static-content-page"],
pageType: "staticcontentpage",
+ pageName: contentPage.data.content_page.page_settings.tracking_page_name,
+ siteSections:
+ contentPage.data.content_page.page_settings.tracking_page_name, // Always the same as pageName for this page
}
return {
diff --git a/server/routers/contentstack/hotelPage/output.ts b/server/routers/contentstack/hotelPage/output.ts
index b07121934..06c029d4e 100644
--- a/server/routers/contentstack/hotelPage/output.ts
+++ b/server/routers/contentstack/hotelPage/output.ts
@@ -22,5 +22,8 @@ export const hotelPageSchema = z.object({
hotel_page_id: z.string(),
title: z.string(),
url: z.string(),
+ page_settings: z.object({
+ tracking_page_name: z.string().nullable(),
+ }),
}),
})
diff --git a/server/routers/contentstack/loyaltyPage/output.ts b/server/routers/contentstack/loyaltyPage/output.ts
index e4ddfe35a..af37613f6 100644
--- a/server/routers/contentstack/loyaltyPage/output.ts
+++ b/server/routers/contentstack/loyaltyPage/output.ts
@@ -178,6 +178,9 @@ export const loyaltyPageSchema = z.object({
updated_at: z.string(),
})
),
+ page_settings: z.object({
+ tracking_page_name: z.string().nullable(),
+ }),
})
.transform((data) => {
return {
@@ -187,6 +190,7 @@ export const loyaltyPageSchema = z.object({
preamble: data.preamble,
sidebar: data.sidebar ? data.sidebar : [],
system: data.system,
+ pageSettings: data.page_settings,
}
}),
})
diff --git a/server/routers/contentstack/loyaltyPage/query.ts b/server/routers/contentstack/loyaltyPage/query.ts
index e6d181d76..2fe467a64 100644
--- a/server/routers/contentstack/loyaltyPage/query.ts
+++ b/server/routers/contentstack/loyaltyPage/query.ts
@@ -176,11 +176,13 @@ export const loyaltyPageQueryRouter = router({
const loyaltyTrackingData: TrackingSDKPageData = {
pageId: loyaltyPage.system.uid,
- lang: loyaltyPage.system.locale as Lang,
+ domainLanguage: loyaltyPage.system.locale as Lang,
publishedDate: loyaltyPage.system.updated_at,
createdDate: loyaltyPage.system.created_at,
channel: TrackingChannelEnum["scandic-friends"],
pageType: "loyaltycontentpage",
+ pageName: loyaltyPage.pageSettings.tracking_page_name,
+ siteSections: loyaltyPage.pageSettings.tracking_page_name, // Always the same as pageName for this page
}
getLoyaltyPageSuccessCounter.add(1, metricsVariables)
console.info(
diff --git a/stores/tracking.ts b/stores/tracking.ts
index 97ea29ac0..8e4851e4e 100644
--- a/stores/tracking.ts
+++ b/stores/tracking.ts
@@ -5,11 +5,20 @@ import { create } from "zustand"
interface TrackingStoreState {
hasRun: boolean
setHasRun: () => void
+ initialStartTime: number
+ setInitialPageLoadTime: (time: number) => void
+ getPageLoadTime: () => number
}
-const useTrackingStore = create((set) => ({
+const useTrackingStore = create((set, get) => ({
hasRun: false,
+ initialStartTime: Date.now(),
+ setInitialPageLoadTime: (time) => set({ initialStartTime: time }),
setHasRun: () => set(() => ({ hasRun: true })),
+ getPageLoadTime: () => {
+ const { initialStartTime } = get()
+ return (Date.now() - initialStartTime) / 1000
+ },
}))
export default useTrackingStore
diff --git a/types/components/tracking.ts b/types/components/tracking.ts
index 92128d939..7af334623 100644
--- a/types/components/tracking.ts
+++ b/types/components/tracking.ts
@@ -13,9 +13,14 @@ export type TrackingSDKPageData = {
pageId: string
createdDate: string
publishedDate: string
- lang: Lang
+ domainLanguage: Lang
pageType: string
channel: TrackingChannel
+ siteVersion?: "new-web"
+ pageName: string | null
+ domain?: string
+ siteSections: string | null
+ pageLoadTime?: number // Page load time in seconds
}
export enum LoginTypeEnum {
@@ -35,16 +40,59 @@ export type TrackingSDKUserData = {
loginAction?: "login success"
}
+export type TrackingSDKHotelInfo = {
+ hotelID?: string
+ arrivalData?: Date
+ departureDate?: Date
+ noAdults?: number
+ noChildren?: number
+ ageOfChildren?: string // "10", "2,5,10"
+ //rewardNight?: boolean
+ //bookingCode?: string
+ //bookingCodeAvailability?: boolean
+ leadTime?: number // Number of days from booking date until arrivalDate
+ noOfRoom?: number
+ //bonuscheque?: boolean
+ childBedPreference?: string
+ duration?: number // Number of nights to stay
+ availableResults?: number // Number of hotels to choose from after a city search
+ bookingTypeofDay?: string // Weekend or weekday
+ searchTerm?: string
+ roomPrice?: string
+ rateCode?: string
+ rateCodeCancellationRule?: string
+ rateCodeName?: string // Scandic Friends - full flex inkl. frukost
+ rateCodeType?: string // regular, promotion etc
+ revenueCurrencyCode?: string // SEK, DKK, NOK, EUR
+ roomTypeCode?: string
+ roomTypePosition?: number // Which position the room had in the list of available rooms
+ roomTypeName?: string
+ bedType?: string
+ bedTypePosition?: number // Which position the bed type had in the list of available bed types
+ breakfastOption?: string // "no breakfast" or "breakfast buffet"
+ bnr?: string // Booking number
+ analyticsrateCode?: string // flex, save, change
+ specialRoomType?: string // allergy room, pet-friendly, accesibillity room
+ //modifyValues?: string // ,roomtype:value>,bed:
+}
+
export type TrackingSDKProps = {
pageData: TrackingSDKPageData
userData: TrackingSDKUserData
+ hotelInfo?: TrackingSDKHotelInfo
}
export type TrackingSDKData = TrackingSDKPageData & {
pathName: string
}
+export type TrackingPosition =
+ | "top menu"
+ | "hamburger menu"
+ | "join scandic friends sidebar"
+
// Old tracking setup types:
+// TODO: Remove this when we delete "current site"
export type TrackingProps = {
pageData: {
pageId: string
@@ -73,8 +121,3 @@ export type SiteSectionObject = {
sitesection5: string
sitesection6: string
}
-
-export type TrackingPosition =
- | "top menu"
- | "hamburger menu"
- | "join scandic friends sidebar"
diff --git a/utils/tracking.ts b/utils/tracking.ts
index bb3b15166..d65c4359c 100644
--- a/utils/tracking.ts
+++ b/utils/tracking.ts
@@ -2,6 +2,7 @@ import { TrackingPosition, TrackingSDKData } from "@/types/components/tracking"
export function trackClick(name: string) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
+ console.log("TRACKING: Tracking click", name)
window.adobeDataLayer.push({
event: "linkClick",
cta: {
@@ -13,6 +14,7 @@ export function trackClick(name: string) {
export function trackPageViewStart() {
if (typeof window !== "undefined" && window.adobeDataLayer) {
+ console.log("TRACKING: Tracking pageViewStart")
window.adobeDataLayer.push({
event: "pageViewStart",
})
@@ -21,6 +23,7 @@ export function trackPageViewStart() {
export function trackLoginClick(position: TrackingPosition) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
+ console.log("TRACKING: Tracking loginStart, position", position)
const loginEvent = {
event: "loginStart",
login: {
@@ -33,26 +36,20 @@ export function trackLoginClick(position: TrackingPosition) {
}
}
-export function createSDKPageObject(trackingData: TrackingSDKData) {
+export function createSDKPageObject(
+ trackingData: TrackingSDKData
+): TrackingSDKData {
const [lang, ...segments] = trackingData.pathName
.split("/")
.filter((seg: string) => seg)
const joinedSegments = segments.join("|")
- const { host: domain } = window.location
- const page_obj = {
- pageType: trackingData.pageType,
- pageName: joinedSegments,
- pageId: trackingData.pageId,
- channel: trackingData.channel,
- siteSection: joinedSegments,
- domain,
- siteversion: "new-web",
- domainlanguage: trackingData.lang ? trackingData.lang : lang,
- createDate: trackingData.createdDate,
- publishDate: trackingData.publishedDate,
- // sessionid: "", // base on what?
+ return {
+ ...trackingData,
+ domain: window.location.host,
+ pageName: trackingData.pageName ?? joinedSegments,
+ siteSections: trackingData.siteSections ?? joinedSegments,
+ domainLanguage: trackingData.domainLanguage ?? lang,
}
- return page_obj
}