Skip to content

Marketing email promotions #14051

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

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const defaultArgs = {
frequency: 'Weekly',
successDescription: "We'll send you The Recap every week",
theme: 'sport',
emailType: 'newsletter',
} satisfies Story['args'];
type Story = StoryObj<typeof EmailSignUpWrapper>;

Expand Down
4 changes: 3 additions & 1 deletion dotcom-rendering/src/components/EmailSignUpWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ export const EmailSignUpWrapper = ({
/>
</Island>
{!emailSignUpProps.hidePrivacyMessage && (
<NewsletterPrivacyMessage />
<NewsletterPrivacyMessage
emailType={emailSignUpProps.emailType}
/>
)}
</EmailSignup>
</InlineSkipToWrapper>
Expand Down
31 changes: 28 additions & 3 deletions dotcom-rendering/src/components/EmailSignup.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LinkButton } from '@guardian/source/react-components';
import type { Meta, StoryObj } from '@storybook/react';
import { allModes } from '../../.storybook/modes';
import { ArticleDesign, ArticleDisplay, Pillar } from '../lib/articleFormat';
Expand Down Expand Up @@ -47,13 +48,14 @@ export const Default = {
name: 'The Week in Patriarchy',
frequency: 'Weekly',
theme: 'opinion',
emailType: 'newsletter',
children: (
<>
<SecureSignup
newsletterId="patriarchy"
successDescription="Reviewing the most important stories on feminism and sexism and those fighting for equality"
/>
<NewsletterPrivacyMessage />
<NewsletterPrivacyMessage emailType="newsletter" />
</>
),
},
Expand All @@ -75,13 +77,14 @@ export const NewsTheme = {
name: 'First Edition',
frequency: 'Every weekday',
theme: 'news',
emailType: 'newsletter',
children: (
<>
<SecureSignup
newsletterId="morning-briefing"
successDescription="Archie Bland and Nimo Omer take you through the top stories and what they mean, free every weekday morning"
/>
<NewsletterPrivacyMessage />
<NewsletterPrivacyMessage emailType="newsletter" />
</>
),
},
Expand All @@ -103,15 +106,37 @@ export const IrregularFrequency = {
name: 'Guardian Documentaries',
frequency: 'Whenever a new film is available',
theme: 'features',
emailType: 'newsletter',
children: (
<>
<SecureSignup
newsletterId="documentaries"
successDescription="Be the first to see our latest thought-provoking films, bringing you bold and original storytelling from around the world"
/>
<NewsletterPrivacyMessage />
<NewsletterPrivacyMessage emailType="newsletter" />
</>
),
},
parameters: Default.parameters,
} satisfies Story;

export const MarketingEmail = {
args: {
description:
'Find your next job with the Guardian Jobs weekly email. Get the latest job listings, as well as tips and advice on taking your next career step.',
name: 'Guardian Jobs',
theme: 'news',
emailType: 'marketingConsent',
children: (
<>
<div>
<LinkButton size="small">
Sign up from my account
</LinkButton>
</div>
<NewsletterPrivacyMessage emailType="marketingConsent" />
</>
),
},
parameters: Default.parameters,
};
24 changes: 19 additions & 5 deletions dotcom-rendering/src/components/EmailSignup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import {
} from '@guardian/source/foundations';
import { buildDetailText } from '../lib/buildNewsletterSignUpText';
import { palette as themePalette } from '../palette';
import type { NewsletterOrMarketingEmail } from '../types/content';
import { NewsletterDetail } from './NewsletterDetail';

export type EmailSignUpProps = {
name: string;
description: string;
frequency: string;
frequency?: string;
theme: string;
children?: React.ReactNode;
emailType: NewsletterOrMarketingEmail['type'];
};

const containerStyles = css`
Expand Down Expand Up @@ -77,22 +79,34 @@ const descriptionStyles = css`
max-width: ${335 + space[3] + 118}px;
`;

const ariaLabel = (emailType: NewsletterOrMarketingEmail['type']) => {
switch (emailType) {
case 'newsletter':
return 'newsletter promotion';
case 'marketingConsent':
return 'marketing newsletter promotion';
}
};

export const EmailSignup = ({
name,
description,
frequency,
theme,
children,
emailType,
}: EmailSignUpProps) => {
return (
<aside css={containerStyles} aria-label="newsletter promotion">
<aside css={containerStyles} aria-label={ariaLabel(emailType)}>
<div css={stackBelowTabletStyles}>
<p css={titleStyles(theme)}>
Sign up to <span>{name}</span>
</p>
<div css={noHeightFromTabletStyles}>
<NewsletterDetail text={buildDetailText(frequency)} />
</div>
{!!frequency && (
<div css={noHeightFromTabletStyles}>
<NewsletterDetail text={buildDetailText(frequency)} />
</div>
)}
</div>
<p css={descriptionStyles}>{description}</p>
{children}
Expand Down
5 changes: 4 additions & 1 deletion dotcom-rendering/src/components/ManyNewslettersForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ export const ManyNewslettersForm = ({
id={'man-newsletter-form-inline-skip-to-wrapper'}
blockDescription="Privacy Notice"
>
<NewsletterPrivacyMessage textColor="regular" />
<NewsletterPrivacyMessage
textColor="regular"
emailType="newsletter"
/>
</InlineSkipToWrapper>
</aside>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Meta, StoryObj } from '@storybook/react';
import { MarketingEmailSignUpWrapper } from './MarketingEmailSignUpWrapper';

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

const defaultArgs = {
index: 10,
emailId: 'jobs',
description:
'Find your next job with the Guardian Jobs weekly email. Get the latest job listings, as well as tips and advice on taking your next career step.',
name: 'Guardian Jobs',
frequency: 'Weekly',
emailType: 'marketingConsent',
theme: 'news',
} satisfies Story['args'];
type Story = StoryObj<typeof MarketingEmailSignUpWrapper>;

export const DefaultStory: Story = {
args: {
...defaultArgs,
},
};

export default meta;
45 changes: 45 additions & 0 deletions dotcom-rendering/src/components/MarketingEmailSignUpWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { LinkButton } from '@guardian/source/react-components';
import type { EmailSignUpProps } from './EmailSignup';
import { EmailSignup } from './EmailSignup';
import { InlineSkipToWrapper } from './InlineSkipToWrapper';
import { NewsletterPrivacyMessage } from './NewsletterPrivacyMessage';

interface MarketingEmailSignUpWrapperProps extends EmailSignUpProps {
index: number;
emailId: string;

Check failure on line 9 in dotcom-rendering/src/components/MarketingEmailSignUpWrapper.tsx

View workflow job for this annotation

GitHub Actions / lint / check

'emailId' PropType is defined but prop is never used
mmaUrl: string;
}

export const MarketingEmailSignUpWrapper = ({
index,
mmaUrl,
name,
description,
emailType,
theme,
}: MarketingEmailSignUpWrapperProps) => {
return (
<InlineSkipToWrapper
id={`EmailSignup-skip-link-${index}`}
blockDescription="marketing email promotion"
>
<EmailSignup
emailType={emailType}
name={name}
description={description}
theme={theme}
>
<div>
<LinkButton size="small" href={`${mmaUrl}/email-prefs`}>
Sign up from my account
</LinkButton>
</div>

<NewsletterPrivacyMessage
emailType={emailType}
textColor="regular"
/>
</EmailSignup>
</InlineSkipToWrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export default {
};

export const Default = () => {
return <NewsletterPrivacyMessage />;
return <NewsletterPrivacyMessage emailType="newsletter" />;
};

export const ForMarketting = () => {
return <NewsletterPrivacyMessage emailType="marketingConsent" />;
};

Default.storyName = 'Default';
16 changes: 14 additions & 2 deletions dotcom-rendering/src/components/NewsletterPrivacyMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
} from '@guardian/source/foundations';
import { Link } from '@guardian/source/react-components';
import { palette as themePalette } from '../palette';
import type { NewsletterOrMarketingEmail } from '../types/content';

interface Props {
textColor?: 'supporting' | 'regular';
emailType: NewsletterOrMarketingEmail['type'];
}

const GUARDIAN_PRIVACY_POLICY =
Expand Down Expand Up @@ -75,13 +77,23 @@ const textStyles = (textColor: 'supporting' | 'regular') => {
}
};

const intro = (emailType: NewsletterOrMarketingEmail['type']) => {
switch (emailType) {
case 'newsletter':
return 'Newsletters may contain info about charities, online ads, and content funded by outside parties.';
// TO DO - need to get compliance & marketing agreement on this wording
case 'marketingConsent':
return 'Marketing emails contain advertisments from the Guardian and third parties.';
}
};

export const NewsletterPrivacyMessage = ({
textColor = 'supporting',
emailType,
}: Props) => (
<span css={[termsStyle, textStyles(textColor)]}>
<strong>Privacy Notice: </strong>
Newsletters may contain info about charities, online ads, and content
funded by outside parties. For more information see our{' '}
{intro(emailType)} For more information see our{' '}
<LegalLink href={GUARDIAN_PRIVACY_POLICY}>Privacy Policy</LegalLink>. We
use Google reCaptcha to protect our website and the Google{' '}
<LegalLink href={GOOGLE_PRIVACY_POLICY}>Privacy Policy</LegalLink> and{' '}
Expand Down
1 change: 1 addition & 0 deletions dotcom-rendering/src/components/Timeline.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const ArticleElementComponent = getNestedArticleElement({
* but there are no rich links in this example.
*/
ajaxUrl: '',
mmaUrl: '',
editionId: 'UK',
isAdFreeUser: false,
isSensitive: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const ContributionsEpicNewsletterSignup = ({
variant: tracking.abTestVariant,
}}
/>
<NewsletterPrivacyMessage />
<NewsletterPrivacyMessage emailType="newsletter" />
</div>
);
};
41 changes: 41 additions & 0 deletions dotcom-rendering/src/frontend/schemas/feArticle.json
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,9 @@
{
"$ref": "#/definitions/NewsletterSignupBlockElement"
},
{
"$ref": "#/definitions/MarketingEmailSignupBlockElement"
},
{
"$ref": "#/definitions/ProfileAtomBlockElement"
},
Expand Down Expand Up @@ -2882,6 +2885,44 @@
"newsletter"
]
},
"MarketingEmailSignupBlockElement": {
"type": "object",
"properties": {
"_type": {
"type": "string",
"const": "model.dotcomrendering.pageElements.MarketingEmailSignupBlockElement"
},
"marketingEmail": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"promotionTagId": {
"type": "string"
}
},
"required": [
"description",
"id",
"name"
]
},
"elementId": {
"type": "string"
}
},
"required": [
"_type",
"marketingEmail"
]
},
"ProfileAtomBlockElement": {
"type": "object",
"properties": {
Expand Down
4 changes: 4 additions & 0 deletions dotcom-rendering/src/layouts/FullPageInteractiveLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type RendererProps = {
pageId: string;
webTitle: string;
ajaxUrl: string;
mmaUrl?: string;
isAdFreeUser: boolean;
isSensitive: boolean;
abTests: ServerSideTests;
Expand All @@ -71,6 +72,7 @@ const Renderer = ({
host,
pageId,
webTitle,
mmaUrl,
ajaxUrl,
isAdFreeUser,
isSensitive,
Expand All @@ -93,6 +95,7 @@ const Renderer = ({
pageId,
webTitle,
ajaxUrl,
mmaUrl,
isAdFreeUser,
isSensitive,
abTests,
Expand Down Expand Up @@ -292,6 +295,7 @@ export const FullPageInteractiveLayout = (props: WebProps | AppsProps) => {
pageId={article.pageId}
webTitle={article.webTitle}
ajaxUrl={article.config.ajaxUrl}
mmaUrl={article.config.mmaUrl}
abTests={article.config.abTests}
switches={article.config.switches}
isAdFreeUser={article.isAdFreeUser}
Expand Down
Loading
Loading