// @refresh reset import AsyncStorage from '@react-native-community/async-storage'; import {format, parse} from 'date-fns'; import {BarCodeEvent, BarCodeScanner, PermissionResponse} from 'expo-barcode-scanner'; // @ts-ignore import * as firebase from 'firebase'; import 'firebase/firestore'; import React, {ReactElement, useCallback, useEffect, useState} from 'react'; import {AppRegistry, SafeAreaView, Text, View, YellowBox} from 'react-native'; import { Appbar, Button, DefaultTheme, HelperText, Provider as PaperProvider, RadioButton, Snackbar, Subheading, TextInput, Title, } from 'react-native-paper'; import {expo as appExpo} from './app.json'; import {CancelButton} from './components/Common'; import {BarCodeDisplay, PrintButton, PrintingMessage} from './components/Print'; import {IdNumberInput, InputIdButton, ScanButton, Scanner} from './components/Scan'; import {colors, styles} from './components/Styles'; import {BarcodeScannerAppState} from './models/BarcodeScannerAppState'; import {CameraType, ElementProps, StateProps} from './models/ElementProps'; import {Sample} from './models/Sample'; 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' }; // Initialize Firebase if not already initialized. if (firebase.apps.length === 0) { firebase.initializeApp(firebaseConfig); } YellowBox.ignoreWarnings([ 'Setting a timer for a long period of time', // Ignore Firebase timer warnings 'Remote debugger is in a background tab', // Ignore Firebase timer warnings ]); const db = firebase.firestore(); const samplesCollection = db.collection('samples'); const theme = { ...DefaultTheme, colors: colors, } export default function Main() { const [appState, setAppState] = useState(BarcodeScannerAppState.INITIAL); const [sampleId, setSampleId] = useState(''); const [barCodeId, setBarCodeId] = useState(''); const [sampleDate, setSampleDate] = useState(new Date()); const [locationStr, setLocationStr] = useState('4321'); const [errorMessage, setErrorMessage] = useState(''); const [samples, setSamples] = useState([]); const [cameraType, setCameraType] = useState('back'); useEffect(() => { BarCodeScanner.requestPermissionsAsync().then((value: PermissionResponse) => { if (value.granted) { setAppState(BarcodeScannerAppState.DEFAULT); } else { setAppState(BarcodeScannerAppState.ERROR); } }); const unsubscribe = samplesCollection.onSnapshot(querySnapshot => { // Transform and sort the data returned from Firebase const samplesFirestore = querySnapshot .docChanges() .filter(({type}) => type === 'added') .map(({doc}) => { const sample = doc.data(); return {...sample, createdAt: sample.createdAt.toDate()} as Sample; }) .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()); appendSamples(samplesFirestore); }); return () => unsubscribe() }, []); const _doNothing = () => { }; const _scan = () => { setErrorMessage(''); setAppState(BarcodeScannerAppState.SCANNING); }; const _inputIdNumber = () => { setErrorMessage(''); setAppState(BarcodeScannerAppState.INPUT); }; const _print = () => setAppState(BarcodeScannerAppState.PRINTING); const _printed = () => setAppState(BarcodeScannerAppState.PRINTED); 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}$|^[\d]{9}$/; console.log('barCodeString', barCodeString); if (pattern.test(barCodeString)) { const cardId = e.data.slice(0, 9); const newSampleDate = new Date(); const newSampleId = [cardId, format(newSampleDate, 'yyyyMMddHHmm'), locationStr].join('-'); setSampleId(newSampleId); setBarCodeId(cardId); setSampleDate(newSampleDate); setAppState(BarcodeScannerAppState.SCANNED); } else { setErrorMessage(`The barcode data "${e.data}" is not from a valid ID card.`); setAppState(BarcodeScannerAppState.ERROR); } }; const appendSamples = useCallback((newSamples) => { setSamples((previousSamples) => previousSamples.concat(newSamples)); }, [samples]); const sendDataToFirebase = async (newSamples: Sample[]) => { const writes = newSamples.map(s => samplesCollection.doc(s.id).set(s)); await Promise.all(writes); } function ErrorMessage(props: ElementProps): ReactElement { return {errorMessage === '' ? 'Something went wrong. Try again.' : errorMessage} } function LoadingMessage(props: ElementProps): ReactElement { return Loading...; } function SuccessMessage(props: ElementProps): ReactElement { return Your barcode label has printed successfully.; } function ActionButtons(props: ElementProps): ReactElement { return } function SettingsScreen(props: ElementProps): ReactElement { const [inputStr, setInputStr] = useState(locationStr); const pattern = /^[\d]{4}$/; const hasErrors = () => { return !pattern.test(inputStr); }; return Which camera to scan bar codes with? setCameraType(value as CameraType)} value={cameraType as string} > Front Back 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. setInputStr(inputStr)} mode="outlined" theme={DefaultTheme} /> Location number must be exactly 4 digits. No other characters are allowed. } function App(props: StateProps): ReactElement { switch (props.appState) { case BarcodeScannerAppState.INITIAL: return ; case BarcodeScannerAppState.DEFAULT: return ; case BarcodeScannerAppState.PRINTED: // 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], 'yyyyMMddHHmm', new Date()), locationId: propsArray[2], } as Sample; }); sendDataToFirebase(newSamples); }); _home(); return ; case BarcodeScannerAppState.PRINTING: return ; case BarcodeScannerAppState.SCANNED: return ; case BarcodeScannerAppState.SCANNING: return ; case BarcodeScannerAppState.INPUT: return ; case BarcodeScannerAppState.SETTINGS: return ; default: return ; } } return ( ); }; AppRegistry.registerComponent(appExpo.name, () => Main);