|
|
|
@ -1,19 +1,17 @@
|
|
|
|
|
import React, { Component } from "react";
|
|
|
|
|
import { Redirect } from "react-router-dom";
|
|
|
|
|
import { withTranslation } from 'react-i18next';
|
|
|
|
|
import { Button, Col, Container, Row } from "reactstrap";
|
|
|
|
|
import { toast, ToastContainer } from "react-toastify";
|
|
|
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
|
|
import { faCheck } from "@fortawesome/free-solid-svg-icons";
|
|
|
|
|
import { resolve } from "url";
|
|
|
|
|
import { i18nGrades } from "../../Util";
|
|
|
|
|
import { AppContext } from "../../AppContext";
|
|
|
|
|
import { errorMessage } from "../../Errors";
|
|
|
|
|
|
|
|
|
|
import React, {Component} from 'react';
|
|
|
|
|
import {Redirect} from 'react-router-dom';
|
|
|
|
|
import {withTranslation} from 'react-i18next';
|
|
|
|
|
import {Button, Col, Container, Row} from 'reactstrap';
|
|
|
|
|
import {toast, ToastContainer} from 'react-toastify';
|
|
|
|
|
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
|
|
|
|
import {faCheck} from '@fortawesome/free-solid-svg-icons';
|
|
|
|
|
import {resolve} from 'url';
|
|
|
|
|
import {i18nGrades} from '../../Util';
|
|
|
|
|
import {AppContext} from '../../AppContext';
|
|
|
|
|
import {errorMessage} from '../../Errors';
|
|
|
|
|
|
|
|
|
|
const shuffle = array => array.sort(() => Math.random() - 0.5);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Vote extends Component {
|
|
|
|
|
static contextType = AppContext;
|
|
|
|
|
constructor(props) {
|
|
|
|
@ -30,7 +28,7 @@ class Vote extends Component {
|
|
|
|
|
colSizeGradeMd: 1,
|
|
|
|
|
colSizeGradeXs: 1,
|
|
|
|
|
redirectTo: null,
|
|
|
|
|
electionGrades: i18nGrades()
|
|
|
|
|
electionGrades: i18nGrades(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -53,18 +51,18 @@ class Vote extends Component {
|
|
|
|
|
const numGrades = response.num_grades;
|
|
|
|
|
const candidates = response.candidates.map((c, i) => ({
|
|
|
|
|
id: i,
|
|
|
|
|
label: c
|
|
|
|
|
label: c,
|
|
|
|
|
}));
|
|
|
|
|
shuffle(candidates);
|
|
|
|
|
|
|
|
|
|
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 => ({
|
|
|
|
@ -86,7 +84,7 @@ class Vote extends Component {
|
|
|
|
|
12 - colSizeGradeXs * numGrades > 0
|
|
|
|
|
? 12 - colSizeGradeXs * numGrades
|
|
|
|
|
: 12,
|
|
|
|
|
electionGrades: i18nGrades().slice(0, numGrades)
|
|
|
|
|
electionGrades: i18nGrades().slice(0, numGrades),
|
|
|
|
|
}));
|
|
|
|
|
return response;
|
|
|
|
|
};
|
|
|
|
@ -97,9 +95,9 @@ class Vote extends Component {
|
|
|
|
|
const detailsEndpoint = resolve(
|
|
|
|
|
this.context.urlServer,
|
|
|
|
|
this.context.routesServer.getElection.replace(
|
|
|
|
|
new RegExp(":slug", "g"),
|
|
|
|
|
electionSlug
|
|
|
|
|
)
|
|
|
|
|
new RegExp(':slug', 'g'),
|
|
|
|
|
electionSlug,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
fetch(detailsEndpoint)
|
|
|
|
|
.then(this.handleErrors)
|
|
|
|
@ -110,33 +108,33 @@ class Vote extends Component {
|
|
|
|
|
|
|
|
|
|
handleGradeClick = event => {
|
|
|
|
|
let data = {
|
|
|
|
|
id: parseInt(event.currentTarget.getAttribute("data-id")),
|
|
|
|
|
value: parseInt(event.currentTarget.value)
|
|
|
|
|
id: parseInt(event.currentTarget.getAttribute('data-id')),
|
|
|
|
|
value: parseInt(event.currentTarget.value),
|
|
|
|
|
};
|
|
|
|
|
//remove candidate
|
|
|
|
|
let ratedCandidates = this.state.ratedCandidates.filter(
|
|
|
|
|
ratedCandidate => ratedCandidate.id !== data.id
|
|
|
|
|
ratedCandidate => ratedCandidate.id !== data.id,
|
|
|
|
|
);
|
|
|
|
|
ratedCandidates.push(data);
|
|
|
|
|
this.setState({ ratedCandidates: ratedCandidates });
|
|
|
|
|
this.setState({ratedCandidates});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
handleSubmitWithoutAllRate = () => {
|
|
|
|
|
const {t} = this.props;
|
|
|
|
|
toast.error(t("You have to judge every candidate/proposal!"), {
|
|
|
|
|
position: toast.POSITION.TOP_CENTER
|
|
|
|
|
toast.error(t('You have to judge every candidate/proposal!'), {
|
|
|
|
|
position: toast.POSITION.TOP_CENTER,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
handleSubmit = event => {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
|
|
const { ratedCandidates } = this.state;
|
|
|
|
|
const {ratedCandidates} = this.state;
|
|
|
|
|
const electionSlug = this.props.match.params.slug;
|
|
|
|
|
const token = this.props.location.search.substr(7);
|
|
|
|
|
const endpoint = resolve(
|
|
|
|
|
this.context.urlServer,
|
|
|
|
|
this.context.routesServer.voteElection
|
|
|
|
|
this.context.routesServer.voteElection,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const gradesById = {};
|
|
|
|
@ -144,34 +142,33 @@ class Vote extends Component {
|
|
|
|
|
gradesById[c.id] = c.value;
|
|
|
|
|
});
|
|
|
|
|
const gradesByCandidate = [];
|
|
|
|
|
Object.keys(gradesById)
|
|
|
|
|
.forEach(id => {
|
|
|
|
|
gradesByCandidate.push(gradesById[id]);
|
|
|
|
|
});
|
|
|
|
|
Object.keys(gradesById).forEach(id => {
|
|
|
|
|
gradesByCandidate.push(gradesById[id]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
|
election: electionSlug,
|
|
|
|
|
grades_by_candidate: gradesByCandidate,
|
|
|
|
|
}
|
|
|
|
|
if (token !== ""){
|
|
|
|
|
payload["token"] = token;
|
|
|
|
|
election: electionSlug,
|
|
|
|
|
grades_by_candidate: gradesByCandidate,
|
|
|
|
|
};
|
|
|
|
|
if (token !== '') {
|
|
|
|
|
payload['token'] = token;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fetch(endpoint, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
body: JSON.stringify(payload)
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {'Content-Type': 'application/json'},
|
|
|
|
|
body: JSON.stringify(payload),
|
|
|
|
|
})
|
|
|
|
|
.then(this.handleErrors)
|
|
|
|
|
.then(result =>
|
|
|
|
|
this.setState({ redirectTo: "/vote-success/" + electionSlug })
|
|
|
|
|
this.setState({redirectTo: '/vote-success/' + electionSlug}),
|
|
|
|
|
)
|
|
|
|
|
.catch(error => error);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
const {t} = this.props;
|
|
|
|
|
const { redirectTo, candidates, electionGrades } = this.state;
|
|
|
|
|
const {redirectTo, candidates, electionGrades} = this.state;
|
|
|
|
|
|
|
|
|
|
if (redirectTo) {
|
|
|
|
|
return <Redirect to={redirectTo} />;
|
|
|
|
@ -190,8 +187,7 @@ class Vote extends Component {
|
|
|
|
|
<Col
|
|
|
|
|
xs={this.state.colSizeCandidateXs}
|
|
|
|
|
md={this.state.colSizeCandidateMd}
|
|
|
|
|
lg={this.state.colSizeCandidateLg}
|
|
|
|
|
>
|
|
|
|
|
lg={this.state.colSizeCandidateLg}>
|
|
|
|
|
<h5> </h5>
|
|
|
|
|
</Col>
|
|
|
|
|
{electionGrades.map((grade, j) => {
|
|
|
|
@ -202,12 +198,10 @@ class Vote extends Component {
|
|
|
|
|
lg={this.state.colSizeGradeLg}
|
|
|
|
|
key={j}
|
|
|
|
|
className="text-center p-0"
|
|
|
|
|
style={{ lineHeight: 2 }}
|
|
|
|
|
>
|
|
|
|
|
style={{lineHeight: 2}}>
|
|
|
|
|
<small
|
|
|
|
|
className="nowrap bold badge"
|
|
|
|
|
style={{ backgroundColor: grade.color, color: "#fff" }}
|
|
|
|
|
>
|
|
|
|
|
style={{backgroundColor: grade.color, color: '#fff'}}>
|
|
|
|
|
{grade.label}
|
|
|
|
|
</small>
|
|
|
|
|
</Col>
|
|
|
|
@ -221,8 +215,7 @@ class Vote extends Component {
|
|
|
|
|
<Col
|
|
|
|
|
xs={this.state.colSizeCandidateXs}
|
|
|
|
|
md={this.state.colSizeCandidateMd}
|
|
|
|
|
lg={this.state.colSizeCandidateLg}
|
|
|
|
|
>
|
|
|
|
|
lg={this.state.colSizeCandidateLg}>
|
|
|
|
|
<h5 className="m-0">{candidate.label}</h5>
|
|
|
|
|
<hr className="d-lg-none" />
|
|
|
|
|
</Col>
|
|
|
|
@ -233,36 +226,33 @@ class Vote extends Component {
|
|
|
|
|
md={this.state.colSizeGradeMd}
|
|
|
|
|
lg={this.state.colSizeGradeLg}
|
|
|
|
|
key={j}
|
|
|
|
|
className="text-lg-center"
|
|
|
|
|
>
|
|
|
|
|
className="text-lg-center">
|
|
|
|
|
<label
|
|
|
|
|
htmlFor={"candidateGrade" + i + "-" + j}
|
|
|
|
|
className="check"
|
|
|
|
|
>
|
|
|
|
|
htmlFor={'candidateGrade' + i + '-' + j}
|
|
|
|
|
className="check">
|
|
|
|
|
<small
|
|
|
|
|
className="nowrap d-lg-none ml-2 bold badge"
|
|
|
|
|
style={
|
|
|
|
|
this.state.ratedCandidates.find(function(
|
|
|
|
|
ratedCandidat
|
|
|
|
|
ratedCandidat,
|
|
|
|
|
) {
|
|
|
|
|
return (
|
|
|
|
|
JSON.stringify(ratedCandidat) ===
|
|
|
|
|
JSON.stringify({ id: candidate.id, value: j })
|
|
|
|
|
JSON.stringify({id: candidate.id, value: j})
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
? { backgroundColor: grade.color, color: "#fff" }
|
|
|
|
|
? {backgroundColor: grade.color, color: '#fff'}
|
|
|
|
|
: {
|
|
|
|
|
backgroundColor: "transparent",
|
|
|
|
|
color: "#000"
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
color: '#000',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
}>
|
|
|
|
|
{grade.label}
|
|
|
|
|
</small>
|
|
|
|
|
<input
|
|
|
|
|
type="radio"
|
|
|
|
|
name={"candidate" + i}
|
|
|
|
|
id={"candidateGrade" + i + "-" + j}
|
|
|
|
|
name={'candidate' + i}
|
|
|
|
|
id={'candidateGrade' + i + '-' + j}
|
|
|
|
|
data-index={i}
|
|
|
|
|
data-id={candidate.id}
|
|
|
|
|
value={j}
|
|
|
|
@ -271,26 +261,26 @@ class Vote extends Component {
|
|
|
|
|
function(element) {
|
|
|
|
|
return (
|
|
|
|
|
JSON.stringify(element) ===
|
|
|
|
|
JSON.stringify({ id: candidate.id, value: j })
|
|
|
|
|
JSON.stringify({id: candidate.id, value: j})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<span
|
|
|
|
|
className="checkmark"
|
|
|
|
|
style={
|
|
|
|
|
this.state.ratedCandidates.find(function(
|
|
|
|
|
ratedCandidat
|
|
|
|
|
ratedCandidat,
|
|
|
|
|
) {
|
|
|
|
|
return (
|
|
|
|
|
JSON.stringify(ratedCandidat) ===
|
|
|
|
|
JSON.stringify({ id: candidate.id, value: j })
|
|
|
|
|
JSON.stringify({id: candidate.id, value: j})
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
? { backgroundColor: grade.color, color: "#fff" }
|
|
|
|
|
? {backgroundColor: grade.color, color: '#fff'}
|
|
|
|
|
: {
|
|
|
|
|
backgroundColor: "transparent",
|
|
|
|
|
color: "#000"
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
color: '#000',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
@ -309,15 +299,14 @@ class Vote extends Component {
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={this.handleSubmitWithoutAllRate}
|
|
|
|
|
className="btn btn-dark "
|
|
|
|
|
>
|
|
|
|
|
className="btn btn-dark ">
|
|
|
|
|
<FontAwesomeIcon icon={faCheck} className="mr-2" />
|
|
|
|
|
{t("Validate")}
|
|
|
|
|
{t('Validate')}
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
<Button type="submit" className="btn btn-success ">
|
|
|
|
|
<FontAwesomeIcon icon={faCheck} className="mr-2" />
|
|
|
|
|
{t("Validate")}
|
|
|
|
|
{t('Validate')}
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</Col>
|
|
|
|
|