Skip to content

Commit c2e2d9f

Browse files
authored
Onwards container view tracking (#14639)
* Add container view tracking to onwards containers * Prefer root margin check for intersection observer
1 parent 345d6f9 commit c2e2d9f

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

dotcom-rendering/src/components/FetchOnwardsData.importable.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { css } from '@emotion/react';
22
import { isNonNullable } from '@guardian/libs';
3+
import type { ComponentEvent } from '@guardian/ophan-tracker-js';
4+
import { useEffect, useState } from 'react';
5+
import { submitComponentEvent } from '../client/ophan/ophan';
36
import { ArticleDesign, type ArticleFormat } from '../lib/articleFormat';
47
import { decideTrail, dedupeTrail } from '../lib/decideTrail';
58
import { useApi } from '../lib/useApi';
69
import { addDiscussionIds } from '../lib/useCommentCount';
10+
import { useIsInView } from '../lib/useIsInView';
711
import { palette } from '../palette';
812
import type { OnwardsSource } from '../types/onwards';
913
import type { RenderingTarget } from '../types/renderingTarget';
@@ -20,6 +24,7 @@ type Props = {
2024
absoluteServerTimes: boolean;
2125
renderingTarget: RenderingTarget;
2226
isAdFreeUser: boolean;
27+
containerPosition: string;
2328
webURL: string;
2429
};
2530

@@ -59,8 +64,35 @@ export const FetchOnwardsData = ({
5964
absoluteServerTimes,
6065
renderingTarget,
6166
isAdFreeUser,
67+
containerPosition,
6268
webURL,
6369
}: Props) => {
70+
const [hasBeenSeen, setIsInViewRef] = useIsInView({ rootMargin: `-100px` });
71+
72+
const [hasTrackedView, setHasTrackedView] = useState(false);
73+
74+
useEffect(() => {
75+
if (hasBeenSeen && !hasTrackedView) {
76+
const ophanComponentEvent: ComponentEvent = {
77+
component: {
78+
componentType: 'CONTAINER',
79+
id: `onwards-${onwardsSource}-${containerPosition}`,
80+
},
81+
action: 'VIEW',
82+
};
83+
84+
void submitComponentEvent(ophanComponentEvent, renderingTarget);
85+
86+
setHasTrackedView(true);
87+
}
88+
}, [
89+
hasBeenSeen,
90+
hasTrackedView,
91+
renderingTarget,
92+
onwardsSource,
93+
containerPosition,
94+
]);
95+
6496
const { data, error } = useApi<OnwardsResponse>(url);
6597

6698
if (error) {
@@ -88,7 +120,7 @@ export const FetchOnwardsData = ({
88120
const trails = buildTrails(data.trails, limit, isAdFreeUser, webURL);
89121

90122
return (
91-
<div css={minHeight}>
123+
<div ref={setIsInViewRef} css={minHeight}>
92124
<Carousel
93125
heading={data.heading || data.displayname} // Sometimes the api returns heading as 'displayName'
94126
trails={trails}

dotcom-rendering/src/components/OnwardsUpper.importable.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ export const OnwardsUpper = ({
311311
const canHaveCuratedContent =
312312
format.design === ArticleDesign.Gallery ? isUndefined(url) : true;
313313

314+
const hasOnwardsContainer = !!url;
315+
const showCuratedContainer =
316+
!!curatedDataUrl && !isPaidContent && canHaveCuratedContent;
317+
314318
return (
315319
<div css={onwardsWrapper}>
316320
{!!url && (
@@ -327,11 +331,12 @@ export const OnwardsUpper = ({
327331
absoluteServerTimes={absoluteServerTimes}
328332
renderingTarget={renderingTarget}
329333
isAdFreeUser={isAdFreeUser}
334+
containerPosition={'first'}
330335
webURL={webURL}
331336
/>
332337
</Section>
333338
)}
334-
{!!curatedDataUrl && !isPaidContent && canHaveCuratedContent && (
339+
{showCuratedContainer && (
335340
<Section
336341
fullWidth={true}
337342
borderColour={palette('--article-section-border')}
@@ -345,6 +350,9 @@ export const OnwardsUpper = ({
345350
absoluteServerTimes={absoluteServerTimes}
346351
renderingTarget={renderingTarget}
347352
isAdFreeUser={isAdFreeUser}
353+
containerPosition={
354+
hasOnwardsContainer ? 'second' : 'first'
355+
}
348356
webURL={webURL}
349357
/>
350358
</Section>

0 commit comments

Comments
 (0)