Skip to content

Commit 4e241d3

Browse files
lindseydewvlbee
andauthored
Listen to article button (#14154)
* Update bridget version * Pass the pageId to meta component * Include the listen to article button * Update the stories * Run linter * Hide button when paused * Tidy up * Refactor ListenToArticle * Fix dark mode * Use promise all * Ensure listen to article stays hidden until ready. --------- Co-authored-by: vanessa <[email protected]>
1 parent eb91e8e commit 4e241d3

14 files changed

+148
-5
lines changed

dotcom-rendering/.storybook/mocks/bridgetApi.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ export const getInteractivesClient: BridgetApi<
9696
getNativePlatform: async () => 0,
9797
});
9898

99+
export const getListenToArticleClient: BridgetApi<
100+
'getListenToArticleClient'
101+
> = () => ({
102+
isAvailable: async () => true,
103+
isPlaying: async () => false,
104+
});
99105
export const ensure_all_exports_are_present = {
100106
getUserClient,
101107
getAcquisitionsClient,
@@ -112,6 +118,7 @@ export const ensure_all_exports_are_present = {
112118
getTagClient,
113119
getInteractionClient,
114120
getInteractivesClient,
121+
getListenToArticleClient,
115122
} satisfies {
116123
[Method in keyof BridgeModule]: BridgetApi<Method>;
117124
};

dotcom-rendering/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"@emotion/server": "11.11.0",
2929
"@guardian/ab-core": "8.0.0",
3030
"@guardian/braze-components": "22.2.0",
31-
"@guardian/bridget": "8.4.0",
31+
"@guardian/bridget": "8.5.1",
3232
"@guardian/browserslist-config": "6.1.0",
3333
"@guardian/cdk": "61.4.0",
3434
"@guardian/commercial": "26.1.2",

dotcom-rendering/src/components/ArticleMeta.apps.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { Contributor } from './Contributor';
2222
import { Dateline } from './Dateline';
2323
import { FollowWrapper } from './FollowWrapper.importable';
2424
import { Island } from './Island';
25+
import { ListenToArticle } from './ListenToArticle.importable';
2526
import { LiveblogNotifications } from './LiveblogNotifications.importable';
2627

2728
type Props = {
@@ -353,6 +354,11 @@ export const ArticleMetaApps = ({
353354
</MetaGridBranding>
354355
)}
355356
</div>
357+
{pageId !== undefined && (
358+
<Island priority="feature" defer={{ until: 'visible' }}>
359+
<ListenToArticle articleId={pageId} />
360+
</Island>
361+
)}
356362
</div>
357363
);
358364
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { log } from '@guardian/libs';
2+
import { useEffect, useState } from 'react';
3+
import { getListenToArticleClient } from '../lib/bridgetApi';
4+
import { useIsBridgetCompatible } from '../lib/useIsBridgetCompatible';
5+
import { ListenToArticleButton } from './ListenToArticleButton';
6+
7+
type Props = {
8+
articleId: string;
9+
};
10+
export const ListenToArticle = ({ articleId }: Props) => {
11+
const [showButton, setShowButton] = useState<boolean>(false);
12+
13+
const isBridgetCompatible = useIsBridgetCompatible('8.5.1');
14+
15+
useEffect(() => {
16+
if (isBridgetCompatible) {
17+
Promise.all([
18+
getListenToArticleClient().isAvailable(articleId),
19+
getListenToArticleClient().isPlaying(articleId),
20+
])
21+
.then(() =>
22+
// setShowButton(isAvailable && !isPlaying),
23+
setShowButton(false),
24+
)
25+
.catch((error) => {
26+
console.error(
27+
'Error fetching article audio status: ',
28+
error,
29+
);
30+
setShowButton(false);
31+
});
32+
}
33+
}, [articleId, isBridgetCompatible]);
34+
35+
const listenToArticleHandler = () => {
36+
void getListenToArticleClient()
37+
.play(articleId)
38+
.then((success: boolean) => {
39+
// hide the audio button once audio is playing until we can
40+
// manage play state syncronisation across the native miniplayer and web layer
41+
success && setShowButton(false);
42+
})
43+
.catch((error: Error) => {
44+
window.guardian.modules.sentry.reportError(
45+
error,
46+
'bridget-getListenToArticleClient-play-error',
47+
),
48+
log(
49+
'dotcom',
50+
'Bridget getListenToArticleClient.play Error:',
51+
error,
52+
);
53+
});
54+
};
55+
return (
56+
showButton && (
57+
<ListenToArticleButton onClickHandler={listenToArticleHandler} />
58+
)
59+
);
60+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Meta, StoryObj } from '@storybook/react';
2+
import { ListenToArticleButton as ListenToArticleButtonComponent } from './ListenToArticleButton';
3+
4+
const meta = {
5+
component: ListenToArticleButtonComponent,
6+
title: 'Components/Listen To Article Button',
7+
} satisfies Meta<typeof ListenToArticleButtonComponent>;
8+
9+
export default meta;
10+
11+
type Story = StoryObj<typeof meta>;
12+
13+
export const ListenToArticleButton = {
14+
args: {
15+
onClickHandler: () => undefined,
16+
},
17+
} satisfies Story;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { css } from '@emotion/react';
2+
import { space } from '@guardian/source/foundations';
3+
import {
4+
Button,
5+
SvgMediaControlsPlay,
6+
} from '@guardian/source/react-components';
7+
import { palette } from '../palette';
8+
9+
const button = css`
10+
background-color: ${palette('--follow-icon-fill')};
11+
&:active,
12+
&:focus,
13+
&:hover {
14+
background-color: ${palette('--follow-icon-fill')};
15+
}
16+
color: ${palette('--follow-icon-background')};
17+
margin-bottom: ${space[4]}px;
18+
margin-left: ${space[2]}px;
19+
`;
20+
type ButtonProps = {
21+
onClickHandler: () => void;
22+
};
23+
export const ListenToArticleButton = ({ onClickHandler }: ButtonProps) => (
24+
<Button
25+
onClick={onClickHandler}
26+
size="small"
27+
cssOverrides={button}
28+
icon={<SvgMediaControlsPlay />}
29+
>
30+
Listen to article
31+
</Button>
32+
);

dotcom-rendering/src/layouts/CommentLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ export const CommentLayout = (props: WebProps | AppsProps) => {
491491
shortUrlId={
492492
article.config.shortUrlId
493493
}
494+
pageId={article.config.pageId}
494495
></ArticleMetaApps>
495496
</Hide>
496497
<Hide when="below" breakpoint="leftCol">

dotcom-rendering/src/layouts/ImmersiveLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ export const ImmersiveLayout = (props: WebProps | AppProps) => {
573573
shortUrlId={
574574
article.config.shortUrlId
575575
}
576+
pageId={article.config.pageId}
576577
></ArticleMetaApps>
577578
</Hide>
578579
<Hide when="below" breakpoint="leftCol">

dotcom-rendering/src/layouts/InteractiveLayout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ export const InteractiveLayout = (props: WebProps | AppsProps) => {
446446
article.config
447447
.shortUrlId
448448
}
449+
pageId={
450+
article.config.pageId
451+
}
449452
></ArticleMetaApps>
450453
</Hide>
451454
<Hide until="leftCol">

dotcom-rendering/src/layouts/PictureLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ export const PictureLayout = (props: WebProps | AppsProps) => {
481481
shortUrlId={
482482
article.config.shortUrlId
483483
}
484+
pageId={article.config.pageId}
484485
></ArticleMetaApps>
485486
</Hide>
486487
<Hide until="leftCol">

0 commit comments

Comments
 (0)