diff --git a/components/ballot/BallotDesktop.tsx b/components/ballot/BallotDesktop.tsx new file mode 100644 index 0000000..2cb0694 --- /dev/null +++ b/components/ballot/BallotDesktop.tsx @@ -0,0 +1,77 @@ +import {MouseEvent} from 'react' +import {useRouter} from 'next/router'; +import {useTranslation} from 'next-i18next'; +import Button from '@components/Button'; +import {Col, Row, Container} from 'reactstrap'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCalendarDays, faCheck} from '@fortawesome/free-solid-svg-icons'; +import {useBallot, BallotTypes, BallotProvider} from '@services/BallotContext'; +import CandidateCard from '@components/ballot/CandidateCard' +import TitleBar from '@components/ballot/TitleBar' +import GradeInput from '@components/ballot/GradeInput' + + +const BallotDesktop = () => { + const {t} = useTranslation(); + + const [ballot, dispatch] = useBallot(); + + const numGrades = ballot.election.grades.length; + const disabled = ballot.votes.length !== ballot.election.candidates.length; + const router = useRouter(); + + const handleSubmit = (event: MouseEvent) => { + 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(`/confirm/${ballot.election.id}`); + // }); + }; + + return ( +
+ +
+

{ballot.election.name}

+ {ballot.election.candidates.map((candidate, candidateId) => { + return ( +
+ +
+ {ballot.election.grades.map((_, gradeId) => { + console.assert(gradeId < numGrades); + return ( + + ); + })} +
+
+ ); + })} + + + +
+
+ ) +} +export default BallotDesktop diff --git a/components/ballot/BallotMobile.tsx b/components/ballot/BallotMobile.tsx new file mode 100644 index 0000000..306c884 --- /dev/null +++ b/components/ballot/BallotMobile.tsx @@ -0,0 +1,65 @@ +import {MouseEvent} from 'react' +import {useRouter} from 'next/router'; +import {useTranslation} from 'next-i18next'; +import Button from '@components/Button'; +import {Col, Row, Container} from 'reactstrap'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCalendarDays, faCheck} from '@fortawesome/free-solid-svg-icons'; +import {useBallot, BallotTypes, BallotProvider} from '@services/BallotContext'; +import CandidateCard from '@components/ballot/CandidateCard' +import TitleBar from '@components/ballot/TitleBar' +import GradeInput from '@components/ballot/GradeInput' + + +const BallotMobile = () => { + const {t} = useTranslation(); + + const [ballot, dispatch] = useBallot(); + + const numGrades = ballot.election.grades.length; + const disabled = ballot.votes.length !== ballot.election.candidates.length; + const router = useRouter(); + + const handleSubmit = (event: MouseEvent) => { + event.preventDefault(); + router.push(`/confirm/${ballot.election.id}`); + }; + + return ( +
+
+

{ballot.election.name}

+ {ballot.election.candidates.map((candidate, candidateId) => { + return ( +
+ +
+ {ballot.election.grades.map((_, gradeId) => { + console.assert(gradeId < numGrades); + return ( + + ); + })} +
+
+ ); + })} + + + +
+
+ ) +} + +export default BallotMobile diff --git a/components/ballot/CandidateCard.tsx b/components/ballot/CandidateCard.tsx new file mode 100644 index 0000000..9ac9463 --- /dev/null +++ b/components/ballot/CandidateCard.tsx @@ -0,0 +1,28 @@ +import Image from 'next/image'; +import {useTranslation} from 'next-i18next'; +import defaultAvatar from '../../public/avatarBlue.svg'; +import {CandidatePayload} from '@services/api'; + +interface CandidateCardInterface { + candidate: CandidatePayload; +} +const CandidateCard = ({candidate}: CandidateCardInterface) => { + const {t} = useTranslation(); + return (
+ {t('common.thumbnail')} +
+ {candidate.name} +
+ {t("vote.more-details")} +
+
) +} + + +export default CandidateCard; diff --git a/components/ballot/GradeInput.tsx b/components/ballot/GradeInput.tsx new file mode 100644 index 0000000..00e14e7 --- /dev/null +++ b/components/ballot/GradeInput.tsx @@ -0,0 +1,34 @@ +import {useState, useCallback, useEffect, MouseEvent} from 'react'; +import {useBallot, BallotTypes} from '@services/BallotContext'; +import {getGradeColor} from '@services/grades'; + +interface GradeInputInterface { + gradeId: number; + candidateId: number; +} +const GradeInput = ({gradeId, candidateId}: GradeInputInterface) => { + const [ballot, dispatch] = useBallot(); + if (!ballot) {throw Error("Ensure the election is loaded")} + + const grade = ballot.election.grades[gradeId]; + const numGrades = ballot.election.grades.length; + + const handleClick = (event: MouseEvent) => { + dispatch({type: BallotTypes.VOTE, candidateId: candidateId, gradeId: gradeId}) + }; + + const active = ballot.votes.some(b => b.gradeId === gradeId && b.candidateId === candidateId) + const color = active ? getGradeColor(gradeId, numGrades) : '#C3BFD8'; + + return ( +
+ {grade.name} +
+ ) +} + +export default GradeInput diff --git a/components/ballot/TitleBar.tsx b/components/ballot/TitleBar.tsx new file mode 100644 index 0000000..1e777ba --- /dev/null +++ b/components/ballot/TitleBar.tsx @@ -0,0 +1,30 @@ +import {useRouter} from 'next/router'; +import Button from '@components/Button'; +import {useTranslation} from 'next-i18next'; +import {getElection, castBallot, apiErrors, ElectionPayload, CandidatePayload, GradePayload} from '@services/api'; +import {getLocaleShort} from '@services/utils'; +import {faCalendarDays} from '@fortawesome/free-solid-svg-icons'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; + + +interface TitleBarInterface { + election: ElectionPayload; +} +const TitleBar = ({election}: TitleBarInterface) => { + const {t} = useTranslation(); + const router = useRouter(); + const locale = getLocaleShort(router); + + return ( +
+
+ +
+
+ {` ${t("vote.open-until")} ${new Date(election.date_end).toLocaleDateString(locale, {dateStyle: "long"})}`} +
+
+ ) +}; + +export default TitleBar diff --git a/pages/ballot/[pid]/[[...tid]].tsx b/pages/ballot/[pid]/[[...tid]].tsx index 83e31ea..35efe43 100644 --- a/pages/ballot/[pid]/[[...tid]].tsx +++ b/pages/ballot/[pid]/[[...tid]].tsx @@ -1,22 +1,13 @@ -import {useState, useCallback, useEffect, MouseEvent} from 'react'; -import Image from 'next/image'; +import {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 {Col, Row, Container} 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, CandidatePayload, GradePayload} from '@services/api'; -import Button from '@components/Button'; -import useEmblaCarousel from 'embla-carousel-react'; -import {DotButton} from '@components/admin/EmblaCarouselButtons'; -import {getGradeColor} from '@services/grades'; +import BallotDesktop from '@components/ballot/BallotDesktop' +import BallotMobile from '@components/ballot/BallotMobile' import {useBallot, BallotTypes, BallotProvider} from '@services/BallotContext'; -import {getLocaleShort} from '@services/utils'; import {ENDED_VOTE} from '@services/routes'; -import defaultAvatar from '../../../public/avatarBlue.svg'; const shuffle = (array) => array.sort(() => Math.random() - 0.5); @@ -64,115 +55,8 @@ export async function getServerSideProps({query: {pid, tid}, locale}) { }; } -interface TitleBarInterface { - election: ElectionPayload; -} -const TitleBar = ({election}: TitleBarInterface) => { - const {t} = useTranslation(); - const router = useRouter(); - const locale = getLocaleShort(router); - - return ( -
-
- -
-
- {` ${t("vote.open-until")} ${new Date(election.date_end).toLocaleDateString(locale, {dateStyle: "long"})}`} -
-
- ) -}; - -interface CandidateCardInterface { - candidate: CandidatePayload; -} -const CandidateCard = ({candidate}: CandidateCardInterface) => { - const {t} = useTranslation(); - return (
- {t('common.thumbnail')} -
- {candidate.name} -
- {t("vote.more-details")} -
-
) -} -interface GradeInputInterface { - gradeId: number; - candidateId: number; -} -const GradeInput = ({gradeId, candidateId}: GradeInputInterface) => { - const [ballot, dispatch] = useBallot(); - if (!ballot) {throw Error("Ensure the election is loaded")} - - const grade = ballot.election.grades[gradeId]; - const numGrades = ballot.election.grades.length; - const color = getGradeColor(gradeId, numGrades); - - const handleClick = (event: MouseEvent) => { - dispatch({type: BallotTypes.VOTE, candidateId: candidateId, gradeId: gradeId}) - }; - - const active = ballot.votes.some(b => b.gradeId === gradeId && b.candidateId === candidateId) - - return ( -
- - {grade.name} - - - { /**/} - {grade.name} - { /**/} - -
- ) -} interface VoteInterface { election: ElectionPayload; @@ -197,7 +81,6 @@ const VoteBallot = ({election, token}: VoteInterface) => { } const numGrades = ballot.election.grades.length; - const disabled = ballot.votes.length !== ballot.election.candidates.length; const colSizeCandidateLg = 4; const colSizeCandidateMd = 6; const colSizeCandidateXs = 12; @@ -254,7 +137,7 @@ const VoteBallot = ({election, token}: VoteInterface) => { // }, [embla, setScrollSnaps, onSelect]); return ( - <> +
{election.name} @@ -266,41 +149,9 @@ const VoteBallot = ({election, token}: VoteInterface) => { /> - -
-

{election.name}

- - {election.candidates.map((candidate, candidateId) => { - return ( -
- -
- {election.grades.map((_, gradeId) => { - console.assert(gradeId < numGrades); - return ( - - ); - })} -
-
- ); - })} - -
- - - - + + + ); }; diff --git a/styles/scss/_button.scss b/styles/scss/_button.scss index cd37c4c..b8301c5 100644 --- a/styles/scss/_button.scss +++ b/styles/scss/_button.scss @@ -76,3 +76,7 @@ top: 20px; right: 20px; } + +.btn_shadow{ + box-shadow: 0px 2px 0px #8F88BA; +} diff --git a/styles/scss/config.scss b/styles/scss/config.scss index 1451474..882ce7d 100644 --- a/styles/scss/config.scss +++ b/styles/scss/config.scss @@ -46,7 +46,7 @@ $font-sizes: ( 2: $h2-font-size, 3: $h3-font-size, 4: $h4-font-size, - 5: $font-size-base, + 5: $font-size-base * 0.9, 6: $font-size-base * 0.75 );