fix: ballot

pull/89/head
Pierre-Louis Guhur 1 year ago
parent 114b07b9d9
commit 58379bfd53

@ -1,165 +0,0 @@
/**
* 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"
>
<div className="my-auto">
<ModalHeader className="modalVoteHeader">{election.name}</ModalHeader>
<ModalBody className="modalVoteBody">
<form onSubmit={handleSubmit} autoComplete="off">
{election.candidates.map((candidate, candidateId) => {
return (
<Row key={candidateId} className="cardVote">
<Col className="cardVoteLabel">
<h5 className="m-0">{candidate.name}</h5>
<h5 className="m-0">{candidate.description}</h5>
</Col>
<Col className="cardVoteGrades">
{election.grades.map((grade, gradeId) => {
console.assert(gradeId < numGrades);
const gradeValue = grade.value;
const color = getGradeColor(gradeId, numGrades);
return (
<Col
key={gradeId}
className="text-lg-center mx-2 voteCheck"
>
<label
htmlFor={
'candidateGrade' +
candidateId +
'-' +
gradeValue
}
className="check"
>
<small
className="nowrap d-lg-none bold badge"
style={
judgments.find((judgment) => {
return (
JSON.stringify(judgment) ===
JSON.stringify({
id: candidate.id,
value: gradeValue,
})
);
})
? {
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: 'transparent',
color: '#000',
}
}
>
{grade.name}
</small>
<input
type="radio"
name={'candidate' + candidateId}
id={
'candidateGrade' +
candidateId +
'-' +
gradeValue
}
data-index={candidateId}
data-id={candidate.id}
value={grade.value}
onClick={handleGradeClick}
defaultChecked={judgments.find((element) => {
return (
JSON.stringify(element) ===
JSON.stringify({
id: candidate.id,
value: gradeValue,
})
);
})}
/>
<span
className="checkmark candidateGrade "
style={
judgments.find(function (judgment) {
return (
JSON.stringify(judgment) ===
JSON.stringify({
id: candidate.id,
value: gradeValue,
})
);
})
? {
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: '#C3BFD8',
color: '#000',
}
}
>
<small
className="nowrap bold badge"
style={{
backgroundColor: 'transparent',
color: '#fff',
}}
>
{grade.name}
</small>
</span>
</label>
</Col>
);
})}
</Col>
</Row>
);
})}
<Row>
<Col className="text-center">
{judgments.length !== election.candidates.length ? (
<VoteButtonWithConfirm
action={handleSubmitWithoutAllRate}
/>
) : (
<Button type="submit" className="mt-5 btn btn-transparent">
<FontAwesomeIcon icon={faCheck} />
{t('Submit my vote')}
</Button>
)}
</Col>
</Row>
</form>
</ModalBody>
</div>
<Footer />
</Modal >

@ -3,7 +3,7 @@ import {useTranslation} from 'next-i18next';
import {CSSProperties, useEffect, useState} from 'react';
import {faArrowRight} from '@fortawesome/free-solid-svg-icons';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {Container} from 'reactstrap';
import {Col, Container, Row} from 'reactstrap';
import Button from '@components/Button';
import ButtonCopy from '@components/ButtonCopy';
import Share from '@components/Share';
@ -45,34 +45,38 @@ const ButtonResults = ({election}) => {
const DiscoverMajorityJudgment = () => {
const {t} = useTranslation();
return (
<div className="bg-secondary h-100 p-4 text-white me-3">
<h5>{t('vote.discover-mj')}</h5>
<p>{t('vote.discover-mj-desc')}</p>
<Col className="d-flex flex-column justify-content-between bg-secondary p-4 text-white" >
<div>
<h5>{t('vote.discover-mj')}</h5>
<p>{t('vote.discover-mj-desc')}</p>
</div>
<a href="https://mieuxvoter.fr/le-jugement-majoritaire">
<div className="d-flex">
<div className="d-flex align-items-center">
<div className="me-2">{t('common.about')}</div>
<FontAwesomeIcon icon={faArrowRight} />
</div>
</a>
</div>)
</Col >)
}
const SupportBetterVote = () => {
const {t} = useTranslation();
return (
<div className="text-secondary h-100 p-4 bg-white">
<div className="d-flex justify-content-between">
<h5>{t('vote.support-better-vote')}</h5>
<Logo title={false} />
<Col className="d-flex flex-column justify-content-between text-secondary p-4 bg-white">
<div>
<div className="d-flex mb-2 align-items-center justify-content-between">
<h5>{t('vote.support-better-vote')}</h5>
<Logo title={false} />
</div>
<p>{t('vote.support-desc')}</p>
</div>
<p>{t('vote.support-desc')}</p>
<a href="https://mieuxvoter.fr/le-jugement-majoritaire">
<div className="d-flex">
<div className="d-flex align-items-center">
<div className="me-2">{t('common.donation')}</div>
<FontAwesomeIcon icon={faArrowRight} />
</div>
</a>
</div>)
</Col>)
}
@ -117,9 +121,11 @@ const Info = ({ballot, error, display}: InfoInterface) => {
</h4>
<ButtonResults election={ballot.election} />
<Container className="d-flex m-4 justify-content-between">
<DiscoverMajorityJudgment />
<SupportBetterVote />
<Container>
<Row className="m-4 row-cols-1 row-cols-md-2 gx-4 justify-content-between">
<DiscoverMajorityJudgment />
<SupportBetterVote />
</Row>
</Container>
<Thanks />
<Share />

@ -121,7 +121,8 @@ const VoteBallot = ({election, token}: VoteInterface) => {
try {
const res = await castBallot(
ballot.votes,
ballot.election, ballot.election.restricted, token)
ballot.election,
token)
if (res.status !== 200) {
console.error(res);
const msg = await res.json();

@ -1,192 +0,0 @@
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 <Error msg={t(apiErrors(err))} />;
}
return (
<Container className="full-height-container">
<Head>
<title>{t('resource.voteSuccess')}</title>
<link rel="icon" href="/favicon.ico" />
<meta key="og:title" property="og:title" content={title} />
<meta
property="og:description"
key="og:description"
content={t('common.application')}
/>
</Head>
<motion.div
className="mx-auto"
initial={{ scale: 1, paddingBottom: '200px' }}
animate={{ scale: 0.5, paddingBottom: '0px' }}
transition={{
type: 'spring',
damping: 100,
delay: 3,
}}
>
<Row>
<motion.div
className="main-animation"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
type: 'spring',
damping: 20,
delay: 1,
}}
>
<motion.div
className="vote-animation"
initial={{ scale: 0, y: 50 }}
animate={{ scale: 1, y: 0 }}
transition={{
type: 'spring',
stiffness: 260,
damping: 20,
delay: 1,
}}
>
<img src="/vote.svg" />
</motion.div>
<motion.div
className="star-animation"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{
type: 'spring',
damping: 20,
delay: 2,
}}
>
<img src="/vote-star.svg" />
</motion.div>
</motion.div>
</Row>
</motion.div>
<motion.div
className=""
initial={{ scale: 0, opacity: 0, y: 100 }}
animate={{ scale: 1, opacity: 1, y: -70 }}
transition={{
type: 'spring',
damping: 100,
delay: 4,
}}
>
<Row className="mt-4 px-3 confirmRowOne">
<Col className="text-center">
<h2 className="confirmH2">{t('resource.voteSuccess')}</h2>
<Button className="voteDesktop mx-auto mt-4 mb-5">
{t('Voir les résultats')}
<img src="/arrow-white.svg" />
</Button>
<Button className="voteMobile mx-auto mt-4 mb-5">
{t('Voir les résultats')}
<img src="/arrow-white.svg" />
</Button>
</Col>
</Row>
<Row className="confirmRowTwo justify-content-center mb-5 px-4">
<Col className="confirmLeft">
<h2 className="confirmH2 mb-4">
{t('Découvrez le jugement majoritaire')}
</h2>
<p>
{t(
'créé par des chercheurs français, le jugement majoritaire est un mode de scrutin qui améliore lexpressivité des électeurs et fournit le meilleur consensus.'
)}
</p>
<Link href="/">
<div>
{t('En savoir plus')}
<FontAwesomeIcon icon={faChevronRight} />
</div>
</Link>
</Col>
<Col className="confirmRight">
<Row className="align-items-center">
<Col xs="8" className="pr-0">
<h2 className="confirmH2">{t('Soutenez Mieux Voter')}</h2>
</Col>
<Col xs="4" className="text-right">
<img src="/logo-red-blue.svg" alt="logo of Mieux Voter" />
</Col>
</Row>
<p className="pt-4">
{t(
'Mieux Voter est une association transpartisane et sans but lucratif. En adhérant à lassociation, vous contribuez à financer son fonctionnement et ses activités. '
)}
</p>
</Col>
</Row>
<Row>
<Col className="text-center col-md-3 mx-auto my-5 thanksVote">
<h4>{t('resource.thanks')}</h4>
<p>
{t('Aidez nous à améliorer lapplication en cliquant ci-dessous')}
</p>
<Gform className="btn btn-secondary mt-3 mx-auto" />
</Col>
</Row>
<div className="mx-auto my-5">
<Row className="justify-content-center">
<Link href="https://www.facebook.com/mieuxvoter.fr/">
<img src="/facebook.svg" />
</Link>
<p className="m-0">
{t('Faites découvrir lapplication a vos amis')}
</p>
</Row>
</div>
</motion.div>
</Container>
);
};
export default VoteSuccess;

@ -49,9 +49,9 @@ export async function getServerSideProps({query, locale}) {
return {
props: {
title: details.title,
numGrades: details.num_grades,
finish: details.finish_at,
title: details.name,
numGrades: details.grades.length,
finish: details.date_end,
candidates: res,
pid: pid,
...translations,

@ -1,192 +0,0 @@
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 <Error msg={t(apiErrors(err))} />;
}
return (
<Container className="full-height-container">
<Head>
<title>{t('resource.voteSuccess')}</title>
<link rel="icon" href="/favicon.ico" />
<meta key="og:title" property="og:title" content={title} />
<meta
property="og:description"
key="og:description"
content={t('common.application')}
/>
</Head>
<motion.div
className="mx-auto"
initial={{ scale: 1, paddingBottom: '200px' }}
animate={{ scale: 0.5, paddingBottom: '0px' }}
transition={{
type: 'spring',
damping: 100,
delay: 3,
}}
>
<Row>
<motion.div
className="main-animation"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
type: 'spring',
damping: 20,
delay: 1,
}}
>
<motion.div
className="vote-animation"
initial={{ scale: 0, y: 50 }}
animate={{ scale: 1, y: 0 }}
transition={{
type: 'spring',
stiffness: 260,
damping: 20,
delay: 1,
}}
>
<img src="/vote.svg" />
</motion.div>
<motion.div
className="star-animation"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{
type: 'spring',
damping: 20,
delay: 2,
}}
>
<img src="/vote-star.svg" />
</motion.div>
</motion.div>
</Row>
</motion.div>
<motion.div
className=""
initial={{ scale: 0, opacity: 0, y: 100 }}
animate={{ scale: 1, opacity: 1, y: -70 }}
transition={{
type: 'spring',
damping: 100,
delay: 4,
}}
>
<Row className="mt-4 px-3 confirmRowOne">
<Col className="text-center">
<h2 className="confirmH2">{t('resource.voteSuccess')}</h2>
<Button className="voteDesktop mx-auto mt-4 mb-5">
{t('Voir les résultats')}
<img src="/arrow-white.svg" />
</Button>
<Button className="voteMobile mx-auto mt-4 mb-5">
{t('Voir les résultats')}
<img src="/arrow-white.svg" />
</Button>
</Col>
</Row>
<Row className="confirmRowTwo justify-content-center mb-5 px-4">
<Col className="confirmLeft">
<h2 className="confirmH2 mb-4">
{t('Découvrez le jugement majoritaire')}
</h2>
<p>
{t(
'créé par des chercheurs français, le jugement majoritaire est un mode de scrutin qui améliore lexpressivité des électeurs et fournit le meilleur consensus.'
)}
</p>
<Link href="/">
<div>
{t('En savoir plus')}
<FontAwesomeIcon icon={faChevronRight} />
</div>
</Link>
</Col>
<Col className="confirmRight">
<Row className="align-items-center">
<Col xs="8" className="pr-0">
<h2 className="confirmH2">{t('Soutenez Mieux Voter')}</h2>
</Col>
<Col xs="4" className="text-right">
<img src="/logo-red-blue.svg" alt="logo of Mieux Voter" />
</Col>
</Row>
<p className="pt-4">
{t(
'Mieux Voter est une association transpartisane et sans but lucratif. En adhérant à lassociation, vous contribuez à financer son fonctionnement et ses activités. '
)}
</p>
</Col>
</Row>
<Row>
<Col className="text-center col-md-3 mx-auto my-5 thanksVote">
<h4>{t('resource.thanks')}</h4>
<p>
{t('Aidez nous à améliorer lapplication en cliquant ci-dessous')}
</p>
<Gform className="btn btn-secondary mt-3 mx-auto" />
</Col>
</Row>
<div className="mx-auto my-5">
<Row className="justify-content-center">
<Link href="https://www.facebook.com/mieuxvoter.fr/">
<img src="/facebook.svg" />
</Link>
<p className="m-0">
{t('Faites découvrir lapplication a vos amis')}
</p>
</Row>
</div>
</motion.div>
</Container>
);
};
export default VoteSuccess;
Loading…
Cancel
Save