Skip to content

Commit

Permalink
WSTEAM1-1300 - Article election banner (#12024)
Browse files Browse the repository at this point in the history
* WSTEAM1-931 - Article election banner iframe

* Update index.styles.ts

* Add AMP version

* Service restriction

* Update index.tsx

* Use rem for height

* Update index.styles.ts

* Fix storybook to show banner

* Set height on container rather than iframe

* Update index.styles.ts

* Find `thingLabel` from `aboutTags`

* Update index.tsx

* Make height configurable

* Move config into separate file

* Add Storybook story

* Update index.tsx

* Rename to `iframeSrc`

* Bail out if toggle returns false/null first

* Update index.styles.ts

* Construct iframe base url

* Disable chromatic snapshot for story

* Check for service in config rather than `iframeSrc`

* Add tests and `isLive` check

* Fix tests

* Use `indianElectionBanner` toggle from iSite

* Update index.stories.jsx

* Update index.tsx

* cache

* Update config.ts

* Update config.ts

* Fix AMP height

* Update bundleSizeConfig.js

* Update config.ts

* logic updates

* Update config.ts

* storybook updates

* test fix

* delete unneeded fixture json

* delete features fixture data

* Update index.tsx

* Add dev source

* Temp - disable toggle check

* Spacing and `aside`

* Consolidate iframe styles

* Include USA `about.tag`

* Set height on iframe for noCSS

* Add separate AMP iframe src

* Pass title to AMP iframe

* Update config.ts

* Re-enable toggle for reviews

* Update index.tsx

* Add local toggle config for `articleElectionBanner`

* Update iframe title - remove `aside` and role` attr

* Remove `United Status` thingId

* Use `thingLabel` for iframe title - Use same `testid` for AMP and canonical

* Remove width restriction

* Simplify styling

* Revert "Simplify styling"

This reverts commit cb47e10.

* Revert "Remove width restriction"

This reverts commit dcdb593.
  • Loading branch information
amoore108 authored Oct 24, 2024
1 parent df4043e commit abef9c6
Show file tree
Hide file tree
Showing 11 changed files with 3,036 additions and 8 deletions.
2,763 changes: 2,763 additions & 0 deletions data/mundo/articles/c206j730722o.json

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions src/app/components/AmpIframe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Props = {
width: number;
height: number;
src: string;
title?: string;
};

type ampMetadata = {
Expand All @@ -19,6 +20,7 @@ type ampMetadata = {
imageHeight: number;
image: string;
src: string;
title?: string;
};
};

Expand All @@ -38,6 +40,7 @@ const AmpIframeElement = ({
width,
height,
src,
title,
}: PropsWithChildren<Props>) => (
<amp-iframe
class={className}
Expand All @@ -47,19 +50,25 @@ const AmpIframeElement = ({
sandbox="allow-scripts allow-same-origin allow-top-navigation-by-user-activation allow-forms"
resizable=""
src={src}
title={title}
>
{children}
</amp-iframe>
);

const AmpIframe = ({
ampMetadata: { imageWidth, imageHeight, image, src },
ampMetadata: { imageWidth, imageHeight, image, src, title },
}: ampMetadata) => {
return (
<>
<AmpHead />
<GridItemMedium gridColumnStart={undefined} gridSpan={undefined}>
<AmpIframeElement width={imageWidth} height={imageHeight} src={src}>
<AmpIframeElement
width={imageWidth}
height={imageHeight}
src={src}
title={title}
>
{/* @ts-expect-error Property 'overflow' does not exist on type 'DivProps & { css?: Interpolation<Theme>; }'. */}
<div overflow="" css={styles.overflow}>
<button type="button" css={styles.button}>
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/react-testing-library-with-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface Props extends PropsWithChildren {
id?: string | null;
isAmp?: boolean;
isApp?: boolean;
isLite?: boolean;
pageData?: object;
atiData?: ATIData;
bbcOrigin?: string | null;
Expand All @@ -40,6 +41,7 @@ const AllTheProviders: FC<Props> = ({
id = null,
isAmp = false,
isApp = false,
isLite = false,
bbcOrigin = 'https://www.test.bbc.com',
pageType = 'article',
derivedPageType,
Expand Down Expand Up @@ -67,6 +69,7 @@ const AllTheProviders: FC<Props> = ({
pageType={pageType}
isAmp={isAmp}
isApp={isApp}
isLite={isLite}
isNextJs={isNextJs}
service={service}
pathname={pathname}
Expand Down Expand Up @@ -97,6 +100,7 @@ const customRender = (
id,
isAmp,
isApp,
isLite,
bbcOrigin,
pageData,
pageType,
Expand All @@ -120,6 +124,7 @@ const customRender = (
id={id}
isAmp={isAmp}
isApp={isApp}
isLite={isLite}
bbcOrigin={bbcOrigin}
pageData={pageData}
atiData={atiData}
Expand Down
3 changes: 3 additions & 0 deletions src/app/lib/config/toggles/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ exports[`Toggles Config when application environment is local should contain cor
"ads": {
"enabled": false,
},
"articleElectionBanner": {
"enabled": true,
},
"chartbeatAnalytics": {
"enabled": true,
},
Expand Down
3 changes: 3 additions & 0 deletions src/app/lib/config/toggles/localConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ export default {
ads: {
enabled: false,
},
articleElectionBanner: {
enabled: true,
},
chartbeatAnalytics: {
enabled: true,
},
Expand Down
5 changes: 4 additions & 1 deletion src/app/pages/ArticlePage/ArticlePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import CpsRecommendations from '#containers/CpsRecommendations';
import InlinePodcastPromo from '#containers/PodcastPromo/Inline';
import { Article, OptimoBylineBlock } from '#app/models/types/optimo';
import ScrollablePromo from '#components/ScrollablePromo';
import ElectionBanner from './ElectionBanner';

import ImageWithCaption from '../../components/ImageWithCaption';
import AdContainer from '../../components/Ad';
import EmbedImages from '../../components/Embeds/EmbedImages';
Expand Down Expand Up @@ -99,7 +101,7 @@ const ArticlePage = ({ pageData }: { pageData: Article }) => {
const aboutTags = getAboutTags(pageData);
const topics = pageData?.metadata?.topics ?? [];
const blocks = pageData?.content?.model?.blocks ?? [];
const startsWithHeading = blocks?.[0]?.type === 'headline' ?? false;
const startsWithHeading = blocks?.[0]?.type === 'headline' || false;

const bylineBlock = blocks.find(
block => block.type === 'byline',
Expand Down Expand Up @@ -271,6 +273,7 @@ const ArticlePage = ({ pageData }: { pageData: Article }) => {
{allowAdvertising && (
<AdContainer slotType="leaderboard" adcampaign={adcampaign} />
)}
<ElectionBanner aboutTags={aboutTags} />
<div css={styles.grid}>
<div css={!isPGL ? styles.primaryColumn : styles.pglColumn}>
<main css={styles.mainContent} role="main">
Expand Down
12 changes: 12 additions & 0 deletions src/app/pages/ArticlePage/ElectionBanner/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';

const IFRAME_BASE_URL = getEnvConfig().SIMORGH_INCLUDES_BASE_URL;

export default {
iframeHeight: 324,
iframeSrc: `${IFRAME_BASE_URL}/include/vjafwest/1365-2024-us-presidential-election-banner/develop/{service}/app`,
iframeSrcAmp: `${IFRAME_BASE_URL}/include/vjafwest/1365-2024-us-presidential-election-banner/develop/{service}/app/amp`,
thingIds: [
'647d5613-e0e2-4ef5-b0ce-b491de38bdbd', // https://www.bbc.co.uk/things/647d5613-e0e2-4ef5-b0ce-b491de38bdbd
],
};
40 changes: 40 additions & 0 deletions src/app/pages/ArticlePage/ElectionBanner/index.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { css, Theme } from '@emotion/react';
import pixelsToRem from '#app/utilities/pixelsToRem';
import BANNER_CONFIG from './config';

const IFRAME_STYLES = css({
border: 'none',
width: '100%',
height: `${pixelsToRem(BANNER_CONFIG.iframeHeight)}rem`,
});

export default {
electionBannerWrapper: ({ mq, spacings }: Theme) =>
css({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
maxWidth: '63rem',
margin: '0 auto',

[mq.GROUP_3_MIN_WIDTH]: {
paddingTop: `${spacings.QUINTUPLE}rem`,
},
}),

electionBannerIframe: () => IFRAME_STYLES,

electionBannerWrapperAmp: ({ mq, spacings }: Theme) =>
css({
overflow: 'hidden',
maxWidth: '63rem',
margin: '0 auto',

[mq.GROUP_3_MIN_WIDTH]: {
paddingTop: `${spacings.QUINTUPLE}rem`,
},

'> div': { padding: '0' },
'& amp-iframe': IFRAME_STYLES,
}),
};
97 changes: 97 additions & 0 deletions src/app/pages/ArticlePage/ElectionBanner/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import { render } from '#app/components/react-testing-library-with-providers';
import { Tag } from '#app/components/Metadata/types';
import isLive from '#app/lib/utilities/isLive';
import BANNER_CONFIG from './config';
import ElectionBanner from '.';

jest.mock('#app/lib/utilities/isLive', () =>
jest.fn().mockImplementation(() => false),
);

const mockAboutTags = [
{ thingId: 'thing1' },
{ thingId: 'thing2' },
...BANNER_CONFIG.thingIds.map(thingId => ({ thingId })),
] as Tag[];

const ELEMENT_ID = 'election-banner';

describe('ElectionBanner', () => {
it('should not render ElectionBanner when isLite is true', () => {
const { queryByTestId } = render(
<ElectionBanner aboutTags={mockAboutTags} />,
{ isLite: true },
);

expect(queryByTestId(ELEMENT_ID)).not.toBeInTheDocument();
});

describe.each(['canonical', 'amp'])('%s', platform => {
const isAmp = platform === 'amp';

it('should render ElectionBanner when aboutTags contain the correct thingLabel', () => {
const { getByTestId } = render(
<ElectionBanner aboutTags={mockAboutTags} />,
{
toggles: { articleElectionBanner: { enabled: true } },
isAmp,
},
);

expect(getByTestId(ELEMENT_ID)).toBeInTheDocument();

const iframe = getByTestId(ELEMENT_ID).querySelector(
isAmp ? 'amp-iframe' : 'iframe',
);

expect(iframe).toHaveAttribute(
'src',
BANNER_CONFIG[isAmp ? 'iframeSrcAmp' : 'iframeSrc'].replace(
'{service}',
'news',
),
);
});

it('should not render ElectionBanner when aboutTags do not contain the correct thingLabel', () => {
const { queryByTestId } = render(
<ElectionBanner aboutTags={[{ thingLabel: 'thing1' }] as Tag[]} />,
{ isAmp },
);

expect(queryByTestId(ELEMENT_ID)).not.toBeInTheDocument();
});

it('should not render ElectionBanner when aboutTags is empty', () => {
const { queryByTestId } = render(<ElectionBanner aboutTags={[]} />, {
isAmp,
});

expect(queryByTestId(ELEMENT_ID)).not.toBeInTheDocument();
});

it('should not render ElectionBanner when toggle is disabled', () => {
const { queryByTestId } = render(
<ElectionBanner aboutTags={mockAboutTags} />,
{
toggles: { articleElectionBanner: { enabled: false } },
isAmp,
},
);

expect(queryByTestId(ELEMENT_ID)).not.toBeInTheDocument();
});

it('should not render ElectionBanner when isLive is true', () => {
(isLive as jest.Mock).mockImplementationOnce(() => true);

const { queryByTestId } = render(
<ElectionBanner aboutTags={mockAboutTags} />,
{ isAmp },
);

expect(queryByTestId(ELEMENT_ID)).not.toBeInTheDocument();
});
});
});
59 changes: 59 additions & 0 deletions src/app/pages/ArticlePage/ElectionBanner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/** @jsx jsx */

import { jsx } from '@emotion/react';
import { useContext } from 'react';
import { RequestContext } from '#app/contexts/RequestContext';
import AmpIframe from '#app/components/AmpIframe';
import useToggle from '#app/hooks/useToggle';
import { Tag } from '#app/components/Metadata/types';
import isLive from '#app/lib/utilities/isLive';
import { ServiceContext } from '#app/contexts/ServiceContext';
import styles from './index.styles';
import BANNER_CONFIG from './config';

export default function ElectionBanner({ aboutTags }: { aboutTags: Tag[] }) {
const { service } = useContext(ServiceContext);
const { isAmp, isLite } = useContext(RequestContext);
const { enabled: electionBannerEnabled }: { enabled: boolean | null } =
useToggle('articleElectionBanner');

if (isLive()) return null; // TODO: Remove once going Live
if (isLite) return null;

const { iframeHeight, iframeSrc, iframeSrcAmp, thingIds } = BANNER_CONFIG;

const validAboutTag = aboutTags?.find(tag => thingIds.includes(tag.thingId));

const showBanner = validAboutTag && electionBannerEnabled;

if (!showBanner) return null;

if (isAmp) {
return (
<div data-testid="election-banner" css={styles.electionBannerWrapperAmp}>
<AmpIframe
ampMetadata={{
imageWidth: 1,
imageHeight: iframeHeight,
src: iframeSrcAmp.replace('{service}', service),
image:
'https://news.files.bbci.co.uk/include/vjassets/img/app-launcher.png',
title: validAboutTag.thingLabel,
}}
/>
</div>
);
}

return (
<div data-testid="election-banner" css={styles.electionBannerWrapper}>
<iframe
title={validAboutTag.thingLabel}
src={iframeSrc.replace('{service}', service)}
scrolling="no"
css={styles.electionBannerIframe}
height={iframeHeight}
/>
</div>
);
}
Loading

0 comments on commit abef9c6

Please sign in to comment.