Merged in fix/SW-3020-paymentInfo-tracking (pull request #2403)

fix(SW-3020): add correct paymentInfo in booking flow and ancillary flow

* fix(SW-3020): add correct paymentInfo in booking flow and ancillary flow

* fix(SW-3020): fix pr comments


Approved-by: Tobias Johansson
This commit is contained in:
Bianca Widstam
2025-06-24 13:38:30 +00:00
parent eb77241a4e
commit 5c3b30ea93
10 changed files with 136 additions and 23 deletions

View File

@@ -8,6 +8,7 @@ import TrackingSDK from "@/components/TrackingSDK"
import useLang from "@/hooks/useLang" import useLang from "@/hooks/useLang"
import { useSearchHistory } from "@/hooks/useSearchHistory" import { useSearchHistory } from "@/hooks/useSearchHistory"
import { clearPaymentInfoSessionStorage } from "../../EnterDetails/Payment/helpers"
import { getTracking } from "./tracking" import { getTracking } from "./tracking"
import type { Room } from "@/types/stores/booking-confirmation" import type { Room } from "@/types/stores/booking-confirmation"
@@ -37,20 +38,31 @@ export default function Tracking({
const searchHistory = useSearchHistory() const searchHistory = useSearchHistory()
const searchTerm = searchHistory.searchHistory[0]?.name const searchTerm = searchHistory.searchHistory[0]?.name
if (!bookingRooms.every(Boolean)) { let trackingData = null
return null
}
const rooms = bookingRooms.filter((room): room is Room => !!room) if (bookingRooms.every(Boolean)) {
const rooms = bookingRooms.filter((room): room is Room => !!room)
const { hotelsTrackingData, pageTrackingData, paymentInfo, ancillaries } = trackingData = getTracking(
getTracking(
lang, lang,
bookingConfirmation.booking, bookingConfirmation.booking,
bookingConfirmation.hotel, bookingConfirmation.hotel,
rooms, rooms,
searchTerm searchTerm
) )
}
useEffect(() => {
if (trackingData?.paymentInfo) {
clearPaymentInfoSessionStorage()
}
}, [trackingData])
if (!trackingData) {
return null
}
const { hotelsTrackingData, pageTrackingData, paymentInfo, ancillaries } =
trackingData
return ( return (
<TrackingSDK <TrackingSDK

View File

@@ -2,6 +2,7 @@ import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { CancellationRuleEnum } from "@/constants/booking" import { CancellationRuleEnum } from "@/constants/booking"
import { readPaymentInfoFromSessionStorage } from "@/components/HotelReservation/EnterDetails/Payment/helpers"
import { getSpecialRoomType } from "@/utils/specialRoomType" import { getSpecialRoomType } from "@/utils/specialRoomType"
import { invertedBedTypeMap } from "../../utils" import { invertedBedTypeMap } from "../../utils"
@@ -66,6 +67,7 @@ export function getTracking(
) { ) {
const arrivalDate = new Date(booking.checkInDate) const arrivalDate = new Date(booking.checkInDate)
const departureDate = new Date(booking.checkOutDate) const departureDate = new Date(booking.checkOutDate)
const paymentInfoSessionData = readPaymentInfoFromSessionStorage()
const pageTrackingData: TrackingSDKPageData = { const pageTrackingData: TrackingSDKPageData = {
channel: TrackingChannelEnum.hotelreservation, channel: TrackingChannelEnum.hotelreservation,
@@ -177,9 +179,7 @@ export function getTracking(
? "glacardsaveconfirmed" ? "glacardsaveconfirmed"
: undefined, : undefined,
type: type:
booking.guaranteeInfo && isFlexBooking booking.guaranteeInfo?.cardType ?? paymentInfoSessionData?.paymentMethod,
? booking.guaranteeInfo.cardType
: undefined,
} }
return { return {

View File

@@ -11,6 +11,10 @@ import { trackPaymentEvent } from "@/utils/tracking"
import { trackEvent } from "@/utils/tracking/base" import { trackEvent } from "@/utils/tracking/base"
import { serializeBookingSearchParams } from "@/utils/url" import { serializeBookingSearchParams } from "@/utils/url"
import {
clearPaymentInfoSessionStorage,
readPaymentInfoFromSessionStorage,
} from "../helpers"
import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers" import { clearGlaSessionStorage, readGlaFromSessionStorage } from "./helpers"
import type { PersistedState } from "@/types/stores/enter-details" import type { PersistedState } from "@/types/stores/enter-details"
@@ -41,6 +45,7 @@ export default function HandleErrorCallback({
) )
const glaSessionData = readGlaFromSessionStorage() const glaSessionData = readGlaFromSessionStorage()
const paymentInfoSessionData = readPaymentInfoFromSessionStorage()
if (status === PaymentCallbackStatusEnum.Cancel) { if (status === PaymentCallbackStatusEnum.Cancel) {
if (glaSessionData) { if (glaSessionData) {
@@ -54,6 +59,8 @@ export default function HandleErrorCallback({
paymentInfo: { paymentInfo: {
hotelId: glaSessionData.hotelId, hotelId: glaSessionData.hotelId,
status: "glacardsavecancelled", status: "glacardsavecancelled",
type: glaSessionData.paymentMethod,
isSavedCreditCard: glaSessionData.isSavedCreditCard,
}, },
}) })
} else { } else {
@@ -61,6 +68,8 @@ export default function HandleErrorCallback({
event: "paymentCancel", event: "paymentCancel",
hotelId: detailsStorage.booking.hotelId, hotelId: detailsStorage.booking.hotelId,
status: "cancelled", status: "cancelled",
method: paymentInfoSessionData?.paymentMethod,
isSavedCreditCard: paymentInfoSessionData?.isSavedCreditCard,
}) })
} }
} }
@@ -76,6 +85,8 @@ export default function HandleErrorCallback({
paymentInfo: { paymentInfo: {
hotelId: glaSessionData.hotelId, hotelId: glaSessionData.hotelId,
status: "glacardsavefailed", status: "glacardsavefailed",
type: glaSessionData.paymentMethod,
isSavedCreditCard: glaSessionData.isSavedCreditCard,
}, },
}) })
} else { } else {
@@ -84,10 +95,13 @@ export default function HandleErrorCallback({
hotelId: detailsStorage.booking.hotelId, hotelId: detailsStorage.booking.hotelId,
errorMessage, errorMessage,
status: "failed", status: "failed",
method: paymentInfoSessionData?.paymentMethod,
isSavedCreditCard: paymentInfoSessionData?.isSavedCreditCard,
}) })
} }
} }
clearGlaSessionStorage() clearGlaSessionStorage()
clearPaymentInfoSessionStorage()
if (searchParams.size > 0) { if (searchParams.size > 0) {
router.replace(`${returnUrl}?${searchParams.toString()}`) router.replace(`${returnUrl}?${searchParams.toString()}`)

View File

@@ -66,6 +66,11 @@ export default function HandleSuccessCallback({
hotelId: glaSessionData.hotelId, hotelId: glaSessionData.hotelId,
guaranteedProduct: "room", guaranteedProduct: "room",
}, },
paymentInfo: {
hotelId: glaSessionData.hotelId,
type: glaSessionData.paymentMethod,
isSavedCreditCard: glaSessionData.isSavedCreditCard,
},
}) })
clearGlaSessionStorage() clearGlaSessionStorage()
} }

View File

@@ -5,6 +5,8 @@ export const glaStorageName = "gla-storage"
type GlaSessionData = { type GlaSessionData = {
lateArrivalGuarantee: string lateArrivalGuarantee: string
hotelId: string hotelId: string
paymentMethod?: string
isSavedCreditCard?: boolean
} }
export function readGlaFromSessionStorage(): GlaSessionData | null { export function readGlaFromSessionStorage(): GlaSessionData | null {
@@ -20,12 +22,19 @@ export function readGlaFromSessionStorage(): GlaSessionData | null {
export function writeGlaToSessionStorage( export function writeGlaToSessionStorage(
lateArrivalGuarantee: string, lateArrivalGuarantee: string,
hotelId: string hotelId: string,
paymentMethod: string,
isSavedCreditCard: boolean
) { ) {
try { try {
sessionStorage.setItem( sessionStorage.setItem(
glaStorageName, glaStorageName,
JSON.stringify({ lateArrivalGuarantee, hotelId }) JSON.stringify({
lateArrivalGuarantee,
hotelId,
paymentMethod,
isSavedCreditCard,
})
) )
} catch (error) { } catch (error) {
console.error("Error writing to session storage:", error) console.error("Error writing to session storage:", error)

View File

@@ -43,7 +43,12 @@ import PriceChangeDialog from "../PriceChangeDialog"
import { writeGlaToSessionStorage } from "./PaymentCallback/helpers" import { writeGlaToSessionStorage } from "./PaymentCallback/helpers"
import BookingAlert from "./BookingAlert" import BookingAlert from "./BookingAlert"
import GuaranteeDetails from "./GuaranteeDetails" import GuaranteeDetails from "./GuaranteeDetails"
import { hasFlexibleRate, hasPrepaidRate, isPaymentMethodEnum } from "./helpers" import {
hasFlexibleRate,
hasPrepaidRate,
isPaymentMethodEnum,
writePaymentInfoToSessionStorage,
} from "./helpers"
import MixedRatePaymentBreakdown from "./MixedRatePaymentBreakdown" import MixedRatePaymentBreakdown from "./MixedRatePaymentBreakdown"
import PaymentOptionsGroup from "./PaymentOptionsGroup" import PaymentOptionsGroup from "./PaymentOptionsGroup"
import { type PaymentFormData, paymentSchema } from "./schema" import { type PaymentFormData, paymentSchema } from "./schema"
@@ -216,10 +221,12 @@ 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 guarantee = methods.getValues("guarantee")
const isSavedCreditCard = savedCreditCards?.some( const savedCreditCard = savedCreditCards?.find(
(card) => card.id === currentPaymentMethod (card) => card.id === currentPaymentMethod
) )
const isSavedCreditCard = !!savedCreditCard
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) { if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory" const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
trackEvent({ trackEvent({
@@ -233,13 +240,14 @@ export default function PaymentClient({
isSavedCreditCard, isSavedCreditCard,
hotelId, hotelId,
status: "glacardsavefailed", status: "glacardsavefailed",
type: savedCreditCard ? savedCreditCard.type : currentPaymentMethod,
}, },
}) })
} else { } else {
trackPaymentEvent({ trackPaymentEvent({
event: "paymentFail", event: "paymentFail",
hotelId, hotelId,
method: currentPaymentMethod, method: savedCreditCard ? savedCreditCard.type : currentPaymentMethod,
isSavedCreditCard, isSavedCreditCard,
smsEnable, smsEnable,
errorMessage, errorMessage,
@@ -355,21 +363,29 @@ export default function PaymentClient({
cancel: `${paymentRedirectUrl}/cancel`, cancel: `${paymentRedirectUrl}/cancel`,
} }
: undefined : undefined
const paymentMethodType = savedCreditCard
? savedCreditCard.type
: paymentMethod
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) { if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory" const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
writeGlaToSessionStorage(lateArrivalGuarantee, hotelId) writeGlaToSessionStorage(
lateArrivalGuarantee,
hotelId,
paymentMethodType,
!!savedCreditCard
)
trackGlaSaveCardAttempt(hotelId, savedCreditCard, lateArrivalGuarantee) trackGlaSaveCardAttempt(hotelId, savedCreditCard, lateArrivalGuarantee)
} else if (!hasOnlyFlexRates) { } else if (!hasOnlyFlexRates) {
trackPaymentEvent({ trackPaymentEvent({
event: "paymentAttemptStart", event: "paymentAttemptStart",
hotelId, hotelId,
method: savedCreditCard ? savedCreditCard.type : paymentMethod, method: paymentMethodType,
isSavedCreditCard: !!savedCreditCard, isSavedCreditCard: !!savedCreditCard,
smsEnable: data.smsConfirmation, smsEnable: data.smsConfirmation,
status: "attempt", status: "attempt",
}) })
} }
writePaymentInfoToSessionStorage(paymentMethodType, !!savedCreditCard)
const payload = { const payload = {
checkInDate: fromDate, checkInDate: fromDate,

View File

@@ -45,3 +45,46 @@ export function calculateTotalRoomPrice(
comparisonPrice, comparisonPrice,
} }
} }
export const paymentInfoStorageName = "payment-info-storage"
type PaymentInfoSessionData = {
paymentMethod: string
isSavedCreditCard: boolean
}
export function readPaymentInfoFromSessionStorage():
| PaymentInfoSessionData
| undefined {
try {
const paymentInfoSessionData = sessionStorage.getItem(
paymentInfoStorageName
)
if (!paymentInfoSessionData) return undefined
return JSON.parse(paymentInfoSessionData)
} catch (error) {
console.error("Error reading from session storage:", error)
return undefined
}
}
export function writePaymentInfoToSessionStorage(
paymentMethod: string,
isSavedCreditCard: boolean
) {
try {
sessionStorage.setItem(
paymentInfoStorageName,
JSON.stringify({
paymentMethod,
isSavedCreditCard,
})
)
} catch (error) {
console.error("Error writing to session storage:", error)
}
}
export function clearPaymentInfoSessionStorage() {
sessionStorage.removeItem(paymentInfoStorageName)
}

View File

@@ -80,7 +80,13 @@ export default function Form() {
cardType: savedCreditCard.cardType, cardType: savedCreditCard.cardType,
} }
: undefined : undefined
writeGlaToSessionStorage("yes", hotelId) const lateArrivalGuarantee = "yes"
writeGlaToSessionStorage(
lateArrivalGuarantee,
hotelId,
savedCreditCard ? savedCreditCard.type : PaymentMethodEnum.card,
!!savedCreditCard
)
guaranteeBooking.mutate({ guaranteeBooking.mutate({
refId, refId,
language: lang, language: lang,

View File

@@ -57,16 +57,18 @@ export default function TrackGuarantee({
} }
const trackGuaranteePaymentEvent = (event: string, status: string) => { const trackGuaranteePaymentEvent = (event: string, status: string) => {
const glaHotelInfo = readGlaFromSessionStorage() const glaSessionData = readGlaFromSessionStorage()
trackEvent({ trackEvent({
event, event,
hotelInfo: { hotelInfo: {
hotelId: glaHotelInfo?.hotelId, hotelId: glaSessionData?.hotelId,
lateArrivalGuarantee: "yes", lateArrivalGuarantee: "yes",
guaranteedProduct: "room", guaranteedProduct: "room",
}, },
paymentInfo: { paymentInfo: {
status, status,
type: glaSessionData?.paymentMethod,
isSavedCreditCard: glaSessionData?.isSavedCreditCard,
...(errorMessage && { errorMessage }), ...(errorMessage && { errorMessage }),
}, },
}) })
@@ -75,14 +77,19 @@ export default function TrackGuarantee({
switch (status) { switch (status) {
case PaymentCallbackStatusEnum.Success: case PaymentCallbackStatusEnum.Success:
const glaHotelInfo = readGlaFromSessionStorage() const glaSessionData = readGlaFromSessionStorage()
trackEvent({ trackEvent({
event: "guaranteeBookingSuccess", event: "guaranteeBookingSuccess",
hotelInfo: { hotelInfo: {
hotelId: glaHotelInfo?.hotelId, hotelId: glaSessionData?.hotelId,
lateArrivalGuarantee: "yes", lateArrivalGuarantee: "yes",
guaranteedProduct: "room", guaranteedProduct: "room",
}, },
paymentInfo: {
type: glaSessionData?.paymentMethod,
hotelId: glaSessionData?.hotelId,
isSavedCreditCard: glaSessionData?.isSavedCreditCard,
},
}) })
clearGlaSessionStorage() clearGlaSessionStorage()
break break

View File

@@ -43,6 +43,7 @@ export function trackGlaSaveCardAttempt(
}, },
paymentInfo: { paymentInfo: {
status: "glacardsaveattempt", status: "glacardsaveattempt",
isSavedCreditCard: !!savedCreditCard,
type: savedCreditCard?.cardType, type: savedCreditCard?.cardType,
}, },
}) })