From 5d05cd268c725fd637bff5c64ea05d040afcf18b Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Wed, 1 Jul 2026 09:17:33 +0100 Subject: [PATCH 01/25] WS-2831: init commit, pseudo code comments --- .../components/ATIAnalytics/atiUrl/index.ts | 4 ++++ .../ATIAnalytics/canonical/index.tsx | 10 ++++++++ src/app/components/ATIAnalytics/index.tsx | 19 ++++++++++++++- .../ATIAnalytics/params/buildParams/index.ts | 11 +++++++++ .../components/ATIAnalytics/params/index.ts | 13 ++++++++++ .../lib/analyticsUtils/sendBeacon/index.ts | 24 ++++++++++++++++++- 6 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/app/components/ATIAnalytics/atiUrl/index.ts b/src/app/components/ATIAnalytics/atiUrl/index.ts index 604dae7a99e..750a3ac47ce 100644 --- a/src/app/components/ATIAnalytics/atiUrl/index.ts +++ b/src/app/components/ATIAnalytics/atiUrl/index.ts @@ -189,3 +189,7 @@ export const buildReverbEventModel = ({ }, }; }; + +// add function to build resonance analytics model, e.g. +// export const buildResonanceAnalyticsModel = ({...}) +// we can do more in the spike here to compare values diff --git a/src/app/components/ATIAnalytics/canonical/index.tsx b/src/app/components/ATIAnalytics/canonical/index.tsx index 2b9f3d011d4..d9c56dc9b73 100644 --- a/src/app/components/ATIAnalytics/canonical/index.tsx +++ b/src/app/components/ATIAnalytics/canonical/index.tsx @@ -39,6 +39,8 @@ const addScript = ({ script, parameters, nonce }: InlineScriptProps) => { }; const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => { + // add resonanceParams to props if needed, e.g. + // const CanonicalATIAnalytics = ({ reverbParams, resonanceParams }: ATIAnalyticsProps) => { const { isLite, nonce } = use(RequestContext); usePWAInstallTracker(); @@ -49,9 +51,17 @@ const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => { const [reverbBeaconConfig] = useState(reverbParams); + // add resonanceBeaconConfig to state? copilot says + // It is likely there to freeze the initial analytics payload so the page-view beacon is sent once per mount, not again on re-renders. + // so likely yes, e.g. + // const [resonanceBeaconConfig] = useState(resonanceParams); + useEffect(() => { if (!isOperaProxy()) sendBeacon(reverbBeaconConfig); }, [reverbBeaconConfig]); + // add resonance to above, e.g. + // if (!isOperaProxy()) sendBeacon(reverbBeaconConfig, resonanceBeaconConfig); + // }, [reverbBeaconConfig, resonanceBeaconConfig]); const liteSiteReverbURL = reverbUrlHelper.getLitePageViewUrl(reverbParams); const operaMiniPageViewReverbURL = diff --git a/src/app/components/ATIAnalytics/index.tsx b/src/app/components/ATIAnalytics/index.tsx index 9b5557dbc32..3a56bc6596e 100644 --- a/src/app/components/ATIAnalytics/index.tsx +++ b/src/app/components/ATIAnalytics/index.tsx @@ -4,20 +4,37 @@ import { ReverbParamsContext } from '#app/contexts/ReverbParamsContext'; import CanonicalATIAnalytics from './canonical'; import AmpATIAnalytics from './amp'; import AmpGeo from '../../legacy/components/AmpGeo'; +// import { ATIProps } from './types'; // blah merge conflict +// import buildReverbParams from './params'; // blah merge conflict +// also fetch buildResonanceParams from './resonanceParams', e.g. import buildResonanceParams from './resonanceParams'; const ATIAnalytics = () => { const requestContext = use(RequestContext); const { isAmp } = requestContext; + // fetch useResonance from serviceContext, e.g. + // const { useResonance } = serviceContext; const { reverbParams } = use(ReverbParamsContext); + // build resonance params if useResonance is true, e.g. + // const resonanceParams = useResonance + // ? buildResonanceParams({ + // requestContext, + // serviceContext, + // atiData: atiData || {}, + // ... + // }) + // : null; + return isAmp ? ( <> ) : ( - + ); }; diff --git a/src/app/components/ATIAnalytics/params/buildParams/index.ts b/src/app/components/ATIAnalytics/params/buildParams/index.ts index 30f12c183c4..70ac8c93451 100644 --- a/src/app/components/ATIAnalytics/params/buildParams/index.ts +++ b/src/app/components/ATIAnalytics/params/buildParams/index.ts @@ -1,5 +1,6 @@ import { LIBRARY_VERSION } from '../../../../lib/analyticsUtils'; import { buildReverbAnalyticsModel } from '../../atiUrl'; +// import e.g. import { buildResonanceAnalyticsModel } from '../../atiUrl'; import { ATIDataWithContexts } from '../../types'; export const buildPageATIParams = ({ @@ -87,3 +88,13 @@ export const buildPageReverbParams = ({ hashedId, }), ); + +// add exported function that builds resonance params calling buildPageATIParams above, e.g. +// export const buildPageResonanceParams = ({ +// atiData, +// requestContext, +// serviceContext, +// }: ATIDataWithContexts) => +// buildResonanceAnalyticsModel( +// buildPageATIParams({ atiData, requestContext, serviceContext }), +// ); diff --git a/src/app/components/ATIAnalytics/params/index.ts b/src/app/components/ATIAnalytics/params/index.ts index b84fe4a8007..4ef36908319 100644 --- a/src/app/components/ATIAnalytics/params/index.ts +++ b/src/app/components/ATIAnalytics/params/index.ts @@ -1,6 +1,19 @@ import { buildPageReverbParams } from './buildParams'; +// add import e.g. import { buildPageResonanceParams } from './buildParams'; import { ReverbDetailsProviders } from '../types'; +// add types as needed, e.g. import { ResonanceDetailsProviders } from '../types'; +// add function to build resonance params, e.g. +// export const buildResonanceParams = ({ +// requestContext, +// serviceContext, +// atiData, +// ... +// }: ResonanceDetailsProviders) => { +// return buildPageReverbParams({ atiData, requestContext, serviceContext }); +// }; + +// change this to not be default export default ({ requestContext, serviceContext, diff --git a/src/app/lib/analyticsUtils/sendBeacon/index.ts b/src/app/lib/analyticsUtils/sendBeacon/index.ts index 26c43469d90..64e34863fbc 100644 --- a/src/app/lib/analyticsUtils/sendBeacon/index.ts +++ b/src/app/lib/analyticsUtils/sendBeacon/index.ts @@ -6,6 +6,8 @@ import { import onClient from '../../utilities/onClient'; import nodeLogger from '../../logger.node'; import { ATI_LOGGING_ERROR } from '../../logger.const'; +// here or somewhere else we will need to import resonance - we can follow the pattern of the reverbURLHelper, e,g. +// import { resonance ... } from '@bbc/resonance...'; const logger = nodeLogger(__filename); @@ -62,7 +64,7 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { // eslint-disable-next-line no-underscore-dangle return window.__reverb.__reverbLoadedPromise.then( async reverb => { - if (!reverb.isReady()) await reverb.initialise(); + if (!reverb.isReady()) await reverb.initialise(); // here we initialise reverb await reverbHandlers[eventName]({ reverbInstance: reverb, @@ -77,10 +79,30 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { ); }; +// add setResonancePageValues function here + +// add callResonance function here - might need to take a different form since we initialise once? + const sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig) => { + // add resonanceBeaconConfig param to function if needed, e.g. + // sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig, resonanceBeaconConfig?: ResonanceBeaconConfig) => { if (onClient()) { try { const { eventDetails } = reverbBeaconConfig; + // add if else statement here to run resonance analytics if resonanceBeaconConfig is passed in + // IF we are not wanting to send both reverb and resonance page view info + // otherwise take a different approach + // e.g. + // if (resonanceBeaconConfig) { + // const { + // params: { page, user }, + // eventDetails, + // } = resonanceBeaconConfig; + + // await setResonancePageValues({ pageVars: page, userVars: user }); + + // await callResonance(eventDetails); + // } else { await callReverb(eventDetails); } catch (error) { From 10cbd5e81882dc57c551fec5ff759462aee94cc5 Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Thu, 6 Aug 2026 08:40:59 +0100 Subject: [PATCH 02/25] WS-2831: Install resonance package --- package.json | 1 + .../lib/analyticsUtils/sendBeacon/index.ts | 4 ++-- yarn.lock | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f305adde950..052839abc98 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "react-is": "19" }, "dependencies": { + "@bbc/resonance": "https://mybbc-analytics.files.bbci.co.uk/resonance/resonance-2.7.2.tgz", "@bbc/reverb-url-helper": "https://mybbc-analytics.files.bbci.co.uk/reverb-url-helper/bbc-reverb-url-helper-2.5.0.tgz", "@bbc/web-vitals": "2.6.0", "@emotion/cache": "11.14.0", diff --git a/src/app/lib/analyticsUtils/sendBeacon/index.ts b/src/app/lib/analyticsUtils/sendBeacon/index.ts index 64e34863fbc..f3e1d3d9f37 100644 --- a/src/app/lib/analyticsUtils/sendBeacon/index.ts +++ b/src/app/lib/analyticsUtils/sendBeacon/index.ts @@ -1,3 +1,5 @@ +// import resonance - we can follow the pattern of the reverbURLHelper, e,g. +// import { Resonance, ... } from '@bbc/resonance'; import { ReverbClient } from '#app/models/types/eventTracking'; import { ReverbBeaconConfig, @@ -6,8 +8,6 @@ import { import onClient from '../../utilities/onClient'; import nodeLogger from '../../logger.node'; import { ATI_LOGGING_ERROR } from '../../logger.const'; -// here or somewhere else we will need to import resonance - we can follow the pattern of the reverbURLHelper, e,g. -// import { resonance ... } from '@bbc/resonance...'; const logger = nodeLogger(__filename); diff --git a/yarn.lock b/yarn.lock index 1758a9c326e..8fada516c9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2213,6 +2213,15 @@ __metadata: languageName: node linkType: hard +"@bbc/resonance@https://mybbc-analytics.files.bbci.co.uk/resonance/resonance-2.7.2.tgz": + version: 2.7.2 + resolution: "@bbc/resonance@https://mybbc-analytics.files.bbci.co.uk/resonance/resonance-2.7.2.tgz" + dependencies: + uuid: "npm:14.0.0" + checksum: 10/b0bb7276ddb297c04373a3b7301f2958bf3914970309585f393bd856c27e44a04a7aff77e0310a704dcc392ad9cce14eea2f51496284e10ac462d4cd47dcf8ff + languageName: node + linkType: hard + "@bbc/reverb-url-helper@https://mybbc-analytics.files.bbci.co.uk/reverb-url-helper/bbc-reverb-url-helper-2.5.0.tgz": version: 2.5.0 resolution: "@bbc/reverb-url-helper@https://mybbc-analytics.files.bbci.co.uk/reverb-url-helper/bbc-reverb-url-helper-2.5.0.tgz" @@ -17046,6 +17055,7 @@ __metadata: "@babel/preset-env": "npm:7.29.7" "@babel/preset-react": "npm:7.29.7" "@babel/preset-typescript": "npm:7.29.7" + "@bbc/resonance": "https://mybbc-analytics.files.bbci.co.uk/resonance/resonance-2.7.2.tgz" "@bbc/reverb-url-helper": "https://mybbc-analytics.files.bbci.co.uk/reverb-url-helper/bbc-reverb-url-helper-2.5.0.tgz" "@bbc/web-vitals": "npm:2.6.0" "@cypress/webpack-preprocessor": "npm:7.1.1" @@ -18786,6 +18796,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:14.0.0": + version: 14.0.0 + resolution: "uuid@npm:14.0.0" + bin: + uuid: dist-node/bin/uuid + checksum: 10/8ee9b98f9650e25555515f7a28d3c3ae9364e72f7bb19b9e08b681bc135338beba5509b2830f6ae1cfaba4d45401da0d16d4d109b977097bc3d6ba0c5583341b + languageName: node + linkType: hard + "uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" From 77aac2036b8dc0f4de88d3706520c3b15550e4aa Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Thu, 6 Aug 2026 09:54:18 +0100 Subject: [PATCH 03/25] WS-2831: Updates comments --- src/app/components/ATIAnalytics/index.tsx | 3 +++ src/app/lib/analyticsUtils/sendBeacon/index.ts | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/components/ATIAnalytics/index.tsx b/src/app/components/ATIAnalytics/index.tsx index 3a56bc6596e..b91e6e3c4ac 100644 --- a/src/app/components/ATIAnalytics/index.tsx +++ b/src/app/components/ATIAnalytics/index.tsx @@ -16,6 +16,9 @@ const ATIAnalytics = () => { const { reverbParams } = use(ReverbParamsContext); + // EITHER build resonance params here like we did for Reverb before these changes https://github.com/bbc/simorgh/pull/14120 + // Or build ResonanceParamsContext (not described in depth in this POC due to implementation change occuring after POC was created) + // build resonance params if useResonance is true, e.g. // const resonanceParams = useResonance // ? buildResonanceParams({ diff --git a/src/app/lib/analyticsUtils/sendBeacon/index.ts b/src/app/lib/analyticsUtils/sendBeacon/index.ts index f3e1d3d9f37..a31f724714d 100644 --- a/src/app/lib/analyticsUtils/sendBeacon/index.ts +++ b/src/app/lib/analyticsUtils/sendBeacon/index.ts @@ -81,7 +81,8 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { // add setResonancePageValues function here -// add callResonance function here - might need to take a different form since we initialise once? +// add initialise Resonance function here inside callResonance function +// option to use resonanceProperties.suppressInitialPageview at initialisation. const sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig) => { // add resonanceBeaconConfig param to function if needed, e.g. From b4607e424d696d7929a672d1b814720143f185ef Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Thu, 6 Aug 2026 16:54:29 +0100 Subject: [PATCH 04/25] WS-2831: Use dummy params to initialise Resonance --- .../ATIAnalytics/canonical/index.tsx | 41 ++++++++++++++++++- .../lib/analyticsUtils/sendBeacon/index.ts | 38 ++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/app/components/ATIAnalytics/canonical/index.tsx b/src/app/components/ATIAnalytics/canonical/index.tsx index 87d21fb0375..afddca4311f 100644 --- a/src/app/components/ATIAnalytics/canonical/index.tsx +++ b/src/app/components/ATIAnalytics/canonical/index.tsx @@ -10,6 +10,12 @@ import addInlineScript, { } from '#app/lib/utilities/addInlineScript'; import usePWAInstallTracker from '#app/hooks/usePWAInstallTracker'; import { reverbUrlHelper } from '@bbc/reverb-url-helper'; +import { Resonance, ResonanceMode } from '@bbc/resonance'; +import type { + ResonanceProperties, + PageviewProperties, + BaseProperties, +} from '@bbc/resonance'; import useConnectionBackOnlineTracker from '#app/hooks/useConnectionBackOnlineTracker'; import useConnectionTypeTracker from '#app/hooks/useConnectionTypeTracker'; import usePWAOfflineTracking from '#app/hooks/usePWAOfflineTracking'; @@ -43,6 +49,35 @@ const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => { // const CanonicalATIAnalytics = ({ reverbParams, resonanceParams }: ATIAnalyticsProps) => { const { isLite, nonce } = use(RequestContext); + const resonanceParams = { + resonanceProperties: { + mode: ResonanceMode.TEST, + }, + baseProperties: { + app: { + name: 'news-mundo', + version: '0.1', + }, + destination: 'WS_NEWS_LANGUAGES_TEST', + hashedUserId: 'veV9rmzQJt0SgWWjYnZTltTO1hXIIpyZVbz0WV-7HAs', + pageName: 'pagename.page', + section: 'test-section::test-subsection::test-subsubsection', + producer: 'BBC_WORLD_NEWS', + siteId: 12345, + }, + pageviewProperties: { + contentId: 'urn:bbc:tipo:topic:c93v2kkze2rt', + contentType: 'index-home', + language: 'es', + destination: 'WS_NEWS_LANGUAGES_TEST', + producer: 'BBC_WORLD_NEWS', + }, + } as { + resonanceProperties: ResonanceProperties; + pageviewProperties: PageviewProperties; + baseProperties: BaseProperties; + }; + usePWAInstallTracker(); useConnectionTypeTracker(); @@ -51,14 +86,16 @@ const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => { const [reverbBeaconConfig] = useState(reverbParams); + const [resonanceBeaconConfig] = useState(resonanceParams); + // add resonanceBeaconConfig to state? copilot says // It is likely there to freeze the initial analytics payload so the page-view beacon is sent once per mount, not again on re-renders. // so likely yes, e.g. // const [resonanceBeaconConfig] = useState(resonanceParams); useEffect(() => { - if (!isOperaProxy()) sendBeacon(reverbBeaconConfig); - }, [reverbBeaconConfig]); + if (!isOperaProxy()) sendBeacon(reverbBeaconConfig, resonanceBeaconConfig); + }, [reverbBeaconConfig, resonanceBeaconConfig]); // add resonance to above, e.g. // if (!isOperaProxy()) sendBeacon(reverbBeaconConfig, resonanceBeaconConfig); // }, [reverbBeaconConfig, resonanceBeaconConfig]); diff --git a/src/app/lib/analyticsUtils/sendBeacon/index.ts b/src/app/lib/analyticsUtils/sendBeacon/index.ts index a31f724714d..ff935fa3ffd 100644 --- a/src/app/lib/analyticsUtils/sendBeacon/index.ts +++ b/src/app/lib/analyticsUtils/sendBeacon/index.ts @@ -1,10 +1,15 @@ // import resonance - we can follow the pattern of the reverbURLHelper, e,g. -// import { Resonance, ... } from '@bbc/resonance'; +import { Resonance, ResonanceMode } from '@bbc/resonance'; import { ReverbClient } from '#app/models/types/eventTracking'; import { ReverbBeaconConfig, ReverbEventDetails, } from '#app/components/ATIAnalytics/types'; +import type { + ResonanceProperties, + PageviewProperties, + BaseProperties, +} from '@bbc/resonance'; import onClient from '../../utilities/onClient'; import nodeLogger from '../../logger.node'; import { ATI_LOGGING_ERROR } from '../../logger.const'; @@ -66,6 +71,8 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { async reverb => { if (!reverb.isReady()) await reverb.initialise(); // here we initialise reverb + console.log('Reverb initialised with params:', eventDetails); + await reverbHandlers[eventName]({ reverbInstance: reverb, eventDetails, @@ -75,16 +82,41 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { logger.error(ATI_LOGGING_ERROR, { error: 'Failed to load reverb. No event sent', }); + console.log('Reverb errored with params:', eventDetails); }, ); }; +const callResonance = (resonanceParams: ResonanceParams) => { + try { + // add checks in here so this only runs when resonanceParams is not undefined. + console.log('Resonance initialised with params:', resonanceParams); + Resonance.initialise( + resonanceParams.resonanceProperties, + resonanceParams.baseProperties, + resonanceParams.pageviewProperties, + ); + } catch (error) { + console.log('throwing error with param:', resonanceParams); + throw new Error(`Error initialising Resonance: ${error}`); + } +}; + // add setResonancePageValues function here // add initialise Resonance function here inside callResonance function // option to use resonanceProperties.suppressInitialPageview at initialisation. -const sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig) => { +type ResonanceParams = { + resonanceProperties: ResonanceProperties; + pageviewProperties: PageviewProperties; + baseProperties: BaseProperties; +}; + +const sendBeacon = async ( + reverbBeaconConfig: ReverbBeaconConfig, + resonanceParams: ResonanceParams, +) => { // add resonanceBeaconConfig param to function if needed, e.g. // sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig, resonanceBeaconConfig?: ResonanceBeaconConfig) => { if (onClient()) { @@ -105,6 +137,8 @@ const sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig) => { // await callResonance(eventDetails); // } else { + callResonance(resonanceParams); + await callReverb(eventDetails); } catch (error) { logger.error(ATI_LOGGING_ERROR, { From 32491ddc34f0d6235978fa1e4bfc2c728392deee Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Fri, 7 Aug 2026 14:10:25 +0100 Subject: [PATCH 05/25] WS-2831: Comments out hardcoded values. Amends Types. --- .../ATIAnalytics/canonical/index.tsx | 59 ++++++++++--------- src/app/components/ATIAnalytics/index.tsx | 16 ++++- .../ATIAnalytics/params/buildParams/index.ts | 26 +++++--- .../components/ATIAnalytics/params/index.ts | 25 ++++---- src/app/components/ATIAnalytics/types.ts | 12 ++++ .../lib/analyticsUtils/sendBeacon/index.ts | 21 +++---- 6 files changed, 98 insertions(+), 61 deletions(-) diff --git a/src/app/components/ATIAnalytics/canonical/index.tsx b/src/app/components/ATIAnalytics/canonical/index.tsx index afddca4311f..5c3d6dabd7a 100644 --- a/src/app/components/ATIAnalytics/canonical/index.tsx +++ b/src/app/components/ATIAnalytics/canonical/index.tsx @@ -44,39 +44,40 @@ const addScript = ({ script, parameters, nonce }: InlineScriptProps) => { return {addInlineScript({ script, parameters, nonce })}; }; -const CanonicalATIAnalytics = ({ reverbParams }: ATIAnalyticsProps) => { +const CanonicalATIAnalytics = ({ + reverbParams, + resonanceParams, +}: ATIAnalyticsProps) => { // add resonanceParams to props if needed, e.g. // const CanonicalATIAnalytics = ({ reverbParams, resonanceParams }: ATIAnalyticsProps) => { const { isLite, nonce } = use(RequestContext); - const resonanceParams = { - resonanceProperties: { - mode: ResonanceMode.TEST, - }, - baseProperties: { - app: { - name: 'news-mundo', - version: '0.1', - }, - destination: 'WS_NEWS_LANGUAGES_TEST', - hashedUserId: 'veV9rmzQJt0SgWWjYnZTltTO1hXIIpyZVbz0WV-7HAs', - pageName: 'pagename.page', - section: 'test-section::test-subsection::test-subsubsection', - producer: 'BBC_WORLD_NEWS', - siteId: 12345, - }, - pageviewProperties: { - contentId: 'urn:bbc:tipo:topic:c93v2kkze2rt', - contentType: 'index-home', - language: 'es', - destination: 'WS_NEWS_LANGUAGES_TEST', - producer: 'BBC_WORLD_NEWS', - }, - } as { - resonanceProperties: ResonanceProperties; - pageviewProperties: PageviewProperties; - baseProperties: BaseProperties; - }; + // const resonanceParams = { + // resonanceProperties: { + // mode: ResonanceMode.TEST, + // }, + // baseProperties: { + // app: { + // name: 'news-mundo', + // }, + // destination: 'WS_NEWS_LANGUAGES_TEST', + // hashedUserId: 'veV9rmzQJt0SgWWjYnZTltTO1hXIIpyZVbz0WV-7HAs', + // pageName: 'pagename.page', + // producer: 'BBC_WORLD_NEWS', + // siteId: 12345, // WS_NEWS_LANGUAGES_TEST: '598343', + // }, + // pageviewProperties: { + // contentId: 'urn:bbc:tipo:topic:c93v2kkze2rt', + // contentType: 'index-home', + // language: 'es', + // destination: 'WS_NEWS_LANGUAGES_TEST', + // producer: 'BBC_WORLD_NEWS', + // }, + // } as { + // resonanceProperties: ResonanceProperties; + // pageviewProperties: PageviewProperties; + // baseProperties: BaseProperties; + // }; usePWAInstallTracker(); diff --git a/src/app/components/ATIAnalytics/index.tsx b/src/app/components/ATIAnalytics/index.tsx index b91e6e3c4ac..689f8475511 100644 --- a/src/app/components/ATIAnalytics/index.tsx +++ b/src/app/components/ATIAnalytics/index.tsx @@ -1,21 +1,34 @@ import { use } from 'react'; import { RequestContext } from '#contexts/RequestContext'; import { ReverbParamsContext } from '#app/contexts/ReverbParamsContext'; +import { AccountContext } from '#contexts/AccountContext'; // temp - this will be context provider +import { ServiceContext } from '#contexts/ServiceContext'; // temp - this will be context provider import CanonicalATIAnalytics from './canonical'; import AmpATIAnalytics from './amp'; import AmpGeo from '../../legacy/components/AmpGeo'; +import buildResonanceParams from './params'; // import { ATIProps } from './types'; // blah merge conflict // import buildReverbParams from './params'; // blah merge conflict // also fetch buildResonanceParams from './resonanceParams', e.g. import buildResonanceParams from './resonanceParams'; const ATIAnalytics = () => { const requestContext = use(RequestContext); + const serviceContext = use(ServiceContext); + const { isSignedIn, hashedUserId: hashedId } = use(AccountContext); const { isAmp } = requestContext; // fetch useResonance from serviceContext, e.g. // const { useResonance } = serviceContext; const { reverbParams } = use(ReverbParamsContext); + // to do - replace this with using context provider + const resonanceParams = buildResonanceParams({ + requestContext, + serviceContext, + isSignedIn, + hashedId, + }); + // EITHER build resonance params here like we did for Reverb before these changes https://github.com/bbc/simorgh/pull/14120 // Or build ResonanceParamsContext (not described in depth in this POC due to implementation change occuring after POC was created) @@ -36,7 +49,8 @@ const ATIAnalytics = () => { ) : ( ); }; diff --git a/src/app/components/ATIAnalytics/params/buildParams/index.ts b/src/app/components/ATIAnalytics/params/buildParams/index.ts index 70ac8c93451..5e82bddf792 100644 --- a/src/app/components/ATIAnalytics/params/buildParams/index.ts +++ b/src/app/components/ATIAnalytics/params/buildParams/index.ts @@ -90,11 +90,21 @@ export const buildPageReverbParams = ({ ); // add exported function that builds resonance params calling buildPageATIParams above, e.g. -// export const buildPageResonanceParams = ({ -// atiData, -// requestContext, -// serviceContext, -// }: ATIDataWithContexts) => -// buildResonanceAnalyticsModel( -// buildPageATIParams({ atiData, requestContext, serviceContext }), -// ); +export const buildPageResonanceParams = ({ + requestContext, + serviceContext, + isSignedIn, + hashedId, +}: ATIDataWithContexts & { + isSignedIn?: boolean; + hashedId?: string | null; +}) => + // need to pass in ATIData - we can get this via the context provider + buildResonanceAnalyticsModel( + buildPageATIParams({ + requestContext, + serviceContext, + isSignedIn, + hashedId, + }), + ); diff --git a/src/app/components/ATIAnalytics/params/index.ts b/src/app/components/ATIAnalytics/params/index.ts index 4ef36908319..79a1c46eaf3 100644 --- a/src/app/components/ATIAnalytics/params/index.ts +++ b/src/app/components/ATIAnalytics/params/index.ts @@ -1,17 +1,22 @@ -import { buildPageReverbParams } from './buildParams'; -// add import e.g. import { buildPageResonanceParams } from './buildParams'; +import { buildPageReverbParams, buildPageResonanceParams } from './buildParams'; import { ReverbDetailsProviders } from '../types'; // add types as needed, e.g. import { ResonanceDetailsProviders } from '../types'; // add function to build resonance params, e.g. -// export const buildResonanceParams = ({ -// requestContext, -// serviceContext, -// atiData, -// ... -// }: ResonanceDetailsProviders) => { -// return buildPageReverbParams({ atiData, requestContext, serviceContext }); -// }; +export const buildResonanceParams = ({ + requestContext, + serviceContext, + isSignedIn, + hashedId, + // ResonanceDetailsProviders +}: any) => { + return buildPageResonanceParams({ + requestContext, + serviceContext, + isSignedIn, + hashedId, + }); +}; // change this to not be default export default ({ diff --git a/src/app/components/ATIAnalytics/types.ts b/src/app/components/ATIAnalytics/types.ts index bebdbf8b4a1..1ec63d851d7 100644 --- a/src/app/components/ATIAnalytics/types.ts +++ b/src/app/components/ATIAnalytics/types.ts @@ -1,4 +1,9 @@ /* eslint-disable camelcase */ +import type { + ResonanceProperties, + PageviewProperties, + BaseProperties, +} from '@bbc/resonance'; import { PageTypes, Platforms, Services } from '../../models/types/global'; import { RequestContextProps } from '../../contexts/RequestContext'; import { ServiceConfig } from '../../models/types/serviceConfig'; @@ -137,6 +142,12 @@ export type ReverbEventDetails = { originalEvent?: Event; }; +export type ResonanceBeaconConfig = { + resonanceProperties: ResonanceProperties; + pageviewProperties: PageviewProperties; + baseProperties: BaseProperties; +}; + export type ReverbBeaconConfig = { params: { page: ReverbPageVars; user: ReverbUserVars }; eventDetails: ReverbEventDetails; @@ -144,6 +155,7 @@ export type ReverbBeaconConfig = { export interface ATIAnalyticsProps { reverbParams: ReverbBeaconConfig; + resonanceParams?: ResonanceBeaconConfig; } export interface ATIEventTrackingProps { diff --git a/src/app/lib/analyticsUtils/sendBeacon/index.ts b/src/app/lib/analyticsUtils/sendBeacon/index.ts index ff935fa3ffd..7d130a6be6c 100644 --- a/src/app/lib/analyticsUtils/sendBeacon/index.ts +++ b/src/app/lib/analyticsUtils/sendBeacon/index.ts @@ -3,13 +3,14 @@ import { Resonance, ResonanceMode } from '@bbc/resonance'; import { ReverbClient } from '#app/models/types/eventTracking'; import { ReverbBeaconConfig, + ResonanceBeaconConfig, ReverbEventDetails, } from '#app/components/ATIAnalytics/types'; -import type { - ResonanceProperties, - PageviewProperties, - BaseProperties, -} from '@bbc/resonance'; +// import type { +// ResonanceProperties, +// PageviewProperties, +// BaseProperties, +// } from '@bbc/resonance'; import onClient from '../../utilities/onClient'; import nodeLogger from '../../logger.node'; import { ATI_LOGGING_ERROR } from '../../logger.const'; @@ -87,7 +88,7 @@ const callReverb = async (eventDetails: ReverbEventDetails) => { ); }; -const callResonance = (resonanceParams: ResonanceParams) => { +const callResonance = (resonanceParams: ResonanceBeaconConfig) => { try { // add checks in here so this only runs when resonanceParams is not undefined. console.log('Resonance initialised with params:', resonanceParams); @@ -107,15 +108,9 @@ const callResonance = (resonanceParams: ResonanceParams) => { // add initialise Resonance function here inside callResonance function // option to use resonanceProperties.suppressInitialPageview at initialisation. -type ResonanceParams = { - resonanceProperties: ResonanceProperties; - pageviewProperties: PageviewProperties; - baseProperties: BaseProperties; -}; - const sendBeacon = async ( reverbBeaconConfig: ReverbBeaconConfig, - resonanceParams: ResonanceParams, + resonanceParams: ResonanceBeaconConfig, ) => { // add resonanceBeaconConfig param to function if needed, e.g. // sendBeacon = async (reverbBeaconConfig: ReverbBeaconConfig, resonanceBeaconConfig?: ResonanceBeaconConfig) => { From bdc3a341b70c99f33d679b8d10556a42e1c4a019 Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Fri, 7 Aug 2026 15:47:54 +0100 Subject: [PATCH 06/25] WS-2831: prepare for context provider --- src/app/components/ATIAnalytics/index.tsx | 31 +++++-------------- src/app/components/ATIAnalytics/types.ts | 1 + .../contexts/ReverbParamsContext/index.tsx | 9 ++++++ 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/app/components/ATIAnalytics/index.tsx b/src/app/components/ATIAnalytics/index.tsx index 689f8475511..94e7e48e551 100644 --- a/src/app/components/ATIAnalytics/index.tsx +++ b/src/app/components/ATIAnalytics/index.tsx @@ -1,46 +1,29 @@ import { use } from 'react'; import { RequestContext } from '#contexts/RequestContext'; import { ReverbParamsContext } from '#app/contexts/ReverbParamsContext'; -import { AccountContext } from '#contexts/AccountContext'; // temp - this will be context provider -import { ServiceContext } from '#contexts/ServiceContext'; // temp - this will be context provider import CanonicalATIAnalytics from './canonical'; import AmpATIAnalytics from './amp'; import AmpGeo from '../../legacy/components/AmpGeo'; -import buildResonanceParams from './params'; +// import buildResonanceParams from './params'; // import { ATIProps } from './types'; // blah merge conflict // import buildReverbParams from './params'; // blah merge conflict // also fetch buildResonanceParams from './resonanceParams', e.g. import buildResonanceParams from './resonanceParams'; const ATIAnalytics = () => { const requestContext = use(RequestContext); - const serviceContext = use(ServiceContext); - const { isSignedIn, hashedUserId: hashedId } = use(AccountContext); const { isAmp } = requestContext; - // fetch useResonance from serviceContext, e.g. - // const { useResonance } = serviceContext; const { reverbParams } = use(ReverbParamsContext); - // to do - replace this with using context provider - const resonanceParams = buildResonanceParams({ - requestContext, - serviceContext, - isSignedIn, - hashedId, - }); + // const { resonanceParams } = use(ResonanceParamsContext); // if we make new one + + // const { reverbParams, resonanceParams } = use(AnalyticsParamsContext); // if we refactor // EITHER build resonance params here like we did for Reverb before these changes https://github.com/bbc/simorgh/pull/14120 // Or build ResonanceParamsContext (not described in depth in this POC due to implementation change occuring after POC was created) - - // build resonance params if useResonance is true, e.g. - // const resonanceParams = useResonance - // ? buildResonanceParams({ - // requestContext, - // serviceContext, - // atiData: atiData || {}, - // ... - // }) - // : null; + // We will still need to evaluate useResonance somewhere - that could be in the context provider + // fetch useResonance from serviceContext, e.g. + // const { useResonance } = serviceContext; return isAmp ? ( <> diff --git a/src/app/components/ATIAnalytics/types.ts b/src/app/components/ATIAnalytics/types.ts index 1ec63d851d7..69d232f8482 100644 --- a/src/app/components/ATIAnalytics/types.ts +++ b/src/app/components/ATIAnalytics/types.ts @@ -142,6 +142,7 @@ export type ReverbEventDetails = { originalEvent?: Event; }; +// possible task - type this ourselves and not rely on imported types export type ResonanceBeaconConfig = { resonanceProperties: ResonanceProperties; pageviewProperties: PageviewProperties; diff --git a/src/app/contexts/ReverbParamsContext/index.tsx b/src/app/contexts/ReverbParamsContext/index.tsx index 641bd464f59..e4969024f5b 100644 --- a/src/app/contexts/ReverbParamsContext/index.tsx +++ b/src/app/contexts/ReverbParamsContext/index.tsx @@ -94,6 +94,14 @@ const ReverbParamsContextProviderComponent = ({ hashedId, }); + // const resonanceParams = buildResonanceParams({ + // requestContext, + // serviceContext, + // atiData: enrichedAtiData, + // isSignedIn, + // hashedId, + // }); + const { params: { page, user }, } = reverbParams; @@ -102,6 +110,7 @@ const ReverbParamsContextProviderComponent = ({ setBbcPage({ page, user }); }, [page, user]); + // somehow add resonanceParams in here. const value = useMemo( () => ({ reverbParams, From d1867de091230c55af9493af893425549845b6e5 Mon Sep 17 00:00:00 2001 From: victranfield Date: Tue, 11 Aug 2026 11:05:07 +0100 Subject: [PATCH 07/25] further investigation for option B --- .../components/ATIAnalytics/atiUrl/index.ts | 40 ++++++++++++++ src/app/components/ATIAnalytics/index.tsx | 22 ++------ .../ATIAnalytics/params/buildParams/index.ts | 54 +++++++++---------- .../components/ATIAnalytics/params/index.ts | 26 ++------- .../contexts/ReverbParamsContext/index.tsx | 18 +++---- .../utilities/getAmpLiteCss/index.test.ts | 12 +++-- 6 files changed, 88 insertions(+), 84 deletions(-) diff --git a/src/app/components/ATIAnalytics/atiUrl/index.ts b/src/app/components/ATIAnalytics/atiUrl/index.ts index 750a3ac47ce..15c8497652a 100644 --- a/src/app/components/ATIAnalytics/atiUrl/index.ts +++ b/src/app/components/ATIAnalytics/atiUrl/index.ts @@ -12,10 +12,12 @@ import { onOnionTld, sanitise, } from '../../../lib/analyticsUtils'; +import { ResonanceMode } from '@bbc/resonance'; import { ATIEventTrackingProps, ATIPageTrackingProps, ReverbBeaconConfig, + ResonanceBeaconConfig, } from '../types'; /* @@ -23,6 +25,44 @@ import { * https://github.com/ampproject/amphtml/blob/master/spec/amp-var-substitutions.md#device-and-browser */ +export const buildResonanceAnalyticsModel = ({ + appName, + contentId, + contentType, + language, + statsDestination, + hashedId, + pageIdentifier, + producerName, + platform, +}: ATIPageTrackingProps): ResonanceBeaconConfig => { + const env = getEnvConfig().SIMORGH_APP_ENV; + + return { + resonanceProperties: { + // TODO: map to ResonanceMode.LIVE once environment-aware logic is confirmed + mode: env === 'live' ? ResonanceMode.LIVE : ResonanceMode.TEST, + }, + baseProperties: { + app: { + name: platform === 'app' ? `${appName}-app` : appName, + }, + destination: statsDestination, + hashedUserId: hashedId ?? undefined, + pageName: pageIdentifier, + producer: producerName, + // TODO: siteId — not yet in ServiceConfig, needs adding per service + }, + pageviewProperties: { + contentId, + contentType, + language, + destination: statsDestination, + producer: producerName, + }, + } as ResonanceBeaconConfig; +}; + export const buildReverbAnalyticsModel = ({ appName, campaigns, diff --git a/src/app/components/ATIAnalytics/index.tsx b/src/app/components/ATIAnalytics/index.tsx index 94e7e48e551..e807ea4ac4a 100644 --- a/src/app/components/ATIAnalytics/index.tsx +++ b/src/app/components/ATIAnalytics/index.tsx @@ -4,26 +4,10 @@ import { ReverbParamsContext } from '#app/contexts/ReverbParamsContext'; import CanonicalATIAnalytics from './canonical'; import AmpATIAnalytics from './amp'; import AmpGeo from '../../legacy/components/AmpGeo'; -// import buildResonanceParams from './params'; -// import { ATIProps } from './types'; // blah merge conflict -// import buildReverbParams from './params'; // blah merge conflict -// also fetch buildResonanceParams from './resonanceParams', e.g. import buildResonanceParams from './resonanceParams'; const ATIAnalytics = () => { - const requestContext = use(RequestContext); - const { isAmp } = requestContext; - - const { reverbParams } = use(ReverbParamsContext); - - // const { resonanceParams } = use(ResonanceParamsContext); // if we make new one - - // const { reverbParams, resonanceParams } = use(AnalyticsParamsContext); // if we refactor - - // EITHER build resonance params here like we did for Reverb before these changes https://github.com/bbc/simorgh/pull/14120 - // Or build ResonanceParamsContext (not described in depth in this POC due to implementation change occuring after POC was created) - // We will still need to evaluate useResonance somewhere - that could be in the context provider - // fetch useResonance from serviceContext, e.g. - // const { useResonance } = serviceContext; + const { isAmp } = use(RequestContext); + const { reverbParams, resonanceParams } = use(ReverbParamsContext); return isAmp ? ( <> @@ -33,7 +17,7 @@ const ATIAnalytics = () => { ) : ( ); }; diff --git a/src/app/components/ATIAnalytics/params/buildParams/index.ts b/src/app/components/ATIAnalytics/params/buildParams/index.ts index 5e82bddf792..b61e22e6382 100644 --- a/src/app/components/ATIAnalytics/params/buildParams/index.ts +++ b/src/app/components/ATIAnalytics/params/buildParams/index.ts @@ -1,6 +1,8 @@ import { LIBRARY_VERSION } from '../../../../lib/analyticsUtils'; -import { buildReverbAnalyticsModel } from '../../atiUrl'; -// import e.g. import { buildResonanceAnalyticsModel } from '../../atiUrl'; +import { + buildReverbAnalyticsModel, + buildResonanceAnalyticsModel, +} from '../../atiUrl'; import { ATIDataWithContexts } from '../../types'; export const buildPageATIParams = ({ @@ -69,42 +71,40 @@ export const buildPageATIParams = ({ }; }; -export const buildPageReverbParams = ({ +type BuildPageParamsArgs = ATIDataWithContexts & { + isSignedIn?: boolean; + hashedId?: string | null; +}; + +const buildPageReverbParams = ({ atiData, requestContext, serviceContext, isSignedIn, hashedId, -}: ATIDataWithContexts & { - isSignedIn?: boolean; - hashedId?: string | null; -}) => +}: BuildPageParamsArgs) => buildReverbAnalyticsModel( - buildPageATIParams({ - atiData, - requestContext, - serviceContext, - isSignedIn, - hashedId, - }), + buildPageATIParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), ); -// add exported function that builds resonance params calling buildPageATIParams above, e.g. -export const buildPageResonanceParams = ({ +const buildPageResonanceParams = ({ + atiData, requestContext, serviceContext, isSignedIn, hashedId, -}: ATIDataWithContexts & { - isSignedIn?: boolean; - hashedId?: string | null; -}) => - // need to pass in ATIData - we can get this via the context provider +}: BuildPageParamsArgs) => buildResonanceAnalyticsModel( - buildPageATIParams({ - requestContext, - serviceContext, - isSignedIn, - hashedId, - }), + buildPageATIParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), ); + +export const buildAnalyticsParams = ({ + atiData, + requestContext, + serviceContext, + isSignedIn, + hashedId, +}: BuildPageParamsArgs) => ({ + reverbParams: buildPageReverbParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), + resonanceParams: buildPageResonanceParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), +}); diff --git a/src/app/components/ATIAnalytics/params/index.ts b/src/app/components/ATIAnalytics/params/index.ts index 79a1c46eaf3..960c52439a9 100644 --- a/src/app/components/ATIAnalytics/params/index.ts +++ b/src/app/components/ATIAnalytics/params/index.ts @@ -1,24 +1,6 @@ -import { buildPageReverbParams, buildPageResonanceParams } from './buildParams'; +import { buildAnalyticsParams } from './buildParams'; import { ReverbDetailsProviders } from '../types'; -// add types as needed, e.g. import { ResonanceDetailsProviders } from '../types'; -// add function to build resonance params, e.g. -export const buildResonanceParams = ({ - requestContext, - serviceContext, - isSignedIn, - hashedId, - // ResonanceDetailsProviders -}: any) => { - return buildPageResonanceParams({ - requestContext, - serviceContext, - isSignedIn, - hashedId, - }); -}; - -// change this to not be default export default ({ requestContext, serviceContext, @@ -28,12 +10,12 @@ export default ({ }: ReverbDetailsProviders & { isSignedIn?: boolean; hashedId?: string | null; -}) => { - return buildPageReverbParams({ +}) => + buildAnalyticsParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId, }); -}; + diff --git a/src/app/contexts/ReverbParamsContext/index.tsx b/src/app/contexts/ReverbParamsContext/index.tsx index e4969024f5b..31f514ffab7 100644 --- a/src/app/contexts/ReverbParamsContext/index.tsx +++ b/src/app/contexts/ReverbParamsContext/index.tsx @@ -9,10 +9,11 @@ import { RequestContext } from '#app/contexts/RequestContext'; import { ServiceContext } from '#app/contexts/ServiceContext'; import { AccountContext } from '#app/contexts/AccountContext'; import withOptimizelyProvider from '#app/legacy/containers/PageHandlers/withOptimizelyProvider'; -import buildReverbParams from '#app/components/ATIAnalytics/params'; +import buildAnalyticsParams from '#app/components/ATIAnalytics/params'; import { ATIData, ReverbBeaconConfig, + ResonanceBeaconConfig, } from '#app/components/ATIAnalytics/types'; import { ARTICLE_PAGE, @@ -31,6 +32,7 @@ import getEnrichedMediaArticleATIData from './getEnrichedMediaArticleATIData'; type ReverbParamsContextProps = { reverbParams: ReverbBeaconConfig; + resonanceParams: ResonanceBeaconConfig; experimentProps?: ComponentExperimentProps; }; @@ -86,7 +88,7 @@ const ReverbParamsContextProviderComponent = ({ pageType: requestContext?.pageType, }); - const reverbParams = buildReverbParams({ + const { reverbParams, resonanceParams } = buildAnalyticsParams({ requestContext, serviceContext, atiData: enrichedAtiData, @@ -94,14 +96,6 @@ const ReverbParamsContextProviderComponent = ({ hashedId, }); - // const resonanceParams = buildResonanceParams({ - // requestContext, - // serviceContext, - // atiData: enrichedAtiData, - // isSignedIn, - // hashedId, - // }); - const { params: { page, user }, } = reverbParams; @@ -110,15 +104,15 @@ const ReverbParamsContextProviderComponent = ({ setBbcPage({ page, user }); }, [page, user]); - // somehow add resonanceParams in here. const value = useMemo( () => ({ reverbParams, + resonanceParams, ...(enrichedAtiData?.experimentProps && { experimentProps: enrichedAtiData.experimentProps, }), }), - [reverbParams, enrichedAtiData?.experimentProps], + [reverbParams, resonanceParams, enrichedAtiData?.experimentProps], ); return ( diff --git a/ws-nextjs-app/utilities/getAmpLiteCss/index.test.ts b/ws-nextjs-app/utilities/getAmpLiteCss/index.test.ts index 964430c119b..2f0d96f61b5 100644 --- a/ws-nextjs-app/utilities/getAmpLiteCss/index.test.ts +++ b/ws-nextjs-app/utilities/getAmpLiteCss/index.test.ts @@ -24,13 +24,15 @@ describe('getAmpLiteCss utilities', () => { afterAll(() => { cwdSpy.mockRestore(); - process.env.NODE_ENV = originalNodeEnv; + (process.env as { [key: string]: string | undefined }).NODE_ENV = + originalNodeEnv; }); afterEach(() => { jest.clearAllMocks(); resetManifestCaches(); - process.env.NODE_ENV = originalNodeEnv; + (process.env as { [key: string]: string | undefined }).NODE_ENV = + originalNodeEnv; }); describe('resolveCssFilePath', () => { @@ -458,7 +460,8 @@ describe('getAmpLiteCss utilities', () => { describe('in development', () => { beforeEach(() => { - process.env.NODE_ENV = 'development'; + (process.env as { [key: string]: string | undefined }).NODE_ENV = + 'development'; }); it('returns the full dev CSS when dev-css-modules.css exists', () => { @@ -494,7 +497,8 @@ describe('getAmpLiteCss utilities', () => { describe('in production', () => { beforeEach(() => { - process.env.NODE_ENV = 'production'; + (process.env as { [key: string]: string | undefined }).NODE_ENV = + 'production'; }); it('returns combined build manifest CSS and dynamic import CSS', () => { From 8221d62e2816c9ab6eee1790d99a6f582d1669f2 Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Tue, 11 Aug 2026 13:48:52 +0100 Subject: [PATCH 08/25] WS-2831: Lint --- .../components/ATIAnalytics/atiUrl/index.ts | 2 +- .../ATIAnalytics/params/buildParams/index.ts | 33 ++++++++++++++++--- .../components/ATIAnalytics/params/index.ts | 1 - 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/app/components/ATIAnalytics/atiUrl/index.ts b/src/app/components/ATIAnalytics/atiUrl/index.ts index 15c8497652a..9bd9070dab8 100644 --- a/src/app/components/ATIAnalytics/atiUrl/index.ts +++ b/src/app/components/ATIAnalytics/atiUrl/index.ts @@ -1,3 +1,4 @@ +import { ResonanceMode } from '@bbc/resonance'; import { CLICK_EVENT, VIEW_EVENT, @@ -12,7 +13,6 @@ import { onOnionTld, sanitise, } from '../../../lib/analyticsUtils'; -import { ResonanceMode } from '@bbc/resonance'; import { ATIEventTrackingProps, ATIPageTrackingProps, diff --git a/src/app/components/ATIAnalytics/params/buildParams/index.ts b/src/app/components/ATIAnalytics/params/buildParams/index.ts index b61e22e6382..5740ab393ba 100644 --- a/src/app/components/ATIAnalytics/params/buildParams/index.ts +++ b/src/app/components/ATIAnalytics/params/buildParams/index.ts @@ -84,7 +84,13 @@ const buildPageReverbParams = ({ hashedId, }: BuildPageParamsArgs) => buildReverbAnalyticsModel( - buildPageATIParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), + buildPageATIParams({ + atiData, + requestContext, + serviceContext, + isSignedIn, + hashedId, + }), ); const buildPageResonanceParams = ({ @@ -94,8 +100,15 @@ const buildPageResonanceParams = ({ isSignedIn, hashedId, }: BuildPageParamsArgs) => + // add service context check in here? buildResonanceAnalyticsModel( - buildPageATIParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), + buildPageATIParams({ + atiData, + requestContext, + serviceContext, + isSignedIn, + hashedId, + }), ); export const buildAnalyticsParams = ({ @@ -105,6 +118,18 @@ export const buildAnalyticsParams = ({ isSignedIn, hashedId, }: BuildPageParamsArgs) => ({ - reverbParams: buildPageReverbParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), - resonanceParams: buildPageResonanceParams({ atiData, requestContext, serviceContext, isSignedIn, hashedId }), + reverbParams: buildPageReverbParams({ + atiData, + requestContext, + serviceContext, + isSignedIn, + hashedId, + }), + resonanceParams: buildPageResonanceParams({ + atiData, + requestContext, + serviceContext, + isSignedIn, + hashedId, + }), }); diff --git a/src/app/components/ATIAnalytics/params/index.ts b/src/app/components/ATIAnalytics/params/index.ts index 960c52439a9..aafe67ce807 100644 --- a/src/app/components/ATIAnalytics/params/index.ts +++ b/src/app/components/ATIAnalytics/params/index.ts @@ -18,4 +18,3 @@ export default ({ isSignedIn, hashedId, }); - From 9e5f8ddcae51e43ec67923b3db526ddbbdcc1b29 Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Tue, 11 Aug 2026 14:54:02 +0100 Subject: [PATCH 09/25] WS-2831: Adds site ID look up --- .../components/ATIAnalytics/atiUrl/index.ts | 4 ++-- .../ATIAnalytics/params/buildParams/index.ts | 3 ++- src/app/components/ATIAnalytics/types.ts | 1 + .../RequestContext/getSiteId/index.ts | 20 +++++++++++++++++++ src/app/contexts/RequestContext/index.tsx | 6 ++++++ 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/app/contexts/RequestContext/getSiteId/index.ts diff --git a/src/app/components/ATIAnalytics/atiUrl/index.ts b/src/app/components/ATIAnalytics/atiUrl/index.ts index 9bd9070dab8..eb42adc0128 100644 --- a/src/app/components/ATIAnalytics/atiUrl/index.ts +++ b/src/app/components/ATIAnalytics/atiUrl/index.ts @@ -31,6 +31,7 @@ export const buildResonanceAnalyticsModel = ({ contentType, language, statsDestination, + siteId, hashedId, pageIdentifier, producerName, @@ -40,7 +41,6 @@ export const buildResonanceAnalyticsModel = ({ return { resonanceProperties: { - // TODO: map to ResonanceMode.LIVE once environment-aware logic is confirmed mode: env === 'live' ? ResonanceMode.LIVE : ResonanceMode.TEST, }, baseProperties: { @@ -51,7 +51,7 @@ export const buildResonanceAnalyticsModel = ({ hashedUserId: hashedId ?? undefined, pageName: pageIdentifier, producer: producerName, - // TODO: siteId — not yet in ServiceConfig, needs adding per service + siteId, }, pageviewProperties: { contentId, diff --git a/src/app/components/ATIAnalytics/params/buildParams/index.ts b/src/app/components/ATIAnalytics/params/buildParams/index.ts index 5740ab393ba..81c0ecc19c9 100644 --- a/src/app/components/ATIAnalytics/params/buildParams/index.ts +++ b/src/app/components/ATIAnalytics/params/buildParams/index.ts @@ -15,7 +15,7 @@ export const buildPageATIParams = ({ isSignedIn?: boolean; hashedId?: string | null; }) => { - const { isUK, platform, statsDestination } = requestContext; + const { isUK, platform, statsDestination, siteId } = requestContext; const { atiAnalyticsAppName, atiAnalyticsProducerId, @@ -61,6 +61,7 @@ export const buildPageATIParams = ({ producerName: atiAnalyticsProducerName, service, statsDestination, + siteId, timePublished, timeUpdated, isSignedIn, diff --git a/src/app/components/ATIAnalytics/types.ts b/src/app/components/ATIAnalytics/types.ts index 69d232f8482..edeba51409d 100644 --- a/src/app/components/ATIAnalytics/types.ts +++ b/src/app/components/ATIAnalytics/types.ts @@ -218,6 +218,7 @@ export interface ATIPageTrackingProps { libraryVersion?: string; platform?: Platforms; statsDestination?: string; + siteId: number; timePublished?: string | null; timeUpdated?: string | null; categoryName?: string | null; diff --git a/src/app/contexts/RequestContext/getSiteId/index.ts b/src/app/contexts/RequestContext/getSiteId/index.ts new file mode 100644 index 00000000000..f7500685883 --- /dev/null +++ b/src/app/contexts/RequestContext/getSiteId/index.ts @@ -0,0 +1,20 @@ +import { Environments, Services } from '#app/models/types/global'; + +type Props = { + env?: Environments | null; + service: Services; +}; + +const getSiteId = ({ env = 'test', service }: Props) => { + let siteId: number; + switch (service) { + case 'japanese': + siteId = env === 'live' ? 646753 : 598290; + break; + default: + siteId = env === 'live' ? 598342 : 598343; + } + return siteId; +}; + +export default getSiteId; diff --git a/src/app/contexts/RequestContext/index.tsx b/src/app/contexts/RequestContext/index.tsx index b40d1908c49..40419b1b7bc 100644 --- a/src/app/contexts/RequestContext/index.tsx +++ b/src/app/contexts/RequestContext/index.tsx @@ -11,6 +11,7 @@ import getStatsDestination from './getStatsDestination'; import getOriginContext from './getOriginContext'; import getEnv from './getEnv'; import getMetaUrls from './getMetaUrls'; +import getSiteId from './getSiteId'; export type RequestContextProps = { ampLink: string; @@ -36,6 +37,7 @@ export type RequestContextProps = { showAdsBasedOnLocation: boolean; showCookieBannerBasedOnCountry: boolean; statsDestination: string; + siteId: number; statusCode: number | null; timeOnServer: number | null; variant: Variants | null; @@ -120,6 +122,8 @@ export const RequestContextProvider = ({ service, }); + const siteId = getSiteId({ env, service }); + const value = useMemo( () => ({ env, @@ -134,6 +138,7 @@ export const RequestContextProvider = ({ isNextJs, platform, statsDestination, + siteId, statusCode, variant, timeOnServer, @@ -165,6 +170,7 @@ export const RequestContextProvider = ({ showAdsBasedOnLocation, showCookieBannerBasedOnCountry, statsDestination, + siteId, statusCode, timeOnServer, variant, From a5db80fb90acbaeca2c7fc07dbf5820a775fd7fb Mon Sep 17 00:00:00 2001 From: Isabella-Mitchell Date: Tue, 11 Aug 2026 15:24:28 +0100 Subject: [PATCH 10/25] WS-2831: Trial useResonance serviceContext check in buildParams --- .../getNoScriptTrackingPixelUrl/index.ts | 9 +++-- .../ATIAnalytics/canonical/index.tsx | 8 +++- .../ATIAnalytics/params/buildParams/index.ts | 37 +++++++++++-------- src/app/components/ATIAnalytics/types.ts | 2 +- .../contexts/ReverbParamsContext/index.tsx | 2 +- .../lib/analyticsUtils/sendBeacon/index.ts | 6 ++- 6 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/app/components/ATIAnalytics/canonical/getNoScriptTrackingPixelUrl/index.ts b/src/app/components/ATIAnalytics/canonical/getNoScriptTrackingPixelUrl/index.ts index 4f5200ad220..d77dff587c9 100644 --- a/src/app/components/ATIAnalytics/canonical/getNoScriptTrackingPixelUrl/index.ts +++ b/src/app/components/ATIAnalytics/canonical/getNoScriptTrackingPixelUrl/index.ts @@ -1,7 +1,10 @@ import { reverbUrlHelper } from '@bbc/reverb-url-helper'; -import { ATIAnalyticsProps } from '../../types'; +import { ReverbBeaconConfig } from '../../types'; -const getNoScriptTrackingPixelUrl = ({ reverbParams }: ATIAnalyticsProps) => - reverbUrlHelper.getTrackingPixelSrc(reverbParams); +const getNoScriptTrackingPixelUrl = ({ + reverbParams, +}: { + reverbParams: ReverbBeaconConfig; +}) => reverbUrlHelper.getTrackingPixelSrc(reverbParams); export default getNoScriptTrackingPixelUrl; diff --git a/src/app/components/ATIAnalytics/canonical/index.tsx b/src/app/components/ATIAnalytics/canonical/index.tsx index 5c3d6dabd7a..ec403b0aafa 100644 --- a/src/app/components/ATIAnalytics/canonical/index.tsx +++ b/src/app/components/ATIAnalytics/canonical/index.tsx @@ -19,11 +19,15 @@ import type { import useConnectionBackOnlineTracker from '#app/hooks/useConnectionBackOnlineTracker'; import useConnectionTypeTracker from '#app/hooks/useConnectionTypeTracker'; import usePWAOfflineTracking from '#app/hooks/usePWAOfflineTracking'; -import { ATIAnalyticsProps } from '../types'; +import { ATIAnalyticsProps, ReverbBeaconConfig } from '../types'; import getNoScriptTrackingPixelUrl from './getNoScriptTrackingPixelUrl'; import sendPageViewBeaconOperaMini from './sendPageViewBeaconOperaMini'; -const renderNoScriptTrackingPixel = ({ reverbParams }: ATIAnalyticsProps) => { +const renderNoScriptTrackingPixel = ({ + reverbParams, +}: { + reverbParams: ReverbBeaconConfig; +}) => { return (