feat(restrict-result) : add an restrict result option on create election form

pull/73/head
Clement G 4 years ago
parent b9ceac688b
commit 590bbe5afc

@ -19,12 +19,12 @@
"Candidates/Proposals": "Kandidaten/Abstimmungsvorschlag ",
"Add a proposal": "Einen Abstimmungsvorschlag hinzufügen",
"Advanced options": "Weitere Optionen",
"Starting date:": "Anfangsdatum:",
"Ending date: ": "Enddatum: ",
"Grades:": "Note",
"Starting date": "Anfangsdatum",
"Ending date": "Enddatum",
"Grades": "Note",
"You can select here the number of grades for your election": " Sie können hier die Anzahl der Noten für Ihre Wahl auswählen ",
"5 = Excellent, Very good, Good, Fair, Passable": "5 = hervorragend, sehr gut, gut, befriedigend, ausreichend",
"Participants:": "Teilnehmer :",
"Participants": "Teilnehmer",
"Add here participants' emails": "Fügen Sie hier die Email Adressen der Teilnehmer hinzu.",
"List voters' emails in case the election is not opened": "Falls die Wahl noch nicht sofort geöffnet werden soll, fügen Sie die Email Adressen der Teilnehmer hier zu.",
"Validate": "Ok",
@ -60,7 +60,6 @@
"The election will take place from": "Die Wahl findet von",
"at": "um",
"to": "bis",
"Grades": "Note",
"Voters' list": "Wählerliste",
"Voters received a link to vote by email. Each link can be used only once!": "Die Wähler erhielten per E-Mail einen Link zur Stimmabgabe. Jeder Link kann nur einmal verwendet werden!",
"Results of the election:": "Ergebnisse der Wahl",
@ -73,5 +72,10 @@
"The election is over. You can't vote anymore": "Die Wahl ist vorbei. Sie können nicht mehr wählen",
"You need a token to vote in this election": "Sie brauchen eine Wertmarke, um an dieser Wahl teilzunehmen",
"You seem to have already voted.": "Sie scheinen bereits abgestimmt zu haben.",
"The parameters of the election are incorrect.": "Die Parameter der Wahl sind falsch."
"The parameters of the election are incorrect.": "Die Parameter der Wahl sind falsch.",
"Access to results" : "Zugang zu den Ergebnissen",
"Immediately": "Sofort",
"At the end of the election": "Am Ende der Wahl",
"The results page will not be accessible until all participants have voted.":"Die Ergebnisseite wird nicht zugänglich sein, bis alle Teilnehmer abgestimmt haben.",
"The results page will not be accessible until the end date is reached.": "Die Ergebnisseite wird nicht zugänglich sein, bis das Enddatum erreicht ist."
}

@ -19,12 +19,12 @@
"Candidates/Proposals": "Candidates/Proposals",
"Add a proposal": "Add a proposal",
"Advanced options": "Advanced options",
"Starting date:": "Starting date:",
"Ending date: ": "Ending date: ",
"Grades:": "Grades:",
"Starting date": "Starting date",
"Ending date": "Ending date",
"Grades": "Grades",
"You can select here the number of grades for your election": "You can select here the number of grades for your election",
"5 = Excellent, Very good, Good, Fair, Passable": "5 = Excellent, Very good, Good, Fair, Passable",
"Participants:": "Participants:",
"Participants": "Participants",
"Add here participants' emails": "Add here participants' emails",
"List voters' emails in case the election is not opened": "List voters' emails in case the election is not opened",
"Validate": "Validate",
@ -62,7 +62,6 @@
"The election will take place from": "The election will take place from",
"at": "at",
"to": "to",
"Grades": "Grades",
"Voters' list": "Voters' list",
"Graph": "Graph",
"Preference profile": "Merit profile",
@ -80,5 +79,10 @@
"The parameters of the election are incorrect.": "The parameters of the election are incorrect.",
"Support us !": "Support us !",
"PayPal - The safer, easier way to pay online!": "PayPal - The safer, easier way to pay online!",
"Number of votes:": "Number of votes:"
"Number of votes:": "Number of votes:",
"Access to results" : "Access to results",
"Immediately": "Immediately",
"At the end of the election": "At the end of the election",
"The results page will not be accessible until all participants have voted.":"The results page will not be accessible until all participants have voted.",
"The results page will not be accessible until the end date is reached.": "The results page will not be accessible until the end date is reached."
}

@ -19,9 +19,9 @@
"Candidates/Proposals": "Candidatos(as)/Propuestas",
"Add a proposal": "Añadir una propuesta",
"Advanced options": "Opciones avanzadas",
"Starting date:": "Fecha de inicio:",
"Ending date: ": "Fecha de finalización: ",
"Grades:": "Escala",
"Starting date": "Fecha de inicio",
"Ending date": "Fecha de finalización",
"Grades": "Escala",
"You can select here the number of grades for your election": "Puede seleccionar aquí el número de niveles de la escala para su elección",
"5 = Excellent, Very good, Good, Fair, Passable": "5 == Excelente, Muy bien, Bien, Regular, Pasable",
"Participants:": "Participantes",
@ -62,7 +62,6 @@
"The election will take place from": "La elección tendrá lugar desde",
"at": "a las",
"to": "hasta",
"Grades": "Escala",
"Voters' list": "Lista de votantes",
"Graph": "Gráfico",
"Preference profile": "Perfil de preferencia",
@ -81,5 +80,10 @@
"The election is over. You can't vote anymore": "La elección ha terminado. Ya no puedes votar.",
"You need a token to vote in this election": "Necesitas una ficha para votar en esta elección",
"You seem to have already voted.": "Parece que ya has votado.",
"The parameters of the election are incorrect.": "Los parámetros de la elección son incorrectos."
"The parameters of the election are incorrect.": "Los parámetros de la elección son incorrectos.",
"Access to results" : "Acceso a los resultados",
"Immediately": "Inmediatamente",
"At the end of the election": "Al final de la elección",
"The results page will not be accessible until all participants have voted.":"La página de resultados no será accesible hasta que todos los participantes hayan votado.",
"The results page will not be accessible until the end date is reached.": "No se podrá acceder a la página de resultados hasta que se alcance la fecha de finalización."
}

@ -19,19 +19,18 @@
"Candidates/Proposals": "Candidats/Propositions",
"Add a proposal": "Ajouter une proposition",
"Advanced options": "Options avancées",
"Starting date:": "Date de début :",
"Ending date: ": "Date de fin : ",
"Ending date:": "Date de fin : ",
"Grades:": "Mentions",
"Starting date": "Date de début",
"Ending date": "Date de fin ",
"Grades": "Mentions",
"You can select here the number of grades for your election": "You pouvez choisir ici le nombre de mentions de votre élection",
"5 = Excellent, Very good, Good, Fair, Passable": "5 = Excellent, Très bien, Bien, Assez bien, Passable",
"Participants:": "Participants :",
"Participants": "Participants",
"Add here participants' emails": "Ajouter ici les emails des participants",
"List voters' emails in case the election is not opened": "Lister ici les emails des électeurs dans le cas où l'élection n'est pas ouverte.",
"Validate": "Valider",
"Confirm your vote": "Confirmer votre vote",
"The form contains no address.": "Aucune adresse email n'a été ajoutée.",
"The election will be opened to anyone with the link": "L'élection sera accessible à tous ceux qui disposent de ce lien",
"The election will be opened to anyone with the link": "L'élection sera accessible à tous ceux qui disposent du lien",
"Start the election": "Démarrer l'élection",
"Cancel": "Annuler",
"Confirm": "Valider",
@ -62,7 +61,6 @@
"The election will take place from": "Le vote se déroulera du",
"at": "à",
"to": "au",
"Grades": "Mentions",
"Voters' list": "Listes des électeurs",
"Graph": "Graphique",
"Preference profile": "Profil de mérites",
@ -80,5 +78,10 @@
"The parameters of the election are incorrect.": "Les paramètres de l'élection sont incorrects.",
"Support us !": "Soutenez-nous !",
"PayPal - The safer, easier way to pay online!": "PayPal - Le moyen le plus sûr et le plus simple de payer en ligne !",
"Number of votes:": "Nombre de votes :"
"Number of votes:": "Nombre de votes :",
"Access to results" : "Accès aux résultats",
"Immediately": "Immédiatement",
"At the end of the election": "A la fin de l'élection",
"The results page will not be accessible until all participants have voted.":"La page de résultats ne sera pas accessible tant que tous les participants n'auront pas voté.",
"The results page will not be accessible until the end date is reached.": "La page de résultats ne sera pas accessible tant que la date de fin ne sera pas atteinte."
}

@ -19,9 +19,9 @@
"Candidates/Proposals": "Кандидаты/Предложения",
"Add a proposal": "Добавьте предложение",
"Advanced options": "Расширенные настройки",
"Starting date:": "Дата начала:",
"Ending date: ": "Дата окончания: ",
"Grades:": "Оценки:",
"Starting date": "Дата начала",
"Ending date": "Дата окончания",
"Grades": "Оценки",
"You can select here the number of grades for your election": "Здесь вы можете выбрать количество оценок для вашего голосования",
"5 = Excellent, Very good, Good, Fair, Passable": "5 = Отлично, Очень хорошо, Хорошо, Удовлетворительно, Допустимо",
"Participants:": "Участники:",
@ -62,7 +62,6 @@
"The election will take place from": "Голосование состоится",
"at": "в",
"to": "к",
"Grades": "Оценки",
"Voters' list": "Список проголосовавших",
"Graph": "Кривая",
"Preference profile": "Профиль заслуг",
@ -80,5 +79,10 @@
"The parameters of the election are incorrect.": "Параметры голосвания неверны.",
"Support us !": "Поддержите нас !",
"PayPal - The safer, easier way to pay online!": "PayPal - Безопасный и простой способ платить онлайн!",
"Number of votes:": "Количество голосов:"
"Number of votes:": "Количество голосов:",
"Access to results" : "Доступ к результатам",
"Immediately": "Немедленно",
"At the end of the election": "По окончании выборов",
"The results page will not be accessible until all participants have voted.":"Страница результатов не будет доступна до тех пор, пока все участники не проголосуют.",
"The results page will not be accessible until the end date is reached.": "Страница результатов не будет доступна до тех пор, пока не будет достигнута конечная дата."
}

@ -25,7 +25,7 @@ class HelpButton extends Component {
render() {
return (
<span>
<span className={this.props.className}>
<span>
{this.state.tooltipOpen ? (
<span

@ -1,5 +1,5 @@
import React, {Component} from 'react';
import {Redirect, withRouter} from 'react-router-dom';
import React, { Component } from "react";
import { Redirect, withRouter } from "react-router-dom";
import {
Collapse,
Container,
@ -11,39 +11,39 @@ import {
InputGroupAddon,
Button,
Card,
CardBody,
} from 'reactstrap';
import {withTranslation} from 'react-i18next';
import {ReactMultiEmail, isEmail} from 'react-multi-email';
import 'react-multi-email/style.css';
import {toast, ToastContainer} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {resolve} from 'url';
import queryString from 'query-string';
CardBody
} from "reactstrap";
import { withTranslation } from "react-i18next";
import { ReactMultiEmail, isEmail } from "react-multi-email";
import "react-multi-email/style.css";
import { toast, ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { resolve } from "url";
import queryString from "query-string";
import {
arrayMove,
sortableContainer,
sortableElement,
sortableHandle,
} from 'react-sortable-hoc';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
sortableHandle
} from "react-sortable-hoc";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faPlus,
faTrashAlt,
faCheck,
faCogs,
} from '@fortawesome/free-solid-svg-icons';
import {i18nGrades} from '../../Util';
import {AppContext} from '../../AppContext';
import HelpButton from '../form/HelpButton';
import ButtonWithConfirm from '../form/ButtonWithConfirm';
import Loader from '../wait';
import i18n from '../../i18n'
faExclamationTriangle
} from "@fortawesome/free-solid-svg-icons";
import { i18nGrades } from "../../Util";
import { AppContext } from "../../AppContext";
import HelpButton from "../form/HelpButton";
import ButtonWithConfirm from "../form/ButtonWithConfirm";
import Loader from "../wait";
import i18n from "../../i18n";
// Error messages
const AT_LEAST_2_CANDIDATES_ERROR = 'Please add at least 2 candidates.'
const NO_TITLE_ERROR = 'Please add a title.'
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);
@ -74,9 +74,10 @@ const displayClockOptions = () =>
</option>
));
const SortableCandidate = sortableElement(({candidate, sortIndex, form, t}) => (
const SortableCandidate = sortableElement(
({ candidate, sortIndex, form, t }) => (
<li className="sortable">
<Row key={'rowCandidate' + sortIndex}>
<Row key={"rowCandidate" + sortIndex}>
<Col>
<InputGroup>
<InputGroupAddon addonType="prepend">
@ -91,7 +92,7 @@ const SortableCandidate = sortableElement(({candidate, sortIndex, form, t}) => (
onKeyPress={event =>
form.handleKeypressOnCandidateLabel(event, sortIndex)
}
placeholder={t('Candidate/proposal name...')}
placeholder={t("Candidate/proposal name...")}
tabIndex={sortIndex + 1}
innerRef={ref => (form.candidateInputs[sortIndex] = ref)}
maxLength="250"
@ -100,21 +101,22 @@ const SortableCandidate = sortableElement(({candidate, sortIndex, form, t}) => (
<div key="button">
<FontAwesomeIcon icon={faTrashAlt} />
</div>
<div key="modal-title">{t('Delete?')}</div>
<div key="modal-title">{t("Delete?")}</div>
<div key="modal-body">
{t('Are you sure to delete')}{' '}
{candidate.label !== '' ? (
{t("Are you sure to delete")}{" "}
{candidate.label !== "" ? (
<b>"{candidate.label}"</b>
) : (
<span>
{t('the row')} {sortIndex + 1}
{t("the row")} {sortIndex + 1}
</span>
)}{' '}
)}{" "}
?
</div>
<div
key="modal-confirm"
onClick={() => form.removeCandidate(sortIndex)}>
onClick={() => form.removeCandidate(sortIndex)}
>
Oui
</div>
<div key="modal-cancel">Non</div>
@ -124,13 +126,14 @@ const SortableCandidate = sortableElement(({candidate, sortIndex, form, t}) => (
<Col xs="auto" className="align-self-center pl-0">
<HelpButton>
{t(
'Write here your question or introduce simple your election (250 characters max.)',
"Write here your question or introduce simple your election (250 characters max.)"
)}
</HelpButton>
</Col>
</Row>
</li>
));
)
);
const SortableCandidatesContainer = sortableContainer(({ items, form, t }) => {
return (
@ -156,40 +159,46 @@ class CreateElection extends Component {
// default value : start at the last hour
const now = new Date();
const start = new Date(
now.getTime() - minutes(now) - seconds(now) - ms(now),
now.getTime() - minutes(now) - seconds(now) - ms(now)
);
const { title } = queryString.parse(this.props.location.search);
this.state = {
candidates: [{label: ''}, {label: ''}],
title: title || '',
candidates: [{ label: "" }, { label: "" }],
title: title || "",
isVisibleTipsDragAndDropCandidate: true,
numGrades: 7,
waiting: false,
successCreate: false,
redirectTo: null,
isAdvancedOptionsOpen: false,
restrictResult: false,
start,
// by default, the election ends in a week
finish: new Date(start.getTime() + 7 * 24 * 3600 * 1000),
electorEmails: [],
electorEmails: []
};
this.candidateInputs = [];
this.focusInput = React.createRef();
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRestrictResultCheck = this.handleRestrictResultCheck.bind(this);
}
handleChangeTitle = event => {
this.setState({ title: event.target.value });
};
handleRestrictResultCheck = event => {
this.setState({ restrictResult: event.target.value === "1" });
};
addCandidate = event => {
let candidates = this.state.candidates;
if (candidates.length < 100) {
candidates.push({label: ''});
candidates.push({ label: "" });
this.setState({ candidates: candidates });
}
if (event.type === 'keypress') {
if (event.type === "keypress") {
setTimeout(() => {
this.candidateInputs[this.state.candidates.length - 1].focus();
}, 250);
@ -200,7 +209,7 @@ class CreateElection extends Component {
let candidates = this.state.candidates;
candidates.splice(index, 1);
if (candidates.length === 0) {
candidates = [{label: ''}];
candidates = [{ label: "" }];
}
this.setState({ candidates: candidates });
};
@ -212,12 +221,12 @@ class CreateElection extends Component {
return candidate.label;
});
this.setState({
candidates: candidates,
candidates: candidates
});
};
handleKeypressOnCandidateLabel = (event, index) => {
if (event.key === 'Enter') {
if (event.key === "Enter") {
event.preventDefault();
if (index + 1 === this.state.candidates.length) {
this.addCandidate(event);
@ -251,7 +260,7 @@ class CreateElection extends Component {
let numCandidates = 0;
candidates.forEach(c => {
if (c !== "") numCandidates += 1;
})
});
if (numCandidates < 2) {
return { ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR };
}
@ -270,31 +279,32 @@ class CreateElection extends Component {
numGrades,
start,
finish,
electorEmails,
electorEmails
} = this.state;
const endpoint = resolve(
this.context.urlServer,
this.context.routesServer.setElection,
this.context.routesServer.setElection
);
const { t } = this.props;
const locale=i18n.language.substring(0,2).toLowerCase()==="fr"?"fr":"en";
const locale =
i18n.language.substring(0, 2).toLowerCase() === "fr" ? "fr" : "en";
const check = this.checkFields();
if (!check.ok) {
toast.error(t(check.msg), {
position: toast.POSITION.TOP_CENTER,
position: toast.POSITION.TOP_CENTER
});
return
return;
}
this.setState({ waiting: true });
fetch(endpoint, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
"Content-Type": "application/json"
},
body: JSON.stringify({
title: title,
@ -305,8 +315,9 @@ class CreateElection extends Component {
start_at: start.getTime() / 1000,
finish_at: finish.getTime() / 1000,
select_language: locale,
front_url : window.location.origin
}),
front_url: window.location.origin,
restrict_result: this.state.restrictResult
})
})
.then(response => response.json())
.then(result => {
@ -319,11 +330,11 @@ class CreateElection extends Component {
this.setState(state => ({
redirectTo: nextPage,
successCreate: true,
waiting: false,
waiting: false
}));
} else {
toast.error(t('Unknown error. Try again please.'), {
position: toast.POSITION.TOP_CENTER,
toast.error(t("Unknown error. Try again please."), {
position: toast.POSITION.TOP_CENTER
});
this.setState({ waiting: false });
}
@ -331,10 +342,10 @@ class CreateElection extends Component {
.catch(error => error);
}
handleSendNotReady = (msg) => {
handleSendNotReady = msg => {
const { t } = this.props;
toast.error(t(msg), {
position: toast.POSITION.TOP_CENTER,
position: toast.POSITION.TOP_CENTER
});
};
@ -349,7 +360,7 @@ class CreateElection extends Component {
candidates,
numGrades,
isAdvancedOptionsOpen,
electorEmails,
electorEmails
} = this.state;
const { t } = this.props;
@ -361,21 +372,21 @@ class CreateElection extends Component {
return (
<Container>
<ToastContainer />
{waiting ? <Loader /> : ''}
{waiting ? <Loader /> : ""}
<form onSubmit={this.handleSubmit} autoComplete="off">
<Row>
<Col>
<h3>{t('Start an election')}</h3>
<h3>{t("Start an election")}</h3>
</Col>
</Row>
<hr />
<Row className="mt-4">
<Col xs="12">
<Label for="title">{t('Question of the election')}</Label>
<Label for="title">{t("Question of the election")}</Label>
</Col>
<Col>
<Input
placeholder={t('Write here the question of your election')}
placeholder={t("Write here the question of your election")}
tabIndex="1"
name="title"
id="title"
@ -389,13 +400,13 @@ class CreateElection extends Component {
<Col xs="auto" className="align-self-center pl-0">
<HelpButton>
{t(
'Write here your question or introduce simple your election (250 characters max.)',
"Write here your question or introduce simple your election (250 characters max.)"
)}
<br />
<u>{t('For example:')}</u>{' '}
<u>{t("For example:")}</u>{" "}
<em>
{t(
'For the role of my representative, I judge this candidate...',
"For the role of my representative, I judge this candidate..."
)}
</em>
</HelpButton>
@ -403,7 +414,7 @@ class CreateElection extends Component {
</Row>
<Row className="mt-4">
<Col xs="12">
<Label for="title">{t('Candidates/Proposals')}</Label>
<Label for="title">{t("Candidates/Proposals")}</Label>
</Col>
<Col xs="12">
<SortableCandidatesContainer
@ -422,22 +433,25 @@ class CreateElection extends Component {
className="btn-block mt-2"
tabIndex={candidates.length + 2}
type="button"
onClick={event => this.addCandidate(event)}>
onClick={event => this.addCandidate(event)}
>
<FontAwesomeIcon icon={faPlus} className="mr-2" />
{t('Add a proposal')}
{t("Add a proposal")}
</Button>
</Col>
<Col
xs="12"
sm="6"
md="12"
className="text-center text-sm-right text-md-left">
className="text-center text-sm-right text-md-left"
>
<Button
color="link"
className="text-white mt-3 mb-1"
onClick={this.toggleAdvancedOptions}>
onClick={this.toggleAdvancedOptions}
>
<FontAwesomeIcon icon={faCogs} className="mr-2" />
{t('Advanced options')}
{t("Advanced options")}
</Button>
</Col>
</Row>
@ -446,7 +460,54 @@ class CreateElection extends Component {
<CardBody className="text-primary">
<Row>
<Col xs="12" md="3" lg="2">
<Label for="title">{t('Starting date:')}</Label>
<Label for="title">{t("Access to results")}</Label>
</Col>
<Col xs="6" md="5" lg="3">
<Label className="radio " htmlFor="restrict_result_false">
<span className="small text-dark">
{t("Immediately")}
</span>
<input
className="radio"
type="radio"
name="restrict_result"
id="restrict_result_false"
onClick={this.handleRestrictResultCheck}
defaultChecked={!this.state.restrictResult}
value="0"
/>
<span className="checkround checkround-gray" />
</Label>
</Col>
<Col xs="6" md="5" lg="3">
<Label className="radio" htmlFor="restrict_result_true">
<span className="small">
<span className="text-dark">
{t("At the end of the election")}
</span>
<HelpButton className="ml-2">
{t(
"Personne ne pourra voir le résultat tant que la date de fin n'est pas atteinte ou que tous les participants n'ont pas voté."
)}
</HelpButton>
</span>
<input
className="radio"
type="radio"
name="restrict_result"
id="restrict_result_true"
onClick={this.handleRestrictResultCheck}
defaultChecked={this.state.restrictResult}
value="1"
/>
<span className="checkround checkround-gray" />
</Label>
</Col>
</Row>
<hr className="mt-2 mb-2" />
<Row>
<Col xs="12" md="3" lg="2">
<span className="label">{t("Starting date")}</span>
</Col>
<Col xs="6" md="4" lg="3">
<input
@ -457,8 +518,8 @@ class CreateElection extends Component {
this.setState({
start: new Date(
timeMinusDate(start) +
new Date(e.target.valueAsNumber).getTime(),
),
new Date(e.target.valueAsNumber).getTime()
)
});
}}
/>
@ -471,10 +532,11 @@ class CreateElection extends Component {
this.setState({
start: new Date(
dateMinusTime(start).getTime() +
e.target.value * 3600000,
),
e.target.value * 3600000
)
})
}>
}
>
{displayClockOptions()}
</select>
</Col>
@ -482,7 +544,7 @@ class CreateElection extends Component {
<hr className="mt-2 mb-2" />
<Row>
<Col xs="12" md="3" lg="2">
<Label for="title">{t('Ending date:')}</Label>
<span className="label">{t("Ending date")}</span>
</Col>
<Col xs="6" md="4" lg="3">
<input
@ -494,8 +556,8 @@ class CreateElection extends Component {
this.setState({
finish: new Date(
timeMinusDate(finish) +
new Date(e.target.valueAsNumber).getTime(),
),
new Date(e.target.valueAsNumber).getTime()
)
});
}}
/>
@ -508,10 +570,11 @@ class CreateElection extends Component {
this.setState({
finish: new Date(
dateMinusTime(finish).getTime() +
e.target.value * 3600000,
),
e.target.value * 3600000
)
})
}>
}
>
{displayClockOptions()}
</select>
</Col>
@ -519,14 +582,15 @@ class CreateElection extends Component {
<hr className="mt-2 mb-2" />
<Row>
<Col xs="12" md="3" lg="2">
<Label for="title">{t('Grades:')}</Label>
<span className="label">{t("Grades")}</span>
</Col>
<Col xs="10" sm="11" md="4" lg="3">
<select
className="form-control"
tabIndex={candidates.length + 3}
onChange={this.handleChangeNumGrades}
defaultValue="7">
defaultValue="7"
>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
@ -535,13 +599,13 @@ class CreateElection extends Component {
<Col xs="auto" className="align-self-center pl-0 ">
<HelpButton>
{t(
'You can select here the number of grades for your election',
"You can select here the number of grades for your election"
)}
<br />
<u>{t('For example:')}</u>{' '}
<u>{t("For example:")}</u>{" "}
<em>
{' '}
{t('5 = Excellent, Very good, Good, Fair, Passable')}
{" "}
{t("5 = Excellent, Very good, Good, Fair, Passable")}
</em>
</HelpButton>
</Col>
@ -549,7 +613,8 @@ class CreateElection extends Component {
xs="12"
md="9"
lg="10"
className="offset-xs-0 offset-md-3 offset-lg-2">
className="offset-xs-0 offset-md-3 offset-lg-2"
>
{grades.map((mention, i) => {
return (
<span
@ -557,9 +622,10 @@ class CreateElection extends Component {
className="badge badge-light mr-2 mt-2 "
style={{
backgroundColor: mention.color,
color: '#fff',
opacity: i < numGrades ? 1 : 0.3,
}}>
color: "#fff",
opacity: i < numGrades ? 1 : 0.3
}}
>
{mention.label}
</span>
);
@ -569,7 +635,7 @@ class CreateElection extends Component {
<hr className="mt-2 mb-2" />
<Row>
<Col xs="12" md="3" lg="2">
<Label for="title">{t('Participants:')}</Label>
<span className="label">{t("Participants")}</span>
</Col>
<Col xs="12" md="9" lg="10">
<ReactMultiEmail
@ -587,7 +653,8 @@ class CreateElection extends Component {
{email}
<span
data-tag-handle
onClick={() => removeEmail(index)}>
onClick={() => removeEmail(index)}
>
×
</span>
</div>
@ -597,7 +664,7 @@ class CreateElection extends Component {
<div>
<small className="text-muted">
{t(
"If you list voters' emails, only them will be able to access the election",
"If you list voters' emails, only them will be able to access the election"
)}
</small>
</div>
@ -612,27 +679,28 @@ class CreateElection extends Component {
{check.ok ? (
<ButtonWithConfirm
className="btn btn-success float-right btn-block"
tabIndex={candidates.length + 4}>
tabIndex={candidates.length + 4}
>
<div key="button">
<FontAwesomeIcon icon={faCheck} className="mr-2" />
{t('Validate')}
{t("Validate")}
</div>
<div key="modal-title">{t('Confirm your vote')}</div>
<div key="modal-title">{t("Confirm your vote")}</div>
<div key="modal-body">
<div className="mt-1 mb-1">
<div className="text-white bg-primary p-1">
{t('Question of the election')}
{t("Question of the election")}
</div>
<div className="p-1 pl-3">
<em>{title}</em>
</div>
<div className="text-white bg-primary p-1">
{t('Candidates/Proposals')}
{t("Candidates/Proposals")}
</div>
<div className="p-1 pl-0">
<ul className="m-0 pl-4">
{candidates.map((candidate, i) => {
if (candidate.label !== '') {
if (candidate.label !== "") {
return (
<li key={i} className="m-0">
{candidate.label}
@ -645,22 +713,22 @@ class CreateElection extends Component {
</ul>
</div>
<div className="text-white bg-primary p-1 mt-1">
{t('Dates')}
{t("Dates")}
</div>
<p className="p-1 pl-3">
{t('The election will take place from')}{' '}
{t("The election will take place from")}{" "}
<b>
{start.toLocaleDateString()}, {t('at')}{' '}
{start.toLocaleDateString()}, {t("at")}{" "}
{start.toLocaleTimeString()}
</b>{' '}
{t('to')}{' '}
</b>{" "}
{t("to")}{" "}
<b>
{finish.toLocaleDateString()}, {t('at')}{' '}
{finish.toLocaleDateString()}, {t("at")}{" "}
{finish.toLocaleTimeString()}
</b>
</p>
<div className="text-white bg-primary p-1">
{t('Grades')}
{t("Grades")}
</div>
<div className="p-1 pl-3">
{grades.map((mention, i) => {
@ -670,8 +738,9 @@ class CreateElection extends Component {
className="badge badge-light mr-2 mt-2"
style={{
backgroundColor: mention.color,
color: '#fff',
}}>
color: "#fff"
}}
>
{mention.label}
</span>
) : (
@ -684,33 +753,63 @@ class CreateElection extends Component {
</div>
<div className="p-1 pl-3">
{electorEmails.length > 0 ? (
electorEmails.join(', ')
electorEmails.join(", ")
) : (
<p>
{t('The form contains no address.')}
{t("The form contains no address.")}
<br />
<em>
{t(
'The election will be opened to anyone with the link',
"The election will be opened to anyone with the link"
)}
</em>
</p>
)}
</div>
{this.state.restrictResult ? (
<div>
<div className=" bg-danger text-white p-2 mt-2">
<h5 className="m-0 p-0">
<FontAwesomeIcon
icon={faExclamationTriangle}
className="mr-2"
/>
<u>{t("Accès aux résultats")}</u>
</h5>
<p className="m-2 p-0">
{electorEmails.length > 0 ? (
<span>
{t(
"The results page will not be accessible until all participants have voted."
)}
</span>
) : <span>
{t(
"The results page will not be accessible until the end date is reached."
)}{" "}
({finish.toLocaleDateString()} {t("at")}{" "}
{finish.toLocaleTimeString()})
</span>}
</p>
</div>
</div>
) : null}
</div>
</div>
<div key="modal-confirm" onClick={this.handleSubmit}>
{t('Start the election')}
{t("Start the election")}
</div>
<div key="modal-cancel">{t('Cancel')}</div>
<div key="modal-cancel">{t("Cancel")}</div>
</ButtonWithConfirm>
) : (
<Button
type="button"
className="btn btn-dark float-right btn-block"
onClick={this.handleSendWithoutCandidate}>
onClick={this.handleSendWithoutCandidate}
>
<FontAwesomeIcon icon={faCheck} className="mr-2" />
{t('Confirm')}
{t("Confirm")}
</Button>
)}
</Col>

@ -154,6 +154,10 @@ li.sortable {
border-radius: 50%;
}
.checkround.checkround-gray{
border-color: $gray-600;
}
/* When the radio button is checked, add a blue background */
.radio input:checked ~ .checkround {
background-color: #fff;
@ -181,6 +185,10 @@ li.sortable {
background: $mv-blue-color;
}
/*.radio .checkround.checkround-gray:after {
background: $gray-600;
}*/
/* The check */
.check {
display: block;

Loading…
Cancel
Save