Adds manual ID number entry screen.
Former-commit-id: ffbc16d1223ac8cf4e144a06fd58d3d421f85903
This commit is contained in:
parent
0a1c5c3399
commit
5729def6ca
33
App.tsx
33
App.tsx
|
@ -14,7 +14,7 @@ import {
|
|||
import {expo as appExpo} from './app.json';
|
||||
import {CancelButton} from './components/Common';
|
||||
import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print';
|
||||
import {ScanButton, Scanner} from './components/Scan';
|
||||
import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan';
|
||||
import {colors, styles} from './components/Styles';
|
||||
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
||||
import {ElementProps, StateProps} from './models/ElementProps';
|
||||
|
@ -29,6 +29,7 @@ export default function Main() {
|
|||
const [barCodeData, setBarCodeData] = useState<string>('');
|
||||
const [date, setDate] = useState<Date>(new Date());
|
||||
const [locationStr, setLocationStr] = useState<string>('4321');
|
||||
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
BarCodeScanner.requestPermissionsAsync().then((value: PermissionResponse) => {
|
||||
|
@ -41,20 +42,31 @@ export default function Main() {
|
|||
}, []);
|
||||
|
||||
const _doNothing = () => {};
|
||||
const _scan = () => setAppState(BarcodeScannerAppState.SCANNING);
|
||||
const _scan = () => {
|
||||
setErrorMessage('');
|
||||
setAppState(BarcodeScannerAppState.SCANNING);
|
||||
};
|
||||
const _inputIdNumber = () => {
|
||||
setErrorMessage('');
|
||||
setAppState(BarcodeScannerAppState.INPUT);
|
||||
};
|
||||
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
||||
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
||||
const _settings = () => setAppState(BarcodeScannerAppState.SETTINGS);
|
||||
|
||||
const handleBarCodeScanned = (e: BarCodeEvent) => {
|
||||
// Make sure the data is the right length.
|
||||
// Scanned barcodes will be exactly 14 digits long.
|
||||
// Manually-entered ID numbers will be exactly 9 digits long.
|
||||
const barCodeString = e.data;
|
||||
const pattern = /^[\d]{14}$/;
|
||||
const pattern = /^[\d]{14}$|^[\d]{9}$/;
|
||||
if (pattern.test(barCodeString)) {
|
||||
setBarCodeData(e.data);
|
||||
const cardId = e.data.slice(0, 9);
|
||||
setBarCodeData(cardId);
|
||||
setDate(new Date());
|
||||
setAppState(BarcodeScannerAppState.SCANNED);
|
||||
} else {
|
||||
setErrorMessage(`The barcode data "${e.data}" is not from a valid ID card.`);
|
||||
setAppState(BarcodeScannerAppState.ERROR);
|
||||
}
|
||||
};
|
||||
|
@ -63,12 +75,13 @@ export default function Main() {
|
|||
return <View style={styles.fullScreen}>
|
||||
<View style={styles.container}>
|
||||
<ScanButton onClicked={_scan}/>
|
||||
<InputIdButton onClicked={_inputIdNumber}/>
|
||||
</View>
|
||||
<Snackbar
|
||||
visible={appState === BarcodeScannerAppState.ERROR}
|
||||
onDismiss={_doNothing}
|
||||
style={styles.error}
|
||||
>Something went wrong. Try again.</Snackbar>
|
||||
>{errorMessage === '' ? 'Something went wrong. Try again.' : errorMessage}</Snackbar>
|
||||
</View>
|
||||
}
|
||||
|
||||
|
@ -90,7 +103,7 @@ export default function Main() {
|
|||
</View>
|
||||
}
|
||||
|
||||
function SettingsModal(props: ElementProps): ReactElement {
|
||||
function SettingsScreen(props: ElementProps): ReactElement {
|
||||
const [inputStr, setInputStr] = useState<string>(locationStr);
|
||||
const pattern = /^[\d]{4}$/;
|
||||
const hasErrors = () => {
|
||||
|
@ -141,6 +154,7 @@ export default function Main() {
|
|||
case BarcodeScannerAppState.DEFAULT:
|
||||
return <View style={styles.container}>
|
||||
<ScanButton onClicked={_scan}/>
|
||||
<InputIdButton onClicked={_inputIdNumber}/>
|
||||
</View>;
|
||||
case BarcodeScannerAppState.PRINTED:
|
||||
return <SuccessMessage/>;
|
||||
|
@ -160,8 +174,13 @@ export default function Main() {
|
|||
onScanned={handleBarCodeScanned}
|
||||
onCancel={_home}
|
||||
/>;
|
||||
case BarcodeScannerAppState.INPUT:
|
||||
return <IdNumberInput
|
||||
onScanned={handleBarCodeScanned}
|
||||
onCancel={_home}
|
||||
/>;
|
||||
case BarcodeScannerAppState.SETTINGS:
|
||||
return <SettingsModal/>;
|
||||
return <SettingsScreen/>;
|
||||
default:
|
||||
return <ErrorMessage/>;
|
||||
}
|
||||
|
|
4
app.json
4
app.json
|
@ -19,7 +19,7 @@
|
|||
],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.ajlouie.uvacovid19testingkiosk"
|
||||
"bundleIdentifier": "com.sartography.uvacovid19testingkiosk"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
|
@ -31,7 +31,7 @@
|
|||
"web"
|
||||
],
|
||||
"android": {
|
||||
"package": "com.ajlouie.uvacovid19testingkiosk"
|
||||
"package": "com.sartography.uvacovid19testingkiosk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {BarCodeProps, ButtonProps, PrintingProps} from '../models/ElementProps';
|
|||
import {colors, styles} from './Styles';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import * as Print from 'expo-print';
|
||||
import {format} from 'date-fns'
|
||||
|
||||
enum PrintStatus {
|
||||
SAVING = 'SAVING',
|
||||
|
@ -35,7 +36,7 @@ const _renderBarCodeRects = (props: PrintingProps): string => {
|
|||
}
|
||||
|
||||
const _propsToDataString = (props: BarCodeProps): string => {
|
||||
return `${props.id}-${props.date.getTime()}-${props.location}`;
|
||||
return props.id + format(props.date, 'yyyymmdd') + props.location;
|
||||
}
|
||||
|
||||
const _save = (props: PrintingProps): Promise<void> => {
|
||||
|
@ -45,6 +46,8 @@ const _save = (props: PrintingProps): Promise<void> => {
|
|||
date: props.date,
|
||||
location: props.location,
|
||||
};
|
||||
console.log('storageKey', storageKey);
|
||||
console.log('storageVal', storageVal);
|
||||
return AsyncStorage.setItem(storageKey, JSON.stringify(storageVal));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {BarCodeScanner} from 'expo-barcode-scanner';
|
||||
import {BarCodeEvent, BarCodeScanner} from 'expo-barcode-scanner';
|
||||
import React, {ReactElement, useState} from 'react';
|
||||
import {View, Text} from 'react-native';
|
||||
import {Button} from 'react-native-paper';
|
||||
import {Button, DefaultTheme, HelperText, Subheading, TextInput, Title} from 'react-native-paper';
|
||||
import {ButtonProps, ScannerProps} from '../models/ElementProps';
|
||||
import {colors, styles} from './Styles';
|
||||
|
||||
|
@ -63,3 +63,58 @@ export const ScanButton = (props: ButtonProps): ReactElement => {
|
|||
labelStyle={styles.btnLg}
|
||||
>Scan Barcode</Button>;
|
||||
};
|
||||
|
||||
export const InputIdButton = (props: ButtonProps): ReactElement => {
|
||||
return <Button
|
||||
icon="keyboard"
|
||||
mode="text"
|
||||
color={colors.onBackground}
|
||||
onPress={props.onClicked}
|
||||
>Enter ID Number Manually</Button>;
|
||||
};
|
||||
|
||||
export const IdNumberInput = (props: ScannerProps): ReactElement => {
|
||||
const [inputStr, setInputStr] = useState<string>('');
|
||||
const pattern = /^[\d]{9}$/;
|
||||
const hasErrors = () => {
|
||||
return !pattern.test(inputStr);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
console.log('onSubmit inputStr =', inputStr);
|
||||
props.onScanned({type: '', data: inputStr});
|
||||
}
|
||||
|
||||
return <View style={styles.settings}>
|
||||
<Title style={styles.headingInverse}>Settings</Title>
|
||||
<View style={{marginBottom: 10}}>
|
||||
<Subheading style={{color: DefaultTheme.colors.text, marginBottom: 60}}>
|
||||
Please double check that you have entered the number correctly. Entering an incorrect ID number will prevent patients from receiving their test results.
|
||||
</Subheading>
|
||||
<TextInput
|
||||
label="ID #"
|
||||
value={inputStr}
|
||||
onChangeText={inputStr => setInputStr(inputStr)}
|
||||
mode="outlined"
|
||||
theme={DefaultTheme}
|
||||
/>
|
||||
<HelperText type="error" visible={hasErrors()}>
|
||||
ID number must be exactly 9 digits. No other characters are allowed.
|
||||
</HelperText>
|
||||
<Button
|
||||
icon="check"
|
||||
mode="contained"
|
||||
color={colors.primary}
|
||||
style={{marginBottom: 10}}
|
||||
disabled={hasErrors()}
|
||||
onPress={onSubmit}
|
||||
>Submit</Button>
|
||||
<Button
|
||||
icon="cancel"
|
||||
mode="outlined"
|
||||
color={colors.primary}
|
||||
onPress={props.onCancel}
|
||||
>Cancel</Button>
|
||||
</View>
|
||||
</View>;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ export enum BarcodeScannerAppState {
|
|||
DEFAULT = 'DEFAULT',
|
||||
SCANNING = 'SCANNING',
|
||||
SCANNED = 'SCANNED',
|
||||
INPUT = 'INPUT',
|
||||
PRINTING = 'PRINTING',
|
||||
PRINTED = 'PRINTED',
|
||||
ERROR = 'ERROR',
|
||||
|
|
|
@ -5440,6 +5440,11 @@
|
|||
"whatwg-url": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
|
||||
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ=="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.8.34",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.34.tgz",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"dependencies": {
|
||||
"@react-native-community/async-storage": "^1.12.0",
|
||||
"@react-native-community/netinfo": "^5.9.6",
|
||||
"date-fns": "^2.16.1",
|
||||
"expo": "~38.0.8",
|
||||
"expo-barcode-scanner": "~8.2.1",
|
||||
"expo-print": "~9.0.1",
|
||||
|
|
Loading…
Reference in New Issue