Merged in feat/SW-1472-destination-tracking (pull request #1474)

Feat/SW-1472 destination tracking

* feat(SW-1472): Added default tracking for destination overview page

* feat(SW-1472): Added default tracking for destination country/city page

* feat(SW-1472): moved tracking functions to different files for better overview

* feat(SW-1472): added destination page tracking


Approved-by: Fredrik Thorsson
Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-03-06 10:15:33 +00:00
parent 47785aa07a
commit 230b56b3bd
25 changed files with 502 additions and 373 deletions
-198
View File
@@ -1,198 +0,0 @@
import type {
LowestRoomPriceEvent,
PaymentEvent,
PaymentFailEvent,
TrackingPosition,
TrackingSDKData,
} from "@/types/components/tracking"
export function trackClick(
name: string,
additionalParams?: Record<string, string>
) {
trackEvent({
event: "linkClick",
cta: {
...additionalParams,
name,
},
})
}
export function trackPageViewStart() {
trackEvent({
event: "pageViewStart",
})
}
export function trackLoginClick(position: TrackingPosition) {
const event = {
event: "loginStart",
login: {
position,
action: "login start",
ctaName: "login",
},
}
trackEvent(event)
}
export function trackSocialMediaClick(socialMediaName: string) {
const event = {
event: "social media",
social: {
socialIconClicked: socialMediaName,
},
}
trackEvent(event)
}
export function trackFooterClick(group: string, name: string) {
const event = {
event: "footer link",
footer: {
footerLinkClicked: `${group}:${name}`,
},
}
trackEvent(event)
}
export function trackHotelMapClick() {
const event = {
event: "map click",
map: {
action: "map click - open/explore mearby",
},
}
trackEvent(event)
}
export function trackAccordionClick(option: string) {
const event = {
event: "accordionClick",
accordion: {
action: "accordion open click",
option,
},
}
trackEvent(event)
}
export function trackHotelTabClick(name: string) {
trackEvent({
event: "linkClick",
link: {
action: "hotel menu click",
option: `hotel menu:${name}`,
},
})
}
export function trackUpdatePaymentMethod(hotelId: string, method: string) {
const paymentSelectionEvent = {
event: "paymentSelection",
hotelInfo: {
hotelId: hotelId,
},
cta: {
name: method,
},
}
trackEvent(paymentSelectionEvent)
}
export function trackOpenSidePeekEvent(
name: string | null,
hotelId: string,
pathName?: string,
roomTypeCode?: string | null
) {
const openSidePeekEvent = {
event: "openSidePeek",
hotelInfo: {
hotelId: hotelId,
},
cta: {
name,
...(roomTypeCode ? { roomTypeCode } : {}),
...(pathName ? { pathName } : {}),
},
}
trackEvent(openSidePeekEvent)
}
export function trackPaymentEvent(paymentEvent: PaymentEvent) {
const paymentAttempt = {
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,
},
}
trackEvent(paymentAttempt)
}
export function trackLowestRoomPrice(event: LowestRoomPriceEvent) {
const lowestRoomPrice = {
event: "lowestRoomPrice",
hotelInfo: {
hotelId: event.hotelId,
arrivalDate: event.arrivalDate,
departureDate: event.departureDate,
},
viewItemInfo: {
lowestPrice: event.lowestPrice,
currency: event.currency,
},
}
trackEvent(lowestRoomPrice)
}
function trackEvent(data: any) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
data = { ...data, siteVersion: "new-web" }
window.adobeDataLayer.push(data)
}
}
export function trackPageView(data: any) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
window.adobeDataLayer.push(data)
}
}
export function createSDKPageObject(
trackingData: TrackingSDKData
): TrackingSDKData {
let pageName = convertSlashToPipe(trackingData.pageName)
let siteSections = convertSlashToPipe(trackingData.siteSections)
if (trackingData.pathName.indexOf("/webview/") > -1) {
pageName = "webview|" + pageName
siteSections = "webview|" + siteSections
}
return {
...trackingData,
domain: typeof window !== "undefined" ? window.location.host : "",
pageName: pageName,
siteSections: siteSections,
}
}
function convertSlashToPipe(url: string) {
const formattedUrl = url.startsWith("/") ? url.slice(1) : url
return formattedUrl.replaceAll("/", "|")
}
function isPaymentFailEvent(event: PaymentEvent): event is PaymentFailEvent {
return "errorMessage" in event
}
+19
View File
@@ -0,0 +1,19 @@
export function trackEvent(data: any) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
data = { ...data, siteVersion: "new-web" }
window.adobeDataLayer.push(data)
}
}
export function trackClick(
name: string,
additionalParams?: Record<string, string>
) {
trackEvent({
event: "linkClick",
cta: {
...additionalParams,
name,
},
})
}
@@ -0,0 +1,18 @@
import { trackEvent } from "./base"
import type { LowestRoomPriceEvent } from "@/types/components/tracking"
export function trackLowestRoomPrice(event: LowestRoomPriceEvent) {
trackEvent({
event: "lowestRoomPrice",
hotelInfo: {
hotelId: event.hotelId,
arrivalDate: event.arrivalDate,
departureDate: event.departureDate,
},
viewItemInfo: {
lowestPrice: event.lowestPrice,
currency: event.currency,
},
})
}
@@ -0,0 +1,30 @@
import { trackEvent } from "./base"
export function trackAccordionClick(option: string) {
trackEvent({
event: "accordionClick",
accordion: {
action: "accordion open click",
option,
},
})
}
export function trackOpenSidePeekEvent(
name: string | null,
hotelId: string,
pathName?: string,
roomTypeCode?: string | null
) {
trackEvent({
event: "openSidePeek",
hotelInfo: {
hotelId: hotelId,
},
cta: {
name,
...(roomTypeCode ? { roomTypeCode } : {}),
...(pathName ? { pathName } : {}),
},
})
}
@@ -0,0 +1,59 @@
import { trackEvent } from "./base"
export function trackSortingChangeEvent(sortOption: string) {
trackEvent({
event: "sortOptionClick",
filter: {
sortOptions: sortOption,
},
})
}
export function trackFilterChangeEvent(
facilityFilters: string[],
surroundingsFilters: string[]
) {
const filtersUsed = []
if (facilityFilters.length) {
filtersUsed.push(`hotelfacilities:${facilityFilters.join(",")}`)
}
if (surroundingsFilters.length) {
filtersUsed.push(`hotelsurroundings:${surroundingsFilters.join(",")}`)
}
trackEvent({
event: "filterUsed",
filter: {
filtersUsed: filtersUsed.join("|"),
},
})
}
export function trackOpenSidePeekOnDestinationPagesEvent(location: string) {
trackEvent({
event: "trackOpenSidePeekEvent",
cta: {
pageName: `explore${location}|sidepeek`,
},
})
}
export function trackMapClick(name: string) {
trackEvent({
event: "map click",
map: {
action: "map click",
clickedItemName: name,
},
})
}
export function trackOpenMapView(pageName: string, pageType: string) {
trackEvent({
event: "openMapView",
map: {
pageName,
pageType,
},
})
}
@@ -0,0 +1,20 @@
import { trackEvent } from "./base"
export function trackHotelMapClick() {
trackEvent({
event: "map click",
map: {
action: "map click - open/explore mearby",
},
})
}
export function trackHotelTabClick(name: string) {
trackEvent({
event: "linkClick",
link: {
action: "hotel menu click",
option: `hotel menu:${name}`,
},
})
}
+15
View File
@@ -0,0 +1,15 @@
export { trackClick } from "./base"
export { trackLowestRoomPrice } from "./booking"
export { trackAccordionClick, trackOpenSidePeekEvent } from "./componentEvents"
export { trackHotelMapClick, trackHotelTabClick } from "./hotelPage"
export {
trackFooterClick,
trackLoginClick,
trackSocialMediaClick,
} from "./navigation"
export {
createSDKPageObject,
trackPageView,
trackPageViewStart,
} from "./pageview"
export { trackPaymentEvent, trackUpdatePaymentMethod } from "./payment"
@@ -0,0 +1,32 @@
import { trackEvent } from "./base"
import type { TrackingPosition } from "@/types/components/tracking"
export function trackFooterClick(group: string, name: string) {
trackEvent({
event: "footer link",
footer: {
footerLinkClicked: `${group}:${name}`,
},
})
}
export function trackSocialMediaClick(socialMediaName: string) {
trackEvent({
event: "social media",
social: {
socialIconClicked: socialMediaName,
},
})
}
export function trackLoginClick(position: TrackingPosition) {
trackEvent({
event: "loginStart",
login: {
position,
action: "login start",
ctaName: "login",
},
})
}
@@ -0,0 +1,39 @@
import { trackEvent } from "./base"
import type { TrackingSDKData } from "@/types/components/tracking"
function convertSlashToPipe(url: string) {
const formattedUrl = url.startsWith("/") ? url.slice(1) : url
return formattedUrl.replaceAll("/", "|")
}
export function trackPageViewStart() {
trackEvent({
event: "pageViewStart",
})
}
export function trackPageView(data: any) {
if (typeof window !== "undefined" && window.adobeDataLayer) {
window.adobeDataLayer.push(data)
}
}
export function createSDKPageObject(
trackingData: TrackingSDKData
): TrackingSDKData {
let pageName = convertSlashToPipe(trackingData.pageName)
let siteSections = convertSlashToPipe(trackingData.siteSections)
if (trackingData.pathName.indexOf("/webview/") > -1) {
pageName = "webview|" + pageName
siteSections = "webview|" + siteSections
}
return {
...trackingData,
domain: typeof window !== "undefined" ? window.location.host : "",
pageName: pageName,
siteSections: siteSections,
}
}
@@ -0,0 +1,38 @@
import { trackEvent } from "./base"
import type { PaymentEvent, PaymentFailEvent } from "@/types/components/tracking"
function isPaymentFailEvent(event: PaymentEvent): event is PaymentFailEvent {
return "errorMessage" in event
}
export function trackUpdatePaymentMethod(hotelId: string, method: string) {
trackEvent({
event: "paymentSelection",
hotelInfo: {
hotelId: hotelId,
},
cta: {
name: method,
},
})
}
export function trackPaymentEvent(paymentEvent: PaymentEvent) {
const paymentAttempt = {
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,
},
}
trackEvent(paymentAttempt)
}