diff --git a/apps/scandic-web/components/TrackingSDK/RouterTransition.tsx b/apps/scandic-web/components/TrackingSDK/RouterTransition.tsx index d6731a207..76339515c 100644 --- a/apps/scandic-web/components/TrackingSDK/RouterTransition.tsx +++ b/apps/scandic-web/components/TrackingSDK/RouterTransition.tsx @@ -13,6 +13,7 @@ import useRouterTransitionStore from "@/stores/router-transition" import useTrackingStore from "@/stores/tracking" import { useSessionId } from "@/hooks/useSessionId" +import { promiseWithTimeout } from "@/utils/promiseWithTimeout" import { createSDKPageObject, trackPageView } from "@/utils/tracking" import type { TrackingSDKProps } from "@/types/components/tracking" @@ -52,7 +53,7 @@ export default function RouterTransition({ hasRunInitial.current = true setHasRun() - const getPageLoadTime = () => { + const getPageLoadTimeEntry = () => { return new Promise((resolve) => { const observer = new PerformanceObserver((entries) => { const navEntry = entries.getEntriesByType("navigation")[0] @@ -65,23 +66,36 @@ export default function RouterTransition({ }) } - const getLCPTime = () => { - return new Promise((resolve) => { + const getLCPTimeEntry = () => { + return new Promise((resolve) => { const observer = new PerformanceObserver((entries) => { - const lastEntry = entries.getEntries().pop() + const lastEntry = entries.getEntries().at(-1) if (lastEntry) { observer.disconnect() 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 [pageLoadTime, lcpTime] = await Promise.all([ - getPageLoadTime(), - getLCPTime(), + promiseWithTimeout(getPageLoadTimeEntry(), 3000), + promiseWithTimeout(getLCPTimeEntry(), 3000), ]) const trackingData = { diff --git a/apps/scandic-web/server/routers/user/query.ts b/apps/scandic-web/server/routers/user/query.ts index 33dfdd2ac..76b050033 100644 --- a/apps/scandic-web/server/routers/user/query.ts +++ b/apps/scandic-web/server/routers/user/query.ts @@ -367,79 +367,87 @@ export const userQueryRouter = router({ if (!isValidSession(ctx.session)) { return notLoggedInUserTrackingData } - const verifiedUserData = await getVerifiedUser({ session: ctx.session }) - if (!verifiedUserData || "error" in verifiedUserData) { - return notLoggedInUserTrackingData - } + let verifiedUserData - const params = new URLSearchParams() - params.set("limit", "1") - getPreviousStaysCounter.add(1, { query: JSON.stringify({ params }) }) - console.info( - "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}`, + try { + verifiedUserData = await getVerifiedUser({ session: ctx.session }) + + if (!verifiedUserData || "error" in verifiedUserData) { + return notLoggedInUserTrackingData + } + + const params = new URLSearchParams() + params.set("limit", "1") + getPreviousStaysCounter.add(1, { query: JSON.stringify({ params }) }) + console.info( + "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) { - getPreviousStaysFailCounter.add(1, { - error_type: "http_error", - error: JSON.stringify({ - status: previousStaysResponse.status, - statusText: previousStaysResponse.statusText, - }), - }) - console.error( - "api.booking.stays.past error", - JSON.stringify({ - error: { + if (!previousStaysResponse.ok) { + getPreviousStaysFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ status: previousStaysResponse.status, 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 } - - 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({ diff --git a/apps/scandic-web/utils/promiseWithTimeout.ts b/apps/scandic-web/utils/promiseWithTimeout.ts new file mode 100644 index 000000000..31e6e6084 --- /dev/null +++ b/apps/scandic-web/utils/promiseWithTimeout.ts @@ -0,0 +1,12 @@ +export const promiseWithTimeout = ( + promise: Promise, + timeoutMs: number, + fallbackValue: T | undefined = undefined +) => { + return Promise.race([ + promise, + new Promise((resolve) => + setTimeout(() => resolve(fallbackValue), timeoutMs) + ), + ]) +}