import React, { Component } from "react"; import { Redirect } from "react-router-dom"; import { Collapse, Container, Row, Col, Input, Label, InputGroup, InputGroupAddon, Button, Card, CardBody } from "reactstrap"; import { toast, ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import { resolve } from "url"; import HelpButton from "../form/HelpButton"; import { arrayMove, sortableContainer, sortableElement, sortableHandle } from "react-sortable-hoc"; import ButtonWithConfirm from "../form/ButtonWithConfirm"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlus, faTrashAlt, faCheck, faCogs } from "@fortawesome/free-solid-svg-icons"; import { grades } from "../../Util"; import { ReactMultiEmail, isEmail } from "react-multi-email"; import "react-multi-email/style.css"; import { AppContext } from "../../AppContext"; const DragHandle = sortableHandle(({ children }) => ( {children} )); const SortableCandidate = sortableElement(({ candidate, sortIndex, form }) => (
  • {sortIndex + 1} form.editCandidateLabel(event, sortIndex)} onKeyPress={event => form.handleKeypressOnCandidateLabel(event, sortIndex) } placeholder="Nom du candidat ou de la proposition ..." tabIndex={sortIndex + 1} innerRef={ref => (form.candidateInputs[sortIndex] = ref)} maxLength="250" />
    Suppression ?
    Êtes-vous sûr de vouloir supprimer{" "} {candidate.label !== "" ? ( "{candidate.label}" ) : ( la ligne {sortIndex + 1} )}{" "} ?
    form.removeCandidate(sortIndex)} > Oui
    Non
    Saisissez ici le nom de votre candidat ou de votre proposition (250 caractères max.)
  • )); const SortableCandidatesContainer = sortableContainer(({ items, form }) => { return ( ); }); class CreateElection extends Component { static contextType = AppContext; constructor(props) { super(props); //default value : start now const startedAt = new Date(); const startedHour = startedAt.getHours(); //default value : finish in one week const finishedAt = new Date(startedAt.getTime() + 7 * 24 * 60 * 60 * 1000); const params = new URLSearchParams(window.location.search); this.state = { candidates: [{ label: "" }, { label: "" }], numCandidatesWithLabel: 0, title: params.get("title") ? params.get("title") : "", isVisibleTipsDragAndDropCandidate: true, numGrades: 7, successCreate: false, redirectTo: null, isAdvancedOptionsOpen: false, startedDayAt: startedAt.toISOString().substring(0, 10), finishedDayAt: finishedAt.toISOString().substring(0, 10), startedTimeAt: Math.floor(startedHour / 2) * 2 + ":00:00", finishedTimeAt: "23:59:59", electorEmails: [] }; this.candidateInputs = []; this.focusInput = React.createRef(); this.handleSubmit = this.handleSubmit.bind(this); } handleChangeTitle = event => { this.setState({ title: event.target.value }); }; addCandidate = event => { let candidates = this.state.candidates; if (candidates.length < 100) { candidates.push({ label: "" }); this.setState({ candidates: candidates }); } if (event.type === "keypress") { setTimeout(() => { this.candidateInputs[this.state.candidates.length - 1].focus(); }, 250); } }; removeCandidate = index => { let candidates = this.state.candidates; candidates.splice(index, 1); if (candidates.length === 0) { candidates = [{ label: "" }]; } this.setState({ candidates: candidates }); }; editCandidateLabel = (event, index) => { let candidates = this.state.candidates; let numLabels = 0; candidates[index].label = event.currentTarget.value; candidates.map((candidate, i) => { if (candidate.label !== "") { numLabels++; } return candidate.label; }); this.setState({ candidates: candidates, numCandidatesWithLabel: numLabels }); }; handleKeypressOnCandidateLabel = (event, index) => { if (event.key === "Enter") { event.preventDefault(); if (index + 1 === this.state.candidates.length) { this.addCandidate(event); } else { this.candidateInputs[index + 1].focus(); } } }; onCandidatesSortEnd = ({ oldIndex, newIndex }) => { let candidates = this.state.candidates; candidates = arrayMove(candidates, oldIndex, newIndex); this.setState({ candidates: candidates }); }; handleChangeNumGrades = event => { this.setState({ numGrades: event.target.value }); }; toggleAdvancedOptions = () => { this.setState({ isAdvancedOptionsOpen: !this.state.isAdvancedOptionsOpen }); }; handleSubmit() { const { candidates, title, numGrades } = this.state; const endpoint = resolve( this.context.urlServer, this.context.routesServer.setElection ); fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title: title, candidates: candidates.map(c => c.label), on_invitation_only: this.state.electorEmails.length > 0, num_grades: numGrades, elector_emails: this.state.electorEmails, started_at: this.state.startedDayAt + " " + this.state.startedTimeAt, finished_at: this.state.finishedDayAt + " " + this.state.finishedTimeAt, time_offset: new Date().getTimezoneOffset() }) }) .then(response => response.json()) .then(result => this.setState(state => ({ redirectTo: "/create-success/" + result.id, successCreate: true })) ) .catch(error => error); } handleSendWithoutCandidate = () => { toast.error("Vous devez saisir au moins deux candidats !", { position: toast.POSITION.TOP_CENTER }); }; formatDate = (dateIsoStr, timeIsoStr) => { let date = new Date(dateIsoStr + "T" + timeIsoStr); let day = date.getDate(); let month = date.getMonth() + 1; //Months are zero based let year = date.getFullYear(); let hours = date.getHours(); let minutes = date.getMinutes(); if (month < 10) { month = "0" + month; } if (day < 10) { day = "0" + day; } if (hours < 10) { hours = "0" + hours; } if (minutes < 10) { minutes = "0" + minutes; } let hoursString = hours + "h" + minutes; if (hoursString === "23h59") { hoursString = "minuit"; } return day + "/" + month + "/" + year + " à " + hoursString; }; render() { const { successCreate, redirectTo } = this.state; const { electorEmails } = this.state; if (successCreate) return ; return (

    Démarrer un vote


    Posez ici votre question ou introduisez simplement votre vote (250 caractères max.)
    Par exemple :{" "} Pour être mon représentant, je juge ce candidat ...
    this.setState({ startedDayAt: e.target.value }) } />
    this.setState({ finishedDayAt: e.target.value }) } />
    Vous pouvez choisir ici le nombre de mentions pour votre vote
    Par exemple : {" "} {" "} 5 = Excellent, Très bien, bien, assez bien, passable
    {grades.map((mention, i) => { return ( {mention.label} ); })}

    { this.setState({ electorEmails: _emails }); }} validateEmail={email => { return isEmail(email); // return boolean }} getLabel={( email: string, index: number, removeEmail: (index: number) => void ) => { return (
    {email} removeEmail(index)} > ×
    ); }} />
    Liste des e-mails à préciser si vous désirez réaliser un vote fermé.

    {this.state.numCandidatesWithLabel >= 2 ? (
    Valider
    Confirmez votre vote
    Question du vote
    {this.state.title}
    Candidats/Propositions
      {this.state.candidates.map((candidate, i) => { if (candidate.label !== "") { return (
    • {candidate.label}
    • ); } else { return
    • ; } })}
    Dates

    Le vote se déroulera du{" "} {this.formatDate( this.state.startedDayAt, this.state.startedTimeAt )} {" "} au{" "} {this.formatDate( this.state.finishedDayAt, this.state.finishedTimeAt )}

    Mentions
    {grades.map((mention, i) => { return i < this.state.numGrades ? ( {mention.label} ) : ( ); })}
    Liste des électeurs
    {electorEmails.length > 0 ? ( electorEmails.join(", ") ) : (

    Aucune adresse e-mail précisée.
    Le vote sera ouvert à tous les utilisateurs ayant le lien du vote

    )}
    Lancer le vote
    Annuler
    ) : ( )}
    ); } } export default CreateElection;