>
)}
@@ -118,9 +127,17 @@ export function MainMenu({
@@ -159,7 +184,7 @@ export function MainMenu({
{myPagesMobileDropdown && user ? (
toggleMyPagesMobileMenu()}
+ onClick={handleMyPagesMobileMenuClick}
className={styles.avatarButton}
>
diff --git a/components/Current/Header/TopMenu/index.tsx b/components/Current/Header/TopMenu/index.tsx
index b2850616b..dd1861267 100644
--- a/components/Current/Header/TopMenu/index.tsx
+++ b/components/Current/Header/TopMenu/index.tsx
@@ -65,10 +65,13 @@ export default async function TopMenu({
>
) : (
+ lang={lang}
+ >
+ {formatMessage({ id: "Log in" })}
+
)}
diff --git a/components/Current/TrackingSDK.tsx b/components/Current/TrackingSDK.tsx
index 1452f62db..eb3820456 100644
--- a/components/Current/TrackingSDK.tsx
+++ b/components/Current/TrackingSDK.tsx
@@ -5,8 +5,6 @@ import { useEffect } from "react"
import {
SiteSectionObject,
- TrackableClickIdEnum,
- TrackingPosition,
TrackingSDKData,
TrackingSDKProps,
} from "@/types/components/tracking"
@@ -63,7 +61,7 @@ function createSDKPageObject(trackingData: TrackingSDKData) {
return page_obj
}
-export default function TrackingSDK({ pageData }: TrackingSDKProps) {
+export default function TrackingSDK({ pageData, userData }: TrackingSDKProps) {
const pathName = usePathname()
function CookiebotCallbackOnAccept() {
@@ -91,9 +89,9 @@ export default function TrackingSDK({ pageData }: TrackingSDKProps) {
if (window.adobeDataLayer) {
const trackingData = { ...pageData, pathName }
const pageObject = createSDKPageObject(trackingData)
- window.adobeDataLayer.push(pageObject)
+ window.adobeDataLayer.push({ ...pageObject, userInfo: userData })
}
- }, [pathName, pageData])
+ }, [pathName, pageData, userData])
useEffect(() => {
// handle consent
@@ -109,66 +107,5 @@ export default function TrackingSDK({ pageData }: TrackingSDKProps) {
}
}, [])
- function loginClick(position: TrackingPosition) {
- if (window.adobeDataLayer) {
- const loginEvent = {
- event: "loginStart",
- login: {
- position,
- action: "login start",
- ctaName: "login",
- },
- }
- window.adobeDataLayer.push(loginEvent)
- }
- }
-
- function linkClick(name: string) {
- if (window.adobeDataLayer) {
- window.adobeDataLayer.push({
- event: "linkClick",
- cta: {
- name: name,
- },
- })
- }
- }
-
- useEffect(() => {
- // Handle clickable events
- document
- .getElementById(TrackableClickIdEnum.LoginStartTopMenu)
- ?.addEventListener("click", () => loginClick("top menu"))
- document
- .getElementById(TrackableClickIdEnum.LoginStartJoinScandicFriends)
- ?.addEventListener("click", () =>
- loginClick("join scandic friends sidebar")
- )
- document
- .getElementById(TrackableClickIdEnum.LoginStartHamburgerMenu)
- ?.addEventListener("click", () => loginClick("hamburger menu"))
-
- document
- .getElementById(TrackableClickIdEnum.ProfilePictureLink)
- ?.addEventListener("click", () => linkClick("profile picture link"))
-
- return () => {
- document
- .getElementById(TrackableClickIdEnum.LoginStartTopMenu)
- ?.removeEventListener("click", () => loginClick("top menu"))
- document
- .getElementById(TrackableClickIdEnum.LoginStartJoinScandicFriends)
- ?.removeEventListener("click", () =>
- loginClick("join scandic friends sidebar")
- )
- document
- .getElementById(TrackableClickIdEnum.LoginStartHamburgerMenu)
- ?.removeEventListener("click", () => loginClick("hamburger menu"))
- document
- .getElementById(TrackableClickIdEnum.ProfilePictureLink)
- ?.removeEventListener("click", () => linkClick("profile picture link"))
- }
- }, [])
-
return null
}
diff --git a/components/Loyalty/Sidebar/JoinLoyalty/index.tsx b/components/Loyalty/Sidebar/JoinLoyalty/index.tsx
index ed1be157b..0718abd31 100644
--- a/components/Loyalty/Sidebar/JoinLoyalty/index.tsx
+++ b/components/Loyalty/Sidebar/JoinLoyalty/index.tsx
@@ -1,5 +1,6 @@
import { serverClient } from "@/lib/trpc/server"
+import LoginButton from "@/components/Current/Header/LoginButton"
import ArrowRight from "@/components/Icons/ArrowRight"
import { ScandicFriends } from "@/components/Levels"
import Button from "@/components/TempDesignSystem/Button"
@@ -13,7 +14,6 @@ import Contact from "./Contact"
import styles from "./joinLoyalty.module.css"
import type { JoinLoyaltyContactProps } from "@/types/components/loyalty/sidebar"
-import { TrackableClickIdEnum } from "@/types/components/tracking"
import { LangParams } from "@/types/params"
export default async function JoinLoyaltyContact({
@@ -53,13 +53,12 @@ export default async function JoinLoyaltyContact({
) : null}
{formatMessage({ id: "Already a friend?" })}
-
{formatMessage({ id: "Log in here" })}
-
+
{block.contact ?
: null}
diff --git a/components/TempDesignSystem/Link/index.tsx b/components/TempDesignSystem/Link/index.tsx
index c23801014..885543bef 100644
--- a/components/TempDesignSystem/Link/index.tsx
+++ b/components/TempDesignSystem/Link/index.tsx
@@ -3,6 +3,8 @@ import NextLink from "next/link"
import { usePathname } from "next/navigation"
import { useEffect } from "react"
+import { trackClick } from "@/utils/tracking"
+
import { linkVariants } from "./variants"
import type { LinkProps } from "./link"
@@ -36,11 +38,13 @@ export default function Link({
useEffect(() => {
if (trackingId) {
- document.getElementById(trackingId)?.addEventListener("click", () => {})
+ document
+ .getElementById(trackingId)
+ ?.addEventListener("click", () => trackClick(trackingId))
return () => {
document
.getElementById(trackingId)
- ?.removeEventListener("click", () => {})
+ ?.removeEventListener("click", () => trackClick(trackingId))
}
}
}, [trackingId])
@@ -51,6 +55,7 @@ export default function Link({
prefetch={prefetch}
className={classNames}
href={href}
+ id={trackingId}
{...props}
/>
)
diff --git a/constants/membershipLevels.ts b/constants/membershipLevels.ts
index 2dda9d05c..3ae0f4650 100644
--- a/constants/membershipLevels.ts
+++ b/constants/membershipLevels.ts
@@ -17,3 +17,5 @@ export enum MembershipLevelEnum {
L6 = "L6",
L7 = "L7",
}
+
+export type MembershipLevel = keyof typeof MembershipLevelEnum
diff --git a/server/routers/user/query.ts b/server/routers/user/query.ts
index 8dc506be7..0fdcf5701 100644
--- a/server/routers/user/query.ts
+++ b/server/routers/user/query.ts
@@ -25,6 +25,11 @@ import { benefits, extendedUser, nextLevelPerks } from "./temp"
import type { Session } from "next-auth"
+import type {
+ LoginType,
+ TrackingSDKUserData,
+} from "@/types/components/tracking"
+
async function getVerifiedUser({ session }: { session: Session }) {
const apiResponse = await api.get(api.endpoints.v1.profile, {
cache: "no-store",
@@ -215,6 +220,73 @@ export const userQueryRouter = router({
const membershipLevel = getMembership(verifiedData.data.memberships)
return membershipLevel
}),
+ tracking: safeProtectedProcedure.query(async function ({ ctx }) {
+ const notLoggedInUserTrackingData: TrackingSDKUserData = {
+ loginStatus: false,
+ }
+
+ if (!ctx.session) {
+ return notLoggedInUserTrackingData
+ }
+ const verifiedUserData = await getVerifiedUser({ session: ctx.session })
+
+ if (!verifiedUserData) {
+ return notLoggedInUserTrackingData
+ }
+
+ const params = new URLSearchParams()
+ params.set("limit", "1")
+
+ const previousStaysResponse = await api.get(
+ api.endpoints.v1.previousStays,
+ {
+ headers: {
+ Authorization: `Bearer ${ctx.session.token.access_token}`,
+ },
+ },
+ params
+ )
+
+ if (!previousStaysResponse.ok) {
+ // switch (apiResponse.status) {
+ // case 400:
+ // throw badRequestError(apiResponse)
+ // case 401:
+ // throw unauthorizedError(apiResponse)
+ // case 403:
+ // throw forbiddenError(apiResponse)
+ // default:
+ // throw internalServerError(apiResponse)
+ // }
+ console.info(`API Response Failed - Getting Previous Stays`)
+ console.info(`User: (${JSON.stringify(ctx.session.user)})`)
+ console.error(previousStaysResponse)
+ return notLoggedInUserTrackingData
+ }
+
+ const previousStaysApiJson = await previousStaysResponse.json()
+ const verifiedPreviousStaysData =
+ getStaysSchema.safeParse(previousStaysApiJson)
+ if (!verifiedPreviousStaysData.success) {
+ console.info(`Failed to validate Previous Stays Data`)
+ console.info(`User: (${JSON.stringify(ctx.session.user)})`)
+ console.error(verifiedPreviousStaysData.error)
+ return notLoggedInUserTrackingData
+ }
+
+ const membership = getMembership(verifiedUserData.data.memberships)
+
+ const loggedInUserTrackingData: TrackingSDKUserData = {
+ loginStatus: true,
+ loginType: ctx.session.token.loginType as LoginType,
+ memberId: membership?.membershipNumber,
+ memberLevel: membership?.membershipLevel,
+ noOfNightsStayed: verifiedPreviousStaysData.data.links?.totalCount ?? 0,
+ totalPointsAvailableToSpend: membership?.currentPoints,
+ }
+
+ return loggedInUserTrackingData
+ }),
benefits: router({
current: protectedProcedure.query(async function (opts) {
// TODO: Make request to get user data from Scandic API
diff --git a/types/auth.d.ts b/types/auth.d.ts
index 3cf582207..debb444a1 100644
--- a/types/auth.d.ts
+++ b/types/auth.d.ts
@@ -25,5 +25,8 @@ declare module "next-auth" {
interface User {
given_name: string
sub: string
+ email?: string
+ login_with: string
+ nonce?: string
}
}
diff --git a/types/components/tracking.ts b/types/components/tracking.ts
index 2bd285d60..20718c132 100644
--- a/types/components/tracking.ts
+++ b/types/components/tracking.ts
@@ -1,3 +1,5 @@
+import { MembershipLevel } from "@/constants/membershipLevels"
+
import type { Lang } from "@/constants/languages"
export enum TrackingChannelEnum {
@@ -14,8 +16,25 @@ export type TrackingSDKPageData = {
channel: TrackingChannel
}
+export enum LoginTypeEnum {
+ Email = "email",
+ MembershipNumber = "membership number",
+ MagicLink = "magic link",
+}
+export type LoginType = keyof typeof LoginTypeEnum
+
+export type TrackingSDKUserData = {
+ loginStatus: boolean
+ loginType?: LoginType
+ memberId?: string
+ memberLevel?: MembershipLevel
+ noOfNightsStayed?: number
+ totalPointsAvailableToSpend?: number
+}
+
export type TrackingSDKProps = {
pageData: TrackingSDKPageData
+ userData: TrackingSDKUserData
}
export type TrackingSDKData = {
@@ -56,22 +75,6 @@ export type SiteSectionObject = {
sitesection6: string
}
-export enum TrackableClickIdEnum {
- LoginStartTopMenu = "LoginStartTopMenu",
- LoginStartHamburgerMenu = "LoginStartHamburgerMenu",
- LoginStartJoinScandicFriends = "LoginStartJoinScandicFriends",
- LoginFail = "LoginFail",
- HamburgerLink = "HamburgerLink",
- ProfilePictureLink = "ProfilePictureLink",
-}
-
-type TrackableClickId = keyof typeof TrackableClickIdEnum
-
-export type TrackableLoginId = Exclude<
- TrackableClickId,
- "HamburgerLink" | "ProfilePictureLink" | "LoginFail"
->
-
export type TrackingPosition =
| "top menu"
| "hamburger menu"
diff --git a/utils/tracking.ts b/utils/tracking.ts
new file mode 100644
index 000000000..d6bacd8a7
--- /dev/null
+++ b/utils/tracking.ts
@@ -0,0 +1,26 @@
+import { TrackingPosition } from "@/types/components/tracking"
+
+export function trackClick(name: string) {
+ if (window.adobeDataLayer) {
+ window.adobeDataLayer.push({
+ event: "linkClick",
+ cta: {
+ name,
+ },
+ })
+ }
+}
+
+export function trackLoginClick(position: TrackingPosition) {
+ if (window.adobeDataLayer) {
+ const loginEvent = {
+ event: "loginStart",
+ login: {
+ position,
+ action: "login start",
+ ctaName: "login",
+ },
+ }
+ window.adobeDataLayer.push(loginEvent)
+ }
+}