fix: ballot & resutls bugs

pull/100/head
Pierre-Louis Guhur 1 year ago
parent 5df5d10296
commit 1f6902d9ae

@ -1,6 +1,6 @@
import { useEffect, useLayoutEffect, useRef, useState } from 'react'; import {useEffect, useLayoutEffect, useRef, useState} from 'react';
import { GradeResultInterface, MeritProfileInterface } from '@services/type'; import {GradeResultInterface, MeritProfileInterface} from '@services/type';
import { getMajorityGrade } from '@services/majorityJudgment'; import {getMajorityGrade} from '@services/majorityJudgment';
interface ParamsInterface { interface ParamsInterface {
numVotes: number; numVotes: number;
@ -14,7 +14,7 @@ interface GradeBarInterface {
params: ParamsInterface; params: ParamsInterface;
} }
const GradeBar = ({ index, grade, size, params }: GradeBarInterface) => { const GradeBar = ({index, grade, size, params}: GradeBarInterface) => {
const width = `${size * 100}%`; const width = `${size * 100}%`;
const textWidth = Math.floor(100 * size); const textWidth = Math.floor(100 * size);
@ -59,14 +59,14 @@ const DashedMedian = () => {
return ( return (
<div <div
className="position-relative d-flex justify-content-center" className="position-relative d-flex justify-content-center"
style={{ top: '60px', height: '50px' }} style={{top: '60px', height: '50px'}}
> >
<div className="border h-100 border-1 border-dark border-opacity-75 border-dashed"></div> <div className="border h-100 border-1 border-dark border-opacity-75 border-dashed"></div>
</div> </div>
); );
}; };
const MajorityGrade = ({ grade, left }) => { const MajorityGrade = ({grade, left}) => {
// const spanRef = useRef<HTMLDivElement>(); // const spanRef = useRef<HTMLDivElement>();
const spanRef = useRef<HTMLDivElement>(); const spanRef = useRef<HTMLDivElement>();
@ -81,7 +81,7 @@ const MajorityGrade = ({ grade, left }) => {
return ( return (
<div <div
style={{ left: `calc(${left * 100}% - ${width / 2}px)` }} style={{left: `calc(${left * 100}% - ${width / 2}px)`}}
className="position-relative" className="position-relative"
> >
<div <div
@ -121,8 +121,8 @@ interface MeritProfileBarInterface {
grades: Array<GradeResultInterface>; grades: Array<GradeResultInterface>;
} }
const MeritProfileBar = ({ profile, grades }: MeritProfileBarInterface) => { const MeritProfileBar = ({profile, grades}: MeritProfileBarInterface) => {
const gradesByValue: { [key: number]: GradeResultInterface } = {}; const gradesByValue: {[key: number]: GradeResultInterface} = {};
grades.forEach((g) => (gradesByValue[g.value] = g)); grades.forEach((g) => (gradesByValue[g.value] = g));
const numVotes = Object.values(profile).reduce((a, b) => a + b, 0); const numVotes = Object.values(profile).reduce((a, b) => a + b, 0);
@ -167,32 +167,37 @@ const MeritProfileBar = ({ profile, grades }: MeritProfileBarInterface) => {
left={proponentWidth + normalized[majorityValue] / 2} left={proponentWidth + normalized[majorityValue] / 2}
/> />
<div className="d-flex"> <div className="d-flex">
<div {proponentWidth > 1e-5 ? (
className={`d-flex border border-${ <div
proponentMajority ? 2 : 1 className={`d-flex border border-${proponentMajority ? 2 : 1
} border-success`} } border-success`}
style={{ flexBasis: `${proponentWidth * 100}%` }} style={{flexBasis: `${proponentWidth * 100}%`}}
> >
{values {values
.filter((v) => v > majorityGrade.value) .filter((v) => v > majorityGrade.value)
.map((v) => { .map((v) => {
const index = values.indexOf(v); const index = values.indexOf(v);
const size = const size =
proponentWidth < 1e-3 ? 0 : normalized[index] / proponentWidth; proponentWidth < 1e-3 ? 0 : normalized[index] / proponentWidth;
return ( return (
<GradeBar <GradeBar
index={index} index={index}
params={params} params={params}
grade={gradesByValue[v]} grade={gradesByValue[v]}
key={index} key={index}
size={size} size={size}
/> />
); );
})} })}
</div> </div>) : (
<div
className="d-flex"
style={{flexBasis: `${proponentWidth * 100}%`}}
>
</div>)}
<div <div
className="border border-2 border-primary" className="border border-2 border-primary"
style={{ flexBasis: `${normalized[majorityValue] * 100}%` }} style={{flexBasis: `${normalized[majorityValue] * 100}%`}}
> >
{values {values
.filter((v) => v === majorityGrade.value) .filter((v) => v === majorityGrade.value)
@ -209,29 +214,32 @@ const MeritProfileBar = ({ profile, grades }: MeritProfileBarInterface) => {
); );
})} })}
</div> </div>
<div {opponentWidth > 1e-5 ? (
className={`d-flex border border-${ <div
proponentMajority ? 1 : 2 className={`d-flex border border-${proponentMajority ? 1 : 2
} border-danger`} } border-danger`}
style={{ flexBasis: `${opponentWidth * 100}%` }} style={{flexBasis: `${opponentWidth * 100}%`}}
> >
{values {values
.filter((v) => v < majorityGrade.value) .filter((v) => v < majorityGrade.value)
.map((v) => { .map((v) => {
const index = values.indexOf(v); const index = values.indexOf(v);
const size = const size =
opponentWidth < 1e-3 ? 0 : normalized[index] / opponentWidth; opponentWidth < 1e-3 ? 0 : normalized[index] / opponentWidth;
return ( return (
<GradeBar <GradeBar
index={index} index={index}
params={params} params={params}
grade={gradesByValue[v]} grade={gradesByValue[v]}
key={index} key={index}
size={size} size={size}
/> />
); );
})} })}
</div> </div>) : (
<div className="d-flex" style={{flexBasis: `${opponentWidth * 100}%`}} >
</div>
)}
</div> </div>
{/* <div className='median dash'> </div> */} {/* <div className='median dash'> </div> */}
</> </>

@ -1,10 +1,10 @@
import { useState } from 'react'; import {useState} from 'react';
import { Container } from 'reactstrap'; import {Container} from 'reactstrap';
import { useBallot } from '@services/BallotContext'; import {useBallot} from '@services/BallotContext';
import CandidateCard from '@components/ballot/CandidateCard'; import CandidateCard from '@components/ballot/CandidateCard';
import TitleBar from '@components/ballot/TitleBar'; import TitleBar from '@components/ballot/TitleBar';
import GradeInput from '@components/ballot/GradeInput'; import GradeInput from '@components/ballot/GradeInput';
import { CandidatePayload } from '@services/api'; import {CandidatePayload} from '@services/api';
import CandidateModal from '@components/CandidateModalGet'; import CandidateModal from '@components/CandidateModalGet';
const BallotDesktop = () => { const BallotDesktop = () => {
@ -19,7 +19,7 @@ const BallotDesktop = () => {
<TitleBar election={ballot.election} /> <TitleBar election={ballot.election} />
<Container <Container
className="w-100 h-100 d-flex flex-column justify-content-center align-items-center" className="w-100 h-100 d-flex flex-column justify-content-center align-items-center"
style={{ maxWidth: '1050px' }} style={{maxWidth: '1050px'}}
> >
<h1 className="mb-5">{ballot.election.name}</h1> <h1 className="mb-5">{ballot.election.name}</h1>
{ballot.election.candidates.map((candidate, candidateId) => { {ballot.election.candidates.map((candidate, candidateId) => {
@ -33,7 +33,9 @@ const BallotDesktop = () => {
candidate={candidate} candidate={candidate}
/> />
<div className="d-flex"> <div className="d-flex">
{ballot.election.grades.map((_, gradeId) => { {ballot.election.grades.sort(
(a, b) => b.value - a.value
).map((_, gradeId) => {
console.assert(gradeId < numGrades); console.assert(gradeId < numGrades);
return ( return (
<GradeInput <GradeInput

@ -56,7 +56,7 @@ const BallotMobile = () => {
<div className="ms-2" onClick={() => moveRight(true)}><FontAwesomeIcon color="#0A004C" icon={faChevronRight} /></div> : null} <div className="ms-2" onClick={() => moveRight(true)}><FontAwesomeIcon color="#0A004C" icon={faChevronRight} /></div> : null}
</div> </div>
<div className="d-flex mt-2 flex-column"> <div className="d-flex mt-2 flex-column">
{ballot.election.grades.map((_, gradeId) => { {ballot.election.grades.sort((a, b) => b.value - a.value).map((_, gradeId) => {
console.assert(gradeId < numGrades); console.assert(gradeId < numGrades);
return ( return (
<GradeInput <GradeInput

@ -23,7 +23,8 @@ const CandidateCard = ({candidate, onClick}: CandidateCardInterface) => {
<div className="d-flex lh-sm flex-column justify-content-center ps-3"> <div className="d-flex lh-sm flex-column justify-content-center ps-3">
<span className="text-black fs-5 m-0 ">{candidate.name}</span> <span className="text-black fs-5 m-0 ">{candidate.name}</span>
<br /> <br />
<span className="text-muted fs-6 m-0 fw-normal">{t("vote.more-details")}</span> { // <span className="text-muted fs-6 m-0 fw-normal">{t("vote.more-details")}</span>
}
</div> </div>
</div>) </div>)
} }

@ -32,7 +32,7 @@ const GradeInput = ({gradeId, candidateId}: GradeInputInterface) => {
}; };
const active = ballot.votes.some(b => b.gradeId === gradeId && b.candidateId === candidateId) const active = ballot.votes.some(b => b.gradeId === gradeId && b.candidateId === candidateId)
const color = active ? getGradeColor(gradeId, numGrades) : '#C3BFD8'; const color = active ? getGradeColor(grade.value, numGrades) : '#C3BFD8';
return (<> return (<>
<div <div

Loading…
Cancel
Save