Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 107x 65x 65x 65x 37x 39x 37x 39x 19x 19x 19x 19x 37x 37x 3x 3x 3x 1x 2x 2x 2x 2x 37x 37x 37x 2x 2x 37x 1x 1x 37x 37x 37x 37x 37x 37x | import { useEffect, useRef } from "react"; import { UserRole } from "shared-types/events/legacy-user"; import { sendGAEvent } from "./SendGAEvent"; type PathTrackerProps = { userRole: UserRole; children: React.ReactNode; }; /** * Wrap around your <C.Layout>. * It will send: * 1) a `custom_page_view` event on initial mount or after every route change * 2) a `page_duration` event when the user leaves the previous route */ export const PathTracker = ({ userRole, children }: PathTrackerProps) => { // keep track of the path of the page the user is leaving const prevPathRef = useRef<string>(window.location.pathname); // record when the current route was "entered" const startTimeRef = useRef<number>(Date.now()); useEffect(() => { //for tracking page views const sendPageView = (path: string) => { sendGAEvent("page_view", { page_path: path, referrer: prevPathRef.current || "", ...(userRole && { user_role: userRole }), }); }; //for tracking duration spent on page const sendPageDuration = (path: string, startTs: number) => { if (userRole) { const now = Date.now(); const deltaMs = now - startTs; const timeOnPageSec = Math.round(deltaMs / 1000); // nearest second sendGAEvent("page_duration", { page_path: path, ...(userRole && { user_role: userRole }), time_on_page_sec: timeOnPageSec, }); } }; // send page_view for the first load sendPageView(window.location.pathname); // when a route change is detected const onRouteChange = () => { const newPath = window.location.pathname; const oldPath = prevPathRef.current; // if the path didn’t actually change, do nothing if (newPath === oldPath) { return; } // 1) send page_duration for the old path sendPageDuration(oldPath, startTimeRef.current); // 2) send a new page_view for the new path, with referrer = old path sendPageView(newPath); // 3) update prevPath and reset startTime for the new page prevPathRef.current = newPath; startTimeRef.current = Date.now(); }; //pushState/replaceState so we catch in‐app ract navigation const origPush = window.history.pushState; const origReplace = window.history.replaceState; window.history.pushState = function (this: History, ...args: any[]) { origPush.apply(this, args); onRouteChange(); }; window.history.replaceState = function (this: History, ...args: any[]) { origReplace.apply(this, args); onRouteChange(); }; //Also catch Back/Forward browser buttons window.addEventListener("popstate", onRouteChange); //cleanup- when PathTracker unmounts return () => { //send duration for whichever page user was on sendPageDuration(prevPathRef.current, startTimeRef.current); //restore history methods and remove listener window.history.pushState = origPush; window.history.replaceState = origReplace; window.removeEventListener("popstate", onRouteChange); }; }, [userRole]); // Render children as usual return <>{children}</>; }; |