|
|
@ -1,14 +1,25 @@
|
|
|
|
import {useEffect, useState} from 'react';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
import {useRouter} from 'next/router';
|
|
|
|
import { useRouter } from 'next/router';
|
|
|
|
import Link from 'next/link'
|
|
|
|
import Link from 'next/link';
|
|
|
|
import {useTranslation} from 'next-i18next';
|
|
|
|
import { useTranslation } from 'next-i18next';
|
|
|
|
import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
|
|
|
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
|
|
|
import {Container, Row, Col} from 'reactstrap';
|
|
|
|
import { Container, Row, Col } from 'reactstrap';
|
|
|
|
import {faArrowRight} from '@fortawesome/free-solid-svg-icons';
|
|
|
|
import { faArrowRight } from '@fortawesome/free-solid-svg-icons';
|
|
|
|
import {getElection, updateElection} from '@services/api';
|
|
|
|
import { getElection, updateElection } from '@services/api';
|
|
|
|
import {ElectionContextInterface, ElectionProvider, ElectionTypes, useElection, isClosed, canViewResults, checkName, hasEnoughGrades, hasEnoughCandidates, canBeFinished} from '@services/ElectionContext';
|
|
|
|
import {
|
|
|
|
import {CandidateItem, GradeItem} from '@services/type';
|
|
|
|
ElectionContextInterface,
|
|
|
|
import {gradeColors} from '@services/grades';
|
|
|
|
ElectionProvider,
|
|
|
|
|
|
|
|
ElectionTypes,
|
|
|
|
|
|
|
|
useElection,
|
|
|
|
|
|
|
|
isClosed,
|
|
|
|
|
|
|
|
canViewResults,
|
|
|
|
|
|
|
|
checkName,
|
|
|
|
|
|
|
|
hasEnoughGrades,
|
|
|
|
|
|
|
|
hasEnoughCandidates,
|
|
|
|
|
|
|
|
canBeFinished,
|
|
|
|
|
|
|
|
} from '@services/ElectionContext';
|
|
|
|
|
|
|
|
import { CandidateItem, GradeItem } from '@services/type';
|
|
|
|
|
|
|
|
import { gradeColors } from '@services/grades';
|
|
|
|
import TitleField from '@components/admin/Title';
|
|
|
|
import TitleField from '@components/admin/Title';
|
|
|
|
import Button from '@components/Button';
|
|
|
|
import Button from '@components/Button';
|
|
|
|
import AccessResults from '@components/admin/AccessResults';
|
|
|
|
import AccessResults from '@components/admin/AccessResults';
|
|
|
@ -18,33 +29,35 @@ import Grades from '@components/admin/Grades';
|
|
|
|
import Order from '@components/admin/Order';
|
|
|
|
import Order from '@components/admin/Order';
|
|
|
|
import Private from '@components/admin/Private';
|
|
|
|
import Private from '@components/admin/Private';
|
|
|
|
import Blur from '@components/Blur';
|
|
|
|
import Blur from '@components/Blur';
|
|
|
|
import {getUrlResults, getUrlVote, RESULTS, VOTE} from '@services/routes';
|
|
|
|
import { getUrlResults, getUrlVote, RESULTS, VOTE } from '@services/routes';
|
|
|
|
import {sendInviteMails} from '@services/mail';
|
|
|
|
import { sendInviteMails } from '@services/mail';
|
|
|
|
import {AppTypes, useAppContext} from '@services/context';
|
|
|
|
import { AppTypes, useAppContext } from '@services/context';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function getServerSideProps({ query, locale }) {
|
|
|
|
export async function getServerSideProps({query, locale}) {
|
|
|
|
const { pid, tid: token } = query;
|
|
|
|
const {pid, tid: token} = query;
|
|
|
|
const electionRef = pid.replaceAll('-', '');
|
|
|
|
const electionRef = pid.replaceAll("-", "");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [payload, translations] = await Promise.all([
|
|
|
|
const [payload, translations] = await Promise.all([
|
|
|
|
getElection(electionRef),
|
|
|
|
getElection(electionRef),
|
|
|
|
serverSideTranslations(locale, ["resource"]),
|
|
|
|
serverSideTranslations(locale, ['resource']),
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
if ("msg" in payload) {
|
|
|
|
if ('msg' in payload) {
|
|
|
|
return {props: {err: payload.msg, ...translations}};
|
|
|
|
return { props: { err: payload.msg, ...translations } };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const grades = payload.grades.map((g, i) => ({...g, active: true}));
|
|
|
|
const grades = payload.grades.map((g, i) => ({ ...g, active: true }));
|
|
|
|
|
|
|
|
|
|
|
|
const candidates: Array<CandidateItem> = payload.candidates.map(c => ({...c, active: true}))
|
|
|
|
const candidates: Array<CandidateItem> = payload.candidates.map((c) => ({
|
|
|
|
const description = JSON.parse(payload.description)
|
|
|
|
...c,
|
|
|
|
const randomOrder = description["randomOrder"]
|
|
|
|
active: true,
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
const description = JSON.parse(payload.description);
|
|
|
|
|
|
|
|
const randomOrder = description['randomOrder'];
|
|
|
|
|
|
|
|
|
|
|
|
const context: ElectionContextInterface = {
|
|
|
|
const context: ElectionContextInterface = {
|
|
|
|
name: payload.name,
|
|
|
|
name: payload.name,
|
|
|
|
description: description["description"],
|
|
|
|
description: description['description'],
|
|
|
|
ref: payload.ref,
|
|
|
|
ref: payload.ref,
|
|
|
|
dateStart: payload.date_start,
|
|
|
|
dateStart: payload.date_start,
|
|
|
|
dateEnd: payload.date_end,
|
|
|
|
dateEnd: payload.date_end,
|
|
|
@ -54,45 +67,51 @@ export async function getServerSideProps({query, locale}) {
|
|
|
|
randomOrder,
|
|
|
|
randomOrder,
|
|
|
|
emails: [],
|
|
|
|
emails: [],
|
|
|
|
grades,
|
|
|
|
grades,
|
|
|
|
candidates
|
|
|
|
candidates,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
props: {
|
|
|
|
props: {
|
|
|
|
context,
|
|
|
|
context,
|
|
|
|
token: token || "",
|
|
|
|
token: token || '',
|
|
|
|
...translations,
|
|
|
|
...translations,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Spinner = () => {
|
|
|
|
const Spinner = () => {
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<div className="spinner-border text-light" role="status">
|
|
|
|
<div className="spinner-border text-light" role="status">
|
|
|
|
<span className="visually-hidden">Loading...</span>
|
|
|
|
<span className="visually-hidden">Loading...</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const HeaderRubbon = () => {
|
|
|
|
const HeaderRubbon = () => {
|
|
|
|
const {t} = useTranslation();
|
|
|
|
const { t } = useTranslation();
|
|
|
|
const [election, dispatch] = useElection();
|
|
|
|
const [election, dispatch] = useElection();
|
|
|
|
const [_, dispatchApp] = useAppContext();
|
|
|
|
const [_, dispatchApp] = useAppContext();
|
|
|
|
const router = useRouter();
|
|
|
|
const router = useRouter();
|
|
|
|
const [waiting, setWaiting] = useState(false);
|
|
|
|
const [waiting, setWaiting] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
const handleClosing = async () => {
|
|
|
|
const handleClosing = async () => {
|
|
|
|
setWaiting(true)
|
|
|
|
setWaiting(true);
|
|
|
|
dispatch({
|
|
|
|
dispatch({
|
|
|
|
type: ElectionTypes.SET,
|
|
|
|
type: ElectionTypes.SET,
|
|
|
|
field: "forceClose",
|
|
|
|
field: 'forceClose',
|
|
|
|
value: true
|
|
|
|
value: true,
|
|
|
|
})
|
|
|
|
});
|
|
|
|
const candidates = election.candidates.filter(c => c.active).map((c: CandidateItem) => ({name: c.name, description: c.description, image: c.image}))
|
|
|
|
const candidates = election.candidates
|
|
|
|
const grades = election.grades.filter(c => c.active).map((g: GradeItem, i: number) => ({name: g.name, value: i}))
|
|
|
|
.filter((c) => c.active)
|
|
|
|
setWaiting(true)
|
|
|
|
.map((c: CandidateItem) => ({
|
|
|
|
|
|
|
|
name: c.name,
|
|
|
|
|
|
|
|
description: c.description,
|
|
|
|
|
|
|
|
image: c.image,
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
const grades = election.grades
|
|
|
|
|
|
|
|
.filter((c) => c.active)
|
|
|
|
|
|
|
|
.map((g: GradeItem, i: number) => ({ name: g.name, value: i }));
|
|
|
|
|
|
|
|
setWaiting(true);
|
|
|
|
const response = await updateElection(
|
|
|
|
const response = await updateElection(
|
|
|
|
election.ref,
|
|
|
|
election.ref,
|
|
|
|
election.name,
|
|
|
|
election.name,
|
|
|
@ -103,130 +122,141 @@ const HeaderRubbon = () => {
|
|
|
|
election.hideResults,
|
|
|
|
election.hideResults,
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
election.restricted,
|
|
|
|
election.restricted,
|
|
|
|
election.randomOrder,
|
|
|
|
election.randomOrder
|
|
|
|
);
|
|
|
|
);
|
|
|
|
if (response.status === 200 && "ref" in response) {
|
|
|
|
if (response.status === 200 && 'ref' in response) {
|
|
|
|
if (election.restricted && election.emails.length > 0) {
|
|
|
|
if (election.restricted && election.emails.length > 0) {
|
|
|
|
if (election.emails.length !== response.invites.length) {
|
|
|
|
if (election.emails.length !== response.invites.length) {
|
|
|
|
throw Error("Unexpected number of invites!")
|
|
|
|
throw Error('Unexpected number of invites!');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const urlVotes = response.invites.map((token: string) => getUrlVote(response.ref, token));
|
|
|
|
const urlVotes = response.invites.map((token: string) =>
|
|
|
|
|
|
|
|
getUrlVote(response.ref, token)
|
|
|
|
|
|
|
|
);
|
|
|
|
const urlResult = getUrlResults(response.ref);
|
|
|
|
const urlResult = getUrlResults(response.ref);
|
|
|
|
await sendInviteMails(
|
|
|
|
await sendInviteMails(
|
|
|
|
election.emails,
|
|
|
|
election.emails,
|
|
|
|
election.name,
|
|
|
|
election.name,
|
|
|
|
urlVotes,
|
|
|
|
urlVotes,
|
|
|
|
urlResult,
|
|
|
|
urlResult,
|
|
|
|
router,
|
|
|
|
router
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setWaiting(false)
|
|
|
|
setWaiting(false);
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "success",
|
|
|
|
status: 'success',
|
|
|
|
message: t("success.election-closed")
|
|
|
|
message: t('success.election-closed'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return <div className="w-100 p-4 bg-primary text-white d-flex justify-content-between align-items-center">
|
|
|
|
|
|
|
|
<h5>{t('admin.admin-title')}</h5>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div className="d-flex">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{election.restricted ? null :
|
|
|
|
|
|
|
|
<Link href={`${VOTE}/${election.ref}`}>
|
|
|
|
|
|
|
|
<Button icon={faArrowRight}
|
|
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
|
|
className="me-3"
|
|
|
|
|
|
|
|
style={{border: "2px solid rgba(255, 255, 255, 0.4)"}}
|
|
|
|
|
|
|
|
position="right">
|
|
|
|
|
|
|
|
{t('admin.go-to-vote')}
|
|
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{canViewResults(election) ?
|
|
|
|
return (
|
|
|
|
<Link href={`${RESULTS}/${election.ref}`}>
|
|
|
|
<div className="w-100 p-4 bg-primary text-white d-flex justify-content-between align-items-center">
|
|
|
|
<Button icon={faArrowRight}
|
|
|
|
<h5>{t('admin.admin-title')}</h5>
|
|
|
|
color="primary"
|
|
|
|
|
|
|
|
className="me-3"
|
|
|
|
<div className="d-flex">
|
|
|
|
style={{border: "2px solid rgba(255, 255, 255, 0.4)"}}
|
|
|
|
{election.restricted ? null : (
|
|
|
|
position="right">
|
|
|
|
<Link href={`${VOTE}/${election.ref}`}>
|
|
|
|
{t('admin.go-to-result')}
|
|
|
|
<Button
|
|
|
|
|
|
|
|
icon={faArrowRight}
|
|
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
|
|
className="me-3"
|
|
|
|
|
|
|
|
style={{ border: '2px solid rgba(255, 255, 255, 0.4)' }}
|
|
|
|
|
|
|
|
position="right"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
{t('admin.go-to-vote')}
|
|
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{canViewResults(election) ? (
|
|
|
|
|
|
|
|
<Link href={`${RESULTS}/${election.ref}`}>
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
|
|
|
icon={faArrowRight}
|
|
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
|
|
className="me-3"
|
|
|
|
|
|
|
|
style={{ border: '2px solid rgba(255, 255, 255, 0.4)' }}
|
|
|
|
|
|
|
|
position="right"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
{t('admin.go-to-result')}
|
|
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{isClosed(election) ? null : (
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
|
|
|
className="me-3 btn_closing"
|
|
|
|
|
|
|
|
style={{ border: '2px solid rgba(255, 255, 255, 0.4)' }}
|
|
|
|
|
|
|
|
onClick={handleClosing}
|
|
|
|
|
|
|
|
position="right"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
{waiting ? <Spinner /> : t('admin.close-election')}
|
|
|
|
</Button>
|
|
|
|
</Button>
|
|
|
|
</Link>
|
|
|
|
)}
|
|
|
|
: null}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{isClosed(election) ? null :
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
|
|
|
className="me-3 btn_closing"
|
|
|
|
|
|
|
|
style={{border: "2px solid rgba(255, 255, 255, 0.4)"}}
|
|
|
|
|
|
|
|
onClick={handleClosing}
|
|
|
|
|
|
|
|
position="right">
|
|
|
|
|
|
|
|
{waiting ?
|
|
|
|
|
|
|
|
<Spinner />
|
|
|
|
|
|
|
|
:
|
|
|
|
|
|
|
|
t('admin.close-election')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
</div >
|
|
|
|
const CreateElection = ({ context, token }) => {
|
|
|
|
}
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
|
|
|
|
|
|
|
const CreateElection = ({context, token}) => {
|
|
|
|
|
|
|
|
const {t} = useTranslation();
|
|
|
|
|
|
|
|
const [election, dispatch] = useElection();
|
|
|
|
const [election, dispatch] = useElection();
|
|
|
|
const [_, dispatchApp] = useAppContext();
|
|
|
|
const [_, dispatchApp] = useAppContext();
|
|
|
|
const router = useRouter();
|
|
|
|
const router = useRouter();
|
|
|
|
const [waiting, setWaiting] = useState(false);
|
|
|
|
const [waiting, setWaiting] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
dispatch({type: ElectionTypes.RESET, value: context})
|
|
|
|
dispatch({ type: ElectionTypes.RESET, value: context });
|
|
|
|
}, [])
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
if (!checkName(election)) {
|
|
|
|
if (!checkName(election)) {
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "error",
|
|
|
|
status: 'error',
|
|
|
|
message: t("error.uncorrect-name")
|
|
|
|
message: t('error.uncorrect-name'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasEnoughGrades(election)) {
|
|
|
|
if (!hasEnoughGrades(election)) {
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "error",
|
|
|
|
status: 'error',
|
|
|
|
message: t("error.not-enough-grades")
|
|
|
|
message: t('error.not-enough-grades'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!hasEnoughCandidates(election)) {
|
|
|
|
if (!hasEnoughCandidates(election)) {
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "error",
|
|
|
|
status: 'error',
|
|
|
|
message: t("error.not-enough-candidates")
|
|
|
|
message: t('error.not-enough-candidates'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!canBeFinished(election)) {
|
|
|
|
if (!canBeFinished(election)) {
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "error",
|
|
|
|
status: 'error',
|
|
|
|
message: t("error.cant-be-finished")
|
|
|
|
message: t('error.cant-be-finished'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const candidates = election.candidates.filter(c => c.active).map((c: CandidateItem) => ({name: c.name, description: c.description, image: c.image}))
|
|
|
|
const candidates = election.candidates
|
|
|
|
const grades = election.grades.filter(c => c.active).map((g: GradeItem, i: number) => ({name: g.name, value: i}))
|
|
|
|
.filter((c) => c.active)
|
|
|
|
setWaiting(true)
|
|
|
|
.map((c: CandidateItem) => ({
|
|
|
|
|
|
|
|
name: c.name,
|
|
|
|
|
|
|
|
description: c.description,
|
|
|
|
|
|
|
|
image: c.image,
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
const grades = election.grades
|
|
|
|
|
|
|
|
.filter((c) => c.active)
|
|
|
|
|
|
|
|
.map((g: GradeItem, i: number) => ({ name: g.name, value: i }));
|
|
|
|
|
|
|
|
setWaiting(true);
|
|
|
|
|
|
|
|
|
|
|
|
const response = await updateElection(
|
|
|
|
const response = await updateElection(
|
|
|
|
election.ref,
|
|
|
|
election.ref,
|
|
|
@ -238,43 +268,51 @@ const CreateElection = ({context, token}) => {
|
|
|
|
election.hideResults,
|
|
|
|
election.hideResults,
|
|
|
|
true,
|
|
|
|
true,
|
|
|
|
election.restricted,
|
|
|
|
election.restricted,
|
|
|
|
election.randomOrder,
|
|
|
|
election.randomOrder
|
|
|
|
);
|
|
|
|
);
|
|
|
|
if (response.status === 200 && "ref" in response) {
|
|
|
|
if (response.status === 200 && 'ref' in response) {
|
|
|
|
if (election.restricted && election.emails.length > 0) {
|
|
|
|
if (election.restricted && election.emails.length > 0) {
|
|
|
|
if (election.emails.length !== response.invites.length) {
|
|
|
|
if (election.emails.length !== response.invites.length) {
|
|
|
|
throw Error("Unexpected number of invites!")
|
|
|
|
throw Error('Unexpected number of invites!');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const urlVotes = response.invites.map((token: string) => getUrlVote(response.ref, token));
|
|
|
|
const urlVotes = response.invites.map((token: string) =>
|
|
|
|
|
|
|
|
getUrlVote(response.ref, token)
|
|
|
|
|
|
|
|
);
|
|
|
|
const urlResult = getUrlResults(response.ref);
|
|
|
|
const urlResult = getUrlResults(response.ref);
|
|
|
|
await sendInviteMails(
|
|
|
|
await sendInviteMails(
|
|
|
|
election.emails,
|
|
|
|
election.emails,
|
|
|
|
election.name,
|
|
|
|
election.name,
|
|
|
|
urlVotes,
|
|
|
|
urlVotes,
|
|
|
|
urlResult,
|
|
|
|
urlResult,
|
|
|
|
router,
|
|
|
|
router
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setWaiting(false)
|
|
|
|
setWaiting(false);
|
|
|
|
|
|
|
|
|
|
|
|
dispatchApp({
|
|
|
|
dispatchApp({
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
type: AppTypes.TOAST_ADD,
|
|
|
|
status: "success",
|
|
|
|
status: 'success',
|
|
|
|
message: t("success.election-updated")
|
|
|
|
message: t('success.election-updated'),
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const numCandidates = election.candidates.filter(c => c.active && c.name != "").length;
|
|
|
|
const numCandidates = election.candidates.filter(
|
|
|
|
const numGrades = election.grades.filter(g => g.active && g.name != "").length;
|
|
|
|
(c) => c.active && c.name != ''
|
|
|
|
const disabled = (
|
|
|
|
).length;
|
|
|
|
!election.name || election.name == "" ||
|
|
|
|
const numGrades = election.grades.filter(
|
|
|
|
|
|
|
|
(g) => g.active && g.name != ''
|
|
|
|
|
|
|
|
).length;
|
|
|
|
|
|
|
|
const disabled =
|
|
|
|
|
|
|
|
!election.name ||
|
|
|
|
|
|
|
|
election.name == '' ||
|
|
|
|
numCandidates < 2 ||
|
|
|
|
numCandidates < 2 ||
|
|
|
|
numGrades < 2 || numGrades > gradeColors.length
|
|
|
|
numGrades < 2 ||
|
|
|
|
)
|
|
|
|
numGrades > gradeColors.length;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<><HeaderRubbon />
|
|
|
|
<>
|
|
|
|
|
|
|
|
<HeaderRubbon />
|
|
|
|
<Container
|
|
|
|
<Container
|
|
|
|
fluid="xl"
|
|
|
|
fluid="xl"
|
|
|
|
className="my-5 flex-column d-flex justify-content-center"
|
|
|
|
className="my-5 flex-column d-flex justify-content-center"
|
|
|
@ -319,12 +357,11 @@ const CreateElection = ({context, token}) => {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const CreateElectionProviding = ({ children, context, token }) => (
|
|
|
|
const CreateElectionProviding = ({children, context, token}) => (
|
|
|
|
|
|
|
|
<ElectionProvider>
|
|
|
|
<ElectionProvider>
|
|
|
|
<Blur />
|
|
|
|
<Blur />
|
|
|
|
<CreateElection context={context} token={token} />
|
|
|
|
<CreateElection context={context} token={token} />
|
|
|
|
</ElectionProvider>
|
|
|
|
</ElectionProvider>
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
export default CreateElectionProviding;
|
|
|
|
export default CreateElectionProviding;
|
|
|
|