Merged in feat/SW-1414-guarantee-enter-details-tracking (pull request #1744)

Feat/SW-1414 guarantee enter details tracking

* feat(SW-1414): add tracking for gla enter details

* feat(SW-1414): add tracking for gla

* feat(SW-1414): add tracking for gla in enter details

* feat(SW-1414): fix pr comments

* feat(SW-1414): fix pr comment client only

* feat(SW-1414): fix pr comments

* feat(SW-1414): add tracking on load


Approved-by: Christian Andolf
This commit is contained in:
Bianca Widstam
2025-04-09 06:26:19 +00:00
parent 701a80b7c1
commit c41dea4118
7 changed files with 160 additions and 31 deletions

View File

@@ -1,5 +1,7 @@
import { differenceInCalendarDays, format, isWeekend } from "date-fns" import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { CancellationRuleEnum } from "@/constants/booking"
import { getSpecialRoomType } from "@/utils/specialRoomType" import { getSpecialRoomType } from "@/utils/specialRoomType"
import { invertedBedTypeMap } from "../../utils" import { invertedBedTypeMap } from "../../utils"
@@ -77,6 +79,9 @@ export function getTracking(
const noOfAdults = rooms.map((r) => r.adults).join(",") const noOfAdults = rooms.map((r) => r.adults).join(",")
const noOfChildren = rooms.map((r) => r.childrenAges?.length ?? 0).join(",") const noOfChildren = rooms.map((r) => r.childrenAges?.length ?? 0).join(",")
const noOfRooms = rooms.length const noOfRooms = rooms.length
const isFlexBooking =
booking.rateDefinition.cancellationRule ===
CancellationRuleEnum.CancellableBefore6PM
const hotelsTrackingData: TrackingSDKHotelInfo = { const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "-").join("|"), ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "-").join("|"),
@@ -144,10 +149,26 @@ export function getTracking(
.map((room) => getSpecialRoomType(room.packages)) .map((room) => getSpecialRoomType(room.packages))
.join(","), .join(","),
totalPrice: rooms.map((r) => r.totalPrice).join(","), totalPrice: rooms.map((r) => r.totalPrice).join(","),
lateArrivalGuarantee: booking.rateDefinition.mustBeGuaranteed
? "mandatory"
: isFlexBooking
? booking.guaranteeInfo
? "yes"
: "no"
: "na",
guaranteedProduct: booking.guaranteeInfo && isFlexBooking ? "room" : "na",
} }
const paymentInfo: TrackingSDKPaymentInfo = { const paymentInfo: TrackingSDKPaymentInfo = {
paymentStatus: "confirmed", paymentStatus: "confirmed",
status:
booking.guaranteeInfo && isFlexBooking
? "glacardsaveconfirmed"
: undefined,
type:
booking.guaranteeInfo && isFlexBooking
? booking.guaranteeInfo.cardType
: undefined,
} }
return { return {

View File

@@ -8,8 +8,11 @@ import { detailsStorageName } from "@/stores/enter-details"
import LoadingSpinner from "@/components/LoadingSpinner" import LoadingSpinner from "@/components/LoadingSpinner"
import { trackPaymentEvent } from "@/utils/tracking" import { trackPaymentEvent } from "@/utils/tracking"
import { trackEvent } from "@/utils/tracking/base"
import { convertObjToSearchParams } from "@/utils/url" import { convertObjToSearchParams } from "@/utils/url"
import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers"
import type { PersistedState } from "@/types/stores/enter-details" import type { PersistedState } from "@/types/stores/enter-details"
export default function HandleErrorCallback({ export default function HandleErrorCallback({
@@ -35,21 +38,54 @@ export default function HandleErrorCallback({
searchObject searchObject
) )
const lateArrivalGuarantee = readGlaFromSessionStorage()
if (status === PaymentCallbackStatusEnum.Cancel) { if (status === PaymentCallbackStatusEnum.Cancel) {
trackPaymentEvent({ if (lateArrivalGuarantee) {
event: "paymentCancel", trackEvent({
hotelId: detailsStorage.booking.hotelId, event: "glaCardSaveCancelled",
status: "cancelled", hotelInfo: {
}) hotelId: detailsStorage.booking.hotelId,
lateArrivalGuarantee,
guaranteedProduct: "room",
},
paymentInfo: {
hotelId: detailsStorage.booking.hotelId,
status: "glacardsavecancelled",
},
})
} else {
trackPaymentEvent({
event: "paymentCancel",
hotelId: detailsStorage.booking.hotelId,
status: "cancelled",
})
}
} }
if (status === PaymentCallbackStatusEnum.Error) { if (status === PaymentCallbackStatusEnum.Error) {
trackPaymentEvent({ if (lateArrivalGuarantee) {
event: "paymentFail", trackEvent({
hotelId: detailsStorage.booking.hotelId, event: "glaCardSaveFailed",
errorMessage, hotelInfo: {
status: "failed", hotelId: detailsStorage.booking.hotelId,
}) lateArrivalGuarantee,
guaranteedProduct: "room",
},
paymentInfo: {
hotelId: detailsStorage.booking.hotelId,
status: "glacardsavefailed",
},
})
} else {
trackPaymentEvent({
event: "paymentFail",
hotelId: detailsStorage.booking.hotelId,
errorMessage,
status: "failed",
})
}
} }
clearGlaSessionStorage()
if (searchParams.size > 0) { if (searchParams.size > 0) {
router.replace(`${returnUrl}?${searchParams.toString()}`) router.replace(`${returnUrl}?${searchParams.toString()}`)

View File

@@ -7,7 +7,9 @@ import { BookingStatusEnum, MEMBERSHIP_FAILED_ERROR } from "@/constants/booking"
import LoadingSpinner from "@/components/LoadingSpinner" import LoadingSpinner from "@/components/LoadingSpinner"
import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus" import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
import { trackEvent } from "@/utils/tracking/base"
import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers"
import TimeoutSpinner from "./TimeoutSpinner" import TimeoutSpinner from "./TimeoutSpinner"
const validBookingStatuses = [ const validBookingStatuses = [
@@ -48,6 +50,17 @@ export default function HandleSuccessCallback({
bookingStatus.reservationStatus as BookingStatusEnum bookingStatus.reservationStatus as BookingStatusEnum
) )
) { ) {
const lateArrivalGuarantee = readGlaFromSessionStorage()
if (lateArrivalGuarantee) {
trackEvent({
event: "guaranteeBookingSuccess",
hotelInfo: {
lateArrivalGuarantee,
guaranteedProduct: "room",
},
})
clearGlaSessionStorage()
}
// a successful booking can still have membership errors // a successful booking can still have membership errors
const membershipFailedError = bookingStatus.errors.find( const membershipFailedError = bookingStatus.errors.find(
(e) => e.errorCode === MEMBERSHIP_FAILED_ERROR (e) => e.errorCode === MEMBERSHIP_FAILED_ERROR

View File

@@ -0,0 +1,24 @@
import "client-only"
export const glaStorageName = "gla-storage"
export function readGlaFromSessionStorage(): string | null {
try {
return sessionStorage.getItem(glaStorageName)
} catch (error) {
console.error("Error reading from session storage:", error)
return null
}
}
export function writeGlaToSessionStorage(lateArrivalGuarantee: string) {
try {
sessionStorage.setItem(glaStorageName, lateArrivalGuarantee)
} catch (error) {
console.error("Error writing to session storage:", error)
}
}
export function clearGlaSessionStorage() {
sessionStorage.removeItem(glaStorageName)
}

View File

@@ -30,10 +30,13 @@ import { useAvailablePaymentOptions } from "@/hooks/booking/useAvailablePaymentO
import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus" import { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { trackPaymentEvent } from "@/utils/tracking" import { trackPaymentEvent } from "@/utils/tracking"
import { trackEvent } from "@/utils/tracking/base"
import { trackGlaSaveCardAttempt } from "@/utils/tracking/myStay"
import { bedTypeMap } from "../../utils" import { bedTypeMap } from "../../utils"
import ConfirmBooking, { ConfirmBookingRedemption } from "../Confirm" import ConfirmBooking, { ConfirmBookingRedemption } from "../Confirm"
import PriceChangeDialog from "../PriceChangeDialog" import PriceChangeDialog from "../PriceChangeDialog"
import { writeGlaToSessionStorage } from "./PaymentCallback/helpers"
import GuaranteeDetails from "./GuaranteeDetails" import GuaranteeDetails from "./GuaranteeDetails"
import { hasFlexibleRate, hasPrepaidRate, isPaymentMethodEnum } from "./helpers" import { hasFlexibleRate, hasPrepaidRate, isPaymentMethodEnum } from "./helpers"
import MixedRatePaymentBreakdown from "./MixedRatePaymentBreakdown" import MixedRatePaymentBreakdown from "./MixedRatePaymentBreakdown"
@@ -194,21 +197,45 @@ export default function PaymentClient({
const currentPaymentMethod = methods.getValues("paymentMethod") const currentPaymentMethod = methods.getValues("paymentMethod")
const smsEnable = methods.getValues("smsConfirmation") const smsEnable = methods.getValues("smsConfirmation")
const guarantee = methods.getValues("guarantee")
const isSavedCreditCard = savedCreditCards?.some( const isSavedCreditCard = savedCreditCards?.some(
(card) => card.id === currentPaymentMethod (card) => card.id === currentPaymentMethod
) )
trackPaymentEvent({ if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
event: "paymentFail", const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
hotelId, trackEvent({
method: currentPaymentMethod, event: "glaCardSaveFailed",
isSavedCreditCard, hotelInfo: {
smsEnable, hotelId,
errorMessage, lateArrivalGuarantee,
status: "failed", guaranteedProduct: "room",
}) },
paymentInfo: {
isSavedCreditCard,
hotelId,
status: "glacardsavefailed",
},
})
} else {
trackPaymentEvent({
event: "paymentFail",
hotelId,
method: currentPaymentMethod,
isSavedCreditCard,
smsEnable,
errorMessage,
status: "failed",
})
}
}, },
[methods, savedCreditCards, hotelId] [
methods,
savedCreditCards,
hotelId,
bookingMustBeGuaranteed,
hasOnlyFlexRates,
]
) )
useEffect(() => { useEffect(() => {
@@ -273,14 +300,20 @@ export default function PaymentClient({
} }
: undefined : undefined
trackPaymentEvent({ if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
event: "paymentAttemptStart", const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
hotelId, writeGlaToSessionStorage(lateArrivalGuarantee)
method: paymentMethod, trackGlaSaveCardAttempt(hotelId, savedCreditCard, lateArrivalGuarantee)
isSavedCreditCard: !!savedCreditCard, } else {
smsEnable: data.smsConfirmation, trackPaymentEvent({
status: "attempt", event: "paymentAttemptStart",
}) hotelId,
method: paymentMethod,
isSavedCreditCard: !!savedCreditCard,
smsEnable: data.smsConfirmation,
status: "attempt",
})
}
const payload = { const payload = {
checkInDate: fromDate, checkInDate: fromDate,

View File

@@ -93,6 +93,8 @@ export type TrackingSDKHotelInfo = {
searchType?: "destination" | "hotel" searchType?: "destination" | "hotel"
specialRoomType?: string // allergy room, pet-friendly, accesibillity room specialRoomType?: string // allergy room, pet-friendly, accesibillity room
totalPrice?: number | string totalPrice?: number | string
lateArrivalGuarantee?: string
guaranteedProduct?: string
} }
export type Ancillary = { export type Ancillary = {
@@ -114,6 +116,8 @@ export type TrackingSDKPaymentInfo = {
isCreditCard?: boolean isCreditCard?: boolean
paymentStatus?: "confirmed" paymentStatus?: "confirmed"
paymentType?: string paymentType?: string
type?: string
status?: string
} }
export type TrackingSDKProps = { export type TrackingSDKProps = {

View File

@@ -38,7 +38,6 @@ export function trackGlaSaveCardAttempt(
guaranteedProduct: "room", guaranteedProduct: "room",
}, },
paymentInfo: { paymentInfo: {
isSavedCreditCard: !!savedCreditCard,
status: "glacardsaveattempt", status: "glacardsaveattempt",
type: savedCreditCard?.cardType, type: savedCreditCard?.cardType,
}, },
@@ -58,7 +57,6 @@ export function trackGlaAncillaryAttempt(
trackEvent({ trackEvent({
event: "GuaranteeAttemptAncillary", event: "GuaranteeAttemptAncillary",
paymentInfo: { paymentInfo: {
isSavedCreditCard: !!savedCreditCard,
status: "glacardsaveattempt", status: "glacardsaveattempt",
type: savedCreditCard?.cardType, type: savedCreditCard?.cardType,
}, },