diff --git a/components/Advantages.tsx b/components/Advantages.tsx
new file mode 100644
index 0000000..fe6e1c8
--- /dev/null
+++ b/components/Advantages.tsx
@@ -0,0 +1,48 @@
+import {useTranslation} from 'next-i18next';
+import Image from 'next/image';
+import {Row, Col} from 'reactstrap';
+import ballotBox from '../public/urne.svg';
+import email from '../public/email.svg';
+import respect from '../public/respect.svg';
+
+const AdvantagesRow = () => {
+ const {t} = useTranslation('resource');
+ const resources = [
+ {
+ src: ballotBox,
+ alt: t('home.alt-icon-ballot-box'),
+ name: t('home.advantage-1-name'),
+ desc: t('home.advantage-1-desc'),
+ },
+ {
+ src: email,
+ alt: t('home.alt-icon-envelop'),
+ name: t('home.advantage-2-name'),
+ desc: t('home.advantage-2-desc'),
+ },
+ {
+ src: respect,
+ alt: t('home.alt-icon-respect'),
+ name: t('home.advantage-3-name'),
+ desc: t('home.advantage-3-desc'),
+ },
+ ];
+ return (
+
+ {resources.map((item, i) => (
+
+
+ {item.name}
+ {item.desc}
+
+ ))}
+
+ );
+};
+
+export default AdvantagesRow
diff --git a/components/CandidateModal.tsx b/components/CandidateModal.tsx
new file mode 100644
index 0000000..f67b338
--- /dev/null
+++ b/components/CandidateModal.tsx
@@ -0,0 +1,165 @@
+/**
+ * A modal to details a candidate
+ */
+import {ElectionPayload} from '@services/api';
+import {
+ Button,
+ Col,
+ Container,
+ Row,
+ Modal,
+ ModalHeader,
+ ModalBody,
+} from 'reactstrap';
+
+interface CandidateModal {
+ isOpen: boolean;
+ toggle: Function;
+ election: ElectionPayload;
+}
+
+const CandidateModal = ({isOpen, toggle, election}) =>
+(
+ < Modal
+ isOpen={isOpen}
+ toggle={toggle}
+ keyboard={true}
+ className="modalVote voteDesktop"
+ >
+
+ {election.name}
+
+
+
+
+
+
diff --git a/components/Experience.tsx b/components/Experience.tsx
new file mode 100644
index 0000000..d3f6520
--- /dev/null
+++ b/components/Experience.tsx
@@ -0,0 +1,47 @@
+import {useTranslation} from 'next-i18next';
+import Image from 'next/image';
+import {Row, Col, Button} from 'reactstrap';
+import arrowRight from '../public/arrow-white.svg';
+import vote from '../public/vote.svg';
+
+
+const ExperienceRow = () => {
+ const {t} = useTranslation('resource');
+ return (
+
+
+
+
+
+ {t('home.experience-name')}
+
+
+
+ {t('home.experience-1-name')}
+ {t('home.experience-1-desc')}
+
+
+ {t('home.experience-2-name')}
+ {t('home.experience-2-desc')}
+
+
+
+
+
+
+ {t('home.experience-call-to-action')}
+
+
+
+
+
+ );
+};
+
+
+export default ExperienceRow
diff --git a/pages/admin/confirm/[pid].tsx b/pages/admin/confirm/[pid].tsx
deleted file mode 100644
index 62f3091..0000000
--- a/pages/admin/confirm/[pid].tsx
+++ /dev/null
@@ -1,247 +0,0 @@
-import { createRef } from 'react';
-import Head from 'next/head';
-import { useRouter } from 'next/router';
-import { useTranslation } from 'next-i18next';
-import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
-import {
- getElection,
- apiErrors,
- ELECTION_NOT_STARTED_ERROR,
-} from '@services/api';
-import { Col, Container, Row, Button } from 'reactstrap';
-import Link from 'next/link';
-import {
- faCopy,
- faVoteYea,
- faExclamationTriangle,
- faExternalLinkAlt,
- faPollH,
-} from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import CopyField from '@components/CopyField';
-import Error from '@components/Error';
-import Facebook from '@components/banner/Facebook';
-import Twitter from '@components/banner/Twitter';
-import config from '../../../next-i18next.config.js';
-import { AnimatePresence, motion } from 'framer-motion';
-export async function getServerSideProps({ query: { pid }, locale }) {
- let [details, translations] = await Promise.all([
- getElection(pid, console.log, console.log),
- serverSideTranslations(locale, [], config),
- ]);
-
- // if (details.includes(ELECTION_NOT_STARTED_ERROR)) {
- // details = { title: "", on_invitation_only: true, restrict_results: true };
- // } else {
- // if (typeof details === "string" || details instanceof String) {
- // return { props: { err: details, ...translations } };
- // }
-
- // if (!details.title) {
- // return { props: { err: "Unknown error", ...translations } };
- // }
- // }
-
- return {
- props: {
- invitationOnly: details.on_invitation_only,
- restrictResults: details.restrict_results,
- title: details.title,
- pid: pid,
- ...translations,
- },
- };
-}
-
-const ConfirmElection = ({
- title,
- restrictResults,
- invitationOnly,
- pid,
- err,
-}) => {
- const { t } = useTranslation();
-
- if (err) {
- return ;
- }
-
- const origin =
- typeof window !== 'undefined' && window.location.origin
- ? window.location.origin
- : 'http://localhost';
- const urlVote = new URL(`/vote/${pid}`, origin);
- const urlResult = new URL(`/result/${pid}`, origin);
-
- const electionLink = invitationOnly ? (
- <>
-
- {t(
- 'Voters received a link to vote by email. Each link can be used only once!'
- )}
-
- >
- ) : (
- <>
-
- >
- );
- const fb = invitationOnly ? null : (
-
- );
- const tw = invitationOnly ? null : (
-
- );
- const participate = invitationOnly ? null : (
- <>
-
-
-
-
- {t('resource.participateBtn')}
-
-
-
- >
- );
-
- return (
-
-
- {t('Successful election creation!')}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {t('Successful election creation!')}
-
-
-
-
-
-
-
-
-
-
-
-
- {/* {participate}
-
-
-
-
- {t("resource.resultsBtn")}
-
-
- */}
-
- {t('Administrez le vote')}
-
-
-
-
-
- {fb}
- {tw}
- {t('Partagez l’élection')}
-
-
-
-
- );
-};
-
-export default ConfirmElection;
diff --git a/pages/ballot/[pid]/[[...tid]].tsx b/pages/ballot/[pid]/[[...tid]].tsx
new file mode 100644
index 0000000..25a88ea
--- /dev/null
+++ b/pages/ballot/[pid]/[[...tid]].tsx
@@ -0,0 +1,321 @@
+import {useState, useCallback, useEffect, MouseEvent} from 'react';
+import Head from 'next/head';
+import {useRouter} from 'next/router';
+import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
+import {useTranslation} from 'next-i18next';
+import {
+ Button,
+ Col,
+ Container,
+ Row,
+} from 'reactstrap';
+// import {toast, ToastContainer} from "react-toastify";
+import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
+import {faCalendarDays, faCheck} from '@fortawesome/free-solid-svg-icons';
+import {getElection, castBallot, apiErrors, ElectionPayload} from '@services/api';
+import ErrorMessage from '@components/Error';
+import useEmblaCarousel from 'embla-carousel-react';
+import {DotButton} from '@components/admin/EmblaCarouselButtons';
+import VoteButtonWithConfirm from '@components/admin/VoteButtonWithConfirm';
+import {getGradeColor} from '@services/grades';
+
+const shuffle = (array) => array.sort(() => Math.random() - 0.5);
+
+export async function getServerSideProps({query: {pid, tid}, locale}) {
+ const [election, translations] = await Promise.all([
+ getElection(pid),
+ serverSideTranslations(locale, ['resource']),
+ ]);
+
+ if (typeof election === 'string' || election instanceof String) {
+ return {props: {err: election, ...translations}};
+ }
+
+ if (!election || !election.candidates || !Array.isArray(election.candidates)) {
+ return {props: {err: 'Unknown error', ...translations}};
+ }
+
+ const description = JSON.parse(election.description);
+
+ if (description.randomOrder) {
+ shuffle(election.candidates);
+ }
+
+ return {
+ props: {
+ ...translations,
+ election,
+ pid: pid,
+ token: tid || null,
+ },
+ };
+}
+
+interface VoteInterface {
+ election?: ElectionPayload;
+ err: string;
+ token?: string;
+}
+
+const VoteBallot = ({election, err, token}: VoteInterface) => {
+ const {t} = useTranslation();
+
+ if (err || !election) {
+ return ;
+ }
+
+ const numGrades = election.grades.length;
+ const [judgments, setJudgments] = useState([]);
+ const colSizeCandidateLg = 4;
+ const colSizeCandidateMd = 6;
+ const colSizeCandidateXs = 12;
+ const colSizeGradeLg = Math.floor((12 - colSizeCandidateLg) / numGrades);
+ const colSizeGradeMd = Math.floor((12 - colSizeCandidateMd) / numGrades);
+ const colSizeGradeXs = Math.floor((12 - colSizeCandidateXs) / numGrades);
+
+ const router = useRouter();
+
+ const handleGradeClick = (event: MouseEvent) => {
+ let data = {
+ id: parseInt(event.currentTarget.getAttribute('data-id')),
+ value: parseInt(event.currentTarget.value),
+ };
+ //remove candidate
+ const newJudgments = judgments.filter(
+ (judgment) => judgment.id !== data.id
+ );
+ newJudgments.push(data);
+ setJudgments(newJudgments);
+ };
+
+ const handleSubmitWithoutAllRate = () => {
+ alert(t('You have to judge every candidate/proposal!'));
+ };
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+
+ const gradesById = {};
+ judgments.forEach((c) => {
+ gradesById[c.id] = c.value;
+ });
+ const gradesByCandidate = [];
+ Object.keys(gradesById).forEach((id) => {
+ gradesByCandidate.push(gradesById[id]);
+ });
+
+ castBallot(gradesByCandidate, election.id.toString(), token, () => {
+ router.push(`/vote/${election.id}/confirm`);
+ });
+ };
+
+ const [viewportRef, embla] = useEmblaCarousel({skipSnaps: false});
+ const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
+ const [nextBtnEnabled, setNextBtnEnabled] = useState(false);
+ const [selectedIndex, setSelectedIndex] = useState(0);
+ const [scrollSnaps, setScrollSnaps] = useState([]);
+
+ const scrollPrev = useCallback(() => embla && embla.scrollPrev(), [embla]);
+ const scrollNext = useCallback(() => embla && embla.scrollNext(), [embla]);
+ const scrollTo = useCallback(
+ (index) => embla && embla.scrollTo(index),
+ [embla]
+ );
+
+ const onSelect = useCallback(() => {
+ if (!embla) return;
+ setSelectedIndex(embla.selectedScrollSnap());
+ setPrevBtnEnabled(embla.canScrollPrev());
+ setNextBtnEnabled(embla.canScrollNext());
+ }, [embla, setSelectedIndex]);
+
+ useEffect(() => {
+ if (!embla) return;
+ onSelect();
+ setScrollSnaps(embla.scrollSnapList());
+ embla.on('select', onSelect);
+ }, [embla, setScrollSnaps, onSelect]);
+
+ return (
+
+
+ {election.name}
+
+
+
+
+
+
+
+ VOTE OUVERT
+
+
+
+
+ {judgments.length !== election.candidates.length ? (
+
+ ) : (
+
+
+ {t('Submit my vote')}
+
+ )}
+
+
+
+ );
+};
+export default VoteBallot;
diff --git a/pages/ballot/[pid]/confirm.tsx b/pages/ballot/[pid]/confirm.tsx
new file mode 100644
index 0000000..efd35b5
--- /dev/null
+++ b/pages/ballot/[pid]/confirm.tsx
@@ -0,0 +1,192 @@
+import Head from 'next/head';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faChevronRight } from '@fortawesome/free-solid-svg-icons';
+import { Col, Container, Row, Button } from 'reactstrap';
+import Link from 'next/link';
+import { useTranslation } from 'next-i18next';
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+// import PaypalNoLogo from "@components/banner/PaypalNoLogo";
+import Gform from '@components/banner/Gform';
+import Error from '@components/Error';
+import { getElection, apiErrors } from '@services/api';
+import config from '../../../next-i18next.config.js';
+import { motion } from 'framer-motion';
+
+export async function getServerSideProps({ query: { pid }, locale }) {
+ const [details, translations] = await Promise.all([
+ getElection(pid),
+ serverSideTranslations(locale, [], config),
+ ]);
+
+ if (typeof details === 'string' || details instanceof String) {
+ return { props: { err: details.slice(1, -1), ...translations } };
+ }
+
+ if (!details.candidates || !Array.isArray(details.candidates)) {
+ return { props: { err: 'Unknown error', ...translations } };
+ }
+
+ return {
+ props: {
+ ...translations,
+ invitationOnly: details.on_invitation_only,
+ restrictResults: details.restrict_results,
+ candidates: details.candidates.map((name, i) => ({ id: i, label: name })),
+ title: details.title,
+ numGrades: details.num_grades,
+ pid: pid,
+ },
+ };
+}
+
+const VoteSuccess = ({ title, invitationOnly, pid, err }) => {
+ const { t } = useTranslation();
+ if (err && err !== '') {
+ return ;
+ }
+
+ return (
+
+
+ {t('resource.voteSuccess')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('resource.voteSuccess')}
+
+ {t('Voir les résultats')}
+
+
+
+ {t('Voir les résultats')}
+
+
+
+
+
+
+
+ {t('Découvrez le jugement majoritaire')}
+
+
+ {t(
+ 'créé par des chercheurs français, le jugement majoritaire est un mode de scrutin qui améliore l’expressivité des électeurs et fournit le meilleur consensus.'
+ )}
+
+
+
+ {t('En savoir plus')}
+
+
+
+
+
+
+
+ {t('Soutenez Mieux Voter')}
+
+
+
+
+
+
+ {t(
+ 'Mieux Voter est une association transpartisane et sans but lucratif. En adhérant à l’association, vous contribuez à financer son fonctionnement et ses activités. '
+ )}
+
+
+
+
+
+
+ {t('resource.thanks')}
+
+ {t('Aidez nous à améliorer l’application en cliquant ci-dessous')}
+
+
+
+
+
+
+
+
+
+
+
+ {t('Faites découvrir l’application a vos amis')}
+
+
+
+
+
+ );
+};
+export default VoteSuccess;
diff --git a/pages/index.tsx b/pages/index.tsx
index eeb04e3..62e9e88 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -7,11 +7,9 @@ import {useTranslation} from 'next-i18next';
import {Container, Row, Col, Button, Input} from 'reactstrap';
import Logo from '@components/Logo';
import Share from '@components/Share';
+import AdvantagesRow from '@components/Advantages'
+import ExperienceRow from '@components/Experience'
import {CREATE_ELECTION} from '@services/routes';
-import ballotBox from '../public/urne.svg';
-import email from '../public/email.svg';
-import respect from '../public/respect.svg';
-import vote from '../public/vote.svg';
import arrowRight from '../public/arrow-white.svg';
export const getStaticProps: GetStaticProps = async ({locale}) => ({
@@ -76,83 +74,6 @@ const StartForm = () => {
);
};
-const AdvantagesRow = () => {
- const {t} = useTranslation('resource');
- const resources = [
- {
- src: ballotBox,
- alt: t('home.alt-icon-ballot-box'),
- name: t('home.advantage-1-name'),
- desc: t('home.advantage-1-desc'),
- },
- {
- src: email,
- alt: t('home.alt-icon-envelop'),
- name: t('home.advantage-2-name'),
- desc: t('home.advantage-2-desc'),
- },
- {
- src: respect,
- alt: t('home.alt-icon-respect'),
- name: t('home.advantage-3-name'),
- desc: t('home.advantage-3-desc'),
- },
- ];
- return (
-
- {resources.map((item, i) => (
-
-
- {item.name}
- {item.desc}
-
- ))}
-
- );
-};
-
-const ExperienceRow = () => {
- const {t} = useTranslation('resource');
- return (
-
-
-
-
-
- {t('home.experience-name')}
-
-
-
- {t('home.experience-1-name')}
- {t('home.experience-1-desc')}
-
-
- {t('home.experience-2-name')}
- {t('home.experience-2-desc')}
-
-
-
-
-
-
- {t('home.experience-call-to-action')}
-
-
-
-
-
- );
-};
const Home = () => {
const {t} = useTranslation('resource');
diff --git a/pages/vote/[pid]/[[...tid]].tsx b/pages/vote/[pid]/[[...tid]].tsx
index fc0b32d..a9701a7 100644
--- a/pages/vote/[pid]/[[...tid]].tsx
+++ b/pages/vote/[pid]/[[...tid]].tsx
@@ -1,627 +1,97 @@
-import {useState, useCallback, useEffect} from 'react';
-import Head from 'next/head';
import {useRouter} from 'next/router';
import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
import {useTranslation} from 'next-i18next';
import {
- Button,
Col,
Container,
Row,
- Modal,
- ModalHeader,
- ModalBody,
} from 'reactstrap';
import Link from 'next/link';
-// import {toast, ToastContainer} from "react-toastify";
-import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
-import {faCheck} from '@fortawesome/free-solid-svg-icons';
-import {getElection, castBallot, apiErrors, ElectionPayload} from '@services/api';
-import ErrorMessage from '@components/Error';
import Footer from '@components/layouts/Footer';
-import useEmblaCarousel from 'embla-carousel-react';
-import {
- DotButton,
- PrevButton,
- NextButton,
-} from '@components/admin/EmblaCarouselButtons';
-import VoteButtonWithConfirm from '@components/admin/VoteButtonWithConfirm';
-import {getGradeColor} from '@services/grades';
+import ShareRow from '@components/Share';
+import Button from '@components/Button';
+import ExperienceRow from '@components/Experience';
+import AdvantagesRow from '@components/Advantages';
+import Logo from '@components/Logo';
+import {BALLOT} from '@services/routes';
+import {faArrowRight} from '@fortawesome/free-solid-svg-icons';
-const shuffle = (array) => array.sort(() => Math.random() - 0.5);
export async function getServerSideProps({query: {pid, tid}, locale}) {
- const [details, translations] = await Promise.all([
- getElection(pid),
- serverSideTranslations(locale, ['resource']),
- ]);
-
- if (typeof details === 'string' || details instanceof String) {
- return {props: {err: details, ...translations}};
- }
-
- if (!details.candidates || !Array.isArray(details.candidates)) {
- return {props: {err: 'Unknown error', ...translations}};
- }
-
- shuffle(details.candidates);
-
return {
props: {
- ...translations,
- invitationOnly: details.on_invitation_only,
- restrictResults: details.restrict_results,
- candidates: details.candidates.map((name, i, infos) => ({
- id: i,
- name: name,
- description: infos,
- })),
- title: details.title,
- numGrades: details.num_grades,
- pid: pid,
+ ...(await serverSideTranslations(locale, ['resource'])),
+ electionId: pid,
token: tid || null,
},
- };
+ }
}
interface VoteInterface {
- election: ElectionPayload;
- err: string;
+ electionId: string;
token?: string;
}
-const VoteBallot = ({election, err, token}: VoteInterface) => {
- const {t} = useTranslation();
-
- if (err) {
- return ;
- }
-
- const numGrades = election.grades.length;
- const [judgments, setJudgments] = useState([]);
- const colSizeCandidateLg = 4;
- const colSizeCandidateMd = 6;
- const colSizeCandidateXs = 12;
- const colSizeGradeLg = Math.floor((12 - colSizeCandidateLg) / numGrades);
- const colSizeGradeMd = Math.floor((12 - colSizeCandidateMd) / numGrades);
- const colSizeGradeXs = Math.floor((12 - colSizeCandidateXs) / numGrades);
-
- const router = useRouter();
-
- const handleGradeClick = (event) => {
- let data = {
- id: parseInt(event.currentTarget.getAttribute('data-id')),
- value: parseInt(event.currentTarget.value),
- };
- //remove candidate
- const newJudgments = judgments.filter(
- (judgment) => judgment.id !== data.id
- );
- newJudgments.push(data);
- setJudgments(newJudgments);
- };
-
- const handleSubmitWithoutAllRate = () => {
- alert(t('You have to judge every candidate/proposal!'));
- };
-
- const handleSubmit = (event) => {
- event.preventDefault();
- const gradesById = {};
- judgments.forEach((c) => {
- gradesById[c.id] = c.value;
- });
- const gradesByCandidate = [];
- Object.keys(gradesById).forEach((id) => {
- gradesByCandidate.push(gradesById[id]);
- });
+const GoToBallotConfirm = ({electionId, token}) => {
- castBallot(gradesByCandidate, election.id.toString(), token, () => {
- router.push(`/vote/${election.id}/confirm`);
- });
- };
- const toggle = () => setVisibility(!visibled);
- const [visibled, setVisibility] = useState(false);
- const toggleMobile = () => setVisibilityMobile(!visibledMobile);
- const [visibledMobile, setVisibilityMobile] = useState(false);
- const toggleDesktop = () => setVisibilityDesktop(!visibledDesktop);
- const [visibledDesktop, setVisibilityDesktop] = useState(false);
-
- const [viewportRef, embla] = useEmblaCarousel({skipSnaps: false});
- const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
- const [nextBtnEnabled, setNextBtnEnabled] = useState(false);
- const [selectedIndex, setSelectedIndex] = useState(0);
- const [scrollSnaps, setScrollSnaps] = useState([]);
-
- const scrollPrev = useCallback(() => embla && embla.scrollPrev(), [embla]);
- const scrollNext = useCallback(() => embla && embla.scrollNext(), [embla]);
- const scrollTo = useCallback(
- (index) => embla && embla.scrollTo(index),
- [embla]
- );
-
- const onSelect = useCallback(() => {
- if (!embla) return;
- setSelectedIndex(embla.selectedScrollSnap());
- setPrevBtnEnabled(embla.canScrollPrev());
- setNextBtnEnabled(embla.canScrollNext());
- }, [embla, setSelectedIndex]);
-
- useEffect(() => {
- if (!embla) return;
- onSelect();
- setScrollSnaps(embla.scrollSnapList());
- embla.on('select', onSelect);
- }, [embla, setScrollSnaps, onSelect]);
+ const {t} = useTranslation();
return (
-
-
- {election.name}
-
-
-
-
- {
- //
- }
-
-
-
-
-
-
-
-
-
- {t('Bienvenue')}
-
-
-
- {t(
- 'Participez au vote et découvrez le vote par jugement majoritaire.'
- )}
-
-
-
-
-
- {t('Je participe au vote')}
-
-
-
- {t('Je participe au vote')}
-
-
-
-
- {t('resource.noAds')}
-
-
-
-
- {t('En savoir plus sur Mieux voter')}
-
-
-
-
-
-
-
|
-
-
-
-
-
-
- Simple
- Créez un vote en moins d’une minute
-
-
-
- Gratuit
- Envoyez des invitations par courriel sans limite d'envoi
-
-
-
- Respect de votre vie privée
- Aucune donnée personnelle n'est enregistrée
-
+
+
+
+
+
+ {t('common.welcome')}
-
-
-
-
-
-
- Une expérience de vote démocratique et intuitive
-
-
-
-
- Exprimez toute votre opinion
-
- Au jugement majoritaire, chaque candidat est évalué sur une
- grille de mention. Vous n’aurez plus besoin de faire un vote
- stratégique.
-
-
-
- Obtenez le meilleur consensus
-
- Le profil des mérites dresse un panorama précis de l’opinion
- des électeurs. Le gagnant du vote est celui qui est la
- meilleure mention majoritaire.
-
-
-
-
-
- Découvrez le jugement majoritaire
-
-
-
+
+
+ {t('vote.home-desc')}
+
-
- Partagez l’application Mieux voter
-
-
+
+
+
+
+ {t('vote.home-start')}
-
-
+
+
+ {t('resource.noAds')}
+
+
+
+
+ {t('common.about-mj')}
+
-
-
-
-
-
- {election.name}
-
-
+ )
+}
-
-
- {judgments.length !== election.candidates.length ? (
-
- ) : (
-
-
- {t('Submit my vote')}
-
- )}
-
-
-
-
-
-
-
+const Vote = ({electionId, token}: VoteInterface) => {
-
-
-
{election.name}
-
-
-
-
-
-
- {judgments.length !== election.candidates.length ? (
-
- ) : (
-
-
- {t('Submit my vote')}
-
- )}
-
-
-
-
-
+ return (
+ <>
+
+
+ >
);
};
-export default VoteBallot;
+export default Vote;
diff --git a/public/locales/en/resource.json b/public/locales/en/resource.json
index af5433e..4e4d236 100644
--- a/public/locales/en/resource.json
+++ b/public/locales/en/resource.json
@@ -26,6 +26,7 @@
"menu.faq": "FAQ",
"menu.news": "News",
"menu.contact-us": "Contact us",
+ "common.about-mj": "Read more about Better Vote",
"common.error": "Oh no... An error has occured...",
"common.better-vote": "Better Vote",
"common.share": "Share the application Better Vote",
@@ -44,8 +45,10 @@
"common.vote": "Vote",
"common.the-vote": "The vote",
"common.the-params": "The parameters",
- "error.help": "Ask for our help",
+ "common.welcome": "Welcome!",
"error.at-least-2-candidates": "At least two candidates are required.",
+ "error.catch22": "Erreur inconnue...",
+ "error.help": "Ask for our help",
"error.no-title": "Please add a title to your election.",
"grades.very-good": "Very good",
"grades.good": "Good",
@@ -102,5 +105,7 @@
"admin.success-copy-vote": "Copy the voting link",
"admin.success-copy-result": "Copy the result link",
"admin.success-copy-admin": "Copy the admin link",
- "admin.go-to-admin": "Manage the vote"
+ "admin.go-to-admin": "Manage the vote",
+ "vote.home-desc": "Participate in the vote and discover majority judgment",
+ "vote.home-start": "I participate"
}
diff --git a/public/locales/fr/resource.json b/public/locales/fr/resource.json
index 2d4edf2..fc88c20 100644
--- a/public/locales/fr/resource.json
+++ b/public/locales/fr/resource.json
@@ -26,6 +26,7 @@
"menu.faq": "FAQ",
"menu.news": "Actualités",
"menu.contact-us": "Nous contacter",
+ "common.about-mj": "En savoir plus sur Mieux voter",
"common.error": "Oh non ! Une erreur s'est produite...",
"common.better-vote": "Mieux Voter",
"common.share": "Partagez l'application Mieux voter",
@@ -44,9 +45,11 @@
"common.the-vote": "Le vote",
"common.the-params": "Les paramètres",
"common.vote": "Voter",
+ "common.welcome": "Bienvenue !",
"error.help": "Besoin d'aide ?",
"error.at-least-2-candidates": "Ajoutez au moins deux candidats.",
"error.no-title": "Ajoutez un titre à l'élection.",
+ "error.catch22": "Erreur inconnue...",
"grades.very-good": "Très bien",
"grades.good": "Bien",
"grades.passable": "Passable",
@@ -102,5 +105,7 @@
"admin.success-copy-vote": "Copier le lien du vote",
"admin.success-copy-result": "Copier le lien des résultats",
"admin.success-copy-admin": "Copier le lien d'administration",
- "admin.go-to-admin": "Administrez le vote"
+ "admin.go-to-admin": "Administrez le vote",
+ "vote.home-desc": "Participez au vote et découvrez le jugement majoritaire.",
+ "vote.home-start": "Je participe"
}
diff --git a/services/api.ts b/services/api.ts
index 164269c..a673d72 100644
--- a/services/api.ts
+++ b/services/api.ts
@@ -61,6 +61,7 @@ export const createElection = async (
if (successCallback) {
const payload = await req.json();
successCallback(payload);
+ return payload;
}
} else if (failureCallback) {
try {
@@ -104,29 +105,31 @@ export const getResults = (
};
-export const getElection = (
+export const getElection = async (
pid: string,
successCallback = null,
failureCallback = null
-) => {
+): Promise => {
/**
* Fetch data from external API
*/
-
const detailsEndpoint = new URL(
api.routesServer.getElection.replace(new RegExp(':slug', 'g'), pid),
api.urlServer
);
- return fetch(detailsEndpoint.href)
- .then((response) => {
- if (!response.ok) {
- return Promise.reject(response.text());
- }
- return response.json();
- })
- .then(successCallback || ((res) => res))
- .catch(failureCallback || ((err) => err))
- .then((res) => res);
+ try {
+ const res = await fetch(detailsEndpoint.href);
+
+ if (!res.ok) {
+ return failureCallback(res.text())
+ }
+
+ const payload: ElectionPayload = await res.json();
+ if (successCallback) successCallback(payload);
+ return payload;
+ } catch (error) {
+ return failureCallback && failureCallback(error);
+ }
};
diff --git a/services/routes.ts b/services/routes.ts
index efe4426..1b9e043 100644
--- a/services/routes.ts
+++ b/services/routes.ts
@@ -5,17 +5,20 @@ import {getWindowUrl} from './utils';
export const CREATE_ELECTION = '/admin/new/';
+export const BALLOT = '/ballot/';
+export const VOTE = '/vote/';
+export const RESULTS = '/result/';
export const getUrlVote = (electionId: string | number, token?: string): URL => {
const origin = getWindowUrl();
if (token)
- return new URL(`/vote/${electionId}/${token}`, origin);
- return new URL(`/vote/${electionId}`, origin);
+ return new URL(`/${VOTE}/${electionId}/${token}`, origin);
+ return new URL(`/${VOTE}/${electionId}`, origin);
}
export const getUrlResults = (electionId: string | number): URL => {
const origin = getWindowUrl();
- return new URL(`/result/${electionId}`, origin);
+ return new URL(`/${RESULTS}/${electionId}`, origin);
}
export const getUrlAdmin = (electionId: string | number, adminToken: string): URL => {