Skip to content
This repository has been archived by the owner on Nov 3, 2020. It is now read-only.

Commit

Permalink
feat(setup): Error screens & sample implementation
Browse files Browse the repository at this point in the history
- No Card Reader Attached
- Low Power and No Charger Attached
- No Printer Attached
- Printer Error
  • Loading branch information
beausmith committed Jan 9, 2020
1 parent 4821fd0 commit 92765ca
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 0 deletions.
70 changes: 70 additions & 0 deletions src/AppRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ import InvalidCardScreen from './pages/InvalidCardScreen'
import InsertCardScreen from './pages/InsertCardScreen'
import PollWorkerScreen from './pages/PollWorkerScreen'
import PrintOnlyScreen from './pages/PrintOnlyScreen'
import SetupCardReaderPage from './pages/SetupCardReaderPage'
import SetupPrinterPage from './pages/SetupPrinterPage'
import SetupPrinterErrorPage from './pages/SetupPrinterErrorPage'
import SetupPowerPage from './pages/SetupPowerPage'
import UnconfiguredScreen from './pages/UnconfiguredScreen'
import UsedCardScreen from './pages/UsedCardScreen'
import { getBallotStyle, getContests, getZeroTally } from './utils/election'
Expand Down Expand Up @@ -88,6 +92,11 @@ interface SharedState {
appPrecinctId: string
ballotsPrintedCount: number
election: OptionalElection
hasCardReaderAttached: boolean
hasChargerAttached: boolean
hasLowBattery: boolean
hasPrinterAttached: boolean
hasPrinterError: boolean
isFetchingElection: boolean
isLiveMode: boolean
isPollsOpen: boolean
Expand Down Expand Up @@ -121,6 +130,7 @@ class AppRoot extends React.Component<Props, State> {
private machineIdAbortController = new AbortController()

private cardPoller?: Poller
private statusPoller?: Poller
private lastVoteUpdateAt = 0
private lastVoteSaveToCardAt = 0
private cardWriteInterval = 0
Expand Down Expand Up @@ -152,6 +162,11 @@ class AppRoot extends React.Component<Props, State> {
appPrecinctId: '',
ballotsPrintedCount: 0,
election: undefined,
hasCardReaderAttached: true,
hasChargerAttached: true,
hasLowBattery: true,
hasPrinterAttached: true,
hasPrinterError: false,
isFetchingElection: false,
isLiveMode: false,
isPollsOpen: false,
Expand Down Expand Up @@ -456,6 +471,37 @@ class AppRoot extends React.Component<Props, State> {
return true
}

public startStatusPolling = () => {
/* istanbul ignore else */
if (!this.statusPoller) {
this.statusPoller = IntervalPoller.start(
GLOBALS.CARD_POLLING_INTERVAL,
async () => {
try {
// Possible implementation
// const cardReader = await this.props.cardReader.status()
// const battery = await this.props.battery.status()
// const printer = await this.props.printer.status()
// this.setState({
// hasCardReaderAttached: cardReader.connected,
// hasChargerAttached: battery.charging,
// hasLowBattery: battery.charged < 0.5,
// hasPrinterAttached: printer.connected,
// hasPrinterError: printer.error,
// })
} catch (error) {
this.stopStatusPolling() // Assume backend is unavailable.
}
}
)
}
}

public stopStatusPolling = () => {
this.statusPoller && this.statusPoller.stop()
this.statusPoller = undefined
}

public componentDidMount = () => {
const election = this.getElection()
const { ballotStyleId, precinctId } = this.getBallotActivation()
Expand Down Expand Up @@ -497,12 +543,14 @@ class AppRoot extends React.Component<Props, State> {
this.setMachineId()
this.startShortValueReadPolling()
this.startLongValueWritePolling()
this.startStatusPolling()
}

public componentWillUnmount = /* istanbul ignore next - triggering keystrokes issue - https://github.com/votingworks/bmd/issues/62 */ () => {
this.machineIdAbortController.abort()
document.removeEventListener('keydown', handleGamepadKeyboardEvent)
this.stopShortValueReadPolling()
this.stopStatusPolling()
}

public setMachineId = async () => {
Expand Down Expand Up @@ -793,11 +841,33 @@ class AppRoot extends React.Component<Props, State> {
isVoterCardPrinted,
isRecentVoterPrint,
machineId,
hasCardReaderAttached,
hasChargerAttached,
hasLowBattery,
hasPrinterAttached,
hasPrinterError,
precinctId,
tally,
userSettings,
votes,
} = this.state
if (hasLowBattery && !hasChargerAttached) {
return <SetupPowerPage setUserSettings={this.setUserSettings} />
}
if (!hasCardReaderAttached) {
return <SetupCardReaderPage setUserSettings={this.setUserSettings} />
}
if (appMode.isVxPrint) {
if (!hasPrinterAttached) {
return <SetupPrinterPage setUserSettings={this.setUserSettings} />
} else {
if (hasPrinterError) {
return (
<SetupPrinterErrorPage setUserSettings={this.setUserSettings} />
)
}
}
}
if (isClerkCardPresent) {
return (
<ClerkScreen
Expand Down
34 changes: 34 additions & 0 deletions src/pages/SetupCardReaderPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useEffect } from 'react'
import Prose from '../components/Prose'
import Main, { MainChild } from '../components/Main'
import Screen from '../components/Screen'
import { PartialUserSettings } from '../config/types'
import { DEFAULT_FONT_SIZE, LARGE_DISPLAY_FONT_SIZE } from '../config/globals'

interface Props {
setUserSettings: (partial: PartialUserSettings) => void
}

const ExpiredCardScreen = ({ setUserSettings }: Props) => {
useEffect(() => {
setUserSettings({ textSize: LARGE_DISPLAY_FONT_SIZE })
return () => {
setUserSettings({ textSize: DEFAULT_FONT_SIZE })
}
}, [setUserSettings])

return (
<Screen white>
<Main>
<MainChild center>
<Prose textCenter>
<h1>Card Reader Not Detected</h1>
<p>Please ask a poll worker to connect card reader.</p>
</Prose>
</MainChild>
</Main>
</Screen>
)
}

export default ExpiredCardScreen
40 changes: 40 additions & 0 deletions src/pages/SetupPowerPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useEffect } from 'react'
import Prose from '../components/Prose'
import Main, { MainChild } from '../components/Main'
import Screen from '../components/Screen'
import { NoWrap } from '../components/Text'
import { PartialUserSettings } from '../config/types'
import { DEFAULT_FONT_SIZE, LARGE_DISPLAY_FONT_SIZE } from '../config/globals'

interface Props {
setUserSettings: (partial: PartialUserSettings) => void
}

const SetupPowerPage = ({ setUserSettings }: Props) => {
useEffect(() => {
setUserSettings({ textSize: LARGE_DISPLAY_FONT_SIZE })
return () => {
setUserSettings({ textSize: DEFAULT_FONT_SIZE })
}
}, [setUserSettings])

return (
<Screen white>
<Main padded>
<MainChild center>
<Prose textCenter>
<h1>
No Power Detected <NoWrap>and Battery is Low</NoWrap>
</h1>
<p>
Please ask a poll worker to plug-in the power cord for this
machine.
</p>
</Prose>
</MainChild>
</Main>
</Screen>
)
}

export default SetupPowerPage
34 changes: 34 additions & 0 deletions src/pages/SetupPrinterErrorPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useEffect } from 'react'
import Prose from '../components/Prose'
import Main, { MainChild } from '../components/Main'
import Screen from '../components/Screen'
import { PartialUserSettings } from '../config/types'
import { DEFAULT_FONT_SIZE, LARGE_DISPLAY_FONT_SIZE } from '../config/globals'

interface Props {
setUserSettings: (partial: PartialUserSettings) => void
}

const SetupPrinterErrorPage = ({ setUserSettings }: Props) => {
useEffect(() => {
setUserSettings({ textSize: LARGE_DISPLAY_FONT_SIZE })
return () => {
setUserSettings({ textSize: DEFAULT_FONT_SIZE })
}
}, [setUserSettings])

return (
<Screen white>
<Main padded>
<MainChild center>
<Prose textCenter>
<h1>Printer Error Detected</h1>
<p>Please ask a poll worker to resolve printer error.</p>
</Prose>
</MainChild>
</Main>
</Screen>
)
}

export default SetupPrinterErrorPage
34 changes: 34 additions & 0 deletions src/pages/SetupPrinterPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useEffect } from 'react'
import Prose from '../components/Prose'
import Main, { MainChild } from '../components/Main'
import Screen from '../components/Screen'
import { PartialUserSettings } from '../config/types'
import { DEFAULT_FONT_SIZE, LARGE_DISPLAY_FONT_SIZE } from '../config/globals'

interface Props {
setUserSettings: (partial: PartialUserSettings) => void
}

const SetupPrinterPage = ({ setUserSettings }: Props) => {
useEffect(() => {
setUserSettings({ textSize: LARGE_DISPLAY_FONT_SIZE })
return () => {
setUserSettings({ textSize: DEFAULT_FONT_SIZE })
}
}, [setUserSettings])

return (
<Screen white>
<Main padded>
<MainChild center>
<Prose textCenter>
<h1>No Printer Detected</h1>
<p>Please ask a poll worker to connect printer.</p>
</Prose>
</MainChild>
</Main>
</Screen>
)
}

export default SetupPrinterPage

0 comments on commit 92765ca

Please sign in to comment.