Adds line count screen.
This commit is contained in:
parent
8b7ef5c8fd
commit
42d195b9de
165
App.tsx
165
App.tsx
|
@ -6,25 +6,18 @@ import {BarCodeEvent, BarCodeScanner, PermissionResponse} from 'expo-barcode-sca
|
||||||
import * as firebase from 'firebase';
|
import * as firebase from 'firebase';
|
||||||
import 'firebase/firestore';
|
import 'firebase/firestore';
|
||||||
import React, {ReactElement, useCallback, useEffect, useState} from 'react';
|
import React, {ReactElement, useCallback, useEffect, useState} from 'react';
|
||||||
import {AppRegistry, SafeAreaView, Text, View, YellowBox} from 'react-native';
|
import {AppRegistry, SafeAreaView, View, YellowBox} from 'react-native';
|
||||||
import {
|
import {Appbar, DefaultTheme, Provider as PaperProvider, Snackbar, Title,} from 'react-native-paper';
|
||||||
Appbar,
|
|
||||||
Button,
|
|
||||||
DefaultTheme,
|
|
||||||
HelperText,
|
|
||||||
Provider as PaperProvider, RadioButton,
|
|
||||||
Snackbar,
|
|
||||||
Subheading,
|
|
||||||
TextInput,
|
|
||||||
Title,
|
|
||||||
} from 'react-native-paper';
|
|
||||||
import {expo as appExpo} from './app.json';
|
import {expo as appExpo} from './app.json';
|
||||||
import {CancelButton} from './components/Common';
|
import {CancelButton} from './components/Common';
|
||||||
|
import {InputLineCountButton, InputLineCountScreen} from './components/LineCount';
|
||||||
import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print';
|
import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print';
|
||||||
import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan';
|
import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan';
|
||||||
|
import {SettingsScreen} from './components/Settings';
|
||||||
import {colors, styles} from './components/Styles';
|
import {colors, styles} from './components/Styles';
|
||||||
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
import {BarcodeScannerAppState} from './models/BarcodeScannerAppState';
|
||||||
import {CameraType, ElementProps, StateProps} from './models/ElementProps';
|
import {CameraType, ElementProps, StateProps} from './models/ElementProps';
|
||||||
|
import {LineCount} from './models/LineCount';
|
||||||
import {Sample} from './models/Sample';
|
import {Sample} from './models/Sample';
|
||||||
|
|
||||||
const firebaseConfig = {
|
const firebaseConfig = {
|
||||||
|
@ -49,6 +42,8 @@ YellowBox.ignoreWarnings([
|
||||||
|
|
||||||
const db = firebase.firestore();
|
const db = firebase.firestore();
|
||||||
const samplesCollection = db.collection('samples');
|
const samplesCollection = db.collection('samples');
|
||||||
|
const countsCollection = db.collection('counts');
|
||||||
|
const dateFormat = 'yyyyMMddHHmm';
|
||||||
|
|
||||||
const theme = {
|
const theme = {
|
||||||
...DefaultTheme,
|
...DefaultTheme,
|
||||||
|
@ -63,6 +58,7 @@ export default function Main() {
|
||||||
const [locationStr, setLocationStr] = useState<string>('4321');
|
const [locationStr, setLocationStr] = useState<string>('4321');
|
||||||
const [errorMessage, setErrorMessage] = useState<string>('');
|
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||||
const [samples, setSamples] = useState<Sample[]>([]);
|
const [samples, setSamples] = useState<Sample[]>([]);
|
||||||
|
const [lineCounts, setLineCounts] = useState<LineCount[]>([]);
|
||||||
const [cameraType, setCameraType] = useState<CameraType>('back');
|
const [cameraType, setCameraType] = useState<CameraType>('back');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -74,7 +70,7 @@ export default function Main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsubscribe = samplesCollection.onSnapshot(querySnapshot => {
|
const unsubscribeSamples = samplesCollection.onSnapshot(querySnapshot => {
|
||||||
// Transform and sort the data returned from Firebase
|
// Transform and sort the data returned from Firebase
|
||||||
const samplesFirestore = querySnapshot
|
const samplesFirestore = querySnapshot
|
||||||
.docChanges()
|
.docChanges()
|
||||||
|
@ -88,7 +84,21 @@ export default function Main() {
|
||||||
appendSamples(samplesFirestore);
|
appendSamples(samplesFirestore);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => unsubscribe()
|
const unsubscribeCounts = countsCollection.onSnapshot(querySnapshot => {
|
||||||
|
// Transform and sort the data returned from Firebase
|
||||||
|
const lineCountsFirestore = querySnapshot
|
||||||
|
.docChanges()
|
||||||
|
.filter(({type}) => type === 'added')
|
||||||
|
.map(({doc}) => {
|
||||||
|
const lineCount = doc.data();
|
||||||
|
return {...lineCount, createdAt: lineCount.createdAt.toDate()} as LineCount;
|
||||||
|
})
|
||||||
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
||||||
|
|
||||||
|
appendLineCounts(lineCountsFirestore);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => unsubscribeSamples()
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const _doNothing = () => {
|
const _doNothing = () => {
|
||||||
|
@ -101,6 +111,10 @@ export default function Main() {
|
||||||
setErrorMessage('');
|
setErrorMessage('');
|
||||||
setAppState(BarcodeScannerAppState.INPUT);
|
setAppState(BarcodeScannerAppState.INPUT);
|
||||||
};
|
};
|
||||||
|
const _inputLineCount = () => {
|
||||||
|
setErrorMessage('');
|
||||||
|
setAppState(BarcodeScannerAppState.COUNT);
|
||||||
|
};
|
||||||
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
||||||
const _printed = () => setAppState(BarcodeScannerAppState.PRINTED);
|
const _printed = () => setAppState(BarcodeScannerAppState.PRINTED);
|
||||||
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
||||||
|
@ -116,7 +130,7 @@ export default function Main() {
|
||||||
if (pattern.test(barCodeString)) {
|
if (pattern.test(barCodeString)) {
|
||||||
const cardId = e.data.slice(0, 9);
|
const cardId = e.data.slice(0, 9);
|
||||||
const newSampleDate = new Date();
|
const newSampleDate = new Date();
|
||||||
const newSampleId = [cardId, format(newSampleDate, 'yyyyMMddHHmm'), locationStr].join('-');
|
const newSampleId = [cardId, format(newSampleDate, dateFormat), locationStr].join('-');
|
||||||
|
|
||||||
setSampleId(newSampleId);
|
setSampleId(newSampleId);
|
||||||
setBarCodeId(cardId);
|
setBarCodeId(cardId);
|
||||||
|
@ -128,16 +142,32 @@ export default function Main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleLineCountSubmitted = (newCount: number) => {
|
||||||
|
const now = new Date();
|
||||||
|
const newId = `${locationStr}-${format(now, dateFormat)}`;
|
||||||
|
const newData: LineCount = {
|
||||||
|
id: newId,
|
||||||
|
lineCount: newCount,
|
||||||
|
locationId: locationStr,
|
||||||
|
createdAt: now,
|
||||||
|
};
|
||||||
|
sendDataToFirebase([newData], countsCollection);
|
||||||
|
}
|
||||||
|
|
||||||
const appendSamples = useCallback((newSamples) => {
|
const appendSamples = useCallback((newSamples) => {
|
||||||
setSamples((previousSamples) => previousSamples.concat(newSamples));
|
setSamples((previousSamples) => previousSamples.concat(newSamples));
|
||||||
}, [samples]);
|
}, [samples]);
|
||||||
|
|
||||||
const sendDataToFirebase = async (newSamples: Sample[]) => {
|
const appendLineCounts = useCallback((newLineCounts) => {
|
||||||
const writes = newSamples.map(s => samplesCollection.doc(s.id).set(s));
|
setLineCounts((previousLineCounts) => previousLineCounts.concat(newLineCounts));
|
||||||
|
}, [lineCounts]);
|
||||||
|
|
||||||
|
const sendDataToFirebase = async (newData: Array<Sample|LineCount>, collection: firebase.firestore.CollectionReference) => {
|
||||||
|
const writes = newData.map((s: Sample|LineCount) => collection.doc(s.id).set(s));
|
||||||
await Promise.all(writes);
|
await Promise.all(writes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ErrorMessage(props: ElementProps): ReactElement {
|
const ErrorMessage = (props: ElementProps): ReactElement => {
|
||||||
return <View style={styles.fullScreen}>
|
return <View style={styles.fullScreen}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ScanButton onClicked={_scan}/>
|
<ScanButton onClicked={_scan}/>
|
||||||
|
@ -151,94 +181,24 @@ export default function Main() {
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
||||||
function LoadingMessage(props: ElementProps): ReactElement {
|
const LoadingMessage = (props: ElementProps): ReactElement => {
|
||||||
return <Snackbar
|
return <Snackbar
|
||||||
visible={appState === BarcodeScannerAppState.INITIAL}
|
visible={appState === BarcodeScannerAppState.INITIAL}
|
||||||
onDismiss={_doNothing}
|
onDismiss={_doNothing}
|
||||||
>Loading...</Snackbar>;
|
>Loading...</Snackbar>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SuccessMessage(props: ElementProps): ReactElement {
|
const SuccessMessage = (props: ElementProps): ReactElement => {
|
||||||
return <Title>Your barcode label has printed successfully.</Title>;
|
return <Title>Your barcode label has printed successfully.</Title>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ActionButtons(props: ElementProps): ReactElement {
|
const ActionButtons = (props: ElementProps): ReactElement => {
|
||||||
return <View>
|
return <View>
|
||||||
<PrintButton onClicked={_print}/>
|
<PrintButton onClicked={_print}/>
|
||||||
<CancelButton onClicked={_home}/>
|
<CancelButton onClicked={_home}/>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
||||||
function SettingsScreen(props: ElementProps): ReactElement {
|
|
||||||
const [inputStr, setInputStr] = useState<string>(locationStr);
|
|
||||||
|
|
||||||
const pattern = /^[\d]{4}$/;
|
|
||||||
const hasErrors = () => {
|
|
||||||
return !pattern.test(inputStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
return <View style={styles.settings}>
|
|
||||||
<View style={{marginBottom: 10}}>
|
|
||||||
<Subheading style={{color: DefaultTheme.colors.text}}>Which camera to scan bar codes with?</Subheading>
|
|
||||||
<RadioButton.Group
|
|
||||||
onValueChange={value => setCameraType(value as CameraType)}
|
|
||||||
value={cameraType as string}
|
|
||||||
>
|
|
||||||
<View style={styles.row}>
|
|
||||||
<Text>Front</Text>
|
|
||||||
<RadioButton
|
|
||||||
value="front"
|
|
||||||
color={colors.primary}
|
|
||||||
uncheckedColor={colors.accent}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={styles.row}>
|
|
||||||
<Text>Back</Text>
|
|
||||||
<RadioButton
|
|
||||||
value="back"
|
|
||||||
color={colors.primary}
|
|
||||||
uncheckedColor={colors.accent}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</RadioButton.Group>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<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="content-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 {
|
function App(props: StateProps): ReactElement {
|
||||||
switch (props.appState) {
|
switch (props.appState) {
|
||||||
case BarcodeScannerAppState.INITIAL:
|
case BarcodeScannerAppState.INITIAL:
|
||||||
|
@ -247,6 +207,7 @@ export default function Main() {
|
||||||
return <View style={styles.container}>
|
return <View style={styles.container}>
|
||||||
<ScanButton onClicked={_scan}/>
|
<ScanButton onClicked={_scan}/>
|
||||||
<InputIdButton onClicked={_inputIdNumber}/>
|
<InputIdButton onClicked={_inputIdNumber}/>
|
||||||
|
<InputLineCountButton onClicked={_inputLineCount}/>
|
||||||
</View>;
|
</View>;
|
||||||
case BarcodeScannerAppState.PRINTED:
|
case BarcodeScannerAppState.PRINTED:
|
||||||
// Upload any changes to Firebase
|
// Upload any changes to Firebase
|
||||||
|
@ -258,15 +219,13 @@ export default function Main() {
|
||||||
return {
|
return {
|
||||||
id: s,
|
id: s,
|
||||||
barcodeId: propsArray[0],
|
barcodeId: propsArray[0],
|
||||||
createdAt: parse(propsArray[1], 'yyyyMMddHHmm', new Date()),
|
createdAt: parse(propsArray[1], dateFormat, new Date()),
|
||||||
locationId: propsArray[2],
|
locationId: propsArray[2],
|
||||||
} as Sample;
|
} as Sample;
|
||||||
});
|
});
|
||||||
sendDataToFirebase(newSamples);
|
sendDataToFirebase(newSamples, samplesCollection).then(_home);
|
||||||
});
|
});
|
||||||
|
|
||||||
_home();
|
|
||||||
|
|
||||||
return <SuccessMessage/>;
|
return <SuccessMessage/>;
|
||||||
case BarcodeScannerAppState.PRINTING:
|
case BarcodeScannerAppState.PRINTING:
|
||||||
return <View style={styles.container}>
|
return <View style={styles.container}>
|
||||||
|
@ -300,8 +259,22 @@ export default function Main() {
|
||||||
onCancel={_home}
|
onCancel={_home}
|
||||||
cameraType={undefined}
|
cameraType={undefined}
|
||||||
/>;
|
/>;
|
||||||
|
case BarcodeScannerAppState.COUNT:
|
||||||
|
return <InputLineCountScreen
|
||||||
|
onSave={handleLineCountSubmitted}
|
||||||
|
onCancel={_home}
|
||||||
|
/>;
|
||||||
case BarcodeScannerAppState.SETTINGS:
|
case BarcodeScannerAppState.SETTINGS:
|
||||||
return <SettingsScreen/>;
|
return <SettingsScreen
|
||||||
|
cameraType={cameraType}
|
||||||
|
locationStr={locationStr}
|
||||||
|
onSave={(newCameraType: CameraType, newLocationStr: string) => {
|
||||||
|
setCameraType(newCameraType);
|
||||||
|
setLocationStr(newLocationStr);
|
||||||
|
_home();
|
||||||
|
}}
|
||||||
|
onCancel={_home}
|
||||||
|
/>;
|
||||||
default:
|
default:
|
||||||
return <ErrorMessage/>;
|
return <ErrorMessage/>;
|
||||||
}
|
}
|
||||||
|
|
2
app.json
2
app.json
|
@ -4,7 +4,7 @@
|
||||||
"name": "uva-covid19-testing-kiosk",
|
"name": "uva-covid19-testing-kiosk",
|
||||||
"slug": "uva-covid19-testing-kiosk",
|
"slug": "uva-covid19-testing-kiosk",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "landscape",
|
"orientation": "portrait",
|
||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/splash.png",
|
"image": "./assets/splash.png",
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
import {ButtonProps, InputLineCountScreenProps} from '../models/ElementProps';
|
||||||
|
import React, {ReactElement, useState} from 'react';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {DefaultTheme, Subheading, Title, RadioButton, Paragraph, TextInput, HelperText, Button} from 'react-native-paper';
|
||||||
|
import {TextInput as NumberInput} from 'react-native';
|
||||||
|
import {colors, styles} from './Styles';
|
||||||
|
|
||||||
|
export const InputLineCountButton = (props: ButtonProps): ReactElement => {
|
||||||
|
return <Button
|
||||||
|
icon="timer"
|
||||||
|
mode="text"
|
||||||
|
color={colors.onBackground}
|
||||||
|
onPress={props.onClicked}
|
||||||
|
style={{marginTop: 30}}
|
||||||
|
>Enter Line Count</Button>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InputLineCountScreen = (props: InputLineCountScreenProps): ReactElement => {
|
||||||
|
const [newLineCount, setNewLineCount] = useState<string>('0');
|
||||||
|
|
||||||
|
const hasErrors = () => {
|
||||||
|
if (newLineCount !== undefined && newLineCount !== null) {
|
||||||
|
const newInt = parseInt(newLineCount, 10);
|
||||||
|
return (
|
||||||
|
isNaN(newInt) ||
|
||||||
|
!isFinite(newInt) ||
|
||||||
|
newInt < 0 ||
|
||||||
|
newInt > 14000
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return <View style={styles.settings}>
|
||||||
|
<Title style={{color: DefaultTheme.colors.text}}>Enter Line Count</Title>
|
||||||
|
<View style={{marginBottom: 10}}>
|
||||||
|
<Subheading style={{color: DefaultTheme.colors.text}}>How many people are waiting in line?</Subheading>
|
||||||
|
<TextInput
|
||||||
|
label="# of people"
|
||||||
|
value={newLineCount}
|
||||||
|
onChangeText={inputStr => setNewLineCount(inputStr)}
|
||||||
|
mode="outlined"
|
||||||
|
theme={DefaultTheme}
|
||||||
|
keyboardType="numeric"
|
||||||
|
/>
|
||||||
|
<HelperText type="error" visible={hasErrors()}>
|
||||||
|
Line count must be a whole number greater than 0.
|
||||||
|
</HelperText>
|
||||||
|
<Button
|
||||||
|
icon="content-save"
|
||||||
|
mode="contained"
|
||||||
|
color={colors.primary}
|
||||||
|
style={{marginBottom: 10}}
|
||||||
|
disabled={hasErrors()}
|
||||||
|
onPress={() => props.onSave(parseInt(newLineCount, 10))}
|
||||||
|
>Save</Button>
|
||||||
|
<Button
|
||||||
|
icon="cancel"
|
||||||
|
mode="outlined"
|
||||||
|
color={colors.primary}
|
||||||
|
onPress={props.onCancel}
|
||||||
|
>Cancel</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
import React, {ReactElement, useState} from 'react';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {DefaultTheme, Subheading, Title, RadioButton, Paragraph, TextInput, HelperText, Button} from 'react-native-paper';
|
||||||
|
import {CameraType, SettingsScreenProps} from '../models/ElementProps';
|
||||||
|
import {colors, styles} from './Styles';
|
||||||
|
|
||||||
|
export const SettingsScreen = (props: SettingsScreenProps): ReactElement => {
|
||||||
|
const [newCameraType, setNewCameraType] = useState<CameraType>(props.cameraType);
|
||||||
|
const [newLocationStr, setNewLocationStr] = useState<string>(props.locationStr);
|
||||||
|
|
||||||
|
const pattern = /^[\d]{4}$/;
|
||||||
|
const hasErrors = () => {
|
||||||
|
return !pattern.test(newLocationStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <View style={styles.settings}>
|
||||||
|
<Title style={{color: DefaultTheme.colors.text}}>Settings</Title>
|
||||||
|
<View style={{marginBottom: 40}}>
|
||||||
|
<Subheading style={{color: DefaultTheme.colors.text}}>Camera to Use</Subheading>
|
||||||
|
<RadioButton.Group
|
||||||
|
onValueChange={value => setNewCameraType(value as CameraType)}
|
||||||
|
value={newCameraType as string}
|
||||||
|
>
|
||||||
|
<RadioButton.Item
|
||||||
|
value="front"
|
||||||
|
label="Front"
|
||||||
|
theme={DefaultTheme}
|
||||||
|
/>
|
||||||
|
<RadioButton.Item
|
||||||
|
value="back"
|
||||||
|
label="Back"
|
||||||
|
theme={DefaultTheme}
|
||||||
|
/>
|
||||||
|
</RadioButton.Group>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={{marginBottom: 10}}>
|
||||||
|
<Subheading style={{color: DefaultTheme.colors.text}}>Location Code</Subheading>
|
||||||
|
<Paragraph style={{color: DefaultTheme.colors.text}}>
|
||||||
|
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.
|
||||||
|
</Paragraph>
|
||||||
|
<TextInput
|
||||||
|
label="Location #"
|
||||||
|
value={newLocationStr}
|
||||||
|
onChangeText={inputStr => setNewLocationStr(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="content-save"
|
||||||
|
mode="contained"
|
||||||
|
color={colors.primary}
|
||||||
|
style={{marginBottom: 10}}
|
||||||
|
disabled={hasErrors()}
|
||||||
|
onPress={() => props.onSave(newCameraType, newLocationStr)}
|
||||||
|
>Save</Button>
|
||||||
|
<Button
|
||||||
|
icon="cancel"
|
||||||
|
mode="outlined"
|
||||||
|
color={colors.primary}
|
||||||
|
onPress={props.onCancel}
|
||||||
|
>Cancel</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
}
|
|
@ -136,6 +136,9 @@ export const styles = StyleSheet.create({
|
||||||
safeAreaView: {
|
safeAreaView: {
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
radio: {
|
||||||
|
backgroundColor: '#EEEEEE',
|
||||||
|
},
|
||||||
row: {
|
row: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -143,10 +146,10 @@ export const styles = StyleSheet.create({
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
flex: 1,
|
// flex: 1,
|
||||||
alignItems: 'stretch',
|
// alignItems: 'stretch',
|
||||||
flexDirection: 'column',
|
// flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
// justifyContent: 'center',
|
||||||
padding: 80,
|
padding: 80,
|
||||||
backgroundColor: DefaultTheme.colors.background,
|
backgroundColor: DefaultTheme.colors.background,
|
||||||
color: DefaultTheme.colors.text,
|
color: DefaultTheme.colors.text,
|
||||||
|
|
|
@ -4,6 +4,7 @@ export enum BarcodeScannerAppState {
|
||||||
SCANNING = 'SCANNING',
|
SCANNING = 'SCANNING',
|
||||||
SCANNED = 'SCANNED',
|
SCANNED = 'SCANNED',
|
||||||
INPUT = 'INPUT',
|
INPUT = 'INPUT',
|
||||||
|
COUNT = 'COUNT',
|
||||||
PRINTING = 'PRINTING',
|
PRINTING = 'PRINTING',
|
||||||
PRINTED = 'PRINTED',
|
PRINTED = 'PRINTED',
|
||||||
ERROR = 'ERROR',
|
ERROR = 'ERROR',
|
||||||
|
|
|
@ -23,6 +23,18 @@ export interface ButtonProps extends ElementProps {
|
||||||
onClicked: () => void;
|
onClicked: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InputLineCountScreenProps extends ElementProps {
|
||||||
|
onSave: (newCount: number) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SettingsScreenProps extends ElementProps {
|
||||||
|
cameraType: CameraType;
|
||||||
|
locationStr: string;
|
||||||
|
onSave: (newCameraType: CameraType, newLocationStr: string) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ScannerProps extends ElementProps {
|
export interface ScannerProps extends ElementProps {
|
||||||
onScanned: BarCodeScannedCallback;
|
onScanned: BarCodeScannedCallback;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export interface LineCount {
|
||||||
|
id: string;
|
||||||
|
lineCount: number;
|
||||||
|
locationId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
Loading…
Reference in New Issue