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 { CancellationRuleEnum } from "@/constants/booking"
import { getSpecialRoomType } from "@/utils/specialRoomType"
import { invertedBedTypeMap } from "../../utils"
@@ -77,6 +79,9 @@ export function getTracking(
const noOfAdults = rooms.map((r) => r.adults).join(",")
const noOfChildren = rooms.map((r) => r.childrenAges?.length ?? 0).join(",")
const noOfRooms = rooms.length
const isFlexBooking =
booking.rateDefinition.cancellationRule ===
CancellationRuleEnum.CancellableBefore6PM
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "-").join("|"),
@@ -144,10 +149,26 @@ export function getTracking(
.map((room) => getSpecialRoomType(room.packages))
.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 = {
paymentStatus: "confirmed",
status:
booking.guaranteeInfo && isFlexBooking
? "glacardsaveconfirmed"
: undefined,
type:
booking.guaranteeInfo && isFlexBooking
? booking.guaranteeInfo.cardType
: undefined,
}
return {

View File

@@ -8,8 +8,11 @@ import { detailsStorageName } from "@/stores/enter-details"
import LoadingSpinner from "@/components/LoadingSpinner"
import { trackPaymentEvent } from "@/utils/tracking"
import { trackEvent } from "@/utils/tracking/base"
import { convertObjToSearchParams } from "@/utils/url"
import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers"
import type { PersistedState } from "@/types/stores/enter-details"
export default function HandleErrorCallback({
@@ -35,21 +38,54 @@ export default function HandleErrorCallback({
searchObject
)
const lateArrivalGuarantee = readGlaFromSessionStorage()
if (status === PaymentCallbackStatusEnum.Cancel) {
trackPaymentEvent({
event: "paymentCancel",
hotelId: detailsStorage.booking.hotelId,
status: "cancelled",
})
if (lateArrivalGuarantee) {
trackEvent({
event: "glaCardSaveCancelled",
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) {
trackPaymentEvent({
event: "paymentFail",
hotelId: detailsStorage.booking.hotelId,
errorMessage,
status: "failed",
})
if (lateArrivalGuarantee) {
trackEvent({
event: "glaCardSaveFailed",
hotelInfo: {
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) {
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 { useHandleBookingStatus } from "@/hooks/booking/useHandleBookingStatus"
import { trackEvent } from "@/utils/tracking/base"
import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers"
import TimeoutSpinner from "./TimeoutSpinner"
const validBookingStatuses = [
@@ -48,6 +50,17 @@ export default function HandleSuccessCallback({
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
const membershipFailedError = bookingStatus.errors.find(
(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 useLang from "@/hooks/useLang"
import { trackPaymentEvent } from "@/utils/tracking"
import { trackEvent } from "@/utils/tracking/base"
import { trackGlaSaveCardAttempt } from "@/utils/tracking/myStay"
import { bedTypeMap } from "../../utils"
import ConfirmBooking, { ConfirmBookingRedemption } from "../Confirm"
import PriceChangeDialog from "../PriceChangeDialog"
import { writeGlaToSessionStorage } from "./PaymentCallback/helpers"
import GuaranteeDetails from "./GuaranteeDetails"
import { hasFlexibleRate, hasPrepaidRate, isPaymentMethodEnum } from "./helpers"
import MixedRatePaymentBreakdown from "./MixedRatePaymentBreakdown"
@@ -194,21 +197,45 @@ export default function PaymentClient({
const currentPaymentMethod = methods.getValues("paymentMethod")
const smsEnable = methods.getValues("smsConfirmation")
const guarantee = methods.getValues("guarantee")
const isSavedCreditCard = savedCreditCards?.some(
(card) => card.id === currentPaymentMethod
)
trackPaymentEvent({
event: "paymentFail",
hotelId,
method: currentPaymentMethod,
isSavedCreditCard,
smsEnable,
errorMessage,
status: "failed",
})
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
trackEvent({
event: "glaCardSaveFailed",
hotelInfo: {
hotelId,
lateArrivalGuarantee,
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(() => {
@@ -273,14 +300,20 @@ export default function PaymentClient({
}
: undefined
trackPaymentEvent({
event: "paymentAttemptStart",
hotelId,
method: paymentMethod,
isSavedCreditCard: !!savedCreditCard,
smsEnable: data.smsConfirmation,
status: "attempt",
})
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
writeGlaToSessionStorage(lateArrivalGuarantee)
trackGlaSaveCardAttempt(hotelId, savedCreditCard, lateArrivalGuarantee)
} else {
trackPaymentEvent({
event: "paymentAttemptStart",
hotelId,
method: paymentMethod,
isSavedCreditCard: !!savedCreditCard,
smsEnable: data.smsConfirmation,
status: "attempt",
})
}
const payload = {
checkInDate: fromDate,

View File

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

View File

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