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 | 5x 5x 5x 5x 7x 5x 7x 7x 7x 7x 7x 5x 5x 3x 3x 3x 1x 2x 2x 2x 2x 5x 5x 5x 2x 2x 5x 1x 1x 5x 5x 5x 5x 5x 5x | import { useEffect, useRef } from "react"; import { sendGAEvent } from "./SendGAEvent"; type PathTrackerProps = { userRole: "cms" | "state"; 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 default function 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) => { Eif (userRole) { const now = Date.now(); const deltaMs = now - startTs; const timeOnPageSec = Math.round(deltaMs / 1000); // nearest second sendGAEvent("page_duration", { page_path: path, 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}</>; } |