Refactors settings into config file. Syncs data with Firebase if connected.
This commit is contained in:
parent
632bb0c324
commit
93c7cdd008
|
@ -668,3 +668,4 @@ buck-out/
|
||||||
.expo/*
|
.expo/*
|
||||||
web-build/
|
web-build/
|
||||||
*.hprof
|
*.hprof
|
||||||
|
config/default.tsx
|
||||||
|
|
30
App.tsx
30
App.tsx
|
@ -16,7 +16,7 @@ import {IdNumberInput, InitialsInput, InputIdButton, ScanButton, Scanner} from '
|
||||||
import {SettingsScreen} from './components/Settings';
|
import {SettingsScreen} from './components/Settings';
|
||||||
import {styles, theme} from './components/Styles';
|
import {styles, theme} from './components/Styles';
|
||||||
import {sendDataToFirebase, SyncMessage} from './components/Sync';
|
import {sendDataToFirebase, SyncMessage} from './components/Sync';
|
||||||
import {dateFormat, firebaseConfig} from './config/default';
|
import {firebaseConfig, defaults} from './config/default';
|
||||||
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 {LineCount} from './models/LineCount';
|
||||||
|
@ -33,20 +33,20 @@ if (firebase.apps.length === 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = firebase.firestore();
|
const db = firebase.firestore();
|
||||||
const samplesCollection = db.collection('samples');
|
const samplesCollection = db.collection(defaults.samplesCollection);
|
||||||
const countsCollection = db.collection('counts');
|
const countsCollection = db.collection(defaults.countsCollection);
|
||||||
|
|
||||||
export default function Main() {
|
export default function Main() {
|
||||||
const [appState, setAppState] = useState<BarcodeScannerAppState>(BarcodeScannerAppState.INITIAL);
|
const [appState, setAppState] = useState<BarcodeScannerAppState>(BarcodeScannerAppState.INITIAL);
|
||||||
const [sampleId, setSampleId] = useState<string>('');
|
const [sampleId, setSampleId] = useState<string>('');
|
||||||
const [barCodeId, setBarCodeId] = useState<string>('');
|
const [barCodeId, setBarCodeId] = useState<string>('');
|
||||||
const [sampleDate, setSampleDate] = useState<Date>(new Date());
|
const [sampleDate, setSampleDate] = useState<Date>(new Date());
|
||||||
const [locationStr, setLocationStr] = useState<string>('0000');
|
const [locationStr, setLocationStr] = useState<string>(defaults.locationId);
|
||||||
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 [lineCounts, setLineCounts] = useState<LineCount[]>([]);
|
||||||
const [cameraType, setCameraType] = useState<CameraType>('back');
|
const [cameraType, setCameraType] = useState<CameraType>(defaults.cameraType);
|
||||||
const [numCopies, setNumCopies] = useState<number>(0);
|
const [numCopies, setNumCopies] = useState<number>(defaults.numCopies);
|
||||||
const [isConnected, setIsConnected] = useState<boolean>(false);
|
const [isConnected, setIsConnected] = useState<boolean>(false);
|
||||||
const [initials, setInitials] = useState<string>('');
|
const [initials, setInitials] = useState<string>('');
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ export default function Main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for changes to internet connectivity.
|
// Watch for changes to internet connectivity.
|
||||||
|
// TODO: Set up a timer that periodically syncs data with the database if connected.
|
||||||
NetInfo.addEventListener((state: NetInfoState) => {
|
NetInfo.addEventListener((state: NetInfoState) => {
|
||||||
if (state.type === NetInfoStateType.wifi) {
|
if (state.type === NetInfoStateType.wifi) {
|
||||||
setIsConnected(!!(state.isConnected && state.isInternetReachable));
|
setIsConnected(!!(state.isConnected && state.isInternetReachable));
|
||||||
|
@ -100,7 +101,7 @@ export default function Main() {
|
||||||
setAppState(BarcodeScannerAppState.INPUT_LINE_COUNT);
|
setAppState(BarcodeScannerAppState.INPUT_LINE_COUNT);
|
||||||
};
|
};
|
||||||
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
const _print = () => setAppState(BarcodeScannerAppState.PRINTING);
|
||||||
const _printed = () => setAppState(BarcodeScannerAppState.PRINTED);
|
const _sync = () => setAppState(BarcodeScannerAppState.SYNC);
|
||||||
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
const _home = () => setAppState(BarcodeScannerAppState.DEFAULT);
|
||||||
const _settings = () => setAppState(BarcodeScannerAppState.SETTINGS);
|
const _settings = () => setAppState(BarcodeScannerAppState.SETTINGS);
|
||||||
|
|
||||||
|
@ -125,21 +126,22 @@ export default function Main() {
|
||||||
|
|
||||||
const handleInitialsInput = (newInitials: string) => {
|
const handleInitialsInput = (newInitials: string) => {
|
||||||
setInitials(newInitials);
|
setInitials(newInitials);
|
||||||
const newSampleId = [barCodeId, newInitials, format(sampleDate, dateFormat), locationStr].join('-');
|
const newSampleId = [barCodeId, newInitials, format(sampleDate, defaults.dateEncodedFormat), locationStr].join('-');
|
||||||
setSampleId(newSampleId);
|
setSampleId(newSampleId);
|
||||||
setAppState(BarcodeScannerAppState.SCANNED);
|
setAppState(BarcodeScannerAppState.SCANNED);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLineCountSubmitted = (newCount: number) => {
|
const handleLineCountSubmitted = (newCount: number) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const newId = `${locationStr}-${format(now, dateFormat)}`;
|
const newId = `${locationStr}-${format(now, defaults.dateEncodedFormat)}`;
|
||||||
const newData: LineCount = {
|
const newData: LineCount = {
|
||||||
id: newId,
|
id: newId,
|
||||||
lineCount: newCount,
|
lineCount: newCount,
|
||||||
locationId: locationStr,
|
locationId: locationStr,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
};
|
};
|
||||||
sendDataToFirebase([newData], countsCollection);
|
|
||||||
|
AsyncStorage.setItem(newData.id, JSON.stringify(newData)).then(_sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorMessage = (props: ElementProps): ReactElement => {
|
const ErrorMessage = (props: ElementProps): ReactElement => {
|
||||||
|
@ -170,7 +172,7 @@ export default function Main() {
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
||||||
function App(props: StateProps): ReactElement {
|
const AppContent = (props: StateProps): ReactElement => {
|
||||||
switch (props.appState) {
|
switch (props.appState) {
|
||||||
case BarcodeScannerAppState.INITIAL:
|
case BarcodeScannerAppState.INITIAL:
|
||||||
return <LoadingMessage/>;
|
return <LoadingMessage/>;
|
||||||
|
@ -180,7 +182,7 @@ export default function Main() {
|
||||||
<InputIdButton onClicked={_inputIdNumber}/>
|
<InputIdButton onClicked={_inputIdNumber}/>
|
||||||
<InputLineCountButton onClicked={_inputLineCount}/>
|
<InputLineCountButton onClicked={_inputLineCount}/>
|
||||||
</View>;
|
</View>;
|
||||||
case BarcodeScannerAppState.PRINTED:
|
case BarcodeScannerAppState.SYNC:
|
||||||
return <SyncMessage
|
return <SyncMessage
|
||||||
isConnected={isConnected}
|
isConnected={isConnected}
|
||||||
samplesCollection={samplesCollection}
|
samplesCollection={samplesCollection}
|
||||||
|
@ -192,7 +194,7 @@ export default function Main() {
|
||||||
return <View style={styles.container}>
|
return <View style={styles.container}>
|
||||||
<PrintingMessage
|
<PrintingMessage
|
||||||
numCopies={numCopies}
|
numCopies={numCopies}
|
||||||
onCancel={_printed}
|
onCancel={_sync}
|
||||||
id={sampleId}
|
id={sampleId}
|
||||||
barCodeId={barCodeId}
|
barCodeId={barCodeId}
|
||||||
date={sampleDate}
|
date={sampleDate}
|
||||||
|
@ -270,7 +272,7 @@ export default function Main() {
|
||||||
<Appbar.Action icon="settings" onPress={_settings}/>
|
<Appbar.Action icon="settings" onPress={_settings}/>
|
||||||
</Appbar.Header>
|
</Appbar.Header>
|
||||||
<SafeAreaView style={styles.safeAreaView}>
|
<SafeAreaView style={styles.safeAreaView}>
|
||||||
<App appState={appState}/>
|
<AppContent appState={appState}/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</PaperProvider>
|
</PaperProvider>
|
||||||
);
|
);
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
||||||
#Fri Sep 11 17:23:10 EDT 2020
|
#Sun Sep 13 08:50:53 EDT 2020
|
||||||
VERSION_NAME=1.0.7
|
VERSION_NAME=1.0.10
|
||||||
VERSION_BUILD=16
|
VERSION_BUILD=19
|
||||||
VERSION_CODE=11
|
VERSION_CODE=14
|
||||||
|
|
|
@ -5,7 +5,7 @@ import React, {ReactElement, useEffect, useState} from 'react';
|
||||||
import {Text, View} from 'react-native';
|
import {Text, View} from 'react-native';
|
||||||
import {Button, Title} from 'react-native-paper';
|
import {Button, Title} from 'react-native-paper';
|
||||||
import QRCode from 'react-native-qrcode-svg';
|
import QRCode from 'react-native-qrcode-svg';
|
||||||
import {dateDisplayFormat} from '../config/default';
|
import {defaults} from '../config/default';
|
||||||
import {BarCodeProps, ButtonProps, PrintingProps} from '../models/ElementProps';
|
import {BarCodeProps, ButtonProps, PrintingProps} from '../models/ElementProps';
|
||||||
import {Sample} from '../models/Sample';
|
import {Sample} from '../models/Sample';
|
||||||
import {colors, styles} from './Styles';
|
import {colors, styles} from './Styles';
|
||||||
|
@ -223,7 +223,7 @@ export const PrintingMessage = (props: PrintingProps): ReactElement => {
|
||||||
export const BarCodeDisplay = (props: BarCodeProps): ReactElement => {
|
export const BarCodeDisplay = (props: BarCodeProps): ReactElement => {
|
||||||
return <View style={styles.printPreview}>
|
return <View style={styles.printPreview}>
|
||||||
<Text style={styles.label}>ID #: {props.id}</Text>
|
<Text style={styles.label}>ID #: {props.id}</Text>
|
||||||
<Text style={styles.label}>Date: {format(props.date, dateDisplayFormat)}</Text>
|
<Text style={styles.label}>Date: {format(props.date, defaults.dateDisplayFormat)}</Text>
|
||||||
<Text style={styles.label}>Location #: {props.location}</Text>
|
<Text style={styles.label}>Location #: {props.location}</Text>
|
||||||
<QRCode value={props.id}/>
|
<QRCode value={props.id}/>
|
||||||
</View>;
|
</View>;
|
||||||
|
|
|
@ -110,7 +110,7 @@ export const InitialsInput = (props: InputInitialsProps): ReactElement => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
props.onSave(inputStr);
|
props.onSave(inputStr.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
return <View style={styles.settings}>
|
return <View style={styles.settings}>
|
||||||
|
@ -122,7 +122,7 @@ export const InitialsInput = (props: InputInitialsProps): ReactElement => {
|
||||||
<TextInput
|
<TextInput
|
||||||
label="Initials"
|
label="Initials"
|
||||||
value={inputStr}
|
value={inputStr}
|
||||||
onChangeText={inputStr => setInputStr(inputStr.toLowerCase())}
|
onChangeText={inputStr => setInputStr(inputStr)}
|
||||||
mode="outlined"
|
mode="outlined"
|
||||||
theme={DefaultTheme}
|
theme={DefaultTheme}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
import {parse} from 'date-fns';
|
|
||||||
import React, {ReactElement, useEffect, useState} from 'react';
|
import React, {ReactElement, useEffect, useState} from 'react';
|
||||||
import {View} from 'react-native';
|
import {View} from 'react-native';
|
||||||
import {Title} from 'react-native-paper';
|
import {Snackbar, Title} from 'react-native-paper';
|
||||||
import {dateFormat} from '../config/default';
|
import {defaults} from '../config/default';
|
||||||
|
import {CollectionMeta} from '../models/Collection';
|
||||||
import {SyncProps} from '../models/ElementProps';
|
import {SyncProps} from '../models/ElementProps';
|
||||||
import {LineCount} from '../models/LineCount';
|
import {LineCount} from '../models/LineCount';
|
||||||
import {Sample} from '../models/Sample';
|
import {Sample} from '../models/Sample';
|
||||||
|
@ -19,38 +19,70 @@ export const sendDataToFirebase = async (newData: Array<Sample | LineCount>, col
|
||||||
|
|
||||||
export const SyncMessage = (props: SyncProps): ReactElement => {
|
export const SyncMessage = (props: SyncProps): ReactElement => {
|
||||||
const [syncStatus, setSyncStatus] = useState<string>('Syncing data...');
|
const [syncStatus, setSyncStatus] = useState<string>('Syncing data...');
|
||||||
|
const [isError, setIsError] = useState<boolean>(false);
|
||||||
|
const [errorMessage, setErrorMessage] = useState<string>('');
|
||||||
|
|
||||||
useEffect(() => {
|
// Display an error message if Firebase sync fails.
|
||||||
// TODO: Alternatively, set up a timer that periodically syncs data with the database.
|
const _handleError = (error: any, dataTypeLabel: string) => {
|
||||||
|
setIsError(true);
|
||||||
|
setErrorMessage(error);
|
||||||
|
setSyncStatus(`Error occurred while syncing ${dataTypeLabel} data.`);
|
||||||
|
props.onCancel();
|
||||||
|
};
|
||||||
|
|
||||||
// Detect when user is online. If online, sync data with Firebase.
|
// Delete locally-cached data from AsyncStorage
|
||||||
if (props.isConnected) {
|
const _clearLocalCache = (keysToRemove: string[], dataTypeLabel: string) => {
|
||||||
// Get the collection subscription
|
AsyncStorage.multiRemove(keysToRemove).then(() => {
|
||||||
const unsubscribe = props.samplesCollection.onSnapshot(q => {}, e => {});
|
setSyncStatus(`${dataTypeLabel} data synced.`);
|
||||||
|
|
||||||
// Upload any changes to Firebase
|
|
||||||
AsyncStorage.getAllKeys().then(keys => {
|
|
||||||
const newSamples = keys
|
|
||||||
.filter(s => /^[\d]{9}-[\d]{12}-[\d]{4}$/.test(s))
|
|
||||||
.map(s => {
|
|
||||||
const propsArray = s.split('-');
|
|
||||||
return {
|
|
||||||
id: s,
|
|
||||||
barcodeId: propsArray[0],
|
|
||||||
createdAt: parse(propsArray[1], dateFormat, new Date()),
|
|
||||||
locationId: propsArray[2],
|
|
||||||
} as Sample;
|
|
||||||
});
|
|
||||||
|
|
||||||
sendDataToFirebase(newSamples, props.samplesCollection).then(() => {
|
|
||||||
// TODO: Delete stored keys in AsyncStorage
|
|
||||||
|
|
||||||
setSyncStatus('Data synced.');
|
|
||||||
props.onSync();
|
props.onSync();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload any new locally-stored items to Firebase, then remove them from local storage.
|
||||||
|
const _syncCollection = (localStorageKeys: string[], collection: CollectionMeta) => {
|
||||||
|
const newItemsKeys = localStorageKeys.filter(k => collection.keyRegex.test(k));
|
||||||
|
AsyncStorage.multiGet(newItemsKeys, (errors, dataTuples) => {
|
||||||
|
if (dataTuples && (dataTuples.length > 0)) {
|
||||||
|
const data: Sample[] | LineCount[] = [];
|
||||||
|
dataTuples.forEach(t => {
|
||||||
|
if (t[1] !== null) {
|
||||||
|
const lineCount = JSON.parse(t[1]);
|
||||||
|
data.push(lineCount);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => unsubscribe();
|
sendDataToFirebase(data, collection.firebaseCollection)
|
||||||
|
.then(() => _clearLocalCache(newItemsKeys, collection.label))
|
||||||
|
.catch(error => _handleError(error, collection.label));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Detect when user is online. If online, sync data with Firebase.
|
||||||
|
if (props.isConnected) {
|
||||||
|
const collectionsToSync = [
|
||||||
|
{
|
||||||
|
firebaseCollection: props.countsCollection,
|
||||||
|
keyRegex: defaults.lineCountRegex,
|
||||||
|
label: 'Line Counts',
|
||||||
|
unsubscribe: props.countsCollection.onSnapshot(q => {}, e => {}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
firebaseCollection: props.samplesCollection,
|
||||||
|
keyRegex: defaults.qrCodeRegex,
|
||||||
|
label: 'QR Codes',
|
||||||
|
unsubscribe: props.samplesCollection.onSnapshot(q => {}, e => {}),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Upload new data to Firebase
|
||||||
|
AsyncStorage.getAllKeys().then(keys => {
|
||||||
|
collectionsToSync.forEach(c => _syncCollection(keys, c));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Unsubscribe from all collections
|
||||||
|
return () => collectionsToSync.forEach(c => c.unsubscribe());
|
||||||
} else {
|
} else {
|
||||||
// If not online, just go home.
|
// If not online, just go home.
|
||||||
setSyncStatus('Device is not online. Skipping sync...');
|
setSyncStatus('Device is not online. Skipping sync...');
|
||||||
|
@ -61,6 +93,11 @@ export const SyncMessage = (props: SyncProps): ReactElement => {
|
||||||
return <View style={styles.container}>
|
return <View style={styles.container}>
|
||||||
<View style={styles.centerMiddle}>
|
<View style={styles.centerMiddle}>
|
||||||
<Title style={styles.heading}>{syncStatus}</Title>
|
<Title style={styles.heading}>{syncStatus}</Title>
|
||||||
|
<Snackbar
|
||||||
|
visible={isError}
|
||||||
|
onDismiss={props.onCancel}
|
||||||
|
style={styles.error}
|
||||||
|
>{errorMessage === '' ? 'Something went wrong. Try again.' : errorMessage}</Snackbar>
|
||||||
<CancelButton onClicked={props.onCancel} />
|
<CancelButton onClicked={props.onCancel} />
|
||||||
</View>
|
</View>
|
||||||
</View>;
|
</View>;
|
||||||
|
|
|
@ -1,12 +1,26 @@
|
||||||
|
import {AppDefaults} from '../models/Default';
|
||||||
|
import {CameraType} from '../models/ElementProps';
|
||||||
|
|
||||||
|
// Firebase project config from https://console.firebase.google.com > Project Settings > General > Your apps > Web App
|
||||||
export const firebaseConfig = {
|
export const firebaseConfig = {
|
||||||
apiKey: 'api_key_goes_here',
|
apiKey: 'api_key_goes_here',
|
||||||
authDomain: "uva-covid19-testing-kiosk.firebaseapp.com",
|
authDomain: 'uva-covid19-testing-kiosk.firebaseapp.com',
|
||||||
databaseURL: "https://uva-covid19-testing-kiosk.firebaseio.com",
|
databaseURL: 'https://uva-covid19-testing-kiosk.firebaseio.com',
|
||||||
projectId: 'project_id_goes_here',
|
projectId: 'project_id_goes_here',
|
||||||
storageBucket: "uva-covid19-testing-kiosk.appspot.com",
|
storageBucket: 'uva-covid19-testing-kiosk.appspot.com',
|
||||||
messagingSenderId: 'sender_id_goes_here',
|
messagingSenderId: 'sender_id_goes_here',
|
||||||
appId: 'app_id_goes_here'
|
appId: 'app_id_goes_here',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dateFormat = 'yyyyMMddHHmm';
|
// Default form field and data values
|
||||||
export const dateDisplayFormat = 'MM/dd/yyyy, hh:mm aa';
|
export const defaults: AppDefaults = {
|
||||||
|
countsCollection: 'counts', // Name of collection for Line Counts in Firebase.
|
||||||
|
samplesCollection: 'samples', // Name of collection for Line Counts in Firebase.
|
||||||
|
dateEncodedFormat: 'yyyyMMddHHmm', // Format for dates when encoded in IDs for database records.
|
||||||
|
dateDisplayFormat: 'MM/dd/yyyy, hh:mm aa', // Format for dates when displayed to user.
|
||||||
|
numCopies: 2, // Default number of copies of labels to print. Can be overridden by user setting.
|
||||||
|
cameraType: 'back' as CameraType, // Which camera to use for capturing bar codes. Can be overridden by user setting.
|
||||||
|
locationId: '0000', // Default location ID. Can be overridden by user setting.
|
||||||
|
lineCountRegex: /^[\d]{4}-[\d]{12}$/, // ID format for Line Count records.
|
||||||
|
qrCodeRegex: /^[\d]{9}-[a-zA-Z]+-[\d]{12}-[\d]{4}$/, // ID format for QR Code records.
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
Example configuration file. Make a copy of this file, name it "default.tsx", and place it in the config directory.
|
||||||
|
Then modify the values below to match the actual Firebase configuration.
|
||||||
|
*/
|
||||||
|
import {AppDefaults} from '../models/Default';
|
||||||
|
import {CameraType} from '../models/ElementProps';
|
||||||
|
|
||||||
|
// Firebase project config from https://console.firebase.google.com > Project Settings > General > Your apps > Web App
|
||||||
|
export const firebaseConfig = {
|
||||||
|
apiKey: 'api_key_goes_here',
|
||||||
|
authDomain: 'uva-covid19-testing-kiosk.firebaseapp.com',
|
||||||
|
databaseURL: 'https://uva-covid19-testing-kiosk.firebaseio.com',
|
||||||
|
projectId: 'project_id_goes_here',
|
||||||
|
storageBucket: 'uva-covid19-testing-kiosk.appspot.com',
|
||||||
|
messagingSenderId: 'sender_id_goes_here',
|
||||||
|
appId: 'app_id_goes_here',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default form field and data values
|
||||||
|
export const defaults: AppDefaults = {
|
||||||
|
countsCollection: 'counts', // Name of collection for Line Counts in Firebase.
|
||||||
|
samplesCollection: 'samples', // Name of collection for Line Counts in Firebase.
|
||||||
|
dateEncodedFormat: 'yyyyMMddHHmm', // Format for dates when encoded in IDs for database records.
|
||||||
|
dateDisplayFormat: 'MM/dd/yyyy, hh:mm aa', // Format for dates when displayed to user.
|
||||||
|
numCopies: 2, // Default number of copies of labels to print. Can be overridden by user setting.
|
||||||
|
cameraType: 'back' as CameraType, // Which camera to use for capturing bar codes. Can be overridden by user setting.
|
||||||
|
locationId: '0000', // Default location ID. Can be overridden by user setting.
|
||||||
|
lineCountRegex: /^[\d]{4}-[\d]{12}$/, // ID format for Line Count records.
|
||||||
|
qrCodeRegex: /^[\d]{9}-[a-zA-Z]+-[\d]{12}-[\d]{4}$/, // ID format for QR Code records.
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ export enum BarcodeScannerAppState {
|
||||||
INPUT_INITIALS = 'INPUT_INITIALS',
|
INPUT_INITIALS = 'INPUT_INITIALS',
|
||||||
INPUT_LINE_COUNT = 'INPUT_LINE_COUNT',
|
INPUT_LINE_COUNT = 'INPUT_LINE_COUNT',
|
||||||
PRINTING = 'PRINTING',
|
PRINTING = 'PRINTING',
|
||||||
PRINTED = 'PRINTED',
|
SYNC = 'SYNC',
|
||||||
ERROR = 'ERROR',
|
ERROR = 'ERROR',
|
||||||
SETTINGS = 'SETTINGS',
|
SETTINGS = 'SETTINGS',
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import * as firebase from 'firebase';
|
||||||
|
import 'firebase/firestore';
|
||||||
|
|
||||||
|
export interface CollectionMeta {
|
||||||
|
firebaseCollection: firebase.firestore.CollectionReference;
|
||||||
|
keyRegex: RegExp;
|
||||||
|
label: string;
|
||||||
|
unsubscribe: () => void;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {CameraType} from './ElementProps';
|
||||||
|
|
||||||
|
export interface AppDefaults {
|
||||||
|
countsCollection: string;
|
||||||
|
samplesCollection: string;
|
||||||
|
dateEncodedFormat: string;
|
||||||
|
dateDisplayFormat: string;
|
||||||
|
numCopies: number;
|
||||||
|
cameraType: CameraType;
|
||||||
|
locationId: string;
|
||||||
|
lineCountRegex: RegExp;
|
||||||
|
qrCodeRegex: RegExp;
|
||||||
|
}
|
Loading…
Reference in New Issue