Skip to content

Commit beb122f

Browse files
Merge branch 'main' into mob/new-filter-button
2 parents 0857d8a + ac9cbb5 commit beb122f

24 files changed

+553
-132
lines changed

apps-rendering/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
"@storybook/react-webpack5": "8.6.14",
6464
"@storybook/theming": "8.6.14",
6565
"@types/clean-css": "4.2.11",
66-
"@types/compression": "1.7.5",
67-
"@types/express": "4.17.21",
66+
"@types/compression": "1.8.1",
67+
"@types/express": "5.0.1",
6868
"@types/html-webpack-plugin": "3.2.9",
6969
"@types/jest": "29.5.14",
7070
"@types/jsdom": "16.2.15",
@@ -79,13 +79,13 @@
7979
"buffer": "6.0.3",
8080
"clean-css": "5.3.3",
8181
"compare-versions": "6.1.0",
82-
"compression": "1.7.4",
82+
"compression": "1.8.0",
8383
"constructs": "10.4.2",
8484
"core-js": "3.33.3",
8585
"eslint": "8.56.0",
8686
"eslint-plugin-jsx-a11y": "6.7.1",
8787
"eslint-plugin-react": "7.33.2",
88-
"express": "4.21.2",
88+
"express": "5.1.0",
8989
"html-webpack-plugin": "5.6.3",
9090
"jest": "29.7.0",
9191
"jest-environment-jsdom": "29.7.0",

apps-rendering/src/server/server.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ app.use('/assets', express.static(path.resolve(__dirname, '../assets')));
396396
app.use('/assets', express.static(path.resolve(__dirname, '../dist/assets')));
397397
app.use(compression());
398398

399-
app.all('*', (request, response, next) => {
399+
app.all('/{*splat}', (request, response, next) => {
400400
const start = Date.now();
401401

402402
response.once('finish', () => {
@@ -409,22 +409,29 @@ app.all('*', (request, response, next) => {
409409
next();
410410
});
411411

412-
app.get('/healthcheck', (_req, res) => res.send('Ok'));
412+
app.get('/healthcheck', (_req, res) => {
413+
res.status(200).send('Ok');
414+
});
413415

414-
app.get('/favicon.ico', (_, res) => res.status(404).end());
415-
app.get('/fontSize.css', (_, res) => res.status(404).end());
416+
app.get('/favicon.ico', (_, res) => {
417+
res.sendStatus(404);
418+
});
419+
420+
app.get('/fontSize.css', (_, res) => {
421+
res.sendStatus(404);
422+
});
416423

417424
/**
418425
To enable testing in the mobile device emulators,
419426
this route handler adds compatability with DCR's route for apps articles.
420427
The DCR route follows the pattern:
421-
/AppsArticle/https://www.theguardian.com/cities/2019/sep/13/reclaimed-lakes-and-giant-airports-how-mexico-city-might-have-looked
428+
AppsArticle/https://www.theguardian.com/food/2020/mar/15/easter-taste-test-dan-lepard-hot-cross-bun-milk-dark-chocolate-mini-eggs-bunny-sloth
422429
*/
423430
app.get(
424-
'/AppsArticle/*',
431+
'/AppsArticle/*url',
425432
express.raw(),
426433
(req, res, next) => {
427-
const contentWebUrl = req.params[0];
434+
const contentWebUrl = req.originalUrl.split('/').slice(2).join('/');
428435
const articleId = new URL(contentWebUrl).pathname;
429436
req.params = {
430437
0: articleId,
@@ -436,16 +443,13 @@ app.get(
436443
);
437444

438445
app.get(
439-
'/:edition(uk|us|au|europe|international)?/rendered-items/*',
440-
express.raw(),
441-
serveArticleGet,
442-
);
443-
app.get(
444-
'/:edition(uk|us|au|europe|international)?/*',
446+
['/:edition/rendered-items/*path', '/rendered-items/*path'],
445447
express.raw(),
446448
serveArticleGet,
447449
);
448450

451+
app.get(['/:edition/*path', '/*path'], express.raw(), serveArticleGet);
452+
449453
app.post('/article', express.raw(), serveArticlePost);
450454

451455
app.post('/editions-article', express.raw(), serveEditionsArticlePost);

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: 3 additions & 3 deletions
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",
@@ -73,7 +73,7 @@
7373
"@types/compression": "1.7.5",
7474
"@types/connect": "3.4.38",
7575
"@types/dompurify": "3.0.2",
76-
"@types/express": "4.17.21",
76+
"@types/express": "5.0.1",
7777
"@types/he": "1.2.0",
7878
"@types/html-minifier-terser": "7.0.2",
7979
"@types/jest": "29.5.14",
@@ -130,7 +130,7 @@
130130
"eslint-plugin-unicorn": "48.0.1",
131131
"eslint-stats": "1.0.1",
132132
"execa": "5.1.1",
133-
"express": "4.21.2",
133+
"express": "5.1.0",
134134
"find": "0.3.0",
135135
"he": "1.2.0",
136136
"html-minifier-terser": "7.2.0",

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+
);

0 commit comments

Comments
 (0)