Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reader Revenue message on US front #12593

Merged
merged 16 commits into from
Oct 22, 2024
22 changes: 22 additions & 0 deletions dotcom-rendering/src/components/UsEoy2024.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/react';
import { UsEoy2024 } from './UsEoy2024Wrapper.importable';

const meta = {
title: 'Components/UsEoy2024',
component: UsEoy2024,
} satisfies Meta<typeof UsEoy2024>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default = {
args: {
tickerData: {
total: 1000000,
goal: 2000000,
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
submitTrackingEvent: () => {},
},
} satisfies Story;
299 changes: 299 additions & 0 deletions dotcom-rendering/src/components/UsEoy2024Wrapper.importable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
import { css } from '@emotion/react';
import { isObject } from '@guardian/libs';
import type { ComponentEvent } from '@guardian/ophan-tracker-js';
import {
from,
headlineMedium24,
headlineMedium28,
headlineMedium34,
palette,
space,
textEgyptian17,
textEgyptianBold17,
} from '@guardian/source/foundations';
import { SvgGuardianLogo } from '@guardian/source/react-components';
import { Ticker } from '@guardian/source-development-kitchen/react-components';
import type {
SelectedAmountsVariant,
TickerData,
} from '@guardian/support-dotcom-components/dist/shared/src/types';
import { useEffect, useState } from 'react';
import { submitComponentEvent } from '../client/ophan/ophan';
import { shouldHideSupportMessaging } from '../lib/contributions';
import { useIsSignedIn } from '../lib/useAuthStatus';
import { useConfig } from './ConfigContext';
import type { ChoiceCardSettings } from './marketing/banners/designableBanner/components/choiceCards/ChoiceCards';
import { ChoiceCards } from './marketing/banners/designableBanner/components/choiceCards/ChoiceCards';
import { buttonStyles } from './marketing/banners/designableBanner/styles/buttonStyles';
import { useChoiceCards } from './marketing/hooks/useChoiceCards';
import type { ReactComponent } from './marketing/lib/ReactComponent';

const styles = {
container: css`
/* stylelint-disable-next-line color-no-hex */
background: #051d32;
color: ${palette.neutral[100]};
`,
grid: css`
display: grid;
flex-direction: column;
position: relative;
padding: 0 ${space[3]}px ${space[4]}px ${space[3]}px;
${from.tablet} {
display: grid;
grid-template-columns: 350px 350px;
padding: 0 ${space[5]}px ${space[4]}px ${space[5]}px;
}
${from.desktop} {
grid-template-columns: 462px 462px;
column-gap: ${space[4]}px;
}
${from.leftCol} {
grid-template-columns: 148px 482px 482px;
column-gap: 0;
}
${from.wide} {
grid-template-columns: 228px 482px 482px;
}
`,
logo: css`
display: none;
${from.leftCol} {
display: block;
grid-column: 1;
grid-row: 1;
margin-top: ${space[2]}px;
}
`,
heading: css`
${from.tablet} {
grid-column: 1;
grid-row: 1;
}
h2 {
margin: ${space[2]}px 0 ${space[4]}px;
color: ${palette.neutral[100]};

${headlineMedium24}
${from.tablet} {
${headlineMedium28}
}
${from.leftCol} {
${headlineMedium34}
}
}
${from.leftCol} {
grid-column: 2;
border-left: 1px solid rgba(255, 255, 255, 0.2);
padding-left: ${space[2]}px;
}
`,
body: css`
${textEgyptian17};
strong {
${textEgyptianBold17};
}
`,
ticker: css`
margin-bottom: ${space[4]}px;
`,
choiceCards: css`
margin-top: ${space[6]}px;
${from.tablet} {
grid-column: 2;
grid-row: 1;
align-self: flex-start;
display: flex;
justify-content: flex-end;
}
${from.leftCol} {
grid-column: 3;
margin-right: ${space[3]}px;
}
`,
};

const tickerSettings = {
currencySymbol: '$',
copy: {},
tickerStylingSettings: {
filledProgressColour: '#64B7C4',
progressBarBackgroundColour: 'rgba(34, 75, 95, 1)',
headlineColour: '#000000',
totalColour: '#64B7C4',
goalColour: '#FFFFFF',
},
};

const getTickerData = async (): Promise<TickerData | undefined> => {
const data = await fetch(
'https://support.theguardian.com/ticker/US.json',
).then((response) => response.json());

if (isObject(data)) {
const { total, goal } = data;
if (typeof total === 'number' && typeof goal === 'number') {
return {
total: Math.floor(total),
goal: Math.floor(goal),
};
}
}
return;
};

const choiceCardAmounts: SelectedAmountsVariant = {
testName: 'us-eoy-front-amounts',
variantName: 'CONTROL',
defaultContributionType: 'MONTHLY',
displayContributionType: ['ONE_OFF', 'MONTHLY', 'ANNUAL'],
amountsCardData: {
ONE_OFF: {
amounts: [75, 125],
defaultAmount: 75,
hideChooseYourAmount: false,
},
MONTHLY: {
amounts: [5, 15],
defaultAmount: 15,
hideChooseYourAmount: false,
},
ANNUAL: {
amounts: [60, 150],
defaultAmount: 150,
hideChooseYourAmount: false,
},
},
};
const choiceCardSettings: ChoiceCardSettings = {
buttonColour: '#FFFFFF',
buttonTextColour: '#000000',
buttonBorderColour: '#000000',
buttonSelectColour: '#E3F6FF',
buttonSelectTextColour: '#000000',
buttonSelectBorderColour: '#0077B6',
};
const componentId = 'USEOY24_LAUNCH_UPDATED_THRASHER';
const cta = {
ctaUrl: `https://support.theguardian.com/us/contribute?acquisitionData={"source":"GUARDIAN_WEB","componentType":"ACQUISITIONS_THRASHER","componentId":"${componentId}","campaignCode":"USEOY24"}&INTCMP=USEOY24`,
ctaText: 'Support us',
};

interface Props {
tickerData: TickerData;
submitTrackingEvent: (event: ComponentEvent) => void;
}

export const UsEoy2024: ReactComponent<Props> = ({
tickerData,
submitTrackingEvent,
}: Props): JSX.Element => {
const {
choiceCardSelection,
setChoiceCardSelection,
getCtaText,
getCtaUrl,
currencySymbol,
} = useChoiceCards(choiceCardAmounts, 'US', cta, cta);

return (
<div css={styles.container}>
<div css={styles.grid}>
<div css={styles.logo}>
<SvgGuardianLogo textColor={'#FFFFFF'} width={100} />
</div>
<div css={styles.heading}>
<h2>Can you help us hit our goal?</h2>
<div css={styles.body}>
<div css={styles.ticker}>
<Ticker
currencySymbol={tickerSettings.currencySymbol}
copy={{}}
tickerData={tickerData}
tickerStylingSettings={
tickerSettings.tickerStylingSettings
}
size={'medium'}
/>
</div>
With no billionaire owner or shareholders pulling our
strings, reader support keeps us fiercely independent.
<strong>
{' '}
Help us hit our most important annual fundraising
goal so we can keep going.
</strong>
</div>
</div>
<div css={styles.choiceCards}>
<ChoiceCards
setSelectionsCallback={setChoiceCardSelection}
selection={choiceCardSelection}
submitComponentEvent={submitTrackingEvent}
currencySymbol={currencySymbol}
componentId={'thrasher-choice-cards'}
amountsTest={choiceCardAmounts}
design={choiceCardSettings}
getCtaText={getCtaText}
getCtaUrl={getCtaUrl}
cssCtaOverides={buttonStyles({
default: {
backgroundColour: '#C41C1C',
textColour: '#FFFFFF',
},
hover: {
backgroundColour: '#C41C1C',
textColour: '#FFFFFF',
},
})}
onCtaClick={() => {
submitTrackingEvent({
component: {
componentType: 'ACQUISITIONS_THRASHER',
id: componentId,
},
action: 'CLICK',
});
}}
/>
</div>
</div>
</div>
);
};

export const UsEoy2024Wrapper = (): JSX.Element => {
const [tickerData, setTickerData] = useState<TickerData | undefined>();

const [showSupportMessagingForUser, setShowSupportMessaging] =
useState<boolean>(false);
const isSignedIn = useIsSignedIn();

useEffect(() => {
if (isSignedIn !== 'Pending') {
setShowSupportMessaging(
shouldHideSupportMessaging(isSignedIn) === false,
);
}
}, [isSignedIn]);

useEffect(() => {
void getTickerData().then(setTickerData);
}, []);

const { renderingTarget } = useConfig();
const submitTrackingEvent = (event: ComponentEvent) => {
void submitComponentEvent(event, renderingTarget);
};

return (
<>
{showSupportMessagingForUser && tickerData && (
<UsEoy2024
tickerData={tickerData}
submitTrackingEvent={submitTrackingEvent}
/>
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,12 @@ const DesignableBanner: ReactComponent<BannerRenderProps> = ({
getCtaText,
getCtaUrl,
currencySymbol,
} = useChoiceCards(choiceCardAmounts, countryCode, content);
} = useChoiceCards(
choiceCardAmounts,
countryCode,
content.mainContent.primaryCta,
content.mobileContent.primaryCta,
);

// We can't render anything without a design
if (!design) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const ChoiceCardInteractive: ReactComponent<
label={`${currencySymbol}${amount} ${
contributionType[selection.frequency].suffix
}`}
id={`contributions-banner-${amount}`}
id={`${componentId}-${amount}`}
checked={selection.amount === amount}
onChange={() => updateAmount(amount)}
cssOverrides={style.buttonOverride}
Expand All @@ -190,7 +190,7 @@ export const ChoiceCardInteractive: ReactComponent<
<ChoiceCard
value="third"
label="Other"
id="contributions-banner-third"
id={`${componentId}-third`}
checked={true}
cssOverrides={style.buttonOverride}
/>
Expand All @@ -208,7 +208,7 @@ export const ChoiceCardInteractive: ReactComponent<
key={2}
value="other"
label="Other"
id="contributions-banner-other"
id={`${componentId}-other`}
checked={selection.amount === 'other'}
onChange={() => updateAmount('other')}
cssOverrides={style.buttonOverride}
Expand All @@ -226,7 +226,7 @@ export const ChoiceCardInteractive: ReactComponent<
key={label}
label={label}
value={frequency}
id={`contributions-banner-${frequency}`}
id={`${componentId}-${frequency}`}
checked={selection.frequency === frequency}
onChange={() => updateFrequency(frequency)}
cssOverrides={style.buttonOverride}
Expand All @@ -237,7 +237,7 @@ export const ChoiceCardInteractive: ReactComponent<
return (
<>
<ChoiceCardGroup
name="contribution-frequency"
name={`${componentId}-contribution-frequency`}
label="Contribution frequency"
columns={noOfContributionTabs}
hideLabel={true}
Expand All @@ -255,7 +255,7 @@ export const ChoiceCardInteractive: ReactComponent<
)}
</ChoiceCardGroup>
<ChoiceCardGroup
name="contribution-amount"
name={`${componentId}-contribution-amount`}
label="Contribution amount"
columns={2}
hideLabel={true}
Expand Down
Loading
Loading