You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
2.1 KiB
94 lines
2.1 KiB
/**
|
|
* This file provides a context and a reducer to manage a ballot
|
|
*/
|
|
import {createContext, useContext, useReducer, Dispatch} from 'react';
|
|
import {ElectionPayload} from './api';
|
|
import {Vote} from './type';
|
|
|
|
|
|
export interface BallotContextInterface {
|
|
election: ElectionPayload | null;
|
|
votes: Array<Vote>;
|
|
}
|
|
|
|
const defaultBallot: BallotContextInterface = {
|
|
election: null,
|
|
votes: []
|
|
};
|
|
|
|
|
|
export enum BallotTypes {
|
|
ELECTION = 'ELECTION',
|
|
VOTE = 'VOTE',
|
|
}
|
|
|
|
export type ElectionAction = {
|
|
type: BallotTypes.ELECTION;
|
|
election: ElectionPayload;
|
|
}
|
|
|
|
export type VoteAction = {
|
|
type: BallotTypes.VOTE;
|
|
candidateId: number;
|
|
gradeId: number;
|
|
}
|
|
|
|
export type BallotActionTypes = ElectionAction | VoteAction;
|
|
|
|
|
|
function reducer(ballot: BallotContextInterface, action: BallotActionTypes) {
|
|
/**
|
|
* Manage all types of action doable on an election
|
|
*/
|
|
switch (action.type) {
|
|
case BallotTypes.ELECTION: {
|
|
return {...ballot, election: action.election}
|
|
}
|
|
case BallotTypes.VOTE: {
|
|
const votes = [...ballot.votes];
|
|
const voteForCandidate = votes.filter(v => v.candidateId === action.candidateId);
|
|
if (voteForCandidate.length > 1) {
|
|
throw Error("Inconsistent ballot")
|
|
}
|
|
if (voteForCandidate.length === 1) {
|
|
voteForCandidate[0].candidateId = action.candidateId;
|
|
voteForCandidate[0].gradeId = action.gradeId;
|
|
} else {
|
|
votes.push({
|
|
candidateId: action.candidateId,
|
|
gradeId: action.gradeId,
|
|
})
|
|
}
|
|
return {...ballot, votes};
|
|
}
|
|
default: {
|
|
return ballot
|
|
}
|
|
}
|
|
}
|
|
|
|
type DispatchType = Dispatch<BallotActionTypes>;
|
|
const BallotContext = createContext<[BallotContextInterface, DispatchType]>([defaultBallot, () => {}]);
|
|
|
|
|
|
export function BallotProvider({children}) {
|
|
/**
|
|
* Provide the election and the dispatch to all children components
|
|
*/
|
|
const [ballot, dispatch] = useReducer(reducer, defaultBallot);
|
|
|
|
return (
|
|
<BallotContext.Provider value={[ballot, dispatch]}>
|
|
{children}
|
|
</BallotContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useBallot() {
|
|
/**
|
|
* A simple hook to manage ballots
|
|
*/
|
|
return useContext(BallotContext);
|
|
}
|
|
|