diff --git a/dotcom-rendering/src/components/FootballMatchInfo.tsx b/dotcom-rendering/src/components/FootballMatchInfo.tsx
index d3c9059741d..110468b6c73 100644
--- a/dotcom-rendering/src/components/FootballMatchInfo.tsx
+++ b/dotcom-rendering/src/components/FootballMatchInfo.tsx
@@ -3,7 +3,7 @@ import type {
FootballMatchStats,
FootballMatchTeamWithStats,
} from '../footballMatchStats';
-import type { FootballTable as FootballTableData } from '../footballTables';
+import type { FootballTableSummary } from '../footballTables';
import { grid } from '../grid';
import { FootballMatchStat } from './FootballMatchStat';
import { LeagueTable } from './LeagueTable';
@@ -11,7 +11,7 @@ import { Lineups } from './Lineups';
type Props = {
match: FootballMatchStats;
- table?: FootballTableData;
+ table?: FootballTableSummary;
};
function teamHasStats({
diff --git a/dotcom-rendering/src/components/LeagueTable.tsx b/dotcom-rendering/src/components/LeagueTable.tsx
index 0146ce49de1..143b0188d26 100644
--- a/dotcom-rendering/src/components/LeagueTable.tsx
+++ b/dotcom-rendering/src/components/LeagueTable.tsx
@@ -7,14 +7,11 @@ import {
textSansBold14,
textSansBold15,
} from '@guardian/source/foundations';
-import type {
- Entry,
- FootballTable as FootballTableData,
-} from '../footballTables';
+import type { EntrySummary, FootballTableSummary } from '../footballTables';
import { palette } from '../palette';
type Props = {
- table: FootballTableData;
+ table: FootballTableSummary;
};
export const LeagueTable = ({ table }: Props) => {
@@ -43,7 +40,7 @@ const Title = ({ text }: { text: string }) => (
);
-const Table = ({ table }: { table: FootballTableData }) => {
+const Table = ({ table }: { table: FootballTableSummary }) => {
return (
{
);
};
-const TableRow = ({ entry }: { entry: Entry }) => {
+const TableRow = ({ entry }: { entry: EntrySummary }) => {
return (
|
diff --git a/dotcom-rendering/src/footballTables.ts b/dotcom-rendering/src/footballTables.ts
index 4d69a6aab4a..4e74d071267 100644
--- a/dotcom-rendering/src/footballTables.ts
+++ b/dotcom-rendering/src/footballTables.ts
@@ -3,7 +3,9 @@ import { listParse } from './footballMatches';
import type {
FEFootballTable,
FEGroup,
+ FEGroupSummary,
FELeagueTableEntry,
+ FELeagueTableEntrySummary,
FETeamResult,
} from './frontend/feFootballTablesPage';
import { error, ok, type Result } from './lib/result';
@@ -26,7 +28,7 @@ type Team = {
url?: string;
};
-export type Entry = {
+export type EntrySummary = {
position: number;
team: Team;
gamesPlayed: number;
@@ -37,6 +39,9 @@ export type Entry = {
goalsAgainst: number;
goalDifference: number;
points: number;
+};
+
+type Entry = EntrySummary & {
results: TeamResult[];
};
@@ -53,6 +58,11 @@ export type FootballTable = {
entries: Entry[];
};
+export type FootballTableSummary = {
+ groupName?: string;
+ entries: EntrySummary[];
+};
+
export type FootballTableCompetitions = FootballTableCompetition[];
type MissingScore = {
@@ -62,12 +72,22 @@ type MissingScore = {
type ParserError = MissingScore;
-const parseTable = (feGroup: FEGroup): Result =>
+export const parseTable = (
+ feGroup: FEGroup,
+): Result =>
parseEntries(feGroup.entries).map((entries) => ({
groupName: feGroup.round.name,
entries: entries.sort((a, b) => a.position - b.position),
}));
+export const parseTableSummary = (
+ feGroup: FEGroupSummary,
+): Result =>
+ parseEntriesSummaries(feGroup.entries).map((entries) => ({
+ groupName: feGroup.round.name,
+ entries: entries.sort((a, b) => a.position - b.position),
+ }));
+
const parseTables = listParse(parseTable);
const parseResult = (result: FETeamResult): Result => {
@@ -102,12 +122,12 @@ const parseResult = (result: FETeamResult): Result => {
const parseResults = listParse(parseResult);
-const parseEntry = (
- feEntry: FELeagueTableEntry,
-): Result => {
+const mapBaseEntryFields = (
+ feEntry: FELeagueTableEntrySummary,
+): EntrySummary => {
const { team, teamUrl } = feEntry;
- return parseResults(feEntry.results).map((results) => ({
+ return {
position: team.rank,
team: {
name: cleanTeamName(team.name),
@@ -122,12 +142,28 @@ const parseEntry = (
goalsAgainst: team.total.goalsAgainst,
goalDifference: team.goalDifference,
points: team.points,
+ };
+};
+
+const parseEntry = (
+ feEntry: FELeagueTableEntry,
+): Result => {
+ return parseResults(feEntry.results).map((results) => ({
+ ...mapBaseEntryFields(feEntry),
results,
}));
};
const parseEntries = listParse(parseEntry);
+const parseEntrySummary = (
+ feEntry: FELeagueTableEntrySummary,
+): Result => {
+ return ok(mapBaseEntryFields(feEntry));
+};
+
+const parseEntriesSummaries = listParse(parseEntrySummary);
+
const parseFootballTableCompetition = (
table: FEFootballTable,
): Result =>
diff --git a/dotcom-rendering/src/frontend/feFootballMatchPage.ts b/dotcom-rendering/src/frontend/feFootballMatchPage.ts
index b67f5fb9e62..975456e8791 100644
--- a/dotcom-rendering/src/frontend/feFootballMatchPage.ts
+++ b/dotcom-rendering/src/frontend/feFootballMatchPage.ts
@@ -1,4 +1,5 @@
import type { FEFootballDataPage } from './feFootballDataPage';
+import { type FEGroupSummary } from './feFootballTablesPage';
export type FEFootballPlayerEvent = {
eventTime: string;
@@ -42,4 +43,5 @@ export type FEFootballMatch = {
export type FEFootballMatchPage = FEFootballDataPage & {
footballMatch: FEFootballMatch;
+ group?: FEGroupSummary;
};
diff --git a/dotcom-rendering/src/frontend/feFootballTablesPage.ts b/dotcom-rendering/src/frontend/feFootballTablesPage.ts
index 81109fce21c..58eebd3f116 100644
--- a/dotcom-rendering/src/frontend/feFootballTablesPage.ts
+++ b/dotcom-rendering/src/frontend/feFootballTablesPage.ts
@@ -42,11 +42,14 @@ export type FERecentResultsPerTeam = {
results: FETeamResult[];
};
-export type FELeagueTableEntry = {
+export type FELeagueTableEntrySummary = {
stageNumber: string;
round: FERound;
team: FELeagueTeam;
teamUrl?: string;
+};
+
+export type FELeagueTableEntry = FELeagueTableEntrySummary & {
results: FETeamResult[];
};
@@ -55,6 +58,11 @@ export type FEGroup = {
entries: FELeagueTableEntry[];
};
+export type FEGroupSummary = {
+ round: FERound;
+ entries: FELeagueTableEntrySummary[];
+};
+
export type FEFootballTable = {
competition: FECompetitionSummary;
groups: FEGroup[];
diff --git a/dotcom-rendering/src/frontend/schemas/feFootballMatchPage.json b/dotcom-rendering/src/frontend/schemas/feFootballMatchPage.json
index a5f1ef61a5e..fdc9d4a4d27 100644
--- a/dotcom-rendering/src/frontend/schemas/feFootballMatchPage.json
+++ b/dotcom-rendering/src/frontend/schemas/feFootballMatchPage.json
@@ -294,6 +294,185 @@
"id",
"status"
]
+ },
+ "group": {
+ "type": "object",
+ "properties": {
+ "round": {
+ "type": "object",
+ "properties": {
+ "roundNumber": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "roundNumber"
+ ]
+ },
+ "entries": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "stageNumber": {
+ "type": "string"
+ },
+ "round": {
+ "type": "object",
+ "properties": {
+ "roundNumber": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "roundNumber"
+ ]
+ },
+ "team": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "rank": {
+ "type": "number"
+ },
+ "total": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "home": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "away": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "goalDifference": {
+ "type": "number"
+ },
+ "points": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "away",
+ "goalDifference",
+ "home",
+ "id",
+ "name",
+ "points",
+ "rank",
+ "total"
+ ]
+ },
+ "teamUrl": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "round",
+ "stageNumber",
+ "team"
+ ]
+ }
+ }
+ },
+ "required": [
+ "entries",
+ "round"
+ ]
}
},
"required": [
diff --git a/dotcom-rendering/src/frontend/schemas/feFootballTablesPage.json b/dotcom-rendering/src/frontend/schemas/feFootballTablesPage.json
index 5c2716d518e..b54613460ff 100644
--- a/dotcom-rendering/src/frontend/schemas/feFootballTablesPage.json
+++ b/dotcom-rendering/src/frontend/schemas/feFootballTablesPage.json
@@ -105,210 +105,7 @@
"entries": {
"type": "array",
"items": {
- "type": "object",
- "properties": {
- "stageNumber": {
- "type": "string"
- },
- "round": {
- "type": "object",
- "properties": {
- "roundNumber": {
- "type": "string"
- },
- "name": {
- "type": "string"
- }
- },
- "required": [
- "roundNumber"
- ]
- },
- "team": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "rank": {
- "type": "number"
- },
- "total": {
- "type": "object",
- "properties": {
- "played": {
- "type": "number"
- },
- "won": {
- "type": "number"
- },
- "drawn": {
- "type": "number"
- },
- "lost": {
- "type": "number"
- },
- "goalsFor": {
- "type": "number"
- },
- "goalsAgainst": {
- "type": "number"
- }
- },
- "required": [
- "drawn",
- "goalsAgainst",
- "goalsFor",
- "lost",
- "played",
- "won"
- ]
- },
- "home": {
- "type": "object",
- "properties": {
- "played": {
- "type": "number"
- },
- "won": {
- "type": "number"
- },
- "drawn": {
- "type": "number"
- },
- "lost": {
- "type": "number"
- },
- "goalsFor": {
- "type": "number"
- },
- "goalsAgainst": {
- "type": "number"
- }
- },
- "required": [
- "drawn",
- "goalsAgainst",
- "goalsFor",
- "lost",
- "played",
- "won"
- ]
- },
- "away": {
- "type": "object",
- "properties": {
- "played": {
- "type": "number"
- },
- "won": {
- "type": "number"
- },
- "drawn": {
- "type": "number"
- },
- "lost": {
- "type": "number"
- },
- "goalsFor": {
- "type": "number"
- },
- "goalsAgainst": {
- "type": "number"
- }
- },
- "required": [
- "drawn",
- "goalsAgainst",
- "goalsFor",
- "lost",
- "played",
- "won"
- ]
- },
- "goalDifference": {
- "type": "number"
- },
- "points": {
- "type": "number"
- }
- },
- "required": [
- "away",
- "goalDifference",
- "home",
- "id",
- "name",
- "points",
- "rank",
- "total"
- ]
- },
- "teamUrl": {
- "type": "string"
- },
- "results": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "matchId": {
- "type": "string"
- },
- "self": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "score": {
- "type": "number"
- }
- },
- "required": [
- "id",
- "name"
- ]
- },
- "foe": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "score": {
- "type": "number"
- }
- },
- "required": [
- "id",
- "name"
- ]
- }
- },
- "required": [
- "foe",
- "matchId",
- "self"
- ]
- }
- }
- },
- "required": [
- "results",
- "round",
- "stageNumber",
- "team"
- ]
+ "$ref": "#/definitions/FELeagueTableEntry"
}
}
},
@@ -904,6 +701,223 @@
},
"Record": {
"type": "object"
+ },
+ "FELeagueTableEntry": {
+ "allOf": [
+ {
+ "type": "object",
+ "properties": {
+ "stageNumber": {
+ "type": "string"
+ },
+ "round": {
+ "type": "object",
+ "properties": {
+ "roundNumber": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "roundNumber"
+ ]
+ },
+ "team": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "rank": {
+ "type": "number"
+ },
+ "total": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "home": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "away": {
+ "type": "object",
+ "properties": {
+ "played": {
+ "type": "number"
+ },
+ "won": {
+ "type": "number"
+ },
+ "drawn": {
+ "type": "number"
+ },
+ "lost": {
+ "type": "number"
+ },
+ "goalsFor": {
+ "type": "number"
+ },
+ "goalsAgainst": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "drawn",
+ "goalsAgainst",
+ "goalsFor",
+ "lost",
+ "played",
+ "won"
+ ]
+ },
+ "goalDifference": {
+ "type": "number"
+ },
+ "points": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "away",
+ "goalDifference",
+ "home",
+ "id",
+ "name",
+ "points",
+ "rank",
+ "total"
+ ]
+ },
+ "teamUrl": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "round",
+ "stageNumber",
+ "team"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "results": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "matchId": {
+ "type": "string"
+ },
+ "self": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "score": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id",
+ "name"
+ ]
+ },
+ "foe": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "score": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id",
+ "name"
+ ]
+ }
+ },
+ "required": [
+ "foe",
+ "matchId",
+ "self"
+ ]
+ }
+ }
+ },
+ "required": [
+ "results"
+ ]
+ }
+ ]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
diff --git a/dotcom-rendering/src/server/handler.sportDataPage.web.ts b/dotcom-rendering/src/server/handler.sportDataPage.web.ts
index d39a5ff1b92..6aa6b840526 100644
--- a/dotcom-rendering/src/server/handler.sportDataPage.web.ts
+++ b/dotcom-rendering/src/server/handler.sportDataPage.web.ts
@@ -5,7 +5,10 @@ import {
getParserErrorMessage,
parse as parseFootballMatches,
} from '../footballMatches';
-import { parse as parseFootballTables } from '../footballTables';
+import {
+ parse as parseFootballTables,
+ parseTableSummary,
+} from '../footballTables';
import type { FECricketMatchPage } from '../frontend/feCricketMatchPage';
import type { FEFootballCompetition } from '../frontend/feFootballDataPage';
import type { FEFootballMatchListPage } from '../frontend/feFootballMatchListPage';
@@ -216,6 +219,7 @@ const parseFEFootballMatch = (
data: FEFootballMatchPage,
): FootballMatchSummaryPage => {
const parsedFootballMatch = parseFootballMatch(data.footballMatch);
+ const group = data.group && parseTableSummary(data.group);
if (!parsedFootballMatch.ok) {
throw new Error(
@@ -223,8 +227,15 @@ const parseFEFootballMatch = (
);
}
+ if (group && !group.ok) {
+ throw new Error(
+ `Failed to parse football league table group: ${group.error.kind} ${group.error.message}`,
+ );
+ }
+
return {
match: parsedFootballMatch.value,
+ group: group?.value,
kind: 'FootballMatchSummary',
nav: {
...extractNAV(data.nav),
diff --git a/dotcom-rendering/src/sportDataPage.ts b/dotcom-rendering/src/sportDataPage.ts
index 4bab118adc4..62b6d475db8 100644
--- a/dotcom-rendering/src/sportDataPage.ts
+++ b/dotcom-rendering/src/sportDataPage.ts
@@ -1,7 +1,10 @@
import type { CricketMatch } from './cricketMatch';
import type { FootballMatch } from './footballMatch';
import type { FootballMatches } from './footballMatches';
-import type { FootballTableCompetitions } from './footballTables';
+import type {
+ FootballTableCompetitions,
+ FootballTableSummary,
+} from './footballTables';
import type { FESportPageConfig } from './frontend/feFootballDataPage';
import type { EditionId } from './lib/edition';
import type { NavType } from './model/extract-nav';
@@ -48,6 +51,7 @@ export type CricketMatchPage = SportPageConfig & {
export type FootballMatchSummaryPage = SportPageConfig & {
match: FootballMatch;
+ group?: FootballTableSummary;
kind: 'FootballMatchSummary';
};
|