Merged in feat/sw-3545-update-sas-userinfo-tracking (pull request #2982)

feat(SW-3545): Update partner-sas userinfo tracking

* Update loginType to eurobonus

* Remove tracking booking code properties when disabled

* Add EB user data to tracking

* Fix type issue


Approved-by: Joakim Jäderberg
This commit is contained in:
Anton Gunnarsson
2025-10-17 09:35:37 +00:00
parent c01f440651
commit 710309b7eb
17 changed files with 100 additions and 41 deletions

View File

@@ -63,7 +63,7 @@ const config: NextAuthConfig = {
throw new Error("AuthError: Missing expiry time")
}
const [eurobonusProfile, error] = await safeTry(
getEuroBonusProfileData({ accessToken, loginType: "sas" })
getEuroBonusProfileData({ accessToken, loginType: "eurobonus" })
)
if (error) {
@@ -73,7 +73,7 @@ const config: NextAuthConfig = {
return {
...params.token,
isLinked: eurobonusProfile?.linkStatus === "LINKED",
loginType: "sas",
loginType: "eurobonus",
access_token: accessToken,
expires_at: expiresAt,
}
@@ -93,7 +93,7 @@ const config: NextAuthConfig = {
}
: undefined,
token: {
loginType: "sas",
loginType: "eurobonus",
access_token: token.access_token,
expires_at: token.expires_at,
error: token.error,

View File

@@ -4,6 +4,7 @@ import { useEffect, useState } from "react"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { useBookingFlowConfig } from "../../../bookingFlowConfig/bookingFlowConfigContext"
import { clearPaymentInfoSessionStorage } from "../../../components/EnterDetails/Payment/helpers"
import useLang from "../../../hooks/useLang"
import { useSearchHistory } from "../../../hooks/useSearchHistory"
@@ -23,6 +24,7 @@ export default function BookingConfirmationTracking({
}) {
const lang = useLang()
const bookingRooms = useBookingConfirmationStore((state) => state.rooms)
const config = useBookingFlowConfig()
const [loadedBookingConfirmationRefId] = useState(() => {
if (typeof window !== "undefined") {
@@ -47,6 +49,7 @@ export default function BookingConfirmationTracking({
bookingConfirmation.booking,
bookingConfirmation.hotel,
rooms,
config,
searchTerm
)
}

View File

@@ -14,6 +14,7 @@ import {
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import { type BookingFlowConfig } from "../../../bookingFlowConfig/bookingFlowConfig"
import { invertedBedTypeMap } from "../../../utils/SelectRate"
import { getSpecialRoomType } from "../../../utils/specialRoomType"
import { readPaymentInfoFromSessionStorage } from "../../EnterDetails/Payment/helpers"
@@ -63,6 +64,7 @@ export function getTracking(
booking: BookingConfirmation["booking"],
hotel: BookingConfirmation["hotel"],
rooms: Room[],
config: Pick<BookingFlowConfig, "bookingCodeEnabled">,
searchTerm?: string
) {
const arrivalDate = new Date(booking.checkInDate)
@@ -96,6 +98,13 @@ export function getTracking(
)
.map((pkg) => mapAncillaryPackage(pkg, hotel.operaId))
const bookingCodeProperties = {
bookingCode: rooms.map((room) => room.bookingCode ?? "n/a").join(", "),
bookingCodeAvailability: booking.bookingCode
? rooms.map((room) => (room.bookingCode ? "true" : "false")).join(", ")
: undefined,
}
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "").join("|"),
analyticsRateCode: rooms
@@ -107,10 +116,7 @@ export function getTracking(
.join(",")
.toLowerCase(),
bnr: rooms.map((r) => r.confirmationNumber).join(","),
bookingCode: rooms.map((room) => room.bookingCode ?? "n/a").join(", "),
bookingCodeAvailability: booking.bookingCode
? rooms.map((room) => (room.bookingCode ? "true" : "false")).join(", ")
: undefined,
...(config.bookingCodeEnabled ? bookingCodeProperties : {}),
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
breakfastOption: rooms
.map((r) => {

View File

@@ -2,6 +2,7 @@
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { useBookingFlowConfig } from "../../../bookingFlowConfig/bookingFlowConfigContext"
import { useSearchHistory } from "../../../hooks/useSearchHistory"
import { useEnterDetailsStore } from "../../../stores/enter-details"
import { getTracking } from "./tracking"
@@ -31,7 +32,7 @@ export default function EnterDetailsTrackingWrapper({
storedRooms: state.rooms,
breakfastPackages: state.breakfastPackages,
}))
const config = useBookingFlowConfig()
const searchHistory = useSearchHistory()
const searchTerm = searchHistory.searchHistory[0]?.name
@@ -43,6 +44,7 @@ export default function EnterDetailsTrackingWrapper({
lang,
storedRooms,
breakfastPackages,
config,
searchTerm
)

View File

@@ -24,6 +24,7 @@ import type {
Product,
} from "@scandic-hotels/trpc/types/roomAvailability"
import type { BookingFlowConfig } from "../../../bookingFlowConfig/bookingFlowConfig"
import type { RoomState } from "../../../stores/enter-details/types"
import type { DetailsBooking } from "../../../utils/url"
@@ -35,6 +36,7 @@ export function getTracking(
lang: Lang,
storedRooms: RoomState[],
breakfastPackages: BreakfastPackages,
config: Pick<BookingFlowConfig, "bookingCodeEnabled">,
searchTerm?: string
) {
const arrivalDate = new Date(booking.fromDate)
@@ -62,15 +64,7 @@ export function getTracking(
siteSections: "hotelreservation|details",
siteVersion: "new-web",
}
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: booking.rooms
.map((room) => room.childrenInRoom?.map((kid) => kid.age).join(",") ?? "")
.join("|"),
analyticsRateCode: rooms.map((room) => room.rate).join("|"),
arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
bedType: storedRooms
.map((r) => (r.room.bedType ? r.room.bedType.type : ""))
.join("|"),
const bookingCodeProperties = {
// Comma separated booking code values in "code,code,n/a" format for multiroom and "code" or "n/a" for singleroom
// n/a is used whenever code is Not applicable as defined by Tracking team
bookingCode: rooms
@@ -82,6 +76,17 @@ export function getTracking(
.map((room) => (room.roomRate.bookingCode ? "true" : "false"))
.join(", ")
: undefined,
}
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: booking.rooms
.map((room) => room.childrenInRoom?.map((kid) => kid.age).join(",") ?? "")
.join("|"),
analyticsRateCode: rooms.map((room) => room.rate).join("|"),
arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
bedType: storedRooms
.map((r) => (r.room.bedType ? r.room.bedType.type : ""))
.join("|"),
...(config.bookingCodeEnabled ? bookingCodeProperties : null),
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
breakfastOption,
childBedPreference: booking.rooms

View File

@@ -10,6 +10,7 @@ import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { Child } from "@scandic-hotels/trpc/types/child"
import type { BookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import type { SelectHotelBooking } from "../utils/url"
type ChildrenInRoom = (Child[] | null)[] | null
@@ -30,6 +31,7 @@ type SelectHotelTrackingInput = {
isBookingCodeRateAvailable?: boolean
isRedemption?: boolean
isRedemptionAvailable?: boolean
config: Pick<BookingFlowConfig, "bookingCodeEnabled">
}
export function getSelectHotelTracking({
@@ -45,6 +47,7 @@ export function getSelectHotelTracking({
hotelCity,
searchTerm,
bookingCode,
config,
isBookingCodeRateAvailable = false,
isRedemption = false,
isRedemptionAvailable = false,
@@ -69,16 +72,20 @@ export function getSelectHotelTracking({
childrenInRoom = rooms.map((room) => room.childrenInRoom ?? null)
}
const bookingCodeProperties = {
bookingCode: bookingCode ?? "n/a",
bookingCodeAvailability: bookingCode
? isBookingCodeRateAvailable.toString()
: undefined,
}
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: childrenInRoom
?.map((c) => c?.map((k) => k.age).join(",") ?? "")
.join("|"),
arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
availableResults: hotelsResult,
bookingCode: bookingCode ?? "n/a",
bookingCodeAvailability: bookingCode
? isBookingCodeRateAvailable.toString()
: undefined,
...(config.bookingCodeEnabled ? bookingCodeProperties : {}),
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
childBedPreference: childrenInRoom
?.map((c) => c?.map((k) => ChildBedMapEnum[k.bed]).join(",") ?? "")

View File

@@ -5,6 +5,7 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { env } from "../../env/server"
import { getBookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import { MapContainer } from "../components/MapContainer"
import {
getFiltersFromHotels,
@@ -102,6 +103,7 @@ export async function AlternativeHotelsMapPage({
isBookingCodeRateAvailable,
isRedemption: redemption,
isRedemptionAvailable: isRedemptionAvailability,
config: getBookingFlowConfig(),
})
const filterList = getFiltersFromHotels(hotels, isBookingCodeRateAvailable)

View File

@@ -7,6 +7,7 @@ import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAn
import { NoAvailabilityTracking } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getBookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import { AlternativeHotelsPageTitle } from "../components/AlternativeHotelsPageTitle"
import FnFNotAllowedAlert from "../components/FnFNotAllowedAlert"
import { SelectHotel } from "../components/SelectHotel"
@@ -107,6 +108,7 @@ export async function AlternativeHotelsPage({
isBookingCodeRateAvailable,
isRedemption: searchDetails.redemption,
isRedemptionAvailable: isRedemptionAvailability,
config: getBookingFlowConfig(),
})
const suspenseKey = stringify(searchParams)

View File

@@ -6,6 +6,7 @@ import { safeTry } from "@scandic-hotels/common/utils/safeTry"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { env } from "../../env/server"
import { getBookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import { MapContainer } from "../components/MapContainer"
import {
getFiltersFromHotels,
@@ -103,6 +104,7 @@ export async function SelectHotelMapPage({
isBookingCodeRateAvailable,
isRedemption: redemption,
isRedemptionAvailable: isRedemptionAvailability,
config: getBookingFlowConfig(),
})
const filterList = getFiltersFromHotels(hotels, isBookingCodeRateAvailable)

View File

@@ -7,6 +7,7 @@ import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAn
import { NoAvailabilityTracking } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { getBookingFlowConfig } from "../bookingFlowConfig/bookingFlowConfig"
import FnFNotAllowedAlert from "../components/FnFNotAllowedAlert"
import { SelectHotel } from "../components/SelectHotel"
import { getHotels } from "../components/SelectHotel/helpers"
@@ -93,6 +94,7 @@ export async function SelectHotelPage({
isBookingCodeRateAvailable,
isRedemption: redemption,
isRedemptionAvailable: isRedemptionAvailability,
config: getBookingFlowConfig(),
})
const suspenseKey = stringify(searchParams)

View File

@@ -3,6 +3,6 @@ export enum LoginTypeEnum {
"membership number" = "membership number",
"email link" = "email link",
"dtmc" = "dtmc",
"sas" = "sas",
"eurobonus" = "eurobonus",
}
export type LoginType = keyof typeof LoginTypeEnum

View File

@@ -163,5 +163,5 @@ export async function cancelBooking(
// ToDo - Update the function to return true for Scandic site and
// in case of Partner sites fetch the Scandic Curity token for linked user and service token for unlinked user
export function isPartnerLoggedInUser(session: Session) {
return session.token.loginType === LoginTypeEnum.sas
return session.token.loginType === LoginTypeEnum.eurobonus
}

View File

@@ -48,7 +48,7 @@ const outputSchema = z.object({
const sasLogger = createLogger("SAS")
const url = new URL("/api/scandic-partnership/v1/profile", env.SAS_API_ENDPOINT)
const requiredLoginType: LoginType[] = ["sas"]
const requiredLoginType: LoginType[] = ["eurobonus"]
export const getEuroBonusProfile = protectedProcedure
.output(outputSchema)

View File

@@ -28,18 +28,37 @@ type TrackingSDKChannel =
| "homepage"
| "promo-campaign"
type UserDataError = {
loginStatus: "Error"
}
type UserDataNonLoggedIn = {
loginStatus: "Non-logged in"
memberType: "scandic-friends" | "sas-eurobonus"
}
type UserDataScandicLoggedIn = {
loginStatus: "logged in"
loginType?: LoginType
memberId?: string
membershipNumber?: string
memberLevel?: MembershipLevel
loginAction?: "login success"
memberType: "scandic-friends"
}
type UserDataEurobonusLoggedIn = {
loginStatus: "logged in"
loginType?: LoginType
eurobonusNumber?: string
tier?: string
linkStatus?: string
loginAction?: "login success"
memberType: "sas-eurobonus"
}
export type TrackingUserData =
| {
loginStatus: "logged in"
loginType?: LoginType
memberId?: string
membershipNumber?: string
memberLevel?: MembershipLevel
loginAction?: "login success"
memberType: "scandic-friends" | "sas-eurobonus"
}
| {
loginStatus: "Non-logged in"
memberType: "scandic-friends" | "sas-eurobonus"
}
| { loginStatus: "Error" }
| UserDataScandicLoggedIn
| UserDataEurobonusLoggedIn
| UserDataNonLoggedIn
| UserDataError

View File

@@ -2,6 +2,7 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
import { safeProtectedProcedure } from "../../../procedures"
import { isValidSession } from "../../../utils/session"
import { getEuroBonusProfileData } from "../../partners/sas/getEuroBonusProfile"
import { getFriendsMembership } from "../helpers"
import { getVerifiedUser } from "../utils/getVerifiedUser"
@@ -95,11 +96,19 @@ async function getSasEurobonusUserTrackingData(session: Session | null) {
}
try {
const eurobonusProfile = await getEuroBonusProfileData({
accessToken: session.token.access_token,
loginType: "eurobonus",
})
const loggedInUserTrackingData: TrackingUserData = {
loginStatus: "logged in",
loginType: session.token.loginType,
loginAction: "login success",
memberType: "sas-eurobonus",
eurobonusNumber: eurobonusProfile.eurobonusNumber,
tier: eurobonusProfile.tier,
linkStatus: eurobonusProfile.linkStatus,
}
return loggedInUserTrackingData

View File

@@ -10,12 +10,12 @@ export function getRedemptionTokenSafely(
// ToDo- Get Curity based token when linked user is logged in
// const token =
// session.token.loginType === "sas"
// session.token.loginType === "eurobonus"
// ? session.token.curity_access_token ?? serviceToken
// : session.token.access_token
const token =
session.token.loginType === "sas"
session.token.loginType === "eurobonus"
? serviceToken
: session.token.access_token

View File

@@ -10,7 +10,7 @@ export async function getUserPointsBalance(
if (!isValidSession(session)) return undefined
const verifiedUser =
session.token.loginType === "sas"
session.token.loginType === "eurobonus"
? await getEuroBonusProfileData({
accessToken: session.token.access_token,
loginType: session.token.loginType,