Merged in fix/tracking-fixes (pull request #1930)

Fix/tracking fixes

* fix: remove hotelInfo and paymentInfo when user reloads page on confirmation page

* fix: clean session storage item on unmount

* fix: commented out hard navigation hook

* fix: update price calculation on room ancillary in tracking

* fix: update discount calculation

* fix: add space between fns

* fix: allow useSoftNavigation to fire pageview again on same pathname

* fix: prevent bedSelection and breakfastSelection from tracking twice


Approved-by: Hrishikesh Vaipurkar
This commit is contained in:
Tobias Johansson
2025-05-03 07:27:54 +00:00
parent 0c7836fa59
commit 71f1e9fe2c
6 changed files with 84 additions and 68 deletions

View File

@@ -1,5 +1,7 @@
"use client"
import { useEffect, useState } from "react"
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
import TrackingSDK from "@/components/TrackingSDK"
@@ -17,6 +19,22 @@ export default function Tracking({
}) {
const lang = useLang()
const bookingRooms = useBookingConfirmationStore((state) => state.rooms)
const [hasLoadedBookingConfirmation] = useState(() => {
if (typeof window !== "undefined") {
return sessionStorage.getItem("hasLoadedBookingConfirmation")
}
return null
})
useEffect(() => {
sessionStorage.setItem("hasLoadedBookingConfirmation", "true")
return () => {
sessionStorage.removeItem("hasLoadedBookingConfirmation")
}
}, [])
if (!bookingRooms.every(Boolean)) {
return null
}
@@ -34,8 +52,8 @@ export default function Tracking({
return (
<TrackingSDK
pageData={pageTrackingData}
hotelInfo={hotelsTrackingData}
paymentInfo={paymentInfo}
hotelInfo={hasLoadedBookingConfirmation ? undefined : hotelsTrackingData}
paymentInfo={hasLoadedBookingConfirmation ? undefined : paymentInfo}
ancillaries={ancillaries}
/>
)

View File

@@ -57,7 +57,9 @@ export default function BedType() {
const selectedBedType = methods.watch("bedType")
const handleSubmit = methods.handleSubmit
useEffect(() => {
if (selectedBedType) {
handleSubmit(onSubmit)()
}
}, [selectedBedType, handleSubmit, onSubmit])
return (

View File

@@ -69,7 +69,9 @@ export default function Breakfast() {
const selectedBreakfast = methods.watch("breakfast")
const handleSubmit = methods.handleSubmit
useEffect(() => {
if (selectedBreakfast) {
handleSubmit(onSubmit)()
}
}, [selectedBreakfast, handleSubmit, onSubmit])
return (

View File

@@ -93,8 +93,7 @@ export function getTracking(
.join("|"),
country: hotel?.address.country,
departureDate: format(departureDate, "yyyy-MM-dd"),
discount: rooms
.map((room, idx) => {
discount: rooms.reduce((total, room, idx) => {
const isMainRoom = idx === 0
if (
hasMemberPrice(room.roomRate) &&
@@ -104,11 +103,17 @@ export function getTracking(
) {
const memberPrice = room.roomRate.member.localPrice.pricePerStay
const publicPrice = room.roomRate.public.localPrice.pricePerStay
return publicPrice - memberPrice
total += publicPrice - memberPrice
} else if (
hasPublicPrice(room.roomRate) &&
room.roomRate.public.localPrice.regularPricePerStay
) {
const publicPrice = room.roomRate.public.localPrice.pricePerStay
const regularPrice = room.roomRate.public.localPrice.regularPricePerStay
total += regularPrice - publicPrice
}
return 0
})
.join(","),
return total
}, 0),
duration: differenceInCalendarDays(departureDate, arrivalDate),
hotelID: hotel?.operaId,
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
@@ -194,19 +199,18 @@ export function getTracking(
const ancillaries: TrackingSDKAncillaries = roomsWithPetRoom
.slice(0, 1) // should only be one item
.map((room) => {
const petRoomPackage = room.packages.find(
(p) => p.code === RoomPackageCodeEnum.PET_ROOM
)
return {
return room.packages
.filter((p) => p.code === RoomPackageCodeEnum.PET_ROOM)
.map((pkg) => ({
hotelId: hotel.operaId,
productId: petRoomPackage?.code!, // property is guaranteed at this point
productId: pkg.code,
productUnits: roomsWithPetRoom.length,
productPoints: 0,
productPrice: petRoomPackage?.localPrice.totalPrice ?? 0,
productPrice: pkg.localPrice.totalPrice * roomsWithPetRoom.length,
productType: "room preference",
productName: "pet room",
productCategory: "",
}
}))[0]
})
return {
@@ -215,6 +219,7 @@ export function getTracking(
ancillaries,
}
}
function hasPublicPrice(
roomRate: Product
): roomRate is PriceProduct & { public: NonNullable<PriceProduct["public"]> } {
@@ -223,6 +228,7 @@ function hasPublicPrice(
}
return false
}
function hasMemberPrice(
roomRate: Product
): roomRate is PriceProduct & { member: NonNullable<PriceProduct["member"]> } {
@@ -231,6 +237,7 @@ function hasMemberPrice(
}
return false
}
function hasPetRoom(
room: Room
): room is Room & { packages: NonNullable<Room["packages"]> } {
@@ -239,6 +246,7 @@ function hasPetRoom(
}
return room.packages.some((p) => p.code === RoomPackageCodeEnum.PET_ROOM)
}
function calcTotalPrice(rooms: Room[], isMember: boolean) {
const totalRoomPrice = calcTotalRoomPrice(rooms, isMember)
const totalPackageSum = rooms.reduce((total, room) => {
@@ -247,6 +255,7 @@ function calcTotalPrice(rooms: Room[], isMember: boolean) {
}, 0)
return totalRoomPrice + totalPackageSum
}
function calcTotalRoomPrice(rooms: Room[], isMember: boolean) {
return rooms.reduce((total, room, idx) => {
// When it comes special rates, only redemption has additional price and that should be added

View File

@@ -1,13 +1,7 @@
"use client"
import { usePathname } from "next/navigation"
import {
startTransition,
useEffect,
useOptimistic,
useRef,
useState,
} from "react"
import { startTransition, useEffect, useRef, useState } from "react"
import { trpc } from "@/lib/trpc/client"
import useRouterTransitionStore from "@/stores/router-transition"
@@ -105,7 +99,6 @@ export const useTrackSoftNavigation = ({
isError,
} = trpc.user.userTrackingInfo.useQuery()
const [loading, setLoading] = useOptimistic(false)
const [status, setStatus] = useState<TransitionStatus>(
TransitionStatusEnum.NotRun
)
@@ -125,22 +118,17 @@ export const useTrackSoftNavigation = ({
if (isTransitioning && status === TransitionStatusEnum.NotRun) {
startTransition(() => {
setStatus(TransitionStatusEnum.Running)
setLoading(true)
})
return
}
if (
!loading &&
isTransitioning &&
status === TransitionStatusEnum.Running
) {
if (isTransitioning && status === TransitionStatusEnum.Running) {
setStatus(TransitionStatusEnum.Done)
stopRouterTransition()
return
}
if (!loading && !isTransitioning && status === TransitionStatusEnum.Done) {
if (!isTransitioning && status === TransitionStatusEnum.Done) {
const pageLoadTime = getPageLoadTime()
const trackingData = {
...pageData,
@@ -149,7 +137,6 @@ export const useTrackSoftNavigation = ({
pageLoadTime: pageLoadTime,
}
const pageObject = createSDKPageObject(trackingData)
if (previousPathname.current !== pathName) {
const userData: TrackingSDKUserData = isError
? { loginStatus: "Error" }
: userTrackingData
@@ -162,16 +149,15 @@ export const useTrackSoftNavigation = ({
paymentInfo,
ancillaries,
})
}
setStatus(TransitionStatusEnum.NotRun) // Reset status
previousPathname.current = pathName // Update for next render
}
}, [
isError,
isPending,
isTransitioning,
loading,
status,
setLoading,
stopRouterTransition,
pageData,
pathName,

View File

@@ -1,9 +1,6 @@
"use client"
import {
useTrackHardNavigation,
useTrackSoftNavigation,
} from "@/components/TrackingSDK/hooks"
import { useTrackSoftNavigation } from "@/components/TrackingSDK/hooks"
import type {
TrackingSDKAncillaries,
@@ -23,7 +20,9 @@ export default function TrackingSDK({
paymentInfo?: TrackingSDKPaymentInfo
ancillaries?: TrackingSDKAncillaries
}) {
useTrackHardNavigation({ pageData, hotelInfo, paymentInfo, ancillaries })
// This hook doesnt seem to be needed. Soft navigation hook seems to fire
// on both hard and soft navigations
// useTrackHardNavigation({ pageData, hotelInfo, paymentInfo, ancillaries })
useTrackSoftNavigation({ pageData, hotelInfo, paymentInfo, ancillaries })
return null