Skip to content

Commit c5ef107

Browse files
Football Fixtures/Results Pages - Get More! (#13550)
* feat: implement getMoreDays football data functionality * Add bottom padding to More button * use ajaxURL from config for api - add slash to "All" select value
1 parent 0f5dbbd commit c5ef107

File tree

7 files changed

+105
-36
lines changed

7 files changed

+105
-36
lines changed

dotcom-rendering/src/components/FootballCompetitionSelect.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ const allLabel = (kind: FootballMatchKind): string => {
2323
const getPagePath = (kind: FootballMatchKind) => {
2424
switch (kind) {
2525
case 'Fixture':
26-
return 'football/fixtures';
26+
return '/football/fixtures';
2727
case 'Live':
28-
return 'football/live';
28+
return '/football/live';
2929
case 'Result':
30-
return 'football/results';
30+
return '/football/results';
3131
}
3232
};
3333

dotcom-rendering/src/components/FootballMatchList.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,9 @@ export const FootballMatchList = ({
442442
css={css`
443443
grid-column: centre-column-start / centre-column-end;
444444
445-
padding-top: ${space[10]}px;
445+
${until.leftCol} {
446+
padding-top: ${space[10]}px;
447+
}
446448
`}
447449
>
448450
<Button

dotcom-rendering/src/components/FootballMatchesPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export const FootballMatchesPage = ({
7676
right: 0;
7777
}
7878
}
79+
80+
padding-bottom: ${space[9]}px;
7981
`}
8082
>
8183
<h1
Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,60 @@
1-
import type {
2-
FootballMatches,
3-
FootballMatchKind,
4-
Regions,
1+
import { isObject, isUndefined } from '@guardian/libs';
2+
import type { Dispatch, SetStateAction } from 'react';
3+
import { useState } from 'react';
4+
import type { FEFootballDataPage } from '../feFootballDataPage';
5+
import {
6+
type FootballMatches,
7+
type FootballMatchKind,
8+
getParserErrorMessage,
9+
parse,
10+
type Regions,
511
} from '../footballMatches';
612
import type { EditionId } from '../lib/edition';
13+
import type { Result } from '../lib/result';
14+
import { error, ok } from '../lib/result';
715
import { FootballMatchesPage } from './FootballMatchesPage';
816

17+
export const getMoreDays =
18+
(
19+
ajaxUrl: string,
20+
nextPage: string,
21+
setNextPage: Dispatch<SetStateAction<string | undefined>>,
22+
) =>
23+
async (): Promise<Result<'failed', FootballMatches>> => {
24+
try {
25+
const fetchResponse = await fetch(`${ajaxUrl}${nextPage}.json?dcr`);
26+
27+
const responseJson: unknown = await fetchResponse.json();
28+
29+
if (isObject(responseJson)) {
30+
const feFootballData = responseJson as FEFootballDataPage;
31+
const parsedFootballMatches = parse(feFootballData.matchesList);
32+
33+
if (parsedFootballMatches.kind === 'error') {
34+
throw new Error(
35+
`Failed to parse matches: ${getParserErrorMessage(
36+
parsedFootballMatches.error,
37+
)}`,
38+
);
39+
}
40+
41+
setNextPage(feFootballData.nextPage);
42+
43+
return ok(parsedFootballMatches.value);
44+
}
45+
throw new Error('Failed to parse response JSON as an object');
46+
} catch (e) {
47+
if (e instanceof Error) {
48+
window.guardian.modules.sentry.reportError(
49+
e,
50+
'get-more-football-matches-button',
51+
);
52+
}
53+
54+
return error('failed');
55+
}
56+
};
57+
958
const goToCompetitionSpecificPage =
1059
(guardianBaseUrl: string) => (path: string) => {
1160
const url = `${guardianBaseUrl}${path}`;
@@ -15,8 +64,10 @@ const goToCompetitionSpecificPage =
1564
type Props = {
1665
nations: Regions;
1766
guardianBaseUrl: string;
67+
ajaxUrl: string;
1868
kind: FootballMatchKind;
1969
initialDays: FootballMatches;
70+
secondPage?: string;
2071
edition: EditionId;
2172
renderAds: boolean;
2273
pageId: string;
@@ -25,22 +76,33 @@ type Props = {
2576
export const FootballMatchesPageWrapper = ({
2677
nations,
2778
guardianBaseUrl,
79+
ajaxUrl,
2880
kind,
2981
initialDays,
82+
secondPage,
3083
edition,
3184
renderAds,
3285
pageId,
33-
}: Props) => (
34-
<FootballMatchesPage
35-
regions={nations}
36-
guardianBaseUrl={guardianBaseUrl}
37-
kind={kind}
38-
initialDays={initialDays}
39-
edition={edition}
40-
goToCompetitionSpecificPage={goToCompetitionSpecificPage(
41-
guardianBaseUrl,
42-
)}
43-
renderAds={renderAds}
44-
pageId={pageId}
45-
/>
46-
);
86+
}: Props) => {
87+
const [nextPage, setNextPage] = useState(secondPage);
88+
89+
return (
90+
<FootballMatchesPage
91+
regions={nations}
92+
guardianBaseUrl={guardianBaseUrl}
93+
kind={kind}
94+
initialDays={initialDays}
95+
edition={edition}
96+
goToCompetitionSpecificPage={goToCompetitionSpecificPage(
97+
guardianBaseUrl,
98+
)}
99+
getMoreDays={
100+
isUndefined(nextPage)
101+
? undefined
102+
: getMoreDays(ajaxUrl, nextPage, setNextPage)
103+
}
104+
renderAds={renderAds}
105+
pageId={pageId}
106+
/>
107+
);
108+
};

dotcom-rendering/src/footballMatches.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,17 @@ const parseFootballDay = (
398398
});
399399
};
400400

401+
export const getParserErrorMessage = (parserError: ParserError): string => {
402+
switch (parserError.kind) {
403+
case 'InvalidMatchDay':
404+
return parserError.errors
405+
.map((e) => getParserErrorMessage(e))
406+
.join(', ');
407+
default:
408+
return `${parserError.kind}: ${parserError.message}`;
409+
}
410+
};
411+
401412
export const parse: (
402413
frontendData: FEMatchByDateAndCompetition[],
403414
) => Result<ParserError, FootballMatches> = listParse(parseFootballDay);

dotcom-rendering/src/layouts/FootballDataPageLayout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ export const FootballDataPageLayout = ({ footballData }: Props) => {
6464
<FootballMatchesPageWrapper
6565
nations={footballData.regions}
6666
guardianBaseUrl={footballData.guardianBaseURL}
67+
ajaxUrl={footballData.config.ajaxUrl}
6768
kind={footballData.kind}
6869
initialDays={footballData.matchesList}
70+
secondPage={footballData.nextPage}
6971
edition={footballData.editionId}
7072
renderAds={renderAds}
7173
pageId={footballData.config.pageId}

dotcom-rendering/src/server/handler.footballDataPage.web.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ import type {
66
import type {
77
DCRFootballDataPage,
88
FootballMatchKind,
9-
ParserError,
109
Regions,
1110
} from '../footballMatches';
12-
import { parse } from '../footballMatches';
11+
import { getParserErrorMessage, parse } from '../footballMatches';
1312
import { Pillar } from '../lib/articleFormat';
1413
import { extractNAV } from '../model/extract-nav';
1514
import { validateAsFootballDataPageType } from '../model/validate';
@@ -18,30 +17,21 @@ import { recordTypeAndPlatform } from './lib/logging-store';
1817
import { renderFootballDataPage } from './render.footballDataPage.web';
1918

2019
const decidePageKind = (pageId: string): FootballMatchKind => {
21-
if (pageId?.includes('live')) {
20+
if (pageId.includes('live')) {
2221
return 'Live';
2322
}
2423

25-
if (pageId?.includes('results')) {
24+
if (pageId.includes('results')) {
2625
return 'Result';
2726
}
2827

29-
if (pageId?.includes('fixtures')) {
28+
if (pageId.includes('fixtures')) {
3029
return 'Fixture';
3130
}
3231

3332
throw new Error('Could not determine football page kind');
3433
};
3534

36-
const getParserErrorMessage = (error: ParserError): string => {
37-
switch (error.kind) {
38-
case 'InvalidMatchDay':
39-
return error.errors.map((e) => getParserErrorMessage(e)).join(', ');
40-
default:
41-
return `${error.kind}: ${error.message}`;
42-
}
43-
};
44-
4535
const parseFEFootballCompetitionRegions = (
4636
competitionRegions: Record<string, FEFootballCompetition[]>,
4737
): Regions => {

0 commit comments

Comments
 (0)