From 39347a6012de8719567353ad4c7acfa44d755313 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Guhur Date: Sun, 19 Apr 2020 09:35:20 +0000 Subject: [PATCH 1/6] [CREATE ELECTION] enfore error checkings --- public/locale/i18n/de/common.json | 1 + public/locale/i18n/de/resource.json | 23 +++++++++++- src/components/views/CreateElection.jsx | 47 +++++++++++++++++++++---- 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 public/locale/i18n/de/common.json diff --git a/public/locale/i18n/de/common.json b/public/locale/i18n/de/common.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/public/locale/i18n/de/common.json @@ -0,0 +1 @@ +{} diff --git a/public/locale/i18n/de/resource.json b/public/locale/i18n/de/resource.json index c2e6159..63e5dd7 100644 --- a/public/locale/i18n/de/resource.json +++ b/public/locale/i18n/de/resource.json @@ -49,5 +49,26 @@ "Go back to homepage": "Zurück zur Hompage", "You have to judge every candidate/proposal!": "Sie müssen jeden Kandidaten/Abstimmungsvorschlag bewerten!", "Your participation was recorded with success!": " Ihre Teilnahme wurde gespeichert!", - "Thanks for your participation.": " Vielen Dank für Ihre Teilnahme." + "Thanks for your participation.": " Vielen Dank für Ihre Teilnahme.", + "Unknown error. Try again please.": "__STRING_NOT_TRANSLATED__", + "Ending date:": "__STRING_NOT_TRANSLATED__", + "If you list voters' emails, only them will be able to access the election": "__STRING_NOT_TRANSLATED__", + "Dates": "__STRING_NOT_TRANSLATED__", + "The election will take place from": "__STRING_NOT_TRANSLATED__", + "at": "__STRING_NOT_TRANSLATED__", + "to": "__STRING_NOT_TRANSLATED__", + "Grades": "__STRING_NOT_TRANSLATED__", + "Voters' list": "__STRING_NOT_TRANSLATED__", + "Voters received a link to vote by email. Each link can be used only once!": "__STRING_NOT_TRANSLATED__", + "Results of the election:": "__STRING_NOT_TRANSLATED__", + "Graph": "__STRING_NOT_TRANSLATED__", + "Preference profile": "__STRING_NOT_TRANSLATED__", + "Oops... The election is unknown.": "__STRING_NOT_TRANSLATED__", + "The election is still going on. You can't access now to the results.": "__STRING_NOT_TRANSLATED__", + "No votes have been recorded yet. Come back later.": "__STRING_NOT_TRANSLATED__", + "The election has not started yet.": "__STRING_NOT_TRANSLATED__", + "The election is over. You can't vote anymore": "__STRING_NOT_TRANSLATED__", + "You need a token to vote in this election": "__STRING_NOT_TRANSLATED__", + "You seem to have already voted.": "__STRING_NOT_TRANSLATED__", + "The parameters of the election are incorrect.": "__STRING_NOT_TRANSLATED__" } diff --git a/src/components/views/CreateElection.jsx b/src/components/views/CreateElection.jsx index 7635a8d..59db056 100644 --- a/src/components/views/CreateElection.jsx +++ b/src/components/views/CreateElection.jsx @@ -39,6 +39,11 @@ import HelpButton from '../form/HelpButton'; import ButtonWithConfirm from '../form/ButtonWithConfirm'; import Loader from '../wait'; + +// Error messages +const AT_LEAST_2_CANDIDATES_ERROR = 'Please add at least 2 candidates.' +const NO_TITLE_ERROR = 'Please add a title.' + // Convert a Date object into YYYY-MM-DD const dateToISO = date => date.toISOString().substring(0, 10); @@ -156,7 +161,6 @@ class CreateElection extends Component { this.state = { candidates: [{label: ''}, {label: ''}], - numCandidatesWithLabel: 0, title: title || '', isVisibleTipsDragAndDropCandidate: true, numGrades: 7, @@ -212,7 +216,6 @@ class CreateElection extends Component { }); this.setState({ candidates: candidates, - numCandidatesWithLabel: numLabels, }); }; @@ -241,6 +244,28 @@ class CreateElection extends Component { this.setState({isAdvancedOptionsOpen: !this.state.isAdvancedOptionsOpen}); }; + checkFields() { + const { candidates, title } = this.state; + + if (!candidates) { + return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR}; + } + + let numCandidates = 0; + candidates.forEach(c => { + if (c !== "") numCandidates += 1; + }) + if (numCandidates < 2) { + return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR}; + } + + if (!title || title === "") { + return {ok: false, msg: NO_TITLE_ERROR}; + } + + return {ok: true, msg: "OK"}; + } + handleSubmit() { const { candidates, @@ -258,6 +283,14 @@ class CreateElection extends Component { const {t} = this.props; + const check = this.checkFields(); + if (!check.ok) { + toast.error(t(check.msg), { + position: toast.POSITION.TOP_CENTER, + }); + return + } + this.setState({waiting: true}); fetch(endpoint, { @@ -298,9 +331,9 @@ class CreateElection extends Component { .catch(error => error); } - handleSendWithoutCandidate = () => { + handleSendNotReady = (msg) => { const {t} = this.props; - toast.error(t('Please add at least 2 candidates.'), { + toast.error(t(msg), { position: toast.POSITION.TOP_CENTER, }); }; @@ -316,12 +349,12 @@ class CreateElection extends Component { candidates, numGrades, isAdvancedOptionsOpen, - numCandidatesWithLabel, electorEmails, } = this.state; const {t} = this.props; const grades = i18nGrades(); + const check = this.checkFields(); if (successCreate) return ; @@ -576,7 +609,7 @@ class CreateElection extends Component { - {numCandidatesWithLabel >= 2 ? ( + {check.ok ? ( @@ -675,7 +708,7 @@ class CreateElection extends Component { From 9f837f676e1c8bd48e56b4814858cd3aa14c024d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Guhur Date: Sun, 19 Apr 2020 16:55:09 +0000 Subject: [PATCH 2/6] fix results --- src/Util.jsx | 34 +++++++++++------------ src/components/layouts/Footer.jsx | 8 +++--- src/components/views/Result.jsx | 45 ++++++++++++++----------------- src/components/views/Vote.jsx | 36 +++++++++++++------------ 4 files changed, 60 insertions(+), 63 deletions(-) diff --git a/src/Util.jsx b/src/Util.jsx index e3efb93..d3f5c31 100644 --- a/src/Util.jsx +++ b/src/Util.jsx @@ -1,33 +1,33 @@ import i18n from './i18n.jsx'; const colors = [ - "#015411", - "#019812", - "#6bca24", - "#ffb200", - "#ff5d00", - "#b20616", - "#6f0214" + '#6f0214', + '#b20616', + '#ff5d00', + '#ffb200', + '#6bca24', + '#019812', + '#015411', ]; const gradeNames = [ - "Excellent", - "Very good", - "Good", - "Fair", - "Passable", - "Insufficient", - "To reject", + 'To reject', + 'Insufficient', + 'Passable', + 'Fair', + 'Good', + 'Very good', + 'Excellent', ]; export const grades = gradeNames.map((name, i) => ({ label: name, - color: colors[i] + color: colors[i], })); export const i18nGrades = () => { return gradeNames.map((name, i) => ({ label: i18n.t(name), - color: colors[i] - })); + color: colors[i], + })); }; diff --git a/src/components/layouts/Footer.jsx b/src/components/layouts/Footer.jsx index 687812e..e21bfee 100644 --- a/src/components/layouts/Footer.jsx +++ b/src/components/layouts/Footer.jsx @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component, Fragment } from "react"; import {withTranslation} from 'react-i18next'; import { Link } from "react-router-dom"; @@ -36,13 +36,13 @@ class Footer extends Component { {t("Who are we")} - { - countries.map(({l, flag}) => ( - <> + countries.map(({l, flag}, i) => ( + {" "} - + )) }
diff --git a/src/components/views/Result.jsx b/src/components/views/Result.jsx index cfeb23f..2fc3fbb 100644 --- a/src/components/views/Result.jsx +++ b/src/components/views/Result.jsx @@ -16,6 +16,13 @@ import { i18nGrades } from "../../Util"; import { AppContext } from "../../AppContext"; import { errorMessage, Error } from "../../Errors"; +const meritProfileFromVotes = votes => { + const numGrades = Math.max( ...votes) - Math.min( ...votes ); + const profile = Array(numGrades).fill(0); + votes.forEach(vote => {profile[vote] += 1 }); + return profile; +} + class Result extends Component { static contextType = AppContext; @@ -56,7 +63,6 @@ class Result extends Component { name: c.name, profile: c.profile, grade: c.grade, - score: c.score })); this.setState(state => ({ candidates: candidates })); return response; @@ -124,7 +130,6 @@ class Result extends Component { } ]; this.setState({ candidates: dataTest }); - console.log(this.state.candidates); } else { const detailsEndpoint = resolve( this.context.urlServer, @@ -174,14 +179,10 @@ class Result extends Component { return ; } - let totalOfVote = 0; - - //based on the first candidate - if (candidates.length > 0) { - candidates[0].profile.map((value, i) => (totalOfVote += value)); - } else { - totalOfVote = 1; - } + const sum = seq => Object.values(seq).reduce((a,b) => a + b, 0) + const numVotes = candidates && candidates.length > 0 ? sum(candidates[0].profile) : 1 ; + const gradeIds = candidates && candidates.length > 0 ? Object.keys(candidates[0].profile) : []; + console.log(gradeIds); return ( @@ -196,7 +197,6 @@ class Result extends Component {

{t("Results of the election:")}

    {candidates.map((candidate, i) => { - console.log(candidate); return (
  1. {candidate.name} @@ -209,9 +209,9 @@ class Result extends Component { > {grades[candidate.grade].label} - + { /* {(100 * candidate.score).toFixed(1)}% - + */ }
  2. ); })} @@ -250,12 +250,10 @@ class Result extends Component { - {candidate.profile.map((value, i) => { + {gradeIds.map((id, i) => { + const value = candidate.profile[id]; if (value > 0) { - let percent = - Math.round( - (value * 100) / totalOfVote - ) + "%"; + let percent = (value * 100) / numVotes + "%"; if (i === 0) { percent = "auto"; } @@ -362,13 +360,10 @@ class Result extends Component { return ( - {/*candidate.label*/} - {candidate.profile.map((value, i) => { - let percent = - Math.round( - ((value * 100) / totalOfVote) * 100 - ) / 100; - return ; + {gradeIds.map((id, i) => { + const value = candidate.profile[id]; + const percent = (value / numVotes * 100).toFixed(1); + return ; })} ); diff --git a/src/components/views/Vote.jsx b/src/components/views/Vote.jsx index 6ceca6a..30e38e5 100644 --- a/src/components/views/Vote.jsx +++ b/src/components/views/Vote.jsx @@ -190,13 +190,13 @@ class Vote extends Component { lg={this.state.colSizeCandidateLg}>
     
    - {electionGrades.map((grade, j) => { - return j < this.state.numGrades ? ( + {electionGrades.map((grade, gradeId) => { + return gradeId < this.state.numGrades ? ( - {candidates.map((candidate, i) => { + {candidates.map((candidate, candidateId) => { return ( - + {candidate.label}
    - {this.state.electionGrades.map((grade, j) => { - return j < this.state.numGrades ? ( + {this.state.electionGrades.map((grade, gradeId) => { + console.assert(gradeId < this.state.numGrades) + return (
    - ) : null; + + ) })} ); From 382ebaa43b904ec0716033c126f20245f593d24b Mon Sep 17 00:00:00 2001 From: Clement G Date: Sat, 18 Apr 2020 15:27:41 +0200 Subject: [PATCH 3/6] fix(footer): add target="_blank" on footer's link #29 --- src/components/layouts/Footer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/layouts/Footer.jsx b/src/components/layouts/Footer.jsx index e21bfee..c762599 100644 --- a/src/components/layouts/Footer.jsx +++ b/src/components/layouts/Footer.jsx @@ -31,9 +31,9 @@ class Footer extends Component {
    {t("Homepage")} - - {t("Source code")} + {t("Source code")} - - {t("Who are we")} + {t("Who are we")} - { countries.map(({l, flag}, i) => ( From 3b4b8fc15311aba5dd2402e2dfdea8dbe48e19da Mon Sep 17 00:00:00 2001 From: Clement G Date: Sat, 18 Apr 2020 15:32:29 +0200 Subject: [PATCH 4/6] fix(create-success): Readability problem on warning on page with message confirming the creation of a vote #30 --- src/components/views/CreateSuccess.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/CreateSuccess.jsx b/src/components/views/CreateSuccess.jsx index 9163660..ec308e7 100644 --- a/src/components/views/CreateSuccess.jsx +++ b/src/components/views/CreateSuccess.jsx @@ -79,10 +79,10 @@ class CreateSuccess extends Component {
    -
    -

    +

    +

    {t('Keep these links carefully')} -

    +

    Warning: you will have no other choices to recover the From 5b4fd0be0447fc7b14380d1a4bcda20985eac9d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Guhur Date: Sat, 18 Apr 2020 13:46:22 +0000 Subject: [PATCH 5/6] [VIEW] add fetch for num_votes --- src/components/views/Result.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/Result.jsx b/src/components/views/Result.jsx index 2fc3fbb..d034945 100644 --- a/src/components/views/Result.jsx +++ b/src/components/views/Result.jsx @@ -64,6 +64,7 @@ class Result extends Component { profile: c.profile, grade: c.grade, })); + console.log(response); this.setState(state => ({ candidates: candidates })); return response; }; From 7b4f229bdb510ce8270af563d9cbcbb1a9979fe8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Guhur Date: Sun, 19 Apr 2020 17:02:05 +0000 Subject: [PATCH 6/6] add number of votes --- public/locale/i18n/de/resource.json | 3 +- public/locale/i18n/en/resource.json | 3 +- public/locale/i18n/es/resource.json | 3 +- public/locale/i18n/fr/resource.json | 3 +- src/components/views/Result.jsx | 169 +++++++++++++++------------- 5 files changed, 98 insertions(+), 83 deletions(-) diff --git a/public/locale/i18n/de/resource.json b/public/locale/i18n/de/resource.json index 63e5dd7..76b4777 100644 --- a/public/locale/i18n/de/resource.json +++ b/public/locale/i18n/de/resource.json @@ -70,5 +70,6 @@ "The election is over. You can't vote anymore": "__STRING_NOT_TRANSLATED__", "You need a token to vote in this election": "__STRING_NOT_TRANSLATED__", "You seem to have already voted.": "__STRING_NOT_TRANSLATED__", - "The parameters of the election are incorrect.": "__STRING_NOT_TRANSLATED__" + "The parameters of the election are incorrect.": "__STRING_NOT_TRANSLATED__", + "Number of votes:": "__STRING_NOT_TRANSLATED__" } diff --git a/public/locale/i18n/en/resource.json b/public/locale/i18n/en/resource.json index 4860c47..ec94e02 100644 --- a/public/locale/i18n/en/resource.json +++ b/public/locale/i18n/en/resource.json @@ -77,5 +77,6 @@ "The election is over. You can't vote anymore": "The election is over. You can't vote anymore", "You need a token to vote in this election": "You need a token to vote in this election", "You seem to have already voted.": "You seem to have already voted.", - "The parameters of the election are incorrect.": "The parameters of the election are incorrect." + "The parameters of the election are incorrect.": "The parameters of the election are incorrect.", + "Number of votes:": "Number of votes:" } diff --git a/public/locale/i18n/es/resource.json b/public/locale/i18n/es/resource.json index 0d246ad..5ab4346 100644 --- a/public/locale/i18n/es/resource.json +++ b/public/locale/i18n/es/resource.json @@ -77,5 +77,6 @@ "The election is over. You can't vote anymore": "__STRING_NOT_TRANSLATED__", "You need a token to vote in this election": "__STRING_NOT_TRANSLATED__", "You seem to have already voted.": "__STRING_NOT_TRANSLATED__", - "The parameters of the election are incorrect.": "__STRING_NOT_TRANSLATED__" + "The parameters of the election are incorrect.": "__STRING_NOT_TRANSLATED__", + "Number of votes:": "__STRING_NOT_TRANSLATED__" } diff --git a/public/locale/i18n/fr/resource.json b/public/locale/i18n/fr/resource.json index 2f7d8fc..7e7de65 100644 --- a/public/locale/i18n/fr/resource.json +++ b/public/locale/i18n/fr/resource.json @@ -77,5 +77,6 @@ "The election is over. You can't vote anymore": "L'élection est terminée. Vous ne pouvez plus voter.", "You need a token to vote in this election": "Vous avez besoin d'un jeton pour voter dans cette élection", "You seem to have already voted.": "Il semble que vous ayez déjà voté.", - "The parameters of the election are incorrect.": "Les paramètres de l'élection sont incorrects." + "The parameters of the election are incorrect.": "Les paramètres de l'élection sont incorrects.", + "Number of votes:": "Nombre de votes :" } diff --git a/src/components/views/Result.jsx b/src/components/views/Result.jsx index d034945..edb3d7d 100644 --- a/src/components/views/Result.jsx +++ b/src/components/views/Result.jsx @@ -1,7 +1,7 @@ -import React, { Component } from "react"; -import { Redirect } from "react-router-dom"; -import { withTranslation } from "react-i18next"; -import { resolve } from "url"; +import React, {Component} from 'react'; +import {Redirect} from 'react-router-dom'; +import {withTranslation} from 'react-i18next'; +import {resolve} from 'url'; import { Container, Row, @@ -10,18 +10,20 @@ import { Card, CardHeader, CardBody, - Table -} from "reactstrap"; -import { i18nGrades } from "../../Util"; -import { AppContext } from "../../AppContext"; -import { errorMessage, Error } from "../../Errors"; + Table, +} from 'reactstrap'; +import {i18nGrades} from '../../Util'; +import {AppContext} from '../../AppContext'; +import {errorMessage, Error} from '../../Errors'; const meritProfileFromVotes = votes => { - const numGrades = Math.max( ...votes) - Math.min( ...votes ); + const numGrades = Math.max(...votes) - Math.min(...votes); const profile = Array(numGrades).fill(0); - votes.forEach(vote => {profile[vote] += 1 }); + votes.forEach(vote => { + profile[vote] += 1; + }); return profile; -} +}; class Result extends Component { static contextType = AppContext; @@ -41,7 +43,7 @@ class Result extends Component { collapseGraphics: false, collapseProfiles: false, electionGrades: i18nGrades(), - errorMessage: "", + errorMessage: '', }; } @@ -49,7 +51,7 @@ class Result extends Component { if (!response.ok) { response.json().then(response => { this.setState(state => ({ - errorMessage: errorMessage(response, this.props.t) + errorMessage: errorMessage(response, this.props.t), })); }); throw Error(response); @@ -65,20 +67,20 @@ class Result extends Component { grade: c.grade, })); console.log(response); - this.setState(state => ({ candidates: candidates })); + this.setState(state => ({candidates: candidates})); return response; }; detailsToState = response => { const numGrades = response.num_grades; const colSizeGradeLg = Math.floor( - (12 - this.state.colSizeCandidateLg) / numGrades + (12 - this.state.colSizeCandidateLg) / numGrades, ); const colSizeGradeMd = Math.floor( - (12 - this.state.colSizeCandidateMd) / numGrades + (12 - this.state.colSizeCandidateMd) / numGrades, ); const colSizeGradeXs = Math.floor( - (12 - this.state.colSizeCandidateXs) / numGrades + (12 - this.state.colSizeCandidateXs) / numGrades, ); this.setState(state => ({ title: response.title, @@ -98,7 +100,7 @@ class Result extends Component { 12 - colSizeGradeXs * numGrades > 0 ? 12 - colSizeGradeXs * numGrades : 12, - electionGrades: i18nGrades().slice(0, numGrades) + electionGrades: i18nGrades().slice(0, numGrades), })); return response; }; @@ -106,38 +108,38 @@ class Result extends Component { componentDidMount() { // get details of the election const electionSlug = this.props.match.params.slug; - if (electionSlug === "dev") { + if (electionSlug === 'dev') { const dataTest = [ { - name: "BB", + name: 'BB', id: 1, score: 1.0, profile: [1, 1, 0, 0, 0, 0, 0], - grade: 1 + grade: 1, }, { - name: "CC", + name: 'CC', id: 2, score: 1.0, profile: [0, 0, 2, 0, 0, 0, 0], - grade: 2 + grade: 2, }, { - name: "AA", + name: 'AA', id: 0, score: 1.0, profile: [1, 1, 0, 0, 0, 0, 0], - grade: 1 - } + grade: 1, + }, ]; - this.setState({ candidates: dataTest }); + this.setState({candidates: dataTest}); } else { const detailsEndpoint = resolve( this.context.urlServer, this.context.routesServer.getElection.replace( - new RegExp(":slug", "g"), - electionSlug - ) + new RegExp(':slug', 'g'), + electionSlug, + ), ); fetch(detailsEndpoint) @@ -150,9 +152,9 @@ class Result extends Component { const resultsEndpoint = resolve( this.context.urlServer, this.context.routesServer.getResultsElection.replace( - new RegExp(":slug", "g"), - electionSlug - ) + new RegExp(':slug', 'g'), + electionSlug, + ), ); fetch(resultsEndpoint) @@ -164,25 +166,29 @@ class Result extends Component { } toggleGraphics = () => { - this.setState(state => ({ collapseGraphics: !state.collapseGraphics })); + this.setState(state => ({collapseGraphics: !state.collapseGraphics})); }; toggleProfiles = () => { - this.setState(state => ({ collapseProfiles: !state.collapseProfiles })); + this.setState(state => ({collapseProfiles: !state.collapseProfiles})); }; render() { - const { errorMessage, candidates, electionGrades } = this.state; - const { t } = this.props; + const {errorMessage, candidates, electionGrades} = this.state; + const {t} = this.props; const grades = i18nGrades(); - - if (errorMessage && errorMessage !== "") { + + if (errorMessage && errorMessage !== '') { return ; } - const sum = seq => Object.values(seq).reduce((a,b) => a + b, 0) - const numVotes = candidates && candidates.length > 0 ? sum(candidates[0].profile) : 1 ; - const gradeIds = candidates && candidates.length > 0 ? Object.keys(candidates[0].profile) : []; + const sum = seq => Object.values(seq).reduce((a, b) => a + b, 0); + const numVotes = + candidates && candidates.length > 0 ? sum(candidates[0].profile) : 1; + const gradeIds = + candidates && candidates.length > 0 + ? Object.keys(candidates[0].profile) + : []; console.log(gradeIds); return ( @@ -195,24 +201,30 @@ class Result extends Component {

    -

    {t("Results of the election:")}

    +

    {t('Results of the election:')}

    +
    + + {t('Number of votes:')} + {' ' + numVotes} + +
    +
      {candidates.map((candidate, i) => { return (
    1. - {candidate.name} + {candidate.name} + color: '#fff', + }}> {grades[candidate.grade].label} - { /* + {/* {(100 * candidate.score).toFixed(1)}% - */ } + */}
    2. ); })} @@ -226,11 +238,10 @@ class Result extends Component {

      - {t("Graph")} + 'm-0 panel-title ' + + (this.state.collapseGraphics ? 'collapsed' : '') + }> + {t('Graph')}

      @@ -238,25 +249,26 @@ class Result extends Component {
      -
    {i + 1}{percent}%{percent} %
    +
    {candidates.map((candidate, i) => { return ( - + {/*candidate.label*/}
    {i + 1}{i + 1} - +
    {gradeIds.map((id, i) => { const value = candidate.profile[id]; if (value > 0) { - let percent = (value * 100) / numVotes + "%"; + let percent = + (value * 100) / numVotes + '%'; if (i === 0) { - percent = "auto"; + percent = 'auto'; } return ( ); @@ -289,7 +300,7 @@ class Result extends Component { {candidates.map((candidate, i) => { return ( - {i > 0 ? ", " : ""} + {i > 0 ? ', ' : ''} {i + 1}: {candidate.name} ); @@ -305,9 +316,8 @@ class Result extends Component { className="badge badge-light mr-2 mt-2" style={{ backgroundColor: grade.color, - color: "#fff" - }} - > + color: '#fff', + }}> {grade.label} ); @@ -325,11 +335,10 @@ class Result extends Component {

    - {t("Preference profile")} + 'm-0 panel-title ' + + (this.state.collapseProfiles ? 'collapsed' : '') + }> + {t('Preference profile')}

    @@ -346,10 +355,9 @@ class Result extends Component { className="badge badge-light" style={{ backgroundColor: grade.color, - color: "#fff" - }} - > - {grade.label}{" "} + color: '#fff', + }}> + {grade.label}{' '} ); @@ -363,7 +371,10 @@ class Result extends Component { {gradeIds.map((id, i) => { const value = candidate.profile[id]; - const percent = (value / numVotes * 100).toFixed(1); + const percent = ( + (value / numVotes) * + 100 + ).toFixed(1); return ; })} @@ -376,7 +387,7 @@ class Result extends Component { {candidates.map((candidate, i) => { return ( - {i > 0 ? ", " : ""} + {i > 0 ? ', ' : ''} {i + 1}: {candidate.name} );
    + .electionGrades[i].color, + }}>   {i + 1}{percent} %