Merged in fix/tracking-pageload-issues (pull request #1630)
fix(tracking): fixes not sending pageview events when promise isn't resolving * fix(tracking): fixes not sending pageview events when promise isn't resolving * Refactor Approved-by: Anton Gunnarsson
This commit is contained in:
@@ -13,6 +13,7 @@ import useRouterTransitionStore from "@/stores/router-transition"
|
|||||||
import useTrackingStore from "@/stores/tracking"
|
import useTrackingStore from "@/stores/tracking"
|
||||||
|
|
||||||
import { useSessionId } from "@/hooks/useSessionId"
|
import { useSessionId } from "@/hooks/useSessionId"
|
||||||
|
import { promiseWithTimeout } from "@/utils/promiseWithTimeout"
|
||||||
import { createSDKPageObject, trackPageView } from "@/utils/tracking"
|
import { createSDKPageObject, trackPageView } from "@/utils/tracking"
|
||||||
|
|
||||||
import type { TrackingSDKProps } from "@/types/components/tracking"
|
import type { TrackingSDKProps } from "@/types/components/tracking"
|
||||||
@@ -52,7 +53,7 @@ export default function RouterTransition({
|
|||||||
hasRunInitial.current = true
|
hasRunInitial.current = true
|
||||||
setHasRun()
|
setHasRun()
|
||||||
|
|
||||||
const getPageLoadTime = () => {
|
const getPageLoadTimeEntry = () => {
|
||||||
return new Promise<number>((resolve) => {
|
return new Promise<number>((resolve) => {
|
||||||
const observer = new PerformanceObserver((entries) => {
|
const observer = new PerformanceObserver((entries) => {
|
||||||
const navEntry = entries.getEntriesByType("navigation")[0]
|
const navEntry = entries.getEntriesByType("navigation")[0]
|
||||||
@@ -65,23 +66,36 @@ export default function RouterTransition({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getLCPTime = () => {
|
const getLCPTimeEntry = () => {
|
||||||
return new Promise<number>((resolve) => {
|
return new Promise<number | undefined>((resolve) => {
|
||||||
const observer = new PerformanceObserver((entries) => {
|
const observer = new PerformanceObserver((entries) => {
|
||||||
const lastEntry = entries.getEntries().pop()
|
const lastEntry = entries.getEntries().at(-1)
|
||||||
if (lastEntry) {
|
if (lastEntry) {
|
||||||
observer.disconnect()
|
observer.disconnect()
|
||||||
resolve(lastEntry.startTime / 1000)
|
resolve(lastEntry.startTime / 1000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
observer.observe({ type: "largest-contentful-paint", buffered: true })
|
|
||||||
|
const lcpSupported =
|
||||||
|
PerformanceObserver.supportedEntryTypes?.includes(
|
||||||
|
"largest-contentful-paint"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (lcpSupported) {
|
||||||
|
observer.observe({
|
||||||
|
type: "largest-contentful-paint",
|
||||||
|
buffered: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve(undefined)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const trackPerformance = async () => {
|
const trackPerformance = async () => {
|
||||||
const [pageLoadTime, lcpTime] = await Promise.all([
|
const [pageLoadTime, lcpTime] = await Promise.all([
|
||||||
getPageLoadTime(),
|
promiseWithTimeout(getPageLoadTimeEntry(), 3000),
|
||||||
getLCPTime(),
|
promiseWithTimeout(getLCPTimeEntry(), 3000),
|
||||||
])
|
])
|
||||||
|
|
||||||
const trackingData = {
|
const trackingData = {
|
||||||
|
|||||||
@@ -367,79 +367,87 @@ export const userQueryRouter = router({
|
|||||||
if (!isValidSession(ctx.session)) {
|
if (!isValidSession(ctx.session)) {
|
||||||
return notLoggedInUserTrackingData
|
return notLoggedInUserTrackingData
|
||||||
}
|
}
|
||||||
const verifiedUserData = await getVerifiedUser({ session: ctx.session })
|
|
||||||
|
|
||||||
if (!verifiedUserData || "error" in verifiedUserData) {
|
let verifiedUserData
|
||||||
return notLoggedInUserTrackingData
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = new URLSearchParams()
|
try {
|
||||||
params.set("limit", "1")
|
verifiedUserData = await getVerifiedUser({ session: ctx.session })
|
||||||
getPreviousStaysCounter.add(1, { query: JSON.stringify({ params }) })
|
|
||||||
console.info(
|
if (!verifiedUserData || "error" in verifiedUserData) {
|
||||||
"api.booking.stays.past start",
|
return notLoggedInUserTrackingData
|
||||||
JSON.stringify({ query: { params } })
|
}
|
||||||
)
|
|
||||||
const previousStaysResponse = await api.get(
|
const params = new URLSearchParams()
|
||||||
api.endpoints.v1.Booking.Stays.past,
|
params.set("limit", "1")
|
||||||
{
|
getPreviousStaysCounter.add(1, { query: JSON.stringify({ params }) })
|
||||||
headers: {
|
console.info(
|
||||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
"api.booking.stays.past start",
|
||||||
|
JSON.stringify({ query: { params } })
|
||||||
|
)
|
||||||
|
const previousStaysResponse = await api.get(
|
||||||
|
api.endpoints.v1.Booking.Stays.past,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
params
|
||||||
params
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (!previousStaysResponse.ok) {
|
if (!previousStaysResponse.ok) {
|
||||||
getPreviousStaysFailCounter.add(1, {
|
getPreviousStaysFailCounter.add(1, {
|
||||||
error_type: "http_error",
|
error_type: "http_error",
|
||||||
error: JSON.stringify({
|
error: JSON.stringify({
|
||||||
status: previousStaysResponse.status,
|
|
||||||
statusText: previousStaysResponse.statusText,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
console.error(
|
|
||||||
"api.booking.stays.past error",
|
|
||||||
JSON.stringify({
|
|
||||||
error: {
|
|
||||||
status: previousStaysResponse.status,
|
status: previousStaysResponse.status,
|
||||||
statusText: previousStaysResponse.statusText,
|
statusText: previousStaysResponse.statusText,
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
)
|
console.error(
|
||||||
|
"api.booking.stays.past error",
|
||||||
|
JSON.stringify({
|
||||||
|
error: {
|
||||||
|
status: previousStaysResponse.status,
|
||||||
|
statusText: previousStaysResponse.statusText,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return notLoggedInUserTrackingData
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousStaysApiJson = await previousStaysResponse.json()
|
||||||
|
const verifiedPreviousStaysData =
|
||||||
|
getStaysSchema.safeParse(previousStaysApiJson)
|
||||||
|
if (!verifiedPreviousStaysData.success) {
|
||||||
|
getPreviousStaysFailCounter.add(1, {
|
||||||
|
error_type: "validation_error",
|
||||||
|
error: JSON.stringify(verifiedPreviousStaysData.error),
|
||||||
|
})
|
||||||
|
console.error(
|
||||||
|
"api.booking.stays.past validation error, ",
|
||||||
|
JSON.stringify({ error: verifiedPreviousStaysData.error })
|
||||||
|
)
|
||||||
|
return notLoggedInUserTrackingData
|
||||||
|
}
|
||||||
|
getPreviousStaysSuccessCounter.add(1)
|
||||||
|
console.info("api.booking.stays.past success", JSON.stringify({}))
|
||||||
|
|
||||||
|
const membership = getFriendsMembership(verifiedUserData.data.memberships)
|
||||||
|
|
||||||
|
const loggedInUserTrackingData: TrackingSDKUserData = {
|
||||||
|
loginStatus: "logged in",
|
||||||
|
loginType: ctx.session.token.loginType as LoginType,
|
||||||
|
memberId: verifiedUserData.data.profileId,
|
||||||
|
membershipNumber: membership?.membershipNumber,
|
||||||
|
memberLevel: membership?.membershipLevel as MembershipLevel,
|
||||||
|
noOfNightsStayed: verifiedPreviousStaysData.data.links?.totalCount ?? 0,
|
||||||
|
totalPointsAvailableToSpend: membership?.currentPoints,
|
||||||
|
loginAction: "login success",
|
||||||
|
}
|
||||||
|
return loggedInUserTrackingData
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in userTrackingInfo:", error)
|
||||||
return notLoggedInUserTrackingData
|
return notLoggedInUserTrackingData
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousStaysApiJson = await previousStaysResponse.json()
|
|
||||||
const verifiedPreviousStaysData =
|
|
||||||
getStaysSchema.safeParse(previousStaysApiJson)
|
|
||||||
if (!verifiedPreviousStaysData.success) {
|
|
||||||
getPreviousStaysFailCounter.add(1, {
|
|
||||||
error_type: "validation_error",
|
|
||||||
error: JSON.stringify(verifiedPreviousStaysData.error),
|
|
||||||
})
|
|
||||||
console.error(
|
|
||||||
"api.booking.stays.past validation error, ",
|
|
||||||
JSON.stringify({ error: verifiedPreviousStaysData.error })
|
|
||||||
)
|
|
||||||
return notLoggedInUserTrackingData
|
|
||||||
}
|
|
||||||
getPreviousStaysSuccessCounter.add(1)
|
|
||||||
console.info("api.booking.stays.past success", JSON.stringify({}))
|
|
||||||
|
|
||||||
const membership = getFriendsMembership(verifiedUserData.data.memberships)
|
|
||||||
|
|
||||||
const loggedInUserTrackingData: TrackingSDKUserData = {
|
|
||||||
loginStatus: "logged in",
|
|
||||||
loginType: ctx.session.token.loginType as LoginType,
|
|
||||||
memberId: verifiedUserData.data.profileId,
|
|
||||||
membershipNumber: membership?.membershipNumber,
|
|
||||||
memberLevel: membership?.membershipLevel as MembershipLevel,
|
|
||||||
noOfNightsStayed: verifiedPreviousStaysData.data.links?.totalCount ?? 0,
|
|
||||||
totalPointsAvailableToSpend: membership?.currentPoints,
|
|
||||||
loginAction: "login success",
|
|
||||||
}
|
|
||||||
return loggedInUserTrackingData
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
stays: router({
|
stays: router({
|
||||||
|
|||||||
12
apps/scandic-web/utils/promiseWithTimeout.ts
Normal file
12
apps/scandic-web/utils/promiseWithTimeout.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export const promiseWithTimeout = <T>(
|
||||||
|
promise: Promise<T>,
|
||||||
|
timeoutMs: number,
|
||||||
|
fallbackValue: T | undefined = undefined
|
||||||
|
) => {
|
||||||
|
return Promise.race([
|
||||||
|
promise,
|
||||||
|
new Promise<T | undefined>((resolve) =>
|
||||||
|
setTimeout(() => resolve(fallbackValue), timeoutMs)
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user