@@ -35,6 +35,7 @@ import { TopPlacement } from "./ui/organisms/placement";
35
35
import { Blog } from "./blog" ;
36
36
import { Newsletter } from "./newsletter" ;
37
37
import { Curriculum } from "./curriculum" ;
38
+ import { useGA } from "./ga-context" ;
38
39
39
40
const AllFlaws = React . lazy ( ( ) => import ( "./flaws" ) ) ;
40
41
const Translations = React . lazy ( ( ) => import ( "./translations" ) ) ;
@@ -135,6 +136,7 @@ export function App(appProps: HydrationData) {
135
136
136
137
usePing ( ) ;
137
138
useGleanPage ( pageNotFound , appProps . doc ) ;
139
+ useScrollDepthMeasurement ( ) ;
138
140
139
141
const localeMatch = useMatch ( "/:locale/*" ) ;
140
142
@@ -349,3 +351,46 @@ export function App(appProps: HydrationData) {
349
351
) ;
350
352
return routes ;
351
353
}
354
+
355
+ function useScrollDepthMeasurement ( thresholds = [ 25 , 50 , 75 ] ) {
356
+ const timeoutID = React . useRef < number | null > ( ) ;
357
+ const [ currentDepth , setScrollDepth ] = React . useState ( 0 ) ;
358
+ const { gtag } = useGA ( ) ;
359
+
360
+ useEffect ( ( ) => {
361
+ const listener = ( ) => {
362
+ if ( timeoutID . current ) {
363
+ window . clearTimeout ( timeoutID . current ) ;
364
+ }
365
+ timeoutID . current = window . setTimeout ( ( ) => {
366
+ const { scrollHeight } = document . documentElement ;
367
+ const { innerHeight, scrollY } = window ;
368
+ const scrollPosition = innerHeight + scrollY ;
369
+ const depth = ( 100 * scrollPosition ) / scrollHeight ;
370
+
371
+ const matchingThresholds = thresholds . filter (
372
+ ( threshold ) => currentDepth < threshold && threshold <= depth
373
+ ) ;
374
+
375
+ matchingThresholds . forEach ( ( threshold ) => {
376
+ gtag ( "event" , "scroll" , {
377
+ percent_scrolled : String ( threshold ) ,
378
+ } ) ;
379
+ } ) ;
380
+
381
+ const lastThreshold = matchingThresholds . at ( - 1 ) ;
382
+ if ( lastThreshold ) {
383
+ setScrollDepth ( lastThreshold ) ;
384
+ }
385
+
386
+ timeoutID . current = null ;
387
+ } , 100 ) ;
388
+ } ;
389
+
390
+ window . addEventListener ( "scroll" , listener ) ;
391
+
392
+ return ( ) => window . removeEventListener ( "scroll" , listener ) ;
393
+ } ) ;
394
+
395
+ return currentDepth ;
396
+ }
0 commit comments