fix: linting issues

pull/89/head
Pierre-Louis Guhur 1 year ago
parent ad11fe595c
commit f81629e29b

@ -9,7 +9,7 @@ import {
faRotateLeft,
} from '@fortawesome/free-solid-svg-icons';
import {useElection, useElectionDispatch} from '@services/ElectionContext';
import {gradeColors} from '@services/grades';
import {getGradeColor, gradeColors} from '@services/grades';
import {useSortable} from '@dnd-kit/sortable';
@ -79,15 +79,3 @@ export default ({value}: GradeInterface) => {
};
const getGradeColor = (gradeIdx: number, numGrades: number): string => {
const extraColors = gradeColors.length - numGrades;
if (extraColors < 0) {
throw Error("More grades than available colors");
}
const startIndex = Math.floor(extraColors / 2);
const colors = gradeColors.slice(startIndex, gradeColors.length - (extraColors - startIndex));
if (colors.length < numGrades) {
throw Error("Issue with the number of colors");
}
return colors[colors.length - gradeIdx - 1]
}

@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import {
getDetails,
getElection,
apiErrors,
ELECTION_NOT_STARTED_ERROR,
} from '@services/api';
@ -26,7 +26,7 @@ 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([
getDetails(pid, console.log, console.log),
getElection(pid, console.log, console.log),
serverSideTranslations(locale, [], config),
]);

@ -1,8 +1,8 @@
import { useState } from 'react';
import {useState} from 'react';
import Head from 'next/head';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { useRouter } from 'next/router';
import {useTranslation} from 'next-i18next';
import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
import {useRouter} from 'next/router';
import Link from 'next/link';
import {
Container,
@ -15,37 +15,36 @@ import {
Table,
Button,
} from 'reactstrap';
import { getResults, getDetails, apiErrors } from '@services/api';
import { translateGrades } from '@services/grades';
import Error from '@components/Error';
import {getResults, getElection, apiErrors, ResultsPayload} from '@services/api';
import ErrorMessage from '@components/Error';
import config from '../../../next-i18next.config.js';
import Footer from '@components/layouts/Footer';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {
faChevronDown,
faChevronRight,
faChevronUp,
} from '@fortawesome/free-solid-svg-icons';
export async function getServerSideProps({ query, locale }) {
const { pid, tid } = query;
export async function getServerSideProps({query, locale}) {
const {pid, tid} = query;
const [res, details, translations] = await Promise.all([
getResults(pid),
getDetails(pid),
getElection(pid),
serverSideTranslations(locale, [], config),
]);
if (typeof res === 'string' || res instanceof String) {
return { props: { err: res.slice(1, -1), ...translations } };
return {props: {err: res.slice(1, -1), ...translations}};
}
if (typeof details === 'string' || details instanceof String) {
return { props: { err: res.slice(1, -1), ...translations } };
return {props: {err: res.slice(1, -1), ...translations}};
}
if (!details.candidates || !Array.isArray(details.candidates)) {
return { props: { err: 'Unknown error', ...translations } };
return {props: {err: 'Unknown error', ...translations}};
}
return {
@ -60,23 +59,23 @@ export async function getServerSideProps({ query, locale }) {
};
}
const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
const { t } = useTranslation();
interface ResultsInterface {
results: ResultsPayload;
err: string;
}
const Results = ({results, err}: ResultsInterface) => {
const {t} = useTranslation();
const newstart = new Date(finish * 1000).toLocaleDateString('fr-FR');
const newstart = new Date(results.date_end).toLocaleDateString();
if (err && err !== '') {
return <Error msg={t(apiErrors(err))} />;
return <ErrorMessage msg={t(apiErrors(err))} />;
}
const router = useRouter();
const allGrades = translateGrades(t);
const grades = allGrades.filter(
(grade) => grade.value >= allGrades.length - numGrades
);
const offsetGrade = grades.length - numGrades;
const colSizeCandidateLg = 4;
const colSizeCandidateMd = 6;
const colSizeCandidateXs = 12;
@ -88,27 +87,36 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
typeof window !== 'undefined' && window.location.origin
? window.location.origin
: 'http://localhost';
const urlVote = new URL(`/vote/${pid}`, origin);
const urlVote = new URL(`/vote/${results.id}`, origin);
const collapsee = candidates[0].title;
const [collapseProfiles, setCollapseProfiles] = useState(false);
if (typeof results.candidates === "undefined" || results.candidates.length === 0) {
throw Error("No candidates were loaded in this election")
}
// const collapsee = results.candidates[0].name;
// const [collapseProfiles, setCollapseProfiles] = useState(false);
const [collapseGraphics, setCollapseGraphics] = useState(false);
const sum = (seq: Array<number>) =>
Object.values(seq).reduce((a, b) => a + b, 0);
const numVotes =
candidates && candidates.length > 0 ? sum(candidates[0].profile) : 1;
const gradeIds =
candidates && candidates.length > 0
? Object.keys(candidates[0].profile)
: [];
const anyCandidateName = results.candidates[0].name;
const numVotes = sum(results.votes[anyCandidateName]);
// check each vote contains the same number of votes
// TODO move it to a more appropriate location
Object.values(results.votes).forEach(v => {
if (sum(v) !== numVotes) {
throw Error("The election does not contain the same numberof votes for each candidate")
}
})
const gradeIds = results.grades.map(g => g.value);
return (
<Container className="resultContainer resultPage">
<Head>
<title>{title}</title>
<title>{results.name}</title>
<link rel="icon" href="/favicon.ico" />
<meta property="og:title" content={title} />
<meta property="og:title" content={results.name} />
</Head>
<Row className="sectionHeaderResult componentDesktop mx-0">
<Col className="col-md-3 sectionHeaderResultLeftCol">
@ -127,7 +135,7 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
</Col>
<Col className="sectionHeaderResultMiddleCol">
<h3>{title}</h3>
<h3>{results.name}</h3>
</Col>
<Col className="col-md-3 sectionHeaderResultRightCol">
@ -148,7 +156,7 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
<Row className="sectionHeaderResult componentMobile mx-0">
<Col className="px-0">
<h3>{title}</h3>
<h3>{results.name}</h3>
</Col>
<Row>
<Col className="sectionHeaderResultSideCol">
@ -166,7 +174,7 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
<Row className="mt-5 componentDesktop">
<Col>
<ol className="result px-0">
{candidates.map((candidate, i) => {
{ /* {results.candidates.map((candidate, i) => {
const gradeValue = candidate.grade + offsetGrade;
return (
<li key={i} className="mt-2">
@ -186,13 +194,14 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
</li>
);
})}
*/}
</ol>
</Col>
</Row>
<Row className="mt-5">
<Col>
<h5>
{/* <h5>
<small>{t('Détails des résultats')}</small>
</h5>
{candidates.map((candidate, i) => {
@ -249,13 +258,12 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
<div>
<div
className="median"
style={{ height: '40px' }}
style={{height: '40px'}}
/>
<div style={{ width: '100%' }}>
<div style={{width: '100%'}}>
<div key={i}>
{/*candidate.label*/}
<div style={{ width: '100%' }}>
<div style={{width: '100%'}}>
{gradeIds
.slice(0)
.reverse()
@ -305,6 +313,7 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
</Card>
);
})}
*/}
</Col>
</Row>
<div className="componentMobile mt-5">
@ -326,4 +335,5 @@ const Result = ({ candidates, numGrades, title, pid, err, finish }) => {
</Container>
);
};
export default Result;
export default Results;

@ -1,8 +1,8 @@
import { useState, useCallback, useEffect } from 'react';
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 {useRouter} from 'next/router';
import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
import {useTranslation} from 'next-i18next';
import {
Button,
Col,
@ -14,11 +14,10 @@ import {
} 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 { getDetails, castBallot, apiErrors } from '@services/api';
import Error from '@components/Error';
import { translateGrades } from '@services/grades';
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 {
@ -27,21 +26,22 @@ import {
NextButton,
} 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 }) {
export async function getServerSideProps({query: {pid, tid}, locale}) {
const [details, translations] = await Promise.all([
getDetails(pid),
getElection(pid),
serverSideTranslations(locale, ['resource']),
]);
if (typeof details === 'string' || details instanceof String) {
return { props: { err: details, ...translations } };
return {props: {err: details, ...translations}};
}
if (!details.candidates || !Array.isArray(details.candidates)) {
return { props: { err: 'Unknown error', ...translations } };
return {props: {err: 'Unknown error', ...translations}};
}
shuffle(details.candidates);
@ -53,7 +53,7 @@ export async function getServerSideProps({ query: { pid, tid }, locale }) {
restrictResults: details.restrict_results,
candidates: details.candidates.map((name, i, infos) => ({
id: i,
label: name,
name: name,
description: infos,
})),
title: details.title,
@ -64,13 +64,20 @@ export async function getServerSideProps({ query: { pid, tid }, locale }) {
};
}
const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
const { t } = useTranslation();
interface VoteInterface {
election: ElectionPayload;
err: string;
token?: string;
}
const VoteBallot = ({election, err, token}: VoteInterface) => {
const {t} = useTranslation();
if (err) {
return <Error msg={t(apiErrors(err))} />;
return <ErrorMessage msg={t(apiErrors(err))} />;
}
const numGrades = election.grades.length;
const [judgments, setJudgments] = useState([]);
const colSizeCandidateLg = 4;
const colSizeCandidateMd = 6;
@ -81,11 +88,6 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
const router = useRouter();
const allGrades = translateGrades(t);
const grades = allGrades.filter(
(grade) => grade.value >= allGrades.length - numGrades
);
const handleGradeClick = (event) => {
let data = {
id: parseInt(event.currentTarget.getAttribute('data-id')),
@ -115,8 +117,8 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
gradesByCandidate.push(gradesById[id]);
});
castBallot(gradesByCandidate, pid, token, () => {
router.push(`/vote/${pid}/confirm`);
castBallot(gradesByCandidate, election.id.toString(), token, () => {
router.push(`/vote/${election.id}/confirm`);
});
};
const toggle = () => setVisibility(!visibled);
@ -126,7 +128,7 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
const toggleDesktop = () => setVisibilityDesktop(!visibledDesktop);
const [visibledDesktop, setVisibilityDesktop] = useState(false);
const [viewportRef, embla] = useEmblaCarousel({ skipSnaps: false });
const [viewportRef, embla] = useEmblaCarousel({skipSnaps: false});
const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
const [nextBtnEnabled, setNextBtnEnabled] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);
@ -156,10 +158,9 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
return (
<Container className="homePage">
<Head>
<title>{title}</title>
<title>{election.name}</title>
<title>{title}</title>
<meta key="og:title" property="og:title" content={title} />
<meta key="og:title" property="og:title" content={election.name} />
<meta
property="og:description"
key="og:description"
@ -312,20 +313,21 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
className="modalVote voteDesktop"
>
<div className="my-auto">
<ModalHeader className="modalVoteHeader">{title}</ModalHeader>
<ModalHeader className="modalVoteHeader">{election.name}</ModalHeader>
<ModalBody className="modalVoteBody">
<form onSubmit={handleSubmit} autoComplete="off">
{candidates.map((candidate, candidateId) => {
{election.candidates.map((candidate, candidateId) => {
return (
<Row key={candidateId} className="cardVote">
<Col className="cardVoteLabel">
<h5 className="m-0">{candidate.label}</h5>
<h5 className="m-0">{candidate.infos}</h5>
<h5 className="m-0">{candidate.name}</h5>
<h5 className="m-0">{candidate.description}</h5>
</Col>
<Col className="cardVoteGrades">
{grades.map((grade, gradeId) => {
{election.grades.map((grade, gradeId) => {
console.assert(gradeId < numGrades);
const gradeValue = grade.value;
const color = getGradeColor(gradeId, numGrades);
return (
<Col
key={gradeId}
@ -353,16 +355,16 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
);
})
? {
backgroundColor: grade.color,
color: '#fff',
}
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: 'transparent',
color: '#000',
}
backgroundColor: 'transparent',
color: '#000',
}
}
>
{grade.label}
{grade.name}
</small>
<input
type="radio"
@ -400,13 +402,13 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
);
})
? {
backgroundColor: grade.color,
color: '#fff',
}
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: '#C3BFD8',
color: '#000',
}
backgroundColor: '#C3BFD8',
color: '#000',
}
}
>
<small
@ -416,7 +418,7 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
color: '#fff',
}}
>
{grade.label}
{grade.name}
</small>
</span>
</label>
@ -430,7 +432,7 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
<Row>
<Col className="text-center">
{judgments.length !== candidates.length ? (
{judgments.length !== election.candidates.length ? (
<VoteButtonWithConfirm
action={handleSubmitWithoutAllRate}
/>
@ -454,23 +456,24 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
className="modalVote voteMobile"
>
<div className="my-auto">
<ModalHeader className="modalVoteHeader">{title}</ModalHeader>
<ModalHeader className="modalVoteHeader">{election.name}</ModalHeader>
<ModalBody className="modalVoteBody">
<form onSubmit={handleSubmit} autoComplete="off">
<div className="embla" ref={viewportRef}>
<div className="embla__container">
{candidates.map((candidate, candidateId) => {
{election.candidates.map((candidate, candidateId) => {
return (
<div className="embla__slide">
<Row key={candidateId} className="cardVote">
<Col className="cardVoteLabel mb-3">
<h5 className="m-0">{candidate.label}</h5>
<h5 className="m-0">{candidate.name}</h5>
<h5 className="m-0">{candidate.id + 1}</h5>
</Col>
<Col className="cardVoteGrades">
{grades.map((grade, gradeId) => {
{election.grades.map((grade, gradeId) => {
console.assert(gradeId < numGrades);
const gradeValue = grade.value;
const color = getGradeColor(gradeId, numGrades);
return (
<Col
key={gradeId}
@ -498,16 +501,16 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
);
})
? {
backgroundColor: grade.color,
color: '#fff',
}
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: 'transparent',
color: '#000',
}
backgroundColor: 'transparent',
color: '#000',
}
}
>
{grade.label}
{grade.name}
</small>
<input
type="radio"
@ -547,13 +550,13 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
);
})
? {
backgroundColor: grade.color,
color: '#fff',
}
backgroundColor: color,
color: '#fff',
}
: {
backgroundColor: '#C3BFD8',
color: '#000',
}
backgroundColor: '#C3BFD8',
color: '#000',
}
}
>
<small
@ -563,7 +566,7 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
color: '#fff',
}}
>
{grade.label}
{grade.name}
</small>
</span>
</label>
@ -606,7 +609,7 @@ const VoteBallot = ({ candidates, title, numGrades, pid, err, token }) => {
</div>
<Row className="btn-background mx-0">
<Col className="text-center">
{judgments.length !== candidates.length ? (
{judgments.length !== election.candidates.length ? (
<VoteButtonWithConfirm action={handleSubmitWithoutAllRate} />
) : (
<Button type="submit" className="my-3 btn btn-transparent">

@ -8,13 +8,13 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
// import PaypalNoLogo from "@components/banner/PaypalNoLogo";
import Gform from '@components/banner/Gform';
import Error from '@components/Error';
import { getDetails, apiErrors } from '@services/api';
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([
getDetails(pid),
getElection(pid),
serverSideTranslations(locale, [], config),
]);

@ -5,7 +5,7 @@ import {createContext, useContext, useReducer, useEffect, Dispatch, SetStateActi
import {useRouter} from 'next/router';
import {CandidateItem, GradeItem} from './type';
interface ElectionContextInterface {
export interface ElectionContextInterface {
name: string;
description: string;
candidates: Array<CandidateItem>;

@ -89,7 +89,7 @@ export const getResults = (
};
export const getElectionDetails = (
export const getElection = (
pid: string,
successCallback = null,
failureCallback = null
@ -211,3 +211,9 @@ export interface ElectionPayload {
tokens: Array<string>;
admin: string;
}
export interface ResultsPayload extends ElectionPayload {
ranking: {[key: string]: number};
votes: {[key: string]: Array<number>};
}

@ -29,3 +29,16 @@ export const gradeClass = [
];
export const gradeValues = [0, 1, 2, 3, 4, 5, 6, 7];
export const getGradeColor = (gradeIdx: number, numGrades: number): string => {
const extraColors = gradeColors.length - numGrades;
if (extraColors < 0) {
throw Error("More grades than available colors");
}
const startIndex = Math.floor(extraColors / 2);
const colors = gradeColors.slice(startIndex, gradeColors.length - (extraColors - startIndex));
if (colors.length < numGrades) {
throw Error("Issue with the number of colors");
}
return colors[colors.length - gradeIdx - 1]
}

Loading…
Cancel
Save