client/components/mma/identity/emailAndMarketing/NewsletterSection.tsx (92 lines of code) (raw):
import { palette } from '@guardian/source/foundations';
import uniq from 'lodash/uniq';
import type { FC } from 'react';
import { DropMenu } from '../DropMenu';
import type { ConsentOption } from '../models';
import { NewsletterGroup } from '../models';
import { NewsletterPreference } from '../NewsletterPreference';
import { PageSection } from '../PageSection';
import { ObserverNewsletterLink } from './ObserverNewsletterLink';
type ClickHandler = (id: string) => unknown;
interface NewsletterSectionProps {
newsletters: ConsentOption[];
clickHandler: ClickHandler;
}
const newsletterPreference = (
newsletter: ConsentOption,
clickHandler: ClickHandler,
) => {
const { id, name, description, frequency, subscribed, identityName } =
newsletter;
return (
<NewsletterPreference
id={id}
key={id}
title={name}
// A newsletter always has identityName & frequency (see interface NewsletterAPIResponse)
// but ConsentOption has these as optional so we need to keep ts happy by falling back to
// "" here
identityName={identityName || ''}
frequency={frequency || ''}
description={description || ''}
selected={subscribed}
onClick={clickHandler}
/>
);
};
function notEmpty<T>(value: T | undefined): value is T {
return value !== undefined;
}
function getGroupColor(group: string): string {
const colors: Record<NewsletterGroup, string> = {
[NewsletterGroup.newsInBrief]: palette.news[400],
[NewsletterGroup.newsInDepth]: palette.news[400],
[NewsletterGroup.opinion]: palette.opinion[500],
[NewsletterGroup.features]: palette.neutral[7],
[NewsletterGroup.sport]: palette.sport[400],
[NewsletterGroup.culture]: '#a1845c',
[NewsletterGroup.lifestyle]: palette.lifestyle[400],
[NewsletterGroup.work]: palette.neutral[7],
[NewsletterGroup.fromThePapers]: palette.neutral[7],
};
if (Object.values(NewsletterGroup).includes(group as NewsletterGroup)) {
return colors[group as NewsletterGroup];
}
return palette.neutral[7];
}
const newsletterPreferenceGroups = (
newsletters: ConsentOption[],
clickHandler: ClickHandler,
) => {
const groups = uniq(newsletters.map((_) => _.group)).filter(notEmpty);
return groups.map((group) => (
<DropMenu
key={group}
color={getGroupColor(group.toLowerCase())}
title={group}
>
{newsletters
.filter((n) => n.group === group)
.map((n) => newsletterPreference(n, clickHandler))}
</DropMenu>
));
};
export const NewsletterSection: FC<NewsletterSectionProps> = (props) => {
const { newsletters, clickHandler } = props;
return (
<PageSection
title="Your newsletters"
description={`
Our regular newsletters help you get closer to our quality,
independent journalism. Pick the issues and topics that interest you
below.`}
subtext={`
The Guardian’s newsletters include content from our website, which may
be funded by outside parties. Newsletters may also display information
about Guardian News and Media's other products, services or events
(such as Guardian Jobs), chosen charities or online
advertisements.
`}
>
{newsletterPreferenceGroups(newsletters, clickHandler)}
<ObserverNewsletterLink />
</PageSection>
);
};