From 710309b7eb0c80511655a48d1ea775caa97de642 Mon Sep 17 00:00:00 2001 From: Anton Gunnarsson Date: Fri, 17 Oct 2025 09:35:37 +0000 Subject: [PATCH] Merged in feat/sw-3545-update-sas-userinfo-tracking (pull request #2982) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- apps/partner-sas/auth.ts | 6 +-- .../BookingConfirmation/Tracking/index.tsx | 3 ++ .../BookingConfirmation/Tracking/tracking.ts | 14 ++++-- .../EnterDetails/Tracking/index.tsx | 4 +- .../EnterDetails/Tracking/tracking.ts | 23 +++++---- .../lib/misc/selectHotelTracking.ts | 15 ++++-- .../lib/pages/AlternativeHotelsMapPage.tsx | 2 + .../lib/pages/AlternativeHotelsPage.tsx | 2 + .../lib/pages/SelectHotelMapPage.tsx | 2 + .../lib/pages/SelectHotelPage.tsx | 2 + packages/common/constants/loginType.ts | 2 +- packages/trpc/lib/routers/booking/utils.ts | 2 +- .../partners/sas/getEuroBonusProfile.ts | 2 +- packages/trpc/lib/routers/types.ts | 47 +++++++++++++------ .../routers/user/query/userTrackingInfo.ts | 9 ++++ .../lib/utils/getRedemptionTokenSafely.ts | 4 +- .../trpc/lib/utils/getUserPointsBalance.ts | 2 +- 17 files changed, 100 insertions(+), 41 deletions(-) diff --git a/apps/partner-sas/auth.ts b/apps/partner-sas/auth.ts index 97796fef5..d1e27a8fb 100644 --- a/apps/partner-sas/auth.ts +++ b/apps/partner-sas/auth.ts @@ -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, diff --git a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/index.tsx b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/index.tsx index 526fc64e4..701a59a2f 100644 --- a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/index.tsx +++ b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/index.tsx @@ -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 ) } diff --git a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts index 84272ac0a..5e2294f02 100644 --- a/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts +++ b/packages/booking-flow/lib/components/BookingConfirmation/Tracking/tracking.ts @@ -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, 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) => { diff --git a/packages/booking-flow/lib/components/EnterDetails/Tracking/index.tsx b/packages/booking-flow/lib/components/EnterDetails/Tracking/index.tsx index 178b71271..f4ce3ef7a 100644 --- a/packages/booking-flow/lib/components/EnterDetails/Tracking/index.tsx +++ b/packages/booking-flow/lib/components/EnterDetails/Tracking/index.tsx @@ -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 ) diff --git a/packages/booking-flow/lib/components/EnterDetails/Tracking/tracking.ts b/packages/booking-flow/lib/components/EnterDetails/Tracking/tracking.ts index e6465dbb6..8dd0bf668 100644 --- a/packages/booking-flow/lib/components/EnterDetails/Tracking/tracking.ts +++ b/packages/booking-flow/lib/components/EnterDetails/Tracking/tracking.ts @@ -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, 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 diff --git a/packages/booking-flow/lib/misc/selectHotelTracking.ts b/packages/booking-flow/lib/misc/selectHotelTracking.ts index b5dc8c8e3..43390f1ad 100644 --- a/packages/booking-flow/lib/misc/selectHotelTracking.ts +++ b/packages/booking-flow/lib/misc/selectHotelTracking.ts @@ -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 } 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(",") ?? "") diff --git a/packages/booking-flow/lib/pages/AlternativeHotelsMapPage.tsx b/packages/booking-flow/lib/pages/AlternativeHotelsMapPage.tsx index 4679e1610..5e22ba21d 100644 --- a/packages/booking-flow/lib/pages/AlternativeHotelsMapPage.tsx +++ b/packages/booking-flow/lib/pages/AlternativeHotelsMapPage.tsx @@ -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) diff --git a/packages/booking-flow/lib/pages/AlternativeHotelsPage.tsx b/packages/booking-flow/lib/pages/AlternativeHotelsPage.tsx index 6304a9fa3..bed5c0131 100644 --- a/packages/booking-flow/lib/pages/AlternativeHotelsPage.tsx +++ b/packages/booking-flow/lib/pages/AlternativeHotelsPage.tsx @@ -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) diff --git a/packages/booking-flow/lib/pages/SelectHotelMapPage.tsx b/packages/booking-flow/lib/pages/SelectHotelMapPage.tsx index 66b09addb..f715a4309 100644 --- a/packages/booking-flow/lib/pages/SelectHotelMapPage.tsx +++ b/packages/booking-flow/lib/pages/SelectHotelMapPage.tsx @@ -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) diff --git a/packages/booking-flow/lib/pages/SelectHotelPage.tsx b/packages/booking-flow/lib/pages/SelectHotelPage.tsx index f006d4bda..70fc68aae 100644 --- a/packages/booking-flow/lib/pages/SelectHotelPage.tsx +++ b/packages/booking-flow/lib/pages/SelectHotelPage.tsx @@ -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) diff --git a/packages/common/constants/loginType.ts b/packages/common/constants/loginType.ts index 06c4d4c1a..b9439666d 100644 --- a/packages/common/constants/loginType.ts +++ b/packages/common/constants/loginType.ts @@ -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 diff --git a/packages/trpc/lib/routers/booking/utils.ts b/packages/trpc/lib/routers/booking/utils.ts index f48cb8063..bac5360c7 100644 --- a/packages/trpc/lib/routers/booking/utils.ts +++ b/packages/trpc/lib/routers/booking/utils.ts @@ -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 } diff --git a/packages/trpc/lib/routers/partners/sas/getEuroBonusProfile.ts b/packages/trpc/lib/routers/partners/sas/getEuroBonusProfile.ts index 10e65702f..ddab2555c 100644 --- a/packages/trpc/lib/routers/partners/sas/getEuroBonusProfile.ts +++ b/packages/trpc/lib/routers/partners/sas/getEuroBonusProfile.ts @@ -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) diff --git a/packages/trpc/lib/routers/types.ts b/packages/trpc/lib/routers/types.ts index bfd6b4ff9..bcd4298e4 100644 --- a/packages/trpc/lib/routers/types.ts +++ b/packages/trpc/lib/routers/types.ts @@ -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 diff --git a/packages/trpc/lib/routers/user/query/userTrackingInfo.ts b/packages/trpc/lib/routers/user/query/userTrackingInfo.ts index b85e1f5cf..4c73e2236 100644 --- a/packages/trpc/lib/routers/user/query/userTrackingInfo.ts +++ b/packages/trpc/lib/routers/user/query/userTrackingInfo.ts @@ -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 diff --git a/packages/trpc/lib/utils/getRedemptionTokenSafely.ts b/packages/trpc/lib/utils/getRedemptionTokenSafely.ts index 1caa18f96..9f3e9c626 100644 --- a/packages/trpc/lib/utils/getRedemptionTokenSafely.ts +++ b/packages/trpc/lib/utils/getRedemptionTokenSafely.ts @@ -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 diff --git a/packages/trpc/lib/utils/getUserPointsBalance.ts b/packages/trpc/lib/utils/getUserPointsBalance.ts index 4abd6b1ce..d7c49ee04 100644 --- a/packages/trpc/lib/utils/getUserPointsBalance.ts +++ b/packages/trpc/lib/utils/getUserPointsBalance.ts @@ -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,