diff --git a/src/components/ElectionResultsStackedBar/ElectionResultsStackedBar.stories.tsx b/src/components/ElectionResultsStackedBar/ElectionResultsStackedBar.stories.tsx index d1560e7..462715c 100644 --- a/src/components/ElectionResultsStackedBar/ElectionResultsStackedBar.stories.tsx +++ b/src/components/ElectionResultsStackedBar/ElectionResultsStackedBar.stories.tsx @@ -2,100 +2,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import React from "react"; -import { mockResults } from "../../util/mocks"; +import { mockResults, mockCountyCouncilResults } from "../../util/mocks"; import { ElectionResultsStackedBar } from "./ElectionResultsStackedBar"; -const nationalResultsExample = { - eligibleVoters: 18466219, - totalVotes: 8419716, - validVotes: 7937514, - nullVotes: 482202, - totalSeats: 0, - candidates: [ - { - name: "Partidul Social Democrat", - partyColor: "#FF0000", - partyLogo: "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Partidul+Social+Democrat.jpg", - votes: 16, - seats: 0, - totalSeats: 0, - }, - { - name: "Partidul Național Liberal", - partyColor: "#F8DD1B", - partyLogo: "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Partidul+Na%C8%9Bional+Liberal.jpg", - votes: 15, - seats: 0, - totalSeats: 0, - }, - { - name: "UNIUNEA DEMOCRATA MAGHIARA DIN ROMANIA", - partyColor: "#007300", - partyLogo: - "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Uniunea+Democrat%C4%83+a+Maghiarilor+din+Rom%C3%A2nia.jpg", - votes: 4, - seats: 0, - totalSeats: 0, - }, - { - name: "ALIANȚA ELECTORALĂ ALIANȚA PENTRU MODERNIZAREA NEAMȚULUI 2020", - shortName: "A. ELECTORALĂ PENTRU MODERNIZAREA NEAMȚULUI 2020", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: "ALIANȚA PNL USR PLUS", - shortName: "A. PNL USR PLUS", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: "ALIANȚA PENTRU BISTRIȚA-NĂSĂUD", - shortName: "A. NĂSĂUD", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: "INDEPENDENT", - shortName: "INDEPENDENT", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: "ALIANTA ELECTORALA PSD+ALDE DOLJ", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: "ALIANȚA PSD-PRO BUZĂU", - shortName: "A. PRO BUZĂU", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - { - name: - "ALIANȚA PARTIDUL NAȚIONAL LIBERAL - UNIUNEA SALVAȚI ROMÂNIA - PARTIDUL LIBERTATE, UNITATE ȘI SOLIDARITATE (PNL-USR-PLUS)", - shortName: "A. UNIUNEA SALVAȚI ROMÂNIA - PARTIDUL LIBERTATE, UNITATE ȘI SOLIDARITATE (PNL-USR-PLUS)", - partyColor: "#808080", - votes: 1, - seats: 0, - totalSeats: 0, - }, - ], -}; - export default { title: "Election results stacked bar", component: ElectionResultsStackedBar, @@ -118,7 +27,7 @@ export const ExampleWithDiscreteValues = (args: any) => { }; ExampleWithDiscreteValues.args = { - results: nationalResultsExample, + results: mockCountyCouncilResults, displayPercentages: false, }; diff --git a/src/components/ElectionResultsSummarySection/ElectionResultsSummarySection.stories.tsx b/src/components/ElectionResultsSummarySection/ElectionResultsSummarySection.stories.tsx index 1a279b8..a49d669 100644 --- a/src/components/ElectionResultsSummarySection/ElectionResultsSummarySection.stories.tsx +++ b/src/components/ElectionResultsSummarySection/ElectionResultsSummarySection.stories.tsx @@ -3,6 +3,8 @@ import React from "react"; import { ElectionScopeIncompleteResolved } from "../../types/Election"; import { + mockCountyCouncilElectionMeta, + mockCountyCouncilResults, mockDiasporaElectionScope, mockLocalCouncilElectionMeta, mockLocalityElectionScope, @@ -37,6 +39,16 @@ export const LocalCouncilElection = () => { ); }; +export const CountyCouncilElection = () => { + return ( + + ); +}; + export const DiasporaElection = () => { return ( ( meta={meta} results={results} headers={tableHeaders} + displayVotesAsSeats={!displayPercentages} /> )} {map} diff --git a/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.stories.tsx b/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.stories.tsx index 94cb1a2..3622267 100644 --- a/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.stories.tsx +++ b/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.stories.tsx @@ -2,7 +2,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import React from "react"; -import { mockLocalCouncilElectionMeta, mockResults } from "../../util/mocks"; +import { + mockCountyCouncilElectionMeta, + mockCountyCouncilResults, + mockLocalCouncilElectionMeta, + mockResults, +} from "../../util/mocks"; import { ElectionResultsSummaryTable } from "./ElectionResultsSummaryTable"; export default { @@ -24,3 +29,19 @@ SimpleExample.argTypes = { results: { control: "object" }, header: { control: "object" }, }; + +export const ExampleWithVotesAsSeats = (args: any) => { + return ; +}; + +ExampleWithVotesAsSeats.args = { + meta: mockCountyCouncilElectionMeta, + results: mockCountyCouncilResults, + header: { candidate: "Partid", seats: "Mand.", votes: "Voturi", percentage: "%" }, + displayVotesAsSeats: true, +}; + +ExampleWithVotesAsSeats.argTypes = { + results: { control: "object" }, + header: { control: "object" }, +}; diff --git a/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.tsx b/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.tsx index e2eef57..20e4a50 100644 --- a/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.tsx +++ b/src/components/ElectionResultsSummaryTable/ElectionResultsSummaryTable.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { electionHasSeats, ElectionBallotMeta, ElectionResults } from "../../types/Election"; -import { themable } from "../../hooks/theme"; +import { electionHasSeats, ElectionBallotMeta, ElectionResults, ElectionResultsCandidate } from "../../types/Election"; +import { ClassNames, themable } from "../../hooks/theme"; import { DivBody, Heading3, makeTypographyComponent } from "../Typography/Typography"; import { lightFormat, parseISO } from "date-fns"; import { electionCandidateColor, formatGroupedNumber, formatPercentage, fractionOf } from "../../util/format"; @@ -19,6 +19,7 @@ type Props = { meta: ElectionBallotMeta; results: ElectionResults; headers?: ElectionResultsSummaryTableHeaders; + displayVotesAsSeats?: boolean; }; type CellProps = { @@ -28,10 +29,78 @@ type CellProps = { const THeadRow = makeTypographyComponent("th", "label"); const TCell = makeTypographyComponent("td", "bodyMedium"); +const headerRowForVotesWithSeats = function ( + headers: + | { + candidate?: string; + seats?: string; + votes?: string; + percentage?: string; + bar?: string; + } + | undefined, + isReferendum: boolean, + hasSeats: boolean, + classes: ClassNames, +) { + return ( + + {headers?.candidate ?? (isReferendum ? "Opțiune" : "Partid")} + {hasSeats && {headers?.seats ?? "Mand."}} + {headers?.votes ?? "Voturi"} + {headers?.percentage ?? "%"} + {headers?.bar ?? ""} + + ); +}; + +const headerRowForVotesAsSeatsWon = function () { + return ( + + Partid + Mandate + + ); +}; + +const getRowWithVotesAndSeatsForCandidate = function ( + hasSeats: boolean, + candidate: ElectionResultsCandidate, + classes: ClassNames, + percentages: number[], + index: number, + maxFraction: number, +) { + return ( + <> + {hasSeats && {candidate.seats != null && formatGroupedNumber(candidate.seats)}} + {formatGroupedNumber(candidate.votes)} + {formatPercentage(percentages[index])} + +
+ + + ); +}; + +const getRowWithVotesAsSeatsForCandidate = function (candidate: ElectionResultsCandidate) { + return ( + <> + {formatGroupedNumber(candidate.votes)} + + ); +}; + export const ElectionResultsSummaryTable = themable( "ElectionResultsSummaryTable", cssClasses, -)(({ classes, results, meta, headers }) => { +)(({ classes, results, meta, headers, displayVotesAsSeats }) => { const hasSeats = electionHasSeats(meta.type, results); const isReferendum = meta.type === "referendum"; const percentageBasis = isReferendum ? results.eligibleVoters ?? 0 : results.validVotes; @@ -56,13 +125,9 @@ export const ElectionResultsSummaryTable = themable(
- - {headers?.candidate ?? (isReferendum ? "Opțiune" : "Partid")} - {hasSeats && {headers?.seats ?? "Mand."}} - {headers?.votes ?? "Voturi"} - {headers?.percentage ?? "%"} - {headers?.bar ?? ""} - + {displayVotesAsSeats ?? false + ? headerRowForVotesAsSeatsWon() + : headerRowForVotesWithSeats(headers, isReferendum, hasSeats, classes)} {results.candidates.map((candidate, index) => ( @@ -71,18 +136,9 @@ export const ElectionResultsSummaryTable = themable( {candidate.shortName || candidate.name} - {hasSeats && {candidate.seats != null && formatGroupedNumber(candidate.seats)}} - {formatGroupedNumber(candidate.votes)} - {formatPercentage(percentages[index])} - + {displayVotesAsSeats ?? false + ? getRowWithVotesAsSeatsForCandidate(candidate) + : getRowWithVotesAndSeatsForCandidate(hasSeats, candidate, classes, percentages, index, maxFraction)} ))} diff --git a/src/util/mocks.ts b/src/util/mocks.ts index 2589f7a..4169add 100644 --- a/src/util/mocks.ts +++ b/src/util/mocks.ts @@ -46,6 +46,16 @@ export const mockLocalCouncilElectionMeta: ElectionBallotMeta = { electionId: 2, }; +export const mockCountyCouncilElectionMeta: ElectionBallotMeta = { + type: "county_council", + date: "2016-06-05", + title: "Alegeri Locale", + ballot: "Consiliul judetean", + ballotId: 3, + electionId: 3, +}; + + export const mockPresidentialElectionTurnout: ElectionTurnout = { eligibleVoters: 18217411, totalVotes: 9086696, @@ -181,6 +191,98 @@ export const mockResults: ElectionResults = { ], }; +export const mockCountyCouncilResults = { + eligibleVoters: 18466219, + totalVotes: 8419716, + validVotes: 7937514, + nullVotes: 482202, + totalSeats: 0, + candidates: [ + { + name: "Partidul Social Democrat", + partyColor: "#FF0000", + partyLogo: "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Partidul+Social+Democrat.jpg", + votes: 16, + seats: 0, + totalSeats: 0, + }, + { + name: "Partidul Național Liberal", + partyColor: "#F8DD1B", + partyLogo: "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Partidul+Na%C8%9Bional+Liberal.jpg", + votes: 15, + seats: 0, + totalSeats: 0, + }, + { + name: "UNIUNEA DEMOCRATA MAGHIARA DIN ROMANIA", + partyColor: "#007300", + partyLogo: + "https://rezultatevot-media.s3.eu-central-1.amazonaws.com/v2/Logo__Uniunea+Democrat%C4%83+a+Maghiarilor+din+Rom%C3%A2nia.jpg", + votes: 4, + seats: 0, + totalSeats: 0, + }, + { + name: "ALIANȚA ELECTORALĂ ALIANȚA PENTRU MODERNIZAREA NEAMȚULUI 2020", + shortName: "A. ELECTORALĂ PENTRU MODERNIZAREA NEAMȚULUI 2020", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: "ALIANȚA PNL USR PLUS", + shortName: "A. PNL USR PLUS", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: "ALIANȚA PENTRU BISTRIȚA-NĂSĂUD", + shortName: "A. NĂSĂUD", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: "INDEPENDENT", + shortName: "INDEPENDENT", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: "ALIANTA ELECTORALA PSD+ALDE DOLJ", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: "ALIANȚA PSD-PRO BUZĂU", + shortName: "A. PRO BUZĂU", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + { + name: + "ALIANȚA PARTIDUL NAȚIONAL LIBERAL - UNIUNEA SALVAȚI ROMÂNIA - PARTIDUL LIBERTATE, UNITATE ȘI SOLIDARITATE (PNL-USR-PLUS)", + shortName: "A. UNIUNEA SALVAȚI ROMÂNIA - PARTIDUL LIBERTATE, UNITATE ȘI SOLIDARITATE (PNL-USR-PLUS)", + partyColor: "#808080", + votes: 1, + seats: 0, + totalSeats: 0, + }, + ], +}; + + export const mockElectionList = [ { date: "2019-11-10T00:00:00",
-
-