feat: add tracking events for loyalty pages
This commit is contained in:
@@ -43,6 +43,9 @@ export default async function RootLayout({
|
|||||||
id="Cookiebot"
|
id="Cookiebot"
|
||||||
src="https://consent.cookiebot.com/uc.js"
|
src="https://consent.cookiebot.com/uc.js"
|
||||||
/>
|
/>
|
||||||
|
<Script id="ensure-adobeDataLayer">{`
|
||||||
|
window.adobeDataLayer = window.adobeDataLayer || []
|
||||||
|
`}</Script>
|
||||||
<VwoScript />
|
<VwoScript />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
|
import TrackingSDK from "@/components/Current/TrackingSDK"
|
||||||
import { Blocks } from "@/components/Loyalty/Blocks"
|
import { Blocks } from "@/components/Loyalty/Blocks"
|
||||||
import Sidebar from "@/components/Loyalty/Sidebar"
|
import Sidebar from "@/components/Loyalty/Sidebar"
|
||||||
import MaxWidth from "@/components/MaxWidth"
|
import MaxWidth from "@/components/MaxWidth"
|
||||||
@@ -14,6 +15,10 @@ export default async function LoyaltyPage({ lang }: LangParams) {
|
|||||||
if (!loyaltyPage) {
|
if (!loyaltyPage) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loyaltyPageTracking =
|
||||||
|
await serverClient().contentstack.loyaltyPage.tracking()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.content}>
|
<section className={styles.content}>
|
||||||
{loyaltyPage.sidebar.length ? (
|
{loyaltyPage.sidebar.length ? (
|
||||||
@@ -26,6 +31,7 @@ export default async function LoyaltyPage({ lang }: LangParams) {
|
|||||||
<Blocks blocks={loyaltyPage.blocks} lang={lang} />
|
<Blocks blocks={loyaltyPage.blocks} lang={lang} />
|
||||||
) : null}
|
) : null}
|
||||||
</MaxWidth>
|
</MaxWidth>
|
||||||
|
<TrackingSDK pageData={loyaltyPageTracking} />
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
111
components/Current/TrackingSDK.tsx
Normal file
111
components/Current/TrackingSDK.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { usePathname } from "next/navigation"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
|
||||||
|
import {
|
||||||
|
SiteSectionObject,
|
||||||
|
TrackingSDKData,
|
||||||
|
TrackingSDKProps,
|
||||||
|
} from "@/types/components/tracking"
|
||||||
|
|
||||||
|
function createSDKPageObject(trackingData: TrackingSDKData) {
|
||||||
|
const [lang, ...segments] = trackingData.pathName
|
||||||
|
.split("/")
|
||||||
|
.filter((seg: string) => seg)
|
||||||
|
|
||||||
|
function getSiteSections(segments: string[]): SiteSectionObject {
|
||||||
|
/*
|
||||||
|
Adobe expects the properties sitesection1 - sitessection6, hence the for-loop below
|
||||||
|
The segments ['explore-scandic', 'wifi'] should result in:
|
||||||
|
{
|
||||||
|
sitesection1: "explore-scandic",
|
||||||
|
sitesection2: "explore-scandic|wifi",
|
||||||
|
sitesection3: "explore-scandic|wifi|",
|
||||||
|
sitesection4: "explore-scandic|wifi||",
|
||||||
|
sitesection5: "explore-scandic|wifi|||",
|
||||||
|
sitesection6: "explore-scandic|wifi||||",
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const sitesections = {} as SiteSectionObject
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
const key = ("sitesection" + (i + 1)) as keyof SiteSectionObject
|
||||||
|
|
||||||
|
sitesections[key] = segments.slice(0, i + 1).join("|")
|
||||||
|
if (i > 0 && !segments[i]) {
|
||||||
|
sitesections[key] = sitesections[key].concat(
|
||||||
|
"|".repeat(i + 1 - segments.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sitesections
|
||||||
|
}
|
||||||
|
const siteSections = getSiteSections(segments)
|
||||||
|
const { host: domain } = window.location
|
||||||
|
const page_obj = {
|
||||||
|
event: "pageView",
|
||||||
|
pageInfo: {
|
||||||
|
pageName: segments.join("|"),
|
||||||
|
pageType: "contentpage",
|
||||||
|
pageId: trackingData.pageId,
|
||||||
|
channel: "",
|
||||||
|
siteSections,
|
||||||
|
domain,
|
||||||
|
siteversion: "new-web",
|
||||||
|
domainlanguage: trackingData.lang ? trackingData.lang : lang,
|
||||||
|
createDate: trackingData.createdDate,
|
||||||
|
publishDate: trackingData.publishedDate,
|
||||||
|
// sessionid: "<unique identifier of session>", // base on what?
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return page_obj
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TrackingSDK({ pageData }: TrackingSDKProps) {
|
||||||
|
const pathName = usePathname()
|
||||||
|
|
||||||
|
function CookiebotCallbackOnAccept() {
|
||||||
|
const cookie = window._satellite.cookie.get("CookieConsent")
|
||||||
|
|
||||||
|
if (window.Cookiebot?.changed && window.adobe) {
|
||||||
|
if (cookie?.includes("statistics:true")) {
|
||||||
|
window.adobe.optIn.approve(window.adobe.OptInCategories.ANALYTICS, true)
|
||||||
|
} else {
|
||||||
|
window.adobe.optIn.deny(window.adobe.OptInCategories.ANALYTICS, true)
|
||||||
|
}
|
||||||
|
window.adobe.optIn.complete()
|
||||||
|
console.warn("window.load event explicitly dispatched.")
|
||||||
|
window.dispatchEvent(new Event("load"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function CookebotCallbackOnDecline() {
|
||||||
|
if (window.Cookiebot?.changed && window.adobe) {
|
||||||
|
window.adobe.optIn.deny(window.adobe.OptInCategories.ANALYTICS, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.adobeDataLayer) {
|
||||||
|
const trackingData = { ...pageData, pathName }
|
||||||
|
const pageObject = createSDKPageObject(trackingData)
|
||||||
|
window.adobeDataLayer.push(pageObject)
|
||||||
|
}
|
||||||
|
}, [pathName, pageData])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// handle consent
|
||||||
|
window.addEventListener("CookiebotOnAccept", CookiebotCallbackOnAccept)
|
||||||
|
window.addEventListener("CookiebotOnDecline", CookebotCallbackOnDecline)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("CookiebotOnAccept", CookiebotCallbackOnAccept)
|
||||||
|
window.removeEventListener(
|
||||||
|
"CookiebotOnDecline",
|
||||||
|
CookebotCallbackOnDecline
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -362,3 +362,14 @@ query GetFiNoSvUrlsLoyaltyPage($uid: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query GetTrackingLoyaltyPage($locale: String!, $uid: String!) {
|
||||||
|
loyalty_page(locale: $locale, uid: $uid) {
|
||||||
|
system {
|
||||||
|
locale
|
||||||
|
created_at
|
||||||
|
uid
|
||||||
|
updated_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
GetLoyaltyPage,
|
GetLoyaltyPage,
|
||||||
GetLoyaltyPageRefs,
|
GetLoyaltyPageRefs,
|
||||||
|
GetTrackingLoyaltyPage,
|
||||||
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
||||||
import { request } from "@/lib/graphql/request"
|
import { request } from "@/lib/graphql/request"
|
||||||
import { notFound } from "@/server/errors/trpc"
|
import { notFound } from "@/server/errors/trpc"
|
||||||
@@ -29,6 +30,10 @@ import {
|
|||||||
LoyaltyCardsGridEnum,
|
LoyaltyCardsGridEnum,
|
||||||
SidebarTypenameEnum,
|
SidebarTypenameEnum,
|
||||||
} from "@/types/components/loyalty/enums"
|
} from "@/types/components/loyalty/enums"
|
||||||
|
import {
|
||||||
|
TrackingChannelEnum,
|
||||||
|
TrackingSDKPageData,
|
||||||
|
} from "@/types/components/tracking"
|
||||||
|
|
||||||
function makeImageVaultImage(image: any) {
|
function makeImageVaultImage(image: any) {
|
||||||
return image && !!Object.keys(image).length
|
return image && !!Object.keys(image).length
|
||||||
@@ -224,4 +229,26 @@ export const loyaltyPageQueryRouter = router({
|
|||||||
// Assert LoyaltyPage type to get correct typings for RTE fields
|
// Assert LoyaltyPage type to get correct typings for RTE fields
|
||||||
return validatedLoyaltyPage.data as LoyaltyPage
|
return validatedLoyaltyPage.data as LoyaltyPage
|
||||||
}),
|
}),
|
||||||
|
tracking: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
|
||||||
|
const { lang, uid } = ctx
|
||||||
|
|
||||||
|
const response = await request<any>(GetTrackingLoyaltyPage, {
|
||||||
|
locale: lang,
|
||||||
|
uid,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.data) {
|
||||||
|
throw notFound(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
const loyaltyTrackingData: TrackingSDKPageData = {
|
||||||
|
pageId: response.data.loyalty_page.system.uid,
|
||||||
|
lang: response.data.loyalty_page.system.locale,
|
||||||
|
publishedDate: response.data.loyalty_page.system.published_at,
|
||||||
|
createdDate: response.data.loyalty_page.system.created_at,
|
||||||
|
channel: TrackingChannelEnum["scandic-friends"],
|
||||||
|
}
|
||||||
|
|
||||||
|
return loyaltyTrackingData
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,32 @@
|
|||||||
import type { Lang } from "@/constants/languages"
|
import type { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
|
export enum TrackingChannelEnum {
|
||||||
|
"scandic-friends" = "scandic-friends",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TrackingChannel = keyof typeof TrackingChannelEnum
|
||||||
|
|
||||||
|
export type TrackingSDKPageData = {
|
||||||
|
pageId: string
|
||||||
|
createdDate: string
|
||||||
|
publishedDate: string
|
||||||
|
lang: Lang
|
||||||
|
channel: TrackingChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TrackingSDKProps = {
|
||||||
|
pageData: TrackingSDKPageData
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TrackingSDKData = {
|
||||||
|
lang: Lang
|
||||||
|
pathName: string
|
||||||
|
pageId: string
|
||||||
|
publishedDate: string
|
||||||
|
createdDate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old tracking setup types:
|
||||||
export type TrackingProps = {
|
export type TrackingProps = {
|
||||||
pageData: {
|
pageData: {
|
||||||
pageId: string
|
pageId: string
|
||||||
|
|||||||
1
types/window.d.ts
vendored
1
types/window.d.ts
vendored
@@ -1,5 +1,6 @@
|
|||||||
interface Window {
|
interface Window {
|
||||||
datalayer: { [key: string]: any }
|
datalayer: { [key: string]: any }
|
||||||
|
adobeDataLayer: any[]
|
||||||
_satellite: { cookie: { get: (s: string) => string } }
|
_satellite: { cookie: { get: (s: string) => string } }
|
||||||
adobe: {
|
adobe: {
|
||||||
OptInCategories: { ANALYTICS: string }
|
OptInCategories: { ANALYTICS: string }
|
||||||
|
|||||||
Reference in New Issue
Block a user