From b3c539f35867146b5c11ef441a6414f2ed3bfc7b Mon Sep 17 00:00:00 2001 From: Ben Adida Date: Thu, 30 Jul 2020 11:51:51 -0700 Subject: [PATCH 1/7] First pass --- client/src/components/ElectionManager.tsx | 4 +- .../src/components/HandMarkedPaperBallot.tsx | 5 +- client/src/routerPaths.ts | 1 + .../src/screens/UserTestingBallotScreen.tsx | 48 ++ client/src/screens/testElection.json | 510 ++++++++++++++++++ 5 files changed, 566 insertions(+), 2 deletions(-) create mode 100644 client/src/screens/UserTestingBallotScreen.tsx create mode 100644 client/src/screens/testElection.json diff --git a/client/src/components/ElectionManager.tsx b/client/src/components/ElectionManager.tsx index 8bfad07..94ababf 100644 --- a/client/src/components/ElectionManager.tsx +++ b/client/src/components/ElectionManager.tsx @@ -12,6 +12,8 @@ import TestDeckScreen from '../screens/TestDeckScreen' import TallyScreen from '../screens/TallyScreen' import TallyReportScreen from '../screens/TallyReportScreen' +import UserTestingBallotScreen from '../screens/UserTestingBallotScreen' + import routerPaths from '../routerPaths' import OvervoteCombinationReportScreen from '../screens/OvervoteCombinationReportScreen' @@ -20,7 +22,7 @@ const ElectionManager = () => { const election = e! if (!election) { - return + return } return ( diff --git a/client/src/components/HandMarkedPaperBallot.tsx b/client/src/components/HandMarkedPaperBallot.tsx index c03febf..8c92924 100644 --- a/client/src/components/HandMarkedPaperBallot.tsx +++ b/client/src/components/HandMarkedPaperBallot.tsx @@ -122,7 +122,8 @@ const ballotMetadata = ({ primaryLocaleCode: string secondaryLocaleCode: string ballotId?: string -}): string => { +}): string => { + const params = new URLSearchParams([ ['t', `${!isLiveMode ? 't' : '_'}`], ['pr', precinctId], @@ -449,6 +450,8 @@ const HandMarkedPaperBallot = ({ useLayoutEffect(() => { const printBallot = printBallotRef?.current + console.log("printballot", printBallot) + if (!printBallot) { return } diff --git a/client/src/routerPaths.ts b/client/src/routerPaths.ts index 4ee05c5..fc672cc 100644 --- a/client/src/routerPaths.ts +++ b/client/src/routerPaths.ts @@ -27,6 +27,7 @@ const routerPaths = { `/tally/test-ballot-deck/${precinctId}`, overvoteCombinationReport: '/tally/pairs', export: '/export-election-ballot-package', + userTestingBallot: '/usertesting/ballot', } export default routerPaths diff --git a/client/src/screens/UserTestingBallotScreen.tsx b/client/src/screens/UserTestingBallotScreen.tsx new file mode 100644 index 0000000..d6d8959 --- /dev/null +++ b/client/src/screens/UserTestingBallotScreen.tsx @@ -0,0 +1,48 @@ +import React from 'react' +import { + getPrecinctById, + Election, +} from '@votingworks/ballot-encoder' + +import { BallotLocale } from '../config/types' + +import PrintButton from '../components/PrintButton' +import HandMarkedPaperBallot from '../components/HandMarkedPaperBallot' +import NavigationScreen from '../components/NavigationScreen' + +import testElection from './testElection.json' + +const UserTestingBallotScreen = () => { + const precinctId = "23" + const ballotStyleId = "12" + const election = (testElection as unknown) as Election + const locales: BallotLocale = { + primary: "en-US" + } + + const precinctName = getPrecinctById({ election, precinctId })?.name + + return ( + + +

+ Ballot Style {ballotStyleId} for {precinctName} +

+

+ + Print Ballot + +

+
+ +
+ ) +} + +export default UserTestingBallotScreen diff --git a/client/src/screens/testElection.json b/client/src/screens/testElection.json new file mode 100644 index 0000000..27345ad --- /dev/null +++ b/client/src/screens/testElection.json @@ -0,0 +1,510 @@ +{ + "title": "General Election", + "state": "State of Hamilton", + "county": { + "id": "franklin", + "name": "Franklin County", + "_lang": { + "es-US": { + "name": "Condado de Franklin" + } + } + }, + "date": "2020-11-03T00:00:00-08:00", + "_lang": { + "es-US": { + "title": "Eleccion General", + "state": "Estado de Hamilton" + } + }, + "districts": [ + { + "id": "district-1", + "name": "District 1" + }, + { + "id": "district-2", + "name": "District 2" + }, + { + "id": "district-3", + "name": "District 3" + }, + { + "id": "7", + "name": "District 7" + } + ], + "parties": [ + { + "id": "0", + "name": "Democrat", + "fullName": "Democratic Party", + "abbrev": "D", + "_lang": { + "es-US": { + "name": "Democratico", + "fullName": "Partido Democratico" + } + } + }, + { + "id": "1", + "name": "Republican", + "fullName": "Republican Party", + "abbrev": "R", + "_lang": { + "es-US": { + "name": "Republicano", + "fullName": "Partido Republicano" + } + } + }, + { + "id": "2", + "name": "Libertarian", + "fullName": "Libertarian Party", + "abbrev": "Li", + "_lang": { + "es-US": { + "name": "Libertario", + "fullName": "Partido Libertario" + } + } + }, + { + "id": "3", + "name": "Green", + "fullName": "Green Party", + "abbrev": "G", + "_lang": { + "es-US": { + "name": "Verde", + "fullName": "Partido Verde" + } + } + } + ], + "contests": [ + { + "id": "president2", + "districtId": "district-1", + "type": "candidate", + "section": "United States", + "title": "Best animal to have as a pet", + "seats": 1, + "candidates": [ + { + "id": "dog", + "name": "Dog", + "partyId": "0" + }, + { + "id": "cat", + "name": "Cat", + "partyId": "1" + }, + { + "id": "hamster", + "name": "Hamster", + "partyId": "3" + }, + { + "id": "bird", + "name": "Bird", + "partyId": "3" + }, + { + "id": "snake", + "name": "Snake", + "partyId": "2" + }, + { + "id": "fish", + "name": "Fish" + } + ], + "allowWriteIns": true, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Presidente" + } + } + }, + { + "id": "senator3", + "districtId": "district-2", + "type": "candidate", + "section": "United States", + "title": "Most enjoyable sport to watch", + "seats": 1, + "candidates": [ + { + "id": "football", + "name": "Football", + "partyId": "0" + }, + { + "id": "baseball", + "name": "Baseball", + "partyId": "1" + }, + { + "id": "basketball", + "name": "Basketball", + "partyId": "3" + }, + { + "id": "hockey", + "name": "Hockey", + "partyId": "3" + }, + { + "id": "curling", + "name": "Curling", + "partyId": "3" + } + ], + "allowWriteIns": true, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Senador" + } + } + }, + { + "id": "representative-district-18", + "districtId": "district-1", + "type": "candidate", + "section": "United States", + "title": "Which team would you most like to see dissolved?", + "seats": 1, + "candidates": [ + { + "id": "nyy", + "name": "New York Yankees (baseball)", + "partyId": "0" + }, + { + "id": "lal", + "name": "Los Angeles Lakers (basketball)", + "partyId": "0" + }, + { + "id": "brs", + "name": "Boston Red Sox (baseball)", + "partyId": "0" + }, + { + "id": "drw", + "name": "Detroit Red Wings (hockey)", + "partyId": "0" + }, + { + "id": "bc", + "name": "Boston Celtics (basketball)", + "partyId": "0" + }, + { + "id": "nep", + "name": "New England Patriots (football)", + "partyId": "0" + }, + { + "id": "mc", + "name": "Montreal Canadiens (hockey)", + "partyId": "0" + }, + { + "id": "dc", + "name": "Dallas Cowboys (football)", + "partyId": "0" + }, + + { + "id": "mh", + "name": "Miami Heat (basketball)", + "partyId": "1" + }, + { + "id": "gsw", + "name": "Golden State Warriors (basketball)", + "partyId": "3" + }, + { + "id": "gbp", + "name": "Green Bay Packers (football)", + "partyId": "3" + }, + { + "id": "lvgk", + "name": "Las Vegas Golden Knights (hockey)", + "partyId": "3" + } + ], + "allowWriteIns": false, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Representante, Distrito 18" + } + } + }, + { + "id": "prop-1", + "districtId": "district-2", + "type": "yesno", + "section": "State of Hamilton", + "title": "Is Michael Jordan the best basketball player of all time?", + "description": " ", + "_lang": { + "es-US": { + "section": "Estado de Hamilton", + "title": "Proposición 1", + "description": " " + } + } + }, + { + "id": "prop-2", + "districtId": "district-2", + "type": "yesno", + "section": "State of Hamilton", + "title": "Is a hot dog a sandwich?", + "description": " ", + "_lang": { + "es-US": { + "section": "Estado de Hamilton", + "title": "Proposición 1", + "description": " " + } + } + }, + { + "id": "prop-3", + "districtId": "district-2", + "type": "yesno", + "section": "State of Hamilton", + "title": "Does pineapple belong on a pizza?", + "description": " ", + "_lang": { + "es-US": { + "section": "Estado de Hamilton", + "title": "Proposición 1", + "description": " " + } + } + }, + { + "id": "prop-4", + "districtId": "district-2", + "type": "yesno", + "section": "State of Hamilton", + "title": "Is it better to be too hot or too cold?", + "description": " ", + "_lang": { + "es-US": { + "section": "Estado de Hamilton", + "title": "Proposición 1", + "description": " " + } + } + }, + { + "id": "president", + "districtId": "district-1", + "type": "candidate", + "section": "United States", + "title": "Best animal to have as a pet", + "seats": 1, + "candidates": [ + { + "id": "dog", + "name": "Dog", + "partyId": "0" + }, + { + "id": "cat", + "name": "Cat", + "partyId": "1" + }, + { + "id": "hamster", + "name": "Hamster", + "partyId": "3" + }, + { + "id": "bird", + "name": "Bird", + "partyId": "3" + }, + { + "id": "snake", + "name": "Snake", + "partyId": "2" + }, + { + "id": "fish", + "name": "Fish", + "partyId": "2" + } + ], + "allowWriteIns": true, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Presidente" + } + } + }, + { + "id": "senator2", + "districtId": "district-2", + "type": "candidate", + "section": "United States", + "title": "What decade at thebest hair", + "seats": 1, + "candidates": [ + { + "id": "1950s", + "name": "1950s", + "partyId": "0" + }, + { + "id": "1960s", + "name": "1960s", + "partyId": "1" + }, + { + "id": "1970s", + "name": "1970s", + "partyId": "3" + }, + { + "id": "1980s", + "name": "1980s", + "partyId": "3" + }, + { + "id": "1990s", + "name": "1990s", + "partyId": "3" + }, + { + "id": "2000s", + "name": "2000s", + "partyId": "3" + } + ], + "allowWriteIns": true, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Senador" + } + } + }, + { + "id": "senator", + "districtId": "district-2", + "type": "candidate", + "section": "United States", + "title": "Most likeable member(s) of the British royal family", + "seats": 3, + "candidates": [ + { + "id": "queen-elizabeth", + "name": "Queen Elizabeth", + "partyId": "0" + }, + { + "id": "corgis", + "name": "The Queen’s corgis", + "partyId": "3" + }, + { + "id": "prince-charles", + "name": "Prince Charles", + "partyId": "1" + }, + { + "id": "prince-phillip", + "name": "Prince Phillip", + "partyId": "3" + }, + { + "id": "prince-william", + "name": "Prince William", + "partyId": "3" + }, + { + "id": "prince-harry", + "name": "Prince Harry", + "partyId": "3" + }, + { + "id": "kate-middleton", + "name": "Kate Middleton", + "partyId": "3" + }, + { + "id": "megan-markle", + "name": "Megan Markle", + "partyId": "3" + } + ], + "allowWriteIns": false, + "_lang": { + "es-US": { + "section": "Estados Unidos", + "title": "Senador" + } + } + }, + { + "id": "prop-5", + "districtId": "district-2", + "type": "yesno", + "section": "State of Hamilton", + "title": "Proposition 1", + "description": "S ", + "_lang": { + "es-US": { + "section": "Estado de Hamilton", + "title": "Proposición 1", + "description": " " + } + } + } + ], + "precincts": [ + { + "id": "23", + "name": "Center Springfield" + }, + { + "id": "21", + "name": "North Springfield" + }, + { + "id": "20", + "name": "South Springfield" + } + ], + "ballotStyles": [ + { + "id": "12", + "precincts": ["23", "21"], + "districts": ["district-1", "district-2"] + }, + { + "id": "5", + "precincts": ["21", "20"], + "districts": ["district-1"] + } + ], + "seal": "Seal of Montgomery County, Maryland." + } + \ No newline at end of file From a147d5c4c0d8082c1ec28d57e1834232c841e7c0 Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Tue, 11 Aug 2020 13:41:56 -0700 Subject: [PATCH 2/7] feat: Massaging data. --- client/src/AppRoot.tsx | 45 +- client/src/components/ElectionManager.tsx | 156 +-- .../src/components/HandMarkedPaperBallot.tsx | 5 +- client/src/routerPaths.ts | 1 + .../src/screens/UserTestingBallotScreen.tsx | 19 +- client/src/screens/testElection.json | 965 +++++++++--------- 6 files changed, 597 insertions(+), 594 deletions(-) diff --git a/client/src/AppRoot.tsx b/client/src/AppRoot.tsx index a011d57..6113208 100644 --- a/client/src/AppRoot.tsx +++ b/client/src/AppRoot.tsx @@ -6,7 +6,7 @@ import { sha256 } from 'js-sha256' import { Election, OptionalElection, - parseElection, + // parseElection, } from '@votingworks/ballot-encoder' import AppContext from './contexts/AppContext' @@ -18,6 +18,7 @@ import { Storage } from './utils/Storage' import ElectionManager from './components/ElectionManager' import { SaveElection, OptionalVoteCounts } from './config/types' +import testElection from './screens/testElection.json' export interface AppStorage { election?: Election @@ -36,16 +37,20 @@ export const isOfficialResultsKey = 'isOfficialResults' const AppRoot = ({ storage }: Props) => { const printBallotRef = useRef(null) - const getElection = async () => { - const election = await storage.get(electionStorageKey) + // const getElection = async () => { + // const election = await storage.get(electionStorageKey) - return election ? parseElection(election) : undefined - } + // return election ? parseElection(election) : undefined + // } - const getCVRFiles = async () => storage.get(cvrsStorageKey) - const getIsOfficialResults = async () => storage.get(isOfficialResultsKey) + // const getCVRFiles = async () => storage.get(cvrsStorageKey) + // const getIsOfficialResults = async () => storage.get(isOfficialResultsKey) - const [election, setElection] = useState(undefined) + const [election, setElection] = useState( + undefined + // testElection as Election + ) + // console.log({ election }) const [electionHash, setElectionHash] = useState('') const [castVoteRecordFiles, setCastVoteRecordFiles] = useState( CastVoteRecordFiles.empty @@ -60,19 +65,20 @@ const AppRoot = ({ storage }: Props) => { useEffect(() => { ;(async () => { if (!election) { - const storageElection = await getElection() - if (storageElection) { - setElection(storageElection) - setElectionHash(sha256(JSON.stringify(storageElection))) + // const storageElection = await getElection() + const fooElection = testElection as Election + if (fooElection) { + setElection(fooElection) + setElectionHash(sha256(JSON.stringify(fooElection))) } - if (castVoteRecordFiles === CastVoteRecordFiles.empty) { - const storageCVRFiles = await getCVRFiles() - if (storageCVRFiles) { - setCastVoteRecordFiles(CastVoteRecordFiles.import(storageCVRFiles)) - setIsOfficialResults((await getIsOfficialResults()) || false) - } - } + // if (castVoteRecordFiles === CastVoteRecordFiles.empty) { + // const storageCVRFiles = await getCVRFiles() + // if (storageCVRFiles) { + // setCastVoteRecordFiles(CastVoteRecordFiles.import(storageCVRFiles)) + // setIsOfficialResults((await getIsOfficialResults()) || false) + // } + // } } })() }) @@ -128,6 +134,7 @@ const AppRoot = ({ storage }: Props) => { >
+