parent
4c2759d8c9
commit
f11ee7b535
@ -0,0 +1,166 @@
|
||||
import React from 'react';
|
||||
import plotly from 'plotly.js/dist/plotly';
|
||||
import createPlotComponent from 'react-plotly.js/factory';
|
||||
import LoadingScreen from "./LoadingScreen";
|
||||
|
||||
function Bulles (props) {
|
||||
|
||||
// récupération des résultats de l'élection et stockage en tableau
|
||||
const votesBrut = (Object.values(props))[0];
|
||||
|
||||
// déclaration et initialisation des mentions et couleurs
|
||||
const mentionsBrut = ['Passable', 'Assez bien', 'Bien', 'Très bien', 'Excellent'];
|
||||
const couleursBrut = ['#BB9C42', '#AABA44', '#DCDF44', '#B3D849', '#61AD45'];
|
||||
|
||||
//----------- Traitement des données -----------//
|
||||
|
||||
// fonction d'inversement des éléments de tableau
|
||||
function inverse(obj){
|
||||
var retobj = {};
|
||||
for(var key in obj){
|
||||
retobj[obj[key]] = key;
|
||||
}
|
||||
return retobj;
|
||||
}
|
||||
|
||||
// fonction de réduction d'amplitude permettant de conserver une représentation ordinale du nombre de votes sans décalage visuel trop important
|
||||
/*
|
||||
Pattern de calcul :
|
||||
|
||||
Soient Ai, Bi, Ci, Di, Ei les nombres de votes initiaux fournis dans le tableau classé par ordre mélioratif de mention (de Passable à Excellent). Il vient :
|
||||
A = 1
|
||||
B = <{[1 + (Bi/Ai)] / 40} * A>
|
||||
C = <{[1 + (Ci/Bi)] / 40} * B>
|
||||
D = <{[1 + (Di/Ci)] / 40} * C>
|
||||
E = <{[1 + (Ei/Di)] / 40} * D>
|
||||
*/
|
||||
function redAmpli(tab) {
|
||||
var nvTab = [];
|
||||
nvTab[0] = 100;
|
||||
|
||||
for(i = 1; i < tab.length; i++) {
|
||||
nvTab[i] = ( (1 + ((tab[i]/tab[(i-1)]) / 40 ) ) * nvTab[(i-1)]);
|
||||
}
|
||||
return nvTab;
|
||||
}
|
||||
|
||||
|
||||
// déclaration de l'objet votes-mention et votes-couleur
|
||||
var votesMentionNonOrdonnes = {};
|
||||
var votesCouleurNonOrdonnes = {};
|
||||
|
||||
// initialisation votes-mention ordonnés croissants
|
||||
for (var i = 0; i < mentionsBrut.length; i++) {
|
||||
votesMentionNonOrdonnes[votesBrut[i]] = mentionsBrut[i];
|
||||
votesCouleurNonOrdonnes[votesBrut[i]] = couleursBrut[i];
|
||||
}
|
||||
|
||||
// déclaration des mentions-votes par ordre croissant
|
||||
var votesMentionOrdonnes = inverse(votesMentionNonOrdonnes);
|
||||
var votesCouleurOrdonnes = inverse(votesCouleurNonOrdonnes);
|
||||
|
||||
// vérification du nombre de votes classés par ordre croissant et passés initialement en propriétés au composant
|
||||
console.log("Les données transmises au composant concernant le nombre de votes par mention sont : ");
|
||||
console.log(votesBrut);
|
||||
|
||||
// vérification des mentions destinées à être associées aux votes et ordonnées initialement par ordre mélioratif
|
||||
console.log("Les mentions des votes sont classées initialement par ordre mélioratif de la façon suivante :");
|
||||
console.log(mentionsBrut);
|
||||
|
||||
// vérification du nombre de votes classés par ordre croissant
|
||||
console.log("Les mentions-votes classées par ordre croissant de votes sont : ");
|
||||
console.log(votesMentionOrdonnes);
|
||||
|
||||
// séparation des mentions et des votes
|
||||
const mentions = Object.keys(votesMentionOrdonnes);
|
||||
const votes = Object.values(votesMentionOrdonnes);
|
||||
const couleurs = Object.keys(votesCouleurOrdonnes);
|
||||
|
||||
// vérification des mentions et des votes prêts à être traités pour la représentation graphique
|
||||
console.log('La liste des mentions issue du classement par ordre croissant de votes est :');
|
||||
console.log(mentions);
|
||||
console.log('La liste du nombre de votes correspondant, classée par ordre croissant, est :');
|
||||
console.log(votes);
|
||||
|
||||
// déclaration et initialisation des rayons de bulle pour la représentation graphique
|
||||
var rayons = [];
|
||||
rayons = redAmpli(votes)
|
||||
|
||||
// vérification des rayons
|
||||
console.log('La liste des rayons à représenter graphiquement est la suivante :');
|
||||
console.log(rayons);
|
||||
|
||||
// déclaration et initialisation des textes des bulles
|
||||
const texteBulle1 = (mentions[0] + "<br>" + votes[0] + " votes").toString();
|
||||
const texteBulle2 = (mentions[1] + "<br>" + votes[1] + " votes").toString();
|
||||
const texteBulle3 = (mentions[2] + "<br>" + votes[2] + " votes").toString();
|
||||
const texteBulle4 = (mentions[3] + "<br>" + votes[3] + " votes").toString();
|
||||
const texteBulle5 = (mentions[4] + "<br>" + votes[4] + " votes").toString();
|
||||
|
||||
// déclaration et initialisation d'une instance de graphique en bulles
|
||||
// const Plot = createPlotComponent(plotly);
|
||||
const Plot = require('react-plotly.js').default;
|
||||
|
||||
//---------------------------------------------//
|
||||
|
||||
|
||||
|
||||
//----------- Affichage des données -----------//
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
React.useEffect(() =>{
|
||||
setTimeout(() => setLoading(false), 3000);
|
||||
})
|
||||
return (
|
||||
|
||||
// <div>
|
||||
// {!loading ? (
|
||||
// <React.Fragment>
|
||||
<Plot
|
||||
data={[
|
||||
{
|
||||
x: [0.7, 0.6, 0.5, 0.6, 0.7],
|
||||
y: [0.3, 0.4, 0.5, 0.6, 0.5],
|
||||
hovertemplate:
|
||||
'<b>%{text}</b>' +
|
||||
'<extra></extra>',
|
||||
text: [texteBulle1, texteBulle2, texteBulle3, texteBulle4, texteBulle5],
|
||||
showlegend: false,
|
||||
mode: 'markers',
|
||||
marker: {
|
||||
color: [couleurs[0], couleurs[1], couleurs[2], couleurs[3], couleurs[4]],
|
||||
size: rayons
|
||||
}
|
||||
}
|
||||
]}
|
||||
layout={ {
|
||||
width: 600,
|
||||
height: 600,
|
||||
title: 'Nombre de voix par candidat',
|
||||
xaxis: {
|
||||
showgrid: false,
|
||||
showticklabels: false,
|
||||
showline: false,
|
||||
zeroline: false,
|
||||
range: [0, 1]
|
||||
},
|
||||
yaxis: {
|
||||
showgrid: false,
|
||||
showticklabels: false,
|
||||
showline: false,
|
||||
zeroline: false,
|
||||
range: [0, 1]
|
||||
}
|
||||
} }
|
||||
config={{
|
||||
displayModeBar: false // this is the line that hides the bar.
|
||||
}}
|
||||
/>
|
||||
// </React.Fragment>
|
||||
// ) : (
|
||||
// <LoadingScreen />
|
||||
// )}
|
||||
// </div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Bulles;
|
@ -0,0 +1,41 @@
|
||||
import * as React from "react";
|
||||
import * as d3 from "d3";
|
||||
|
||||
function drawChart(svgRef: React.RefObject<SVGSVGElement>) {
|
||||
const data = [12, 5, 6, 6, 9, 10];
|
||||
const h = 120;
|
||||
const w = 250;
|
||||
const svg = d3.select(svgRef.current);
|
||||
|
||||
svg
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
.style("margin-top", 50)
|
||||
.style("margin-left", 50);
|
||||
|
||||
svg
|
||||
.selectAll("rect")
|
||||
.data(data)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 40)
|
||||
.attr("y", (d, i) => h - 10 * d)
|
||||
.attr("width", 20)
|
||||
.attr("height", (d, i) => d * 10)
|
||||
.attr("fill", "steelblue");
|
||||
}
|
||||
|
||||
const Chart: React.FunctionComponent = () => {
|
||||
const svg = React.useRef<SVGSVGElement>(null);
|
||||
React.useEffect(() => {
|
||||
drawChart(svg);
|
||||
}, [svg]);
|
||||
|
||||
return (
|
||||
<div id="chart">
|
||||
<svg ref={svg} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Chart;
|
@ -0,0 +1,21 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import D3Chart from './D3Chart';
|
||||
|
||||
const ChartWrapper = () => {
|
||||
|
||||
const chartArea = useRef(null);
|
||||
const [chart, setChart] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chart) {
|
||||
setChart(new D3Chart(chartArea.current));
|
||||
}
|
||||
}, [chart]);
|
||||
|
||||
return (
|
||||
<div ref={chartArea}></div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default ChartWrapper;
|
@ -0,0 +1,38 @@
|
||||
import * as d3 from 'd3';
|
||||
|
||||
const url = "https://udemy-react-d3.firebaseio.com/tallest_men.json";
|
||||
|
||||
const WIDTH = 800;
|
||||
const HEIGHT = 500;
|
||||
|
||||
export default class D3Chart {
|
||||
constructor(element) {
|
||||
const svg = d3.select(element)
|
||||
.append("svg")
|
||||
.attr("width", 800)
|
||||
.attr("height", 500)
|
||||
|
||||
d3.json(url).then(data => {
|
||||
const max = d3.max(data, d => d.height)
|
||||
const y = d3.scaleLinear()
|
||||
.domain([0, max])
|
||||
.range([0, HEIGHT])
|
||||
|
||||
const x = d3.scaleBand()
|
||||
.domain(data.map(d => d.name))
|
||||
.range([0, WIDTH])
|
||||
.padding(0.4)
|
||||
|
||||
const rects = svg.selectAll("rect")
|
||||
.data(data)
|
||||
|
||||
rects.enter()
|
||||
.append("rect")
|
||||
.attr("x", d => x(d.name))
|
||||
.attr("y", d => HEIGHT - y(d.height))
|
||||
.attr("width", x.bandwidth)
|
||||
.attr("height", d => y(d.height))
|
||||
.attr("fill", "grey")
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
import React from "react"
|
||||
import styled from "styled-components"
|
||||
|
||||
const Screen = styled.div`
|
||||
position: relative;
|
||||
|
||||
opacity: 0;
|
||||
animation: fade 0.4s ease-in forwards;
|
||||
background: black;
|
||||
|
||||
@keyframes fade {
|
||||
0% {
|
||||
opacity: 0.4;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Balls = styled.div`
|
||||
display: flex;
|
||||
|
||||
|
||||
.ball {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
background: red;
|
||||
margin: 0 6px 0 0;
|
||||
animation: oscillate 0.7s ease-in forwards infinite;
|
||||
}
|
||||
|
||||
.one {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
.two {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
.three {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
@keyframes oscillate {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(20px);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
|
||||
const LoadingScreen = () => {
|
||||
return (
|
||||
<Screen>
|
||||
<Balls>
|
||||
|
||||
<div className="ball one"></div>
|
||||
<div className="ball two"></div>
|
||||
<div className="ball three"></div>
|
||||
</Balls>
|
||||
</Screen>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoadingScreen;
|
@ -0,0 +1,62 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Modal = ({ show, onClose, children, title }) => {
|
||||
|
||||
const handleCloseClick = (e) => {
|
||||
e.preventDefault();
|
||||
onClose();
|
||||
};
|
||||
|
||||
const modalContent = show ? (
|
||||
<StyledModalOverlay>
|
||||
<StyledModal>
|
||||
<StyledModalHeader>
|
||||
<a href="#" onClick={handleCloseClick}>
|
||||
x
|
||||
</a>
|
||||
</StyledModalHeader>
|
||||
{title && <StyledModalTitle>{title}</StyledModalTitle>}
|
||||
<StyledModalBody>{children}</StyledModalBody>
|
||||
</StyledModal>
|
||||
</StyledModalOverlay>
|
||||
) : null;
|
||||
|
||||
|
||||
return (
|
||||
modalContent
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
const StyledModalBody = styled.div`
|
||||
padding-top: 10px;
|
||||
`;
|
||||
|
||||
const StyledModalHeader = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
font-size: 25px;
|
||||
`;
|
||||
|
||||
const StyledModal = styled.div`
|
||||
background: white;
|
||||
width: 500px;
|
||||
height: 600px;
|
||||
border-radius: 15px;
|
||||
padding: 15px;
|
||||
`;
|
||||
const StyledModalOverlay = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
`;
|
||||
|
||||
export default Modal;
|
@ -0,0 +1,37 @@
|
||||
import React, {Fragment} from 'react';
|
||||
import Head from 'next/head';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
|
||||
const Bulles = dynamic(import('./Bulles'), {
|
||||
ssr: false
|
||||
})
|
||||
|
||||
const nbVotesPassables = 15;
|
||||
const nbVotesAssezBien = 200;
|
||||
const nbVotesBien = 389;
|
||||
const nbVotesTresBien = 12;
|
||||
const nbVotesExcellent = 2;
|
||||
|
||||
const resultats = [nbVotesPassables, nbVotesAssezBien, nbVotesBien, nbVotesTresBien, nbVotesExcellent];
|
||||
|
||||
var totalVotes = 0;
|
||||
|
||||
for(var i = 0; i < resultats.length; i++) {
|
||||
totalVotes += resultats[i];
|
||||
}
|
||||
|
||||
function SystemeVote() {
|
||||
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
<Bulles donnees={resultats} />
|
||||
<p style={{color: '#000000'}}>Le total des votes est de {totalVotes}.</p>
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default SystemeVote;
|
@ -0,0 +1,43 @@
|
||||
import {useTranslation} from "next-i18next";
|
||||
import {useRouter} from "next/router"
|
||||
import {faPaypal} from "@fortawesome/free-brands-svg-icons";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
|
||||
const PaypalNoLogo = () => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
// FIXME generate a xx_XX string for locale version
|
||||
const {locale} = useRouter();
|
||||
let localeShort = locale.substring(0, 2);
|
||||
let localeComplete =
|
||||
localeShort.toLowerCase() + "_" + localeShort.toUpperCase();
|
||||
if (localeComplete === "en_EN") {
|
||||
localeComplete = "en_US";
|
||||
}
|
||||
const pixelLink =
|
||||
`https://www.paypal.com/${localeComplete}/i/scr/pixel.gif`;
|
||||
|
||||
return (
|
||||
<div className="d-inline-block m-auto">
|
||||
<form
|
||||
action="https://www.paypal.com/cgi-bin/webscr"
|
||||
method="post"
|
||||
target="_top"
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
className="addButton"
|
||||
title={t("PayPal - The safer, easier way to pay online!")}
|
||||
>
|
||||
{t("Support us !")}
|
||||
<img src="/arrow-blue.svg" className="mr-2" />
|
||||
</button>
|
||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||
<input type="hidden" name="hosted_button_id" value="KB2Z7L9KARS7C" />
|
||||
<img alt="" border="0" src={pixelLink} width="1" height="1" />
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaypalNoLogo;
|
@ -0,0 +1,29 @@
|
||||
/* eslint react/prop-types: 0 */
|
||||
import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faFacebookSquare } from "@fortawesome/free-brands-svg-icons";
|
||||
|
||||
const Twitter = props => {
|
||||
const handleClick = () => {
|
||||
const url =
|
||||
"https://twitter.com/intent/tweet?text=" +
|
||||
|
||||
props.title +
|
||||
"&t=" +
|
||||
props.url;
|
||||
window.open(
|
||||
url,
|
||||
"",
|
||||
"menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=500,width=700"
|
||||
);
|
||||
};
|
||||
return (
|
||||
|
||||
<img src="/twitter.svg" onClick={handleClick} className="cursorPointer mr-2" />
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default Twitter;
|
||||
|
||||
//i
|
@ -0,0 +1,37 @@
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
|
||||
export default function AddPicture(props) {
|
||||
const [image, setImage] = useState(null);
|
||||
const [createObjectURL, setCreateObjectURL] = useState(null);
|
||||
|
||||
const uploadToClient = (event) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
const i = event.target.files[0];
|
||||
|
||||
setImage(i);
|
||||
setCreateObjectURL(URL.createObjectURL(i));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ajout-avatar">
|
||||
<div>
|
||||
<div className="avatar-placeholer">
|
||||
<img src={createObjectURL} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="avatar-text">
|
||||
<h4>Photo <span> (facultatif)</span></h4>
|
||||
|
||||
<p>Importer une photo.<br />format : jpg, png, pdf</p>
|
||||
<div className="btn-ajout-avatar">
|
||||
<input type="file" name="myImage" id="myImage" onChange={uploadToClient} />
|
||||
<label className="inputfile" for="myImage">Importer une photo</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { useState } from 'react'
|
||||
import { Alert, Button } from 'react-bootstrap';
|
||||
import { faTimes, faExclamationCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
export default function AlertDismissibleExample() {
|
||||
const [show, setShow] = useState(true);
|
||||
|
||||
if (show) {
|
||||
return (
|
||||
<Alert className="preventWarning">
|
||||
<Alert.Heading>
|
||||
<div>
|
||||
<FontAwesomeIcon icon={faExclamationCircle} className="mr-2" />
|
||||
<span>2 candidats minimum</span>
|
||||
</div>
|
||||
<FontAwesomeIcon onClick={() => setShow(false)} icon={faTimes} className="mr-2" />
|
||||
</Alert.Heading>
|
||||
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,160 +1,195 @@
|
||||
import {useTranslation} from "next-i18next";
|
||||
import {useState} from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useState } from "react";
|
||||
import TrashButton from "./TrashButton";
|
||||
import {
|
||||
faExclamationTriangle,
|
||||
faCheck,
|
||||
faArrowLeft,
|
||||
faTrashAlt
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import {Button, Modal, ModalHeader, ModalBody, ModalFooter} from "reactstrap";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Row, Col } from "reactstrap";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
const ConfirmModal = ({tabIndex, title, candidates, grades, isTimeLimited, start, finish, emails, restrictResult, className, confirmCallback}) => {
|
||||
const ConfirmModal = ({ tabIndex, title, candidates, grades, isTimeLimited, start, finish, emails, restrictResult, className, confirmCallback }) => {
|
||||
const [visibled, setVisibility] = useState(false);
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
const toggle = () => setVisibility(!visibled)
|
||||
|
||||
return (
|
||||
<div className="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
className={className}
|
||||
onClick={toggle}
|
||||
tabIndex={tabIndex}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCheck} className="mr-2" />
|
||||
{t("Validate")}
|
||||
</button>
|
||||
<Button onClick={toggle}
|
||||
tabIndex={tabIndex} className={"mt-5 componentDesktop btn-transparent cursorPointer btn-validation mb-5 mx-auto" + className} >{t("Confirm")}<img src="/arrow-white.svg" /></Button>
|
||||
<Button
|
||||
|
||||
className={"componentMobile btn-confirm-mobile mb-5" + className}
|
||||
onClick={toggle}
|
||||
tabIndex={tabIndex}>
|
||||
<FontAwesomeIcon className="mr-2" icon={faCheck} />
|
||||
{t("Valider")}
|
||||
</Button>
|
||||
|
||||
<Modal
|
||||
isOpen={visibled}
|
||||
isOpen={!visibled}
|
||||
toggle={toggle}
|
||||
className="modal-dialog-centered"
|
||||
className="modal-dialog-centered settings-modal"
|
||||
>
|
||||
<ModalHeader toggle={toggle}>
|
||||
{t("Confirm your vote")}
|
||||
<ModalHeader className="modal-header-settings">
|
||||
<div onClick={toggle} className="btn-return-candidates"><FontAwesomeIcon icon={faArrowLeft} className="mr-2" />Retour aux paramètres</div>
|
||||
<Row>
|
||||
<Row className="stepForm">
|
||||
<Col className="stepFormCol">
|
||||
<img src="/icone-check-dark.svg" />
|
||||
<h4>Les candidats</h4>
|
||||
</Col>
|
||||
<Col className="stepFormCol">
|
||||
<img src="/icone-check-dark.svg" />
|
||||
<h4>Paramètres du vote</h4>
|
||||
</Col>
|
||||
<Col className="stepFormCol">
|
||||
<img src="/icone-three-white.svg" />
|
||||
<h4>Confirmation</h4>
|
||||
</Col>
|
||||
</Row>
|
||||
</Row>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<div className="mt-1 mb-1">
|
||||
<div className="text-white bg-primary p-2 pl-3 pr-3 rounded">
|
||||
{t("Question of the election")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 bg-light mb-3">{title}</div>
|
||||
<div className="text-white bg-primary p-2 pl-3 pr-3 rounded">
|
||||
{t("Candidates/Proposals")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 bg-light mb-3">
|
||||
<ul className="m-0 pl-4">
|
||||
{candidates.map((candidate, i) => {
|
||||
if (candidate.label !== "") {
|
||||
return (
|
||||
<li key={i} className="m-0">
|
||||
{candidate.label}
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
return <li key={i} className="d-none" />;
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={(isTimeLimited ? "d-block " : "d-none")} >
|
||||
<div className="text-white bg-primary p-2 pl-3 pr-3 rounded">
|
||||
{t("Dates")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 bg-light mb-3">
|
||||
{t("The election will take place from")}{" "}
|
||||
<b>
|
||||
{start.toLocaleDateString()}, {t("at")}{" "}
|
||||
{start.toLocaleTimeString()}
|
||||
</b>{" "}
|
||||
{t("to")}{" "}
|
||||
<b>
|
||||
{finish.toLocaleDateString()}, {t("at")}{" "}
|
||||
{finish.toLocaleTimeString()}
|
||||
</b>
|
||||
<ModalBody className="confirm-modal-body">
|
||||
<Row>
|
||||
<Col md="4" className="p-0">
|
||||
<div className="text-light">{t("Le vote")}</div>
|
||||
<div className="mt-1 mb-1 recap-vote">
|
||||
<Row className="m-0">
|
||||
<div className="recap-vote-label">
|
||||
{t("Question of the election")}
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<div className="p-2 pl-3 pr-3 mb-3 recap-vote-question">{title}</div>
|
||||
</Row>
|
||||
<hr className="confirmation-divider"/>
|
||||
<Row>
|
||||
<div className="recap-vote-label p-2 pl-3 pr-3 ">
|
||||
{t("Candidates/Proposals")}
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<div className="p-2 pl-3 pr-3 mb-3 recap-vote-content">
|
||||
<ul className="m-0 pl-4">
|
||||
{candidates.map((candidate, i) => {
|
||||
if (candidate.label !== "") {
|
||||
return (
|
||||
<li key={i} className="m-0">
|
||||
{candidate.label}
|
||||
|
||||
</li>
|
||||
);
|
||||
} else {
|
||||
return <li key={i} className="d-none" />;
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-white bg-primary p-2 pl-3 pr-3 rounded">
|
||||
{t("Grades")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 bg-light mb-3">
|
||||
{grades.map((mention, i) => {
|
||||
return i < grades.length ? (
|
||||
<span
|
||||
key={i}
|
||||
className="badge badge-light mr-2 mt-2"
|
||||
style={{
|
||||
backgroundColor: mention.color,
|
||||
color: "#fff"
|
||||
}}
|
||||
>
|
||||
{mention.label}
|
||||
</span>
|
||||
) : (
|
||||
<span key={i} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="text-white bg-primary p-2 pl-3 pr-3 rounded">
|
||||
{t("Voters' list")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 bg-light mb-3">
|
||||
{emails.length > 0 ? (
|
||||
emails.join(", ")
|
||||
) : (
|
||||
<p>
|
||||
{t("The form contains no address.")}
|
||||
<br />
|
||||
<em>
|
||||
{t(
|
||||
"The election will be opened to anyone with the link"
|
||||
)}
|
||||
</em>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{restrictResult ? (
|
||||
<div>
|
||||
<div className="small bg-primary text-white p-3 mt-2 rounded">
|
||||
<h6 className="m-0 p-0">
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationTriangle}
|
||||
className="mr-2"
|
||||
/>
|
||||
<u>{t("Results available at the close of the vote")}</u>
|
||||
</h6>
|
||||
<p className="m-2 p-0">
|
||||
<span>
|
||||
{t(
|
||||
"The results page will not be accessible until the end date is reached."
|
||||
)}{" "}
|
||||
({finish.toLocaleDateString()} {t("at")}{" "}
|
||||
{finish.toLocaleTimeString()})
|
||||
</Col>
|
||||
<Col md="8">
|
||||
<div className="text-light">{t("Les paramètres")}</div>
|
||||
<div className="recap-vote">
|
||||
<div className={(isTimeLimited ? "d-block " : "d-none")} >
|
||||
<div className="p-2 pl-3 pr-3 recap-vote-label ">
|
||||
{t("Dates")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 recap-vote-content mb-3">
|
||||
{t("The election will take place from")}{" "}
|
||||
<b>
|
||||
{start.toLocaleDateString()}, {t("at")}{" "}
|
||||
{start.toLocaleTimeString()}
|
||||
</b>{" "}
|
||||
{t("to")}{" "}
|
||||
<b>
|
||||
{finish.toLocaleDateString()}, {t("at")}{" "}
|
||||
{finish.toLocaleTimeString()}
|
||||
</b>
|
||||
</div>
|
||||
</div>
|
||||
<hr className="confirmation-divider"/>
|
||||
<div className="recap-vote-label p-2 pl-3 pr-3">
|
||||
{t("Grades")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 recap-vote-content mb-3">
|
||||
{grades.map((mention, i) => {
|
||||
return i < grades.length ? (
|
||||
<span
|
||||
key={i}
|
||||
className="badge badge-light mr-2 mt-2"
|
||||
style={{
|
||||
backgroundColor: mention.color,
|
||||
color: "#fff"
|
||||
}}
|
||||
>
|
||||
{mention.label}
|
||||
</span>
|
||||
</p>
|
||||
) : (
|
||||
<span key={i} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className="small bg-primary text-white p-3 mt-2 rounded">
|
||||
<h6 className="m-0 p-0">
|
||||
{t("Results available at any time")}
|
||||
</h6>
|
||||
<hr className="confirmation-divider"/>
|
||||
<div className="recap-vote-label p-2 pl-3 pr-3 rounded">
|
||||
{t("Voters' list")}
|
||||
</div>
|
||||
<div className="p-2 pl-3 pr-3 recap-vote-content mb-3">
|
||||
{emails.length > 0 ? (
|
||||
emails.join(", ")
|
||||
) : (
|
||||
<p>
|
||||
{t("The form contains no address.")}
|
||||
<br />
|
||||
<em>
|
||||
{t(
|
||||
"The election will be opened to anyone with the link"
|
||||
)}
|
||||
</em>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<hr className="confirmation-divider"/>
|
||||
{restrictResult ? (
|
||||
<div>
|
||||
<div className="small recap-vote-label p-3 mt-2">
|
||||
<h6 className="m-0 p-0 recap-vote-content">
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationTriangle}
|
||||
className="mr-2"
|
||||
/>
|
||||
<u>{t("Results available at the close of the vote")}</u>
|
||||
</h6>
|
||||
<p className="m-2 p-0 ">
|
||||
<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>
|
||||
) : (
|
||||
<div>
|
||||
<div className="small recap-vote-label p-3 mt-2 ">
|
||||
<h6 className="m-0 p-0 recap-vote-content">
|
||||
{t("Results available at any time")}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||