Skip to content

Commit b56c549

Browse files
authored
Merge branch 'main' into ih/hosted-disclaimer
2 parents 21151c4 + 81bf039 commit b56c549

23 files changed

+850
-409
lines changed

ab-testing/config/abTests.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,6 @@ const ABTests: ABTest[] = [
4343
groups: ["control", "variant"],
4444
shouldForceMetricsCollection: true,
4545
},
46-
{
47-
name: "commercial-user-module-liveramp",
48-
description:
49-
"Test measuring ad targeting from LiveRamp's identityLinkIdSystem module integration",
50-
owners: ["[email protected]"],
51-
expirationDate: `2026-03-04`,
52-
type: "client",
53-
status: "ON",
54-
audienceSize: 10 / 100,
55-
audienceSpace: "B",
56-
groups: ["control", "variant"],
57-
shouldForceMetricsCollection: true,
58-
},
5946
{
6047
name: "webex-football-redesign",
6148
description: "Testing the Redesign for the football pages",
@@ -107,15 +94,16 @@ const ABTests: ABTest[] = [
10794
shouldForceMetricsCollection: false,
10895
},
10996
{
110-
name: "growth-admiral-adblock-recovery",
111-
description: "Test Admiral ad blocker detection and recovery modal",
97+
name: "growth-admiral-adblock-detect",
98+
description:
99+
"Control group for Admiral ad blocker - runs the detection script but does not show the modal",
112100
owners: ["[email protected]"],
113101
expirationDate: "2027-01-21",
114102
type: "client",
115103
status: "ON",
116104
audienceSize: 10 / 100,
117105
audienceSpace: "A",
118-
groups: ["control"],
106+
groups: ["variant-detect"],
119107
shouldForceMetricsCollection: false,
120108
},
121109
{

dotcom-rendering/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"@guardian/shimport": "1.0.2",
4444
"@guardian/source": "11.3.0",
4545
"@guardian/source-development-kitchen": "18.1.1",
46-
"@guardian/support-dotcom-components": "8.4.0",
46+
"@guardian/support-dotcom-components": "8.4.1",
4747
"@guardian/tsconfig": "0.2.0",
4848
"@playwright/test": "1.58.0",
4949
"@sentry/browser": "10.39.0",

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

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -210,103 +210,116 @@ const testName = 'growth-admiral-adblock-recovery';
210210
export const AdmiralScript = () => {
211211
const { renderingTarget } = useConfig();
212212
const abTests = useBetaAB();
213-
const isInControlGroup =
214-
abTests?.isUserInTestGroup(testName, 'control') ?? false;
215-
const variantName = isInControlGroup ? 'control' : undefined;
213+
const isInVariantDetectGroup =
214+
abTests?.isUserInTestGroup(testName, 'variant-detect') ?? false;
215+
const variantName = isInVariantDetectGroup
216+
? 'variant-detect'
217+
: 'variant-recover'; //We need to default to 'variant-recover' for users who are not in the AB test in order to show Admiral Modal to all users in the US who are not blocked by the CMP and meet the other criteria.
216218

217219
useEffect(() => {
218220
/**
219221
* The Admiral bootstrap script should only run under the following conditions:
220222
*
221223
* - Should not run if the CMP is due to show
222224
* - Should only run in the US
223-
* - Should only run if in the AB test (control group)
224225
* - Should not run if the gu_hide_support_messaging cookie is set
225226
* - Should not run for content marked as: shouldHideAdverts, shouldHideReaderRevenue, isSensitive
226227
* - Should not run for paid-content sponsorship type (includes Hosted Content)
227228
* - Should not run for certain sections
228229
*
229-
* Control group loads the script but the modal will not be shown.
230+
* Variant-detect group loads the script but the modal will not be shown.
230231
*/
231232
const page = window.guardian.config.page;
233+
if (!window.guardian.config.switches.consentManagement) return;
232234

233-
const shouldRun =
234-
cmp.hasInitialised() &&
235-
!cmp.willShowPrivacyMessageSync() &&
236-
isInUsa() &&
237-
isInControlGroup &&
238-
!getCookie({
239-
name: 'gu_hide_support_messaging',
240-
shouldMemoize: true,
241-
}) &&
242-
!page.shouldHideAdverts &&
243-
!page.shouldHideReaderRevenue &&
244-
!page.isSensitive &&
245-
page.sponsorshipType !== 'paid-content' &&
246-
![
247-
'about',
248-
'info',
249-
'membership',
250-
'help',
251-
'guardian-live-australia',
252-
'gnm-archive',
253-
'guardian-labs',
254-
'thefilter',
255-
].includes(page.section ?? '');
256-
if (!shouldRun) return;
257-
258-
// Record INSERT Ophan event
259-
void recordAdmiralOphanEvent(
260-
variantName,
261-
{
262-
action: 'INSERT',
263-
},
264-
renderingTarget,
265-
);
235+
let admiralScript: HTMLScriptElement | undefined;
236+
let isCancelled = false;
266237

267-
// Initialize Admiral Adblock Recovery
268-
log('dotcom', '🛡️ Initialising Admiral Adblock Recovery');
238+
const initialiseAdmiral = async () => {
239+
try {
240+
const willShowPrivacyMessage =
241+
await cmp.willShowPrivacyMessage();
269242

270-
// Set up window.admiral stub
271-
// This initializes admiral before the bootstrap script loads
272-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required for Admiral stub initialization
273-
type AdmiralStub = Admiral & { q?: any[] };
274-
const w = window as Window & { admiral?: AdmiralStub };
243+
const shouldRun =
244+
!willShowPrivacyMessage &&
245+
isInUsa() &&
246+
!getCookie({
247+
name: 'gu_hide_support_messaging',
248+
shouldMemoize: true,
249+
}) &&
250+
!page.shouldHideAdverts &&
251+
!page.shouldHideReaderRevenue &&
252+
!page.isSensitive &&
253+
page.sponsorshipType !== 'paid-content' &&
254+
![
255+
'about',
256+
'info',
257+
'membership',
258+
'help',
259+
'guardian-live-australia',
260+
'gnm-archive',
261+
'guardian-labs',
262+
'thefilter',
263+
].includes(page.section ?? '');
275264

276-
if (!w.admiral) {
277-
// Create the Admiral stub function with queue
278-
const stub = function (...args: unknown[]) {
279-
if (!stub.q) stub.q = [];
280-
stub.q.push(args);
281-
} as AdmiralStub;
282-
w.admiral = stub;
283-
}
265+
if (!shouldRun || isCancelled) return;
284266

285-
log('dotcom', '🛡️ Setting up Admiral event logger');
267+
void recordAdmiralOphanEvent(
268+
variantName,
269+
{
270+
action: 'INSERT',
271+
},
272+
renderingTarget,
273+
);
274+
275+
log('dotcom', '🛡️ Initialising Admiral Adblock Recovery');
276+
277+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required for Admiral stub initialization
278+
type AdmiralStub = Admiral & { q?: any[] };
279+
const w = window as Window & { admiral?: AdmiralStub };
286280

287-
// Set up Admiral event logging
288-
setUpAdmiralEventLogger(w.admiral, variantName, renderingTarget);
281+
if (!w.admiral) {
282+
const stub = function (...args: unknown[]) {
283+
if (!stub.q) stub.q = [];
284+
stub.q.push(args);
285+
} as AdmiralStub;
286+
w.admiral = stub;
287+
}
289288

290-
// Set AB test targeting
291-
if (variantName) {
292-
w.admiral('targeting', 'set', 'guAbTest', variantName);
293-
}
289+
log('dotcom', '🛡️ Setting up Admiral event logger');
290+
setUpAdmiralEventLogger(
291+
w.admiral,
292+
variantName,
293+
renderingTarget,
294+
);
294295

295-
// Load Admiral bootstrap script
296-
const BASE_AJAX_URL = window.guardian.config.page.ajaxUrl;
296+
if (variantName) {
297+
w.admiral('targeting', 'set', 'guAbTest', variantName);
298+
}
297299

298-
const admiralScript = document.createElement('script');
299-
admiralScript.src = `${BASE_AJAX_URL}/commercial/admiral-bootstrap.js`;
300-
admiralScript.async = true;
301-
document.head.appendChild(admiralScript);
300+
const BASE_AJAX_URL = window.guardian.config.page.ajaxUrl;
301+
admiralScript = document.createElement('script');
302+
admiralScript.src = `${BASE_AJAX_URL}/commercial/admiral-bootstrap.js`;
303+
admiralScript.async = true;
304+
document.head.appendChild(admiralScript);
305+
306+
log('dotcom', '🛡️ Admiral initialization complete');
307+
} catch (error) {
308+
log(
309+
'dotcom',
310+
'🛡️ Admiral - Error waiting for CMP readiness:',
311+
error,
312+
);
313+
}
314+
};
302315

303-
log('dotcom', '🛡️ Admiral initialization complete');
316+
void initialiseAdmiral();
304317

305318
return () => {
306-
// Clean up Admiral bootstrap script
307-
admiralScript.parentNode?.removeChild(admiralScript);
319+
isCancelled = true;
320+
admiralScript?.parentNode?.removeChild(admiralScript);
308321
};
309-
}, [isInControlGroup, variantName, renderingTarget]);
322+
}, [variantName, renderingTarget]);
310323

311324
return null;
312325
};

dotcom-rendering/src/components/ContainerTitle.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ const headerStyles = css`
4141
`;
4242

4343
const primaryTitleStyles = css`
44-
${headlineBold28};
44+
${headlineBold24};
45+
${from.tablet} {
46+
${headlineBold28};
47+
}
4548
`;
4649
const secondaryTitleStyles = css`
4750
${textSansBold17};
Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { css } from '@emotion/react';
22
import { breakpoints, from } from '@guardian/source/foundations';
33
import type { Meta, StoryObj } from '@storybook/react-webpack5';
4+
import type { FEFootballMatchStatsSummary } from '../frontend/feFootballMatchInfoPage';
45
import { palette } from '../palette';
56
import { FootballMiniMatchStats as FootballMiniMatchStatsComponent } from './FootballMiniMatchStats';
67

@@ -18,23 +19,13 @@ const gridCss = css`
1819
}
1920
`;
2021

21-
const containerCss = css`
22-
padding: 10px;
23-
${from.desktop} {
24-
padding-left: 20px;
25-
padding-right: 0;
26-
}
27-
`;
28-
2922
const meta = {
3023
title: 'Components/Football Mini Match Stats',
3124
component: FootballMiniMatchStatsComponent,
3225
decorators: [
3326
(Story) => (
3427
<div css={gridCss}>
35-
<div css={containerCss}>
36-
<Story />
37-
</div>
28+
<Story />
3829
</div>
3930
),
4031
],
@@ -52,24 +43,41 @@ const meta = {
5243
export default meta;
5344
type Story = StoryObj<typeof meta>;
5445

46+
const feMatchStatsSummaryData: FEFootballMatchStatsSummary = {
47+
id: '4540747',
48+
homeTeam: {
49+
id: '49',
50+
name: 'Bristol City',
51+
possession: 53,
52+
shotsOn: 5,
53+
shotsOff: 3,
54+
colours: '#c70c23',
55+
},
56+
awayTeam: {
57+
id: '91',
58+
name: 'Wrexham',
59+
possession: 47,
60+
shotsOn: 3,
61+
shotsOff: 6,
62+
colours: '#d82529',
63+
},
64+
status: 'FT',
65+
infoURL:
66+
'https://www.theguardian.com/football/match/2026/feb/17/bristolcity-v-wrexham',
67+
};
68+
69+
const getMockData = (data: FEFootballMatchStatsSummary) =>
70+
new Promise((resolve) => {
71+
setTimeout(() => {
72+
resolve(data);
73+
}, 1000);
74+
});
75+
5576
export const FootballMiniMatchStats = {
5677
args: {
57-
homeTeam: {
58-
name: 'Manchester United',
59-
colour: '#da020e',
60-
},
61-
awayTeam: {
62-
name: 'Arsenal',
63-
colour: '#023474',
64-
},
65-
stats: [
66-
{
67-
heading: 'Possession',
68-
homeValue: 39,
69-
awayValue: 61,
70-
isPercentage: true,
71-
},
72-
{ heading: 'Goal Attempts', homeValue: 7, awayValue: 4 },
73-
],
78+
matchStatsUrl:
79+
'https://api.nextgen.guardianapps.co.uk/football/api/match-stats-summary/2026/02/17/49/91.json',
80+
getMatchStatsData: () => getMockData(feMatchStatsSummaryData),
81+
refreshInterval: 16_000,
7482
},
7583
} satisfies Story;

0 commit comments

Comments
 (0)