Skip to content

Commit 97bfc78

Browse files
author
Juarez Mota
committed
Exclude additional page paths from sign-in gate and defer article popups until visible
- Add privacy, complaints-and-corrections, and the-whole-picture to denied paths - Remove gandalfCountryCode from AuxiaGateDisplayData and use fixed 'gandalf-nz' variant - Defer mandatory popup display until visibility for Article content type - Pass contentType through SignInGateSelector chain to enable content-specific logic
1 parent 63e30ba commit 97bfc78

8 files changed

Lines changed: 60 additions & 39 deletions

File tree

dotcom-rendering/src/components/SignInGate/displayRules.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,9 @@ describe('articleIdentifierIsAllowed', () => {
115115
expect(pageIdIsAllowedForGating('tips')).toBe(false);
116116
expect(pageIdIsAllowedForGating('tips#test')).toBe(false);
117117
expect(pageIdIsAllowedForGating('tips/test')).toBe(false);
118+
expect(pageIdIsAllowedForGating('info/privacy')).toBe(false);
119+
expect(pageIdIsAllowedForGating('info/complaints-and-corrections')).toBe(
120+
false,
121+
);
122+
expect(pageIdIsAllowedForGating('the-whole-picture')).toBe(false);
118123
});

dotcom-rendering/src/components/SignInGate/displayRules.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ export const pageIdIsAllowedForGating = (pageId: string): boolean => {
201201
const denyPaths = [
202202
'tips',
203203
'help/ng-interactive/2017/mar/17/contact-the-guardian-securely',
204+
'info/privacy',
205+
'info/complaints-and-corrections',
206+
'the-whole-picture',
204207
];
205208

206209
return !denyPaths.some((denyPath) => pageId.startsWith(denyPath));

dotcom-rendering/src/components/SignInGate/types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,6 @@ export interface AuxiaGateReaderPersonalData {
253253
export interface AuxiaGateDisplayData {
254254
browserId: string | undefined;
255255
auxiaData: AuxiaProxyGetTreatmentsProxyResponseData;
256-
// The country code the gate request was made for. Set by the client so the
257-
// selector can build the per-country Gandalf Ophan variant
258-
// (gandalf-<country>) without re-resolving geolocation.
259-
gandalfCountryCode?: string;
260256
}
261257

262258
export type SignInGatePropsAuxia = {

dotcom-rendering/src/components/SignInGateSelector.island.test.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ const makeTreatment = (
3939
const makeProps = (
4040
userTreatment = makeTreatment(),
4141
gandalfSignInGate = true,
42+
contentType = 'Network Front',
4243
) => ({
4344
isPaidContent: false,
4445
isPreview: false,
4546
pageId: 'crosswords/quick/16914',
47+
contentType,
4648
contributionsServiceUrl: 'https://contributions.example.com',
4749
auxiaGateDisplayData: {
4850
browserId: undefined,
49-
gandalfCountryCode: 'NZ',
5051
auxiaData: {
5152
responseId: 'test-response',
5253
gandalfSignInGate,
@@ -109,6 +110,20 @@ describe('SignInGateSelector view tracking', () => {
109110
expect(mockFetch).not.toHaveBeenCalled();
110111
});
111112

113+
it('keeps a mandatory Article popup deferred until visibility', () => {
114+
const props = makeProps(makeTreatment(), true, 'Article');
115+
const { rerender } = render(<SignInGateSelector {...props} />);
116+
117+
expect(testScreen.queryByTestId('v2-gate')).not.toBeInTheDocument();
118+
expectViews(0);
119+
120+
mockUseIsInView.mockReturnValue([true, mockSetNode]);
121+
rerender(<SignInGateSelector {...props} />);
122+
123+
expect(testScreen.getByTestId('v2-gate')).toBeInTheDocument();
124+
expectViews(1);
125+
});
126+
112127
it('does not recount an equivalent treatment supplied as a new object', () => {
113128
const { rerender } = render(<SignInGateSelector {...makeProps()} />);
114129
rerender(<SignInGateSelector {...makeProps()} />);

dotcom-rendering/src/components/SignInGateSelector.island.tsx

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type Props = {
3434
pageId: string;
3535
contributionsServiceUrl: string;
3636
auxiaGateDisplayData?: AuxiaGateDisplayData | undefined;
37+
contentType?: string;
3738
};
3839

3940
// function to generate the params for use by the profile.theguardian.com url
@@ -81,6 +82,7 @@ export const SignInGateSelector = ({
8182
pageId, // pageId is the path without starting slash
8283
contributionsServiceUrl,
8384
auxiaGateDisplayData,
85+
contentType,
8486
}: Props) => {
8587
if (!pageIdIsAllowedForGating(pageId)) {
8688
return <></>;
@@ -99,6 +101,7 @@ export const SignInGateSelector = ({
99101
isPaidContent={isPaidContent}
100102
auxiaGateDisplayData={auxiaGateDisplayData}
101103
signInGateVersion={signInGateVersion}
104+
contentType={contentType}
102105
/>
103106
);
104107
};
@@ -134,6 +137,7 @@ type PropsAuxia = {
134137
isPaidContent: boolean;
135138
auxiaGateDisplayData?: AuxiaGateDisplayData;
136139
signInGateVersion: AuxiaGateVersion;
140+
contentType?: string;
137141
};
138142

139143
// [1] If true, it indicates that we are using the component for the regular Auxia share of the Audience
@@ -150,6 +154,7 @@ interface ShowSignInGateAuxiaProps {
150154
treatmentId: string;
151155
renderingTarget: RenderingTarget;
152156
isGandalf: boolean;
157+
contentType?: string;
153158
logTreatmentInteractionCall: (
154159
interactionType: AuxiaInteractionInteractionType,
155160
actionName?: AuxiaInteractionActionName,
@@ -272,6 +277,7 @@ const SignInGateSelectorAuxia = ({
272277
isPaidContent,
273278
auxiaGateDisplayData,
274279
signInGateVersion,
280+
contentType,
275281
}: PropsAuxia) => {
276282
const [isGateDismissed, setIsGateDismissed] = useState<boolean | undefined>(
277283
undefined,
@@ -280,23 +286,18 @@ const SignInGateSelectorAuxia = ({
280286
// Gandalf (comment group: gandalf) — the Guardian-managed sign-in gate
281287
// journey (marketing name). SDC marks responses produced by the active
282288
// Gandalf rules. For those responses we report to Ophan under a stable
283-
// Gandalf identity with a per-country variant instead of the Auxia
284-
// experiment metadata, and we never call Auxia's LogTreatmentInteraction
285-
// endpoint. This is reporting metadata only — there is no A/B test
286-
// allocation behind it.
289+
// Gandalf identity instead of the Auxia experiment metadata, and we never
290+
// call Auxia's LogTreatmentInteraction endpoint. This is reporting metadata
291+
// only — there is no A/B test allocation behind it.
287292
const isGandalf =
288293
auxiaGateDisplayData?.auxiaData.gandalfSignInGate === true;
289-
const gandalfCountryCode = auxiaGateDisplayData?.gandalfCountryCode;
290294

291295
// We are using CurrentSignInGateABTest, with the details of the Auxia experiment,
292296
// to allow Ophan tracking
293297
const abTest: CurrentSignInGateABTest = isGandalf
294298
? {
295299
name: 'GandalfSignInGate', // value of dataLinkNames
296-
variant:
297-
gandalfCountryCode !== undefined
298-
? `gandalf-${gandalfCountryCode.toLowerCase()}` // per-country variant
299-
: 'gandalf-rollout', // variant id
300+
variant: 'gandalf-nz', // variant id
300301
id: 'GandalfSignInGate', // test id
301302
}
302303
: {
@@ -376,6 +377,7 @@ const SignInGateSelectorAuxia = ({
376377
}
377378
renderingTarget={renderingTarget}
378379
isGandalf={isGandalf}
380+
contentType={contentType}
379381
logTreatmentInteractionCall={async (
380382
interactionType: AuxiaInteractionInteractionType,
381383
actionName?: AuxiaInteractionActionName,
@@ -422,6 +424,7 @@ const ShowSignInGateAuxia = ({
422424
treatmentId,
423425
renderingTarget,
424426
isGandalf,
427+
contentType,
425428
logTreatmentInteractionCall,
426429
signInGateVersion,
427430
}: ShowSignInGateAuxiaProps) => {
@@ -436,11 +439,12 @@ const ShowSignInGateAuxia = ({
436439
threshold: 0,
437440
});
438441

439-
// The non-dismissible popup is a modal, so it must appear immediately
440-
// rather than waiting for the reader to scroll to the inline host
441-
// element, which on long pages sits far below the viewport.
442+
// Non-article mandatory popups use the portal as a modal and should appear
443+
// immediately. Articles retain the existing visibility-based behaviour so
444+
// the gate waits until the reader reaches the article gate position.
442445
const isMandatoryPopup =
443446
userTreatment.treatmentType === 'NONDISMISSIBLE_SIGN_IN_GATE_POPUP';
447+
const shouldShowImmediately = isMandatoryPopup && contentType !== 'Article';
444448
const lastRecordedView = useRef<string>();
445449

446450
useEffect(() => {
@@ -452,9 +456,10 @@ const ShowSignInGateAuxia = ({
452456
}, [setNode, setSignInGatePlaceholder]);
453457

454458
useEffect(() => {
455-
// The mandatory popup is shown on mount (see shouldShowV2Gate), so
456-
// its view is recorded immediately instead of waiting for scroll.
457-
if (hasBeenSeen === true || isMandatoryPopup) {
459+
// Non-article mandatory popups are shown on mount (see
460+
// shouldShowV2Gate), so their view is recorded immediately. Articles
461+
// wait for the gate position to become visible.
462+
if (hasBeenSeen === true || shouldShowImmediately) {
458463
const viewIdentity = JSON.stringify([
459464
treatmentId,
460465
userTreatment.treatmentTrackingId,
@@ -518,7 +523,7 @@ const ShowSignInGateAuxia = ({
518523
}
519524
}, [
520525
hasBeenSeen,
521-
isMandatoryPopup,
526+
shouldShowImmediately,
522527
browserId,
523528
contributionsServiceUrl,
524529
isGandalf,
@@ -554,7 +559,8 @@ const ShowSignInGateAuxia = ({
554559
setHasScroll(scrollHeight > viewportHeight);
555560
}, []);
556561

557-
const shouldShowV2Gate = isMandatoryPopup || (hasBeenSeen ?? !hasScroll);
562+
const shouldShowV2Gate =
563+
shouldShowImmediately || (hasBeenSeen ?? !hasScroll);
558564

559565
return (
560566
<>

dotcom-rendering/src/components/StickyBottomBanner.island.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ const buildSignInGateConfig = (
212212
pageId={canShowProps.pageId}
213213
contributionsServiceUrl={canShowProps.contributionsServiceUrl}
214214
auxiaGateDisplayData={meta}
215+
contentType={canShowProps.contentType}
215216
/>
216217
),
217218
},

dotcom-rendering/src/components/StickyBottomBanner/SignInGatePortal.test.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ describe('SignInGatePortal', () => {
171171

172172
expect(result).toEqual({
173173
show: true,
174-
meta: { ...auxiaReturn, gandalfCountryCode: 'NZ' },
174+
meta: auxiaReturn,
175175
});
176176
});
177177

@@ -207,7 +207,7 @@ describe('SignInGatePortal', () => {
207207

208208
expect(result).toEqual({
209209
show: true,
210-
meta: { ...auxiaReturn, gandalfCountryCode: 'NZ' },
210+
meta: auxiaReturn,
211211
});
212212
});
213213
});
@@ -247,10 +247,7 @@ describe('SignInGatePortal', () => {
247247
// selector can build the Ophan variant.
248248
expect(result).toEqual({
249249
show: false,
250-
meta: {
251-
...makeAuxiaReturn(undefined, true),
252-
gandalfCountryCode: 'NZ',
253-
},
250+
meta: makeAuxiaReturn(undefined, true),
254251
});
255252
});
256253

@@ -270,7 +267,7 @@ describe('SignInGatePortal', () => {
270267

271268
expect(result).toEqual({
272269
show: true,
273-
meta: { ...auxiaReturn, gandalfCountryCode: 'NZ' },
270+
meta: auxiaReturn,
274271
});
275272
});
276273
});

dotcom-rendering/src/components/StickyBottomBanner/SignInGatePortal.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ export const SignInGatePortal = ({
2929
pageId,
3030
contributionsServiceUrl,
3131
auxiaGateDisplayData,
32+
contentType,
3233
}: {
3334
host?: string;
3435
isPaidContent: boolean;
3536
isPreview: boolean;
3637
pageId: string;
3738
contributionsServiceUrl: string;
3839
auxiaGateDisplayData: AuxiaGateDisplayData;
40+
contentType?: string;
3941
}) => {
4042
const [shouldShowGate, setShouldShowGate] = useState<boolean>(false);
4143
const [targetElement, setTargetElement] = useState<HTMLElement | null>(
@@ -130,6 +132,7 @@ export const SignInGatePortal = ({
130132
pageId={pageId}
131133
contributionsServiceUrl={contributionsServiceUrl}
132134
auxiaGateDisplayData={auxiaGateDisplayData}
135+
contentType={contentType}
133136
/>
134137
</Island>,
135138
targetElement,
@@ -214,18 +217,13 @@ export const canShowSignInGatePortal = async ({
214217
retrieveLastGateDismissedCount('AuxiaSignInGate'),
215218
);
216219

217-
const meta = (
218-
auxiaData
219-
? {
220-
...auxiaData,
221-
gandalfCountryCode: countryCode,
222-
}
223-
: auxiaData
224-
) as AuxiaGateDisplayData;
220+
if (auxiaData === undefined) {
221+
return { show: false };
222+
}
225223

226224
return {
227-
show: auxiaData?.auxiaData.userTreatment !== undefined,
228-
meta,
225+
show: auxiaData.auxiaData.userTreatment !== undefined,
226+
meta: auxiaData,
229227
};
230228
} catch (e) {
231229
const message = `SignInGatePortal canShowSignInGatePortal - error: ${String(

0 commit comments

Comments
 (0)