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:
@@ -1,5 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
|
import { useBookingConfirmationStore } from "@/stores/booking-confirmation"
|
||||||
|
|
||||||
import TrackingSDK from "@/components/TrackingSDK"
|
import TrackingSDK from "@/components/TrackingSDK"
|
||||||
@@ -17,6 +19,22 @@ export default function Tracking({
|
|||||||
}) {
|
}) {
|
||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
const bookingRooms = useBookingConfirmationStore((state) => state.rooms)
|
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)) {
|
if (!bookingRooms.every(Boolean)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -34,8 +52,8 @@ export default function Tracking({
|
|||||||
return (
|
return (
|
||||||
<TrackingSDK
|
<TrackingSDK
|
||||||
pageData={pageTrackingData}
|
pageData={pageTrackingData}
|
||||||
hotelInfo={hotelsTrackingData}
|
hotelInfo={hasLoadedBookingConfirmation ? undefined : hotelsTrackingData}
|
||||||
paymentInfo={paymentInfo}
|
paymentInfo={hasLoadedBookingConfirmation ? undefined : paymentInfo}
|
||||||
ancillaries={ancillaries}
|
ancillaries={ancillaries}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ export default function BedType() {
|
|||||||
const selectedBedType = methods.watch("bedType")
|
const selectedBedType = methods.watch("bedType")
|
||||||
const handleSubmit = methods.handleSubmit
|
const handleSubmit = methods.handleSubmit
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSubmit(onSubmit)()
|
if (selectedBedType) {
|
||||||
|
handleSubmit(onSubmit)()
|
||||||
|
}
|
||||||
}, [selectedBedType, handleSubmit, onSubmit])
|
}, [selectedBedType, handleSubmit, onSubmit])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ export default function Breakfast() {
|
|||||||
const selectedBreakfast = methods.watch("breakfast")
|
const selectedBreakfast = methods.watch("breakfast")
|
||||||
const handleSubmit = methods.handleSubmit
|
const handleSubmit = methods.handleSubmit
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleSubmit(onSubmit)()
|
if (selectedBreakfast) {
|
||||||
|
handleSubmit(onSubmit)()
|
||||||
|
}
|
||||||
}, [selectedBreakfast, handleSubmit, onSubmit])
|
}, [selectedBreakfast, handleSubmit, onSubmit])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -93,22 +93,27 @@ export function getTracking(
|
|||||||
.join("|"),
|
.join("|"),
|
||||||
country: hotel?.address.country,
|
country: hotel?.address.country,
|
||||||
departureDate: format(departureDate, "yyyy-MM-dd"),
|
departureDate: format(departureDate, "yyyy-MM-dd"),
|
||||||
discount: rooms
|
discount: rooms.reduce((total, room, idx) => {
|
||||||
.map((room, idx) => {
|
const isMainRoom = idx === 0
|
||||||
const isMainRoom = idx === 0
|
if (
|
||||||
if (
|
hasMemberPrice(room.roomRate) &&
|
||||||
hasMemberPrice(room.roomRate) &&
|
isMainRoom &&
|
||||||
isMainRoom &&
|
isMember &&
|
||||||
isMember &&
|
hasPublicPrice(room.roomRate)
|
||||||
hasPublicPrice(room.roomRate)
|
) {
|
||||||
) {
|
const memberPrice = room.roomRate.member.localPrice.pricePerStay
|
||||||
const memberPrice = room.roomRate.member.localPrice.pricePerStay
|
const publicPrice = room.roomRate.public.localPrice.pricePerStay
|
||||||
const publicPrice = room.roomRate.public.localPrice.pricePerStay
|
total += publicPrice - memberPrice
|
||||||
return publicPrice - memberPrice
|
} else if (
|
||||||
}
|
hasPublicPrice(room.roomRate) &&
|
||||||
return 0
|
room.roomRate.public.localPrice.regularPricePerStay
|
||||||
})
|
) {
|
||||||
.join(","),
|
const publicPrice = room.roomRate.public.localPrice.pricePerStay
|
||||||
|
const regularPrice = room.roomRate.public.localPrice.regularPricePerStay
|
||||||
|
total += regularPrice - publicPrice
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}, 0),
|
||||||
duration: differenceInCalendarDays(departureDate, arrivalDate),
|
duration: differenceInCalendarDays(departureDate, arrivalDate),
|
||||||
hotelID: hotel?.operaId,
|
hotelID: hotel?.operaId,
|
||||||
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
|
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
|
||||||
@@ -194,19 +199,18 @@ export function getTracking(
|
|||||||
const ancillaries: TrackingSDKAncillaries = roomsWithPetRoom
|
const ancillaries: TrackingSDKAncillaries = roomsWithPetRoom
|
||||||
.slice(0, 1) // should only be one item
|
.slice(0, 1) // should only be one item
|
||||||
.map((room) => {
|
.map((room) => {
|
||||||
const petRoomPackage = room.packages.find(
|
return room.packages
|
||||||
(p) => p.code === RoomPackageCodeEnum.PET_ROOM
|
.filter((p) => p.code === RoomPackageCodeEnum.PET_ROOM)
|
||||||
)
|
.map((pkg) => ({
|
||||||
return {
|
hotelId: hotel.operaId,
|
||||||
hotelId: hotel.operaId,
|
productId: pkg.code,
|
||||||
productId: petRoomPackage?.code!, // property is guaranteed at this point
|
productUnits: roomsWithPetRoom.length,
|
||||||
productUnits: roomsWithPetRoom.length,
|
productPoints: 0,
|
||||||
productPoints: 0,
|
productPrice: pkg.localPrice.totalPrice * roomsWithPetRoom.length,
|
||||||
productPrice: petRoomPackage?.localPrice.totalPrice ?? 0,
|
productType: "room preference",
|
||||||
productType: "room preference",
|
productName: "pet room",
|
||||||
productName: "pet room",
|
productCategory: "",
|
||||||
productCategory: "",
|
}))[0]
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -215,6 +219,7 @@ export function getTracking(
|
|||||||
ancillaries,
|
ancillaries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasPublicPrice(
|
function hasPublicPrice(
|
||||||
roomRate: Product
|
roomRate: Product
|
||||||
): roomRate is PriceProduct & { public: NonNullable<PriceProduct["public"]> } {
|
): roomRate is PriceProduct & { public: NonNullable<PriceProduct["public"]> } {
|
||||||
@@ -223,6 +228,7 @@ function hasPublicPrice(
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasMemberPrice(
|
function hasMemberPrice(
|
||||||
roomRate: Product
|
roomRate: Product
|
||||||
): roomRate is PriceProduct & { member: NonNullable<PriceProduct["member"]> } {
|
): roomRate is PriceProduct & { member: NonNullable<PriceProduct["member"]> } {
|
||||||
@@ -231,6 +237,7 @@ function hasMemberPrice(
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasPetRoom(
|
function hasPetRoom(
|
||||||
room: Room
|
room: Room
|
||||||
): room is Room & { packages: NonNullable<Room["packages"]> } {
|
): room is Room & { packages: NonNullable<Room["packages"]> } {
|
||||||
@@ -239,6 +246,7 @@ function hasPetRoom(
|
|||||||
}
|
}
|
||||||
return room.packages.some((p) => p.code === RoomPackageCodeEnum.PET_ROOM)
|
return room.packages.some((p) => p.code === RoomPackageCodeEnum.PET_ROOM)
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcTotalPrice(rooms: Room[], isMember: boolean) {
|
function calcTotalPrice(rooms: Room[], isMember: boolean) {
|
||||||
const totalRoomPrice = calcTotalRoomPrice(rooms, isMember)
|
const totalRoomPrice = calcTotalRoomPrice(rooms, isMember)
|
||||||
const totalPackageSum = rooms.reduce((total, room) => {
|
const totalPackageSum = rooms.reduce((total, room) => {
|
||||||
@@ -247,6 +255,7 @@ function calcTotalPrice(rooms: Room[], isMember: boolean) {
|
|||||||
}, 0)
|
}, 0)
|
||||||
return totalRoomPrice + totalPackageSum
|
return totalRoomPrice + totalPackageSum
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcTotalRoomPrice(rooms: Room[], isMember: boolean) {
|
function calcTotalRoomPrice(rooms: Room[], isMember: boolean) {
|
||||||
return rooms.reduce((total, room, idx) => {
|
return rooms.reduce((total, room, idx) => {
|
||||||
// When it comes special rates, only redemption has additional price and that should be added
|
// When it comes special rates, only redemption has additional price and that should be added
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { usePathname } from "next/navigation"
|
import { usePathname } from "next/navigation"
|
||||||
import {
|
import { startTransition, useEffect, useRef, useState } from "react"
|
||||||
startTransition,
|
|
||||||
useEffect,
|
|
||||||
useOptimistic,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from "react"
|
|
||||||
|
|
||||||
import { trpc } from "@/lib/trpc/client"
|
import { trpc } from "@/lib/trpc/client"
|
||||||
import useRouterTransitionStore from "@/stores/router-transition"
|
import useRouterTransitionStore from "@/stores/router-transition"
|
||||||
@@ -105,7 +99,6 @@ export const useTrackSoftNavigation = ({
|
|||||||
isError,
|
isError,
|
||||||
} = trpc.user.userTrackingInfo.useQuery()
|
} = trpc.user.userTrackingInfo.useQuery()
|
||||||
|
|
||||||
const [loading, setLoading] = useOptimistic(false)
|
|
||||||
const [status, setStatus] = useState<TransitionStatus>(
|
const [status, setStatus] = useState<TransitionStatus>(
|
||||||
TransitionStatusEnum.NotRun
|
TransitionStatusEnum.NotRun
|
||||||
)
|
)
|
||||||
@@ -125,22 +118,17 @@ export const useTrackSoftNavigation = ({
|
|||||||
if (isTransitioning && status === TransitionStatusEnum.NotRun) {
|
if (isTransitioning && status === TransitionStatusEnum.NotRun) {
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
setStatus(TransitionStatusEnum.Running)
|
setStatus(TransitionStatusEnum.Running)
|
||||||
setLoading(true)
|
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (isTransitioning && status === TransitionStatusEnum.Running) {
|
||||||
!loading &&
|
|
||||||
isTransitioning &&
|
|
||||||
status === TransitionStatusEnum.Running
|
|
||||||
) {
|
|
||||||
setStatus(TransitionStatusEnum.Done)
|
setStatus(TransitionStatusEnum.Done)
|
||||||
stopRouterTransition()
|
stopRouterTransition()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loading && !isTransitioning && status === TransitionStatusEnum.Done) {
|
if (!isTransitioning && status === TransitionStatusEnum.Done) {
|
||||||
const pageLoadTime = getPageLoadTime()
|
const pageLoadTime = getPageLoadTime()
|
||||||
const trackingData = {
|
const trackingData = {
|
||||||
...pageData,
|
...pageData,
|
||||||
@@ -149,29 +137,27 @@ export const useTrackSoftNavigation = ({
|
|||||||
pageLoadTime: pageLoadTime,
|
pageLoadTime: pageLoadTime,
|
||||||
}
|
}
|
||||||
const pageObject = createSDKPageObject(trackingData)
|
const pageObject = createSDKPageObject(trackingData)
|
||||||
if (previousPathname.current !== pathName) {
|
const userData: TrackingSDKUserData = isError
|
||||||
const userData: TrackingSDKUserData = isError
|
? { loginStatus: "Error" }
|
||||||
? { loginStatus: "Error" }
|
: userTrackingData
|
||||||
: userTrackingData
|
|
||||||
|
|
||||||
trackPageView({
|
trackPageView({
|
||||||
event: "pageView",
|
event: "pageView",
|
||||||
pageInfo: pageObject,
|
pageInfo: pageObject,
|
||||||
userInfo: userData,
|
userInfo: userData,
|
||||||
hotelInfo: hotelInfo,
|
hotelInfo: hotelInfo,
|
||||||
paymentInfo,
|
paymentInfo,
|
||||||
ancillaries,
|
ancillaries,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
setStatus(TransitionStatusEnum.NotRun) // Reset status
|
||||||
previousPathname.current = pathName // Update for next render
|
previousPathname.current = pathName // Update for next render
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isError,
|
isError,
|
||||||
isPending,
|
isPending,
|
||||||
isTransitioning,
|
isTransitioning,
|
||||||
loading,
|
|
||||||
status,
|
status,
|
||||||
setLoading,
|
|
||||||
stopRouterTransition,
|
stopRouterTransition,
|
||||||
pageData,
|
pageData,
|
||||||
pathName,
|
pathName,
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import {
|
import { useTrackSoftNavigation } from "@/components/TrackingSDK/hooks"
|
||||||
useTrackHardNavigation,
|
|
||||||
useTrackSoftNavigation,
|
|
||||||
} from "@/components/TrackingSDK/hooks"
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
TrackingSDKAncillaries,
|
TrackingSDKAncillaries,
|
||||||
@@ -23,7 +20,9 @@ export default function TrackingSDK({
|
|||||||
paymentInfo?: TrackingSDKPaymentInfo
|
paymentInfo?: TrackingSDKPaymentInfo
|
||||||
ancillaries?: TrackingSDKAncillaries
|
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 })
|
useTrackSoftNavigation({ pageData, hotelInfo, paymentInfo, ancillaries })
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
Reference in New Issue
Block a user