Skip to content

Commit

Permalink
Merge pull request #13198 from guardian/ph-20250118-2002-auxia1
Browse files Browse the repository at this point in the history
Auxia Integration (Experimental)
  • Loading branch information
shtukas authored Jan 28, 2025
2 parents 5451fda + c5ba082 commit c24d570
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 4 deletions.
245 changes: 244 additions & 1 deletion dotcom-rendering/src/components/SignInGateSelector.importable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getCookie, isUndefined } from '@guardian/libs';
import { useEffect, useState } from 'react';
import { parseCheckoutCompleteCookieData } from '../lib/parser/parseCheckoutOutCookieData';
import { constructQuery } from '../lib/querystring';
import { useAB } from '../lib/useAB';
import { useAuthStatus } from '../lib/useAuthStatus';
import { useCountryCode } from '../lib/useCountryCode';
import { useOnce } from '../lib/useOnce';
Expand All @@ -19,13 +20,18 @@ import {
incrementUserDismissedGateCount,
setUserDismissedGate,
} from './SignInGate/dismissGate';
import { signInGateComponent as gateMainVariant } from './SignInGate/gates/main-variant';
import { signInGateTestIdToComponentId } from './SignInGate/signInGate';
import type {
CheckoutCompleteCookieData,
CurrentSignInGateABTest,
SignInGateComponent,
} from './SignInGate/types';

// ------------------------------------------------------------------------------------------
// Default (pre Auxia Integration Experiment) types, SignInGateSelector and ShowSignInGate //
// ------------------------------------------------------------------------------------------

type Props = {
contentType: string;
sectionId?: string;
Expand Down Expand Up @@ -182,7 +188,8 @@ const useCheckoutCompleteCookieData = () => {
*
* (No visual story exists)
*/
export const SignInGateSelector = ({

const SignInGateSelectorDefault = ({
contentType,
sectionId = '',
tags,
Expand Down Expand Up @@ -327,3 +334,239 @@ export const SignInGateSelector = ({
</>
);
};

// -------------------------------
// Auxia Integration Experiment //
// -------------------------------

export const SignInGateSelector = ({
contentType,
sectionId = '',
tags,
isPaidContent,
isPreview,
host = 'https://theguardian.com/',
pageId,
idUrl = 'https://profile.theguardian.com',
switches,
}: Props) => {
const abTestAPI = useAB()?.api;
const userIsInAuxiaExperiment = !!abTestAPI?.isUserInVariant(
'AuxiaSignInGate',
'auxia-signin-gate',
);

if (!userIsInAuxiaExperiment) {
return SignInGateSelectorDefault({
contentType,
sectionId,
tags,
isPaidContent,
isPreview,
host,
pageId,
idUrl,
switches,
});
} else {
return SignInGateSelectorAuxia({
host,
pageId,
idUrl,
});
}
};

/*
Date: January 2025
comment group: auxia-prototype-e55a86ef
Author: Pascal
We are currently starting to evaluate a new approach for the decision to display the sign gate or not: an
external API, that will be returning that decision. The company offering that API is called Auxia and
can be found here: https://www.auxia.io
At this aim I have move the existing legacy version of the SignInGateSelector to SignInGateSelectorDefault,
and I am introducing SignInGateSelectorAuxia, which is the new component that will be using the Auxia API.
This work, until further notice is the implementation and evaluation of a prototype.
All comments related to this prototype comes under the same comment group: auxia-prototype-e55a86ef
(follow it if one day you want to decommission the entire prototype).
PRs for ab test definition:
- https://github.com/guardian/frontend/pull/27743
- https://github.com/guardian/frontend/pull/27744
- https://github.com/guardian/dotcom-rendering/pull/13197
*/

type PropsAuxia = {
host?: string;
pageId: string;
idUrl?: string;
};

/*
comment group: auxia-prototype-e55a86ef
Signature for the ShowSignInGateAuxia component.
*/
interface ShowSignInGateAuxiaProps {
setShowGate: React.Dispatch<React.SetStateAction<boolean>>;
signInUrl: string;
registerUrl: string;
gateVariant: SignInGateComponent;
host: string;
}

interface SDCProxyData {
shouldShowSignInGate: boolean;
}

/*
comment group: auxia-prototype-e55a86ef
Auxia version of the dismissGate function.
*/
const dismissGateAuxia = (
setShowGate: React.Dispatch<React.SetStateAction<boolean>>,
) => {
setShowGate(false);
};

const fetchAuxiaDisplayDataFromProxy = async (): Promise<SDCProxyData> => {
const url = 'https://contributions.guardianapis.com/auxia';
const headers = {
'Content-Type': 'application/json',
};
const payload = {};
const params = {
method: 'POST',
headers,
body: JSON.stringify(payload),
};

const response = await fetch(url, params);

const data = (await response.json()) as SDCProxyData;

return Promise.resolve(data);
};

const SignInGateSelectorAuxia = ({
host = 'https://theguardian.com/',
pageId,
idUrl = 'https://profile.theguardian.com',
}: PropsAuxia) => {
/*
comment group: auxia-prototype-e55a86ef
This function if the Auxia prototype for the SignInGateSelector component.
*/
const [isGateDismissed, setIsGateDismissed] = useState<boolean | undefined>(
undefined,
);

const [
shouldShowSignInGateUsingAuxiaAnswer,
setShouldShowSignInGateUsingAuxiaAnswer,
] = useState<boolean>(false);

const gateVariant = gateMainVariant;

const currentTest = {
name: 'SignInGateMain',
variant: 'main-variant-5',
id: 'SignInGateMainVariant',
};

const { renderingTarget } = useConfig();

const pageViewId = usePageViewId(renderingTarget);

useOnce(() => {
// this hook will fire when the sign in gate is dismissed
// which will happen when the showGate state is set to false
// this only happens within the dismissGate method
if (isGateDismissed) {
document.dispatchEvent(
new CustomEvent('article:sign-in-gate-dismissed'),
);
}
}, [isGateDismissed]);

useOnce(() => {
void (async () => {
const data = await fetchAuxiaDisplayDataFromProxy();
setShouldShowSignInGateUsingAuxiaAnswer(data.shouldShowSignInGate);
})().catch((error) => {
console.error('Error fetching Auxia display data:', error);
});
}, [shouldShowSignInGateUsingAuxiaAnswer]);

if (isUndefined(pageViewId)) {
return null;
}

const componentId = 'main_variant_5';

const ctaUrlParams = {
pageId,
host,
pageViewId,
idUrl,
currentTest,
componentId,
} satisfies Parameters<typeof generateGatewayUrl>[1];

return (
<>
{!isGateDismissed && shouldShowSignInGateUsingAuxiaAnswer && (
<ShowSignInGateAuxia
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions -- Odd react types, should review
setShowGate={(show) => setIsGateDismissed(!show)}
signInUrl={generateGatewayUrl('signin', ctaUrlParams)}
registerUrl={generateGatewayUrl('register', ctaUrlParams)}
gateVariant={gateVariant}
host={host}
/>
)}
</>
);
};

const ShowSignInGateAuxia = ({
setShowGate,
signInUrl,
registerUrl,
gateVariant,
host,
}: ShowSignInGateAuxiaProps) => {
/*
comment group: auxia-prototype-e55a86ef
This function if the Auxia prototype for the ShowSignInGate component.
*/

const componentId = 'main_variant_5';
const abTest = undefined;
const checkoutCompleteCookieData = undefined;
const personaliseSignInGateAfterCheckoutSwitch = undefined;

// some sign in gate ab test variants may not need to show a gate
// therefore the gate is optional
// this is because we want a section of the audience to never see the gate
// but still fire a view event if they are eligible to see the gate
if (gateVariant.gate) {
return gateVariant.gate({
guUrl: host,
signInUrl,
registerUrl,
dismissGate: () => {
dismissGateAuxia(setShowGate);
},
abTest,
ophanComponentId: componentId,
checkoutCompleteCookieData,
personaliseSignInGateAfterCheckoutSwitch,
});
}
// return nothing if no gate needs to be shown
return <></>;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const auxiaSignInGate = {
import type { ABTest } from '@guardian/ab-core';

export const auxiaSignInGate: ABTest = {
id: 'AuxiaSignInGate',
start: '2025-01-23',
expiry: '2026-01-30',
Expand All @@ -9,15 +11,14 @@ export const auxiaSignInGate = {
audienceOffset: 0,
successMeasure: '',
audienceCriteria: '',
ophanComponentId: 'auxia_signin_gate',
dataLinkNames: 'AuxiaSignInGate',
idealOutcome: '',
showForSensitive: false,
canRun: () => true,
variants: [
{
id: 'auxia-signin-gate',
test: () => {},
test: (): void => {},
},
],
};
1 change: 1 addition & 0 deletions dotcom-rendering/src/lib/ArticleRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const ArticleRenderer = ({
// );
// ^^ Until we decide where to do the "isomorphism split" in this this code is not safe here.
// But should be soon.

return (
<div
className={[
Expand Down

0 comments on commit c24d570

Please sign in to comment.