2020-08-29 03:40:55 +00:00
|
|
|
import {BarCodeEvent, BarCodeScanner, PermissionResponse} from 'expo-barcode-scanner';
|
2020-09-01 19:55:23 +00:00
|
|
|
import React, {ReactElement, useEffect, useState} from 'react';
|
|
|
|
import {AppRegistry, SafeAreaView, View} from 'react-native';
|
|
|
|
import {
|
|
|
|
Appbar,
|
|
|
|
Button, DarkTheme,
|
|
|
|
DefaultTheme,
|
|
|
|
HelperText,
|
|
|
|
Provider as PaperProvider,
|
|
|
|
Snackbar, Subheading,
|
|
|
|
TextInput,
|
|
|
|
Title
|
|
|
|
} from 'react-native-paper';
|
2020-09-01 02:12:32 +00:00
|
|
|
import {expo as appExpo} from './app.json';
|
2020-08-29 03:40:55 +00:00
|
|
|
import {CancelButton} from './components/Common';
|
|
|
|
import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print';
|
|
|
|
import {ScanButton, Scanner} from './components/Scan';
|
2020-09-01 02:12:32 +00:00
|
|
|
import {colors, styles} from './components/Styles';
|
2020-08-29 03:40:55 +00:00
|
|
|
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
|
|
|
import {ElementProps, StateProps} from './models/ElementProps';
|
|
|
|
|
2020-09-01 02:12:32 +00:00
|
|
|
const theme = {
|
|
|
|
...DefaultTheme,
|
|
|
|
colors: colors,
|
|
|
|
}
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
export default function Main() {
|
2020-08-29 03:40:55 +00:00
|
|
|
const [appState, setAppState] = useState<BarcodeScannerAppState>(BarcodeScannerAppState.INITIAL);
|
|
|
|
const [barCodeData, setBarCodeData] = useState<string>('');
|
|
|
|
const [date, setDate] = useState<Date>(new Date());
|
|
|
|
const [locationStr, setLocationStr] = useState<string>('4321');
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
BarCodeScanner.requestPermissionsAsync().then((value: PermissionResponse) => {
|
|
|
|
if (value.granted) {
|
|
|
|
setAppState(BarcodeScannerAppState.DEFAULT);
|
|
|
|
} else {
|
|
|
|
setAppState(BarcodeScannerAppState.ERROR);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
const _doNothing = () => {};
|
2020-09-01 02:12:32 +00:00
|
|
|
const _scan = () => setAppState(BarcodeScannerAppState.SCANNING);
|
|
|
|
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
|
|
|
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
2020-09-01 19:55:23 +00:00
|
|
|
const _settings = () => setAppState(BarcodeScannerAppState.SETTINGS);
|
2020-09-01 02:12:32 +00:00
|
|
|
|
2020-08-29 03:40:55 +00:00
|
|
|
const handleBarCodeScanned = (e: BarCodeEvent) => {
|
2020-09-01 19:55:23 +00:00
|
|
|
// Make sure the data is the right length.
|
|
|
|
const barCodeString = e.data;
|
|
|
|
const pattern = /^[\d]{14}$/;
|
|
|
|
if (pattern.test(barCodeString)) {
|
|
|
|
setBarCodeData(e.data);
|
|
|
|
setDate(new Date());
|
|
|
|
setAppState(BarcodeScannerAppState.SCANNED);
|
|
|
|
} else {
|
|
|
|
setAppState(BarcodeScannerAppState.ERROR);
|
|
|
|
}
|
2020-08-29 03:40:55 +00:00
|
|
|
};
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
function ErrorMessage(props: ElementProps): ReactElement {
|
|
|
|
return <View style={styles.fullScreen}>
|
|
|
|
<View style={styles.container}>
|
|
|
|
<ScanButton onClicked={_scan}/>
|
|
|
|
</View>
|
|
|
|
<Snackbar
|
|
|
|
visible={appState === BarcodeScannerAppState.ERROR}
|
|
|
|
onDismiss={_doNothing}
|
|
|
|
style={styles.error}
|
|
|
|
>Something went wrong. Try again.</Snackbar>
|
|
|
|
</View>
|
2020-08-29 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
function LoadingMessage(props: ElementProps): ReactElement {
|
|
|
|
return <Snackbar
|
|
|
|
visible={appState === BarcodeScannerAppState.INITIAL}
|
|
|
|
onDismiss={_doNothing}
|
|
|
|
>Loading...</Snackbar>;
|
2020-08-29 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
function SuccessMessage(props: ElementProps): ReactElement {
|
|
|
|
return <Title>Your barcode label has printed successfully.</Title>;
|
2020-08-29 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
function ActionButtons(props: ElementProps): ReactElement {
|
|
|
|
return <View>
|
2020-09-01 02:12:32 +00:00
|
|
|
<PrintButton onClicked={_print}/>
|
|
|
|
<CancelButton onClicked={_home}/>
|
|
|
|
</View>
|
|
|
|
}
|
|
|
|
|
2020-09-01 19:55:23 +00:00
|
|
|
function SettingsModal(props: ElementProps): ReactElement {
|
|
|
|
const [inputStr, setInputStr] = useState<string>(locationStr);
|
|
|
|
const pattern = /^[\d]{4}$/;
|
|
|
|
const hasErrors = () => {
|
|
|
|
return !pattern.test(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 do NOT change this unless you know what you are doing. Entering an incorrect location number may prevent patients from getting accurate info about their test results.
|
|
|
|
</Subheading>
|
|
|
|
<TextInput
|
|
|
|
label="Location #"
|
|
|
|
value={inputStr}
|
|
|
|
onChangeText={inputStr => setInputStr(inputStr)}
|
|
|
|
mode="outlined"
|
|
|
|
theme={DefaultTheme}
|
|
|
|
/>
|
|
|
|
<HelperText type="error" visible={hasErrors()}>
|
|
|
|
Location number must be exactly 4 digits. No other characters are allowed.
|
|
|
|
</HelperText>
|
|
|
|
<Button
|
|
|
|
icon="save"
|
|
|
|
mode="contained"
|
|
|
|
color={colors.primary}
|
|
|
|
style={{marginBottom: 10}}
|
|
|
|
disabled={hasErrors()}
|
|
|
|
onPress={() => {
|
|
|
|
setLocationStr(inputStr);
|
|
|
|
_home();
|
|
|
|
}}
|
|
|
|
>Save</Button>
|
|
|
|
<Button
|
|
|
|
icon="cancel"
|
|
|
|
mode="outlined"
|
|
|
|
color={colors.primary}
|
|
|
|
onPress={_home}
|
|
|
|
>Cancel</Button>
|
|
|
|
</View>
|
|
|
|
</View>
|
|
|
|
}
|
|
|
|
|
|
|
|
function App(props: StateProps): ReactElement {
|
2020-08-29 03:40:55 +00:00
|
|
|
switch (props.appState) {
|
|
|
|
case BarcodeScannerAppState.INITIAL:
|
|
|
|
return <LoadingMessage/>;
|
|
|
|
case BarcodeScannerAppState.DEFAULT:
|
2020-09-01 19:55:23 +00:00
|
|
|
return <View style={styles.container}>
|
|
|
|
<ScanButton onClicked={_scan}/>
|
|
|
|
</View>;
|
2020-08-29 03:40:55 +00:00
|
|
|
case BarcodeScannerAppState.PRINTED:
|
|
|
|
return <SuccessMessage/>;
|
|
|
|
case BarcodeScannerAppState.PRINTING:
|
2020-09-01 02:12:32 +00:00
|
|
|
return <PrintingMessage
|
|
|
|
onCancel={_home}
|
|
|
|
id={barCodeData}
|
|
|
|
date={date} location={locationStr}
|
|
|
|
/>;
|
2020-08-29 03:40:55 +00:00
|
|
|
case BarcodeScannerAppState.SCANNED:
|
2020-09-01 02:12:32 +00:00
|
|
|
return <View style={styles.container}>
|
2020-08-29 03:40:55 +00:00
|
|
|
<BarCodeDisplay id={barCodeData} date={date} location={locationStr}/>
|
2020-09-01 19:55:23 +00:00
|
|
|
<ActionButtons/>
|
2020-08-29 03:40:55 +00:00
|
|
|
</View>;
|
|
|
|
case BarcodeScannerAppState.SCANNING:
|
2020-09-01 19:55:23 +00:00
|
|
|
return <Scanner
|
|
|
|
onScanned={handleBarCodeScanned}
|
|
|
|
onCancel={_home}
|
|
|
|
/>;
|
|
|
|
case BarcodeScannerAppState.SETTINGS:
|
|
|
|
return <SettingsModal/>;
|
2020-08-29 03:40:55 +00:00
|
|
|
default:
|
|
|
|
return <ErrorMessage/>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2020-09-01 02:12:32 +00:00
|
|
|
<PaperProvider theme={theme}>
|
2020-09-01 19:55:23 +00:00
|
|
|
<Appbar.Header dark={true}>
|
|
|
|
<Appbar.Content title={`${appExpo.description} #${locationStr}`}/>
|
|
|
|
<Appbar.Action icon="home" onPress={_home}/>
|
|
|
|
<Appbar.Action icon="settings" onPress={_settings}/>
|
2020-09-01 02:12:32 +00:00
|
|
|
</Appbar.Header>
|
2020-09-01 19:55:23 +00:00
|
|
|
<SafeAreaView style={styles.safeAreaView}>
|
2020-09-01 02:12:32 +00:00
|
|
|
<App appState={appState}/>
|
|
|
|
</SafeAreaView>
|
|
|
|
</PaperProvider>
|
2020-08-29 03:40:55 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-09-01 02:12:32 +00:00
|
|
|
AppRegistry.registerComponent(appExpo.name, () => Main);
|