matiru

Blockchain-Based Supply Chain Transparency for Agricultural Produce

frontend/components/Scanner.js (2720B)


  1import { useState, useEffect } from "react";
  2import {
  3  Alert,
  4  Button,
  5  Dimensions,
  6  StyleSheet,
  7  TextInput,
  8  View,
  9} from "react-native";
 10import { CameraView, Camera } from "expo-camera";
 11import styles, { colors } from "../styles";
 12
 13const { width } = Dimensions.get("window");
 14const SCAN_AREA_SIZE = width * 0.7;
 15
 16export default function Scanner({ value, onChange }) {
 17  const [hasPermission, setHasPermission] = useState(null);
 18  const [useCamera, setUseCamera] = useState(false);
 19  const [scanned, setScanned] = useState(false);
 20
 21  useEffect(() => {
 22    (async () => {
 23      const { status } = await Camera.requestCameraPermissionsAsync();
 24      setHasPermission(status === "granted");
 25    })();
 26  }, []);
 27
 28  const handleScanned = ({ data }) => {
 29    if (!data) {
 30      Alert.alert("Scan Failed", "No data found in QR code");
 31      return;
 32    }
 33
 34    setScanned(true);
 35    onChange(data);
 36    setUseCamera(false);
 37  };
 38
 39  return (
 40    <View style={{ marginVertical: 8 }}>
 41      <Button
 42        title={useCamera ? "Use Manual Entry" : "Scan QR Code"}
 43        color={colors.darkGreen}
 44        onPress={() => {
 45          setUseCamera(!useCamera);
 46          setScanned(false);
 47        }}
 48      />
 49      {useCamera ? (
 50        !scanned ? (
 51          <View style={{ height: SCAN_AREA_SIZE * 1.4, marginTop: 10 }}>
 52            <CameraView
 53              style={{ flex: 1 }}
 54              onBarcodeScanned={scanned ? undefined : handleScanned}
 55              barcodeScannerSettings={{ barcodeTypes: ["qr"] }}
 56            />
 57            <View style={cameraStyles.overlay}>
 58              <View style={cameraStyles.topBottomOverlay} />
 59              <View style={cameraStyles.middleRow}>
 60                <View style={cameraStyles.sideOverlay} />
 61                <View style={cameraStyles.scanArea} />
 62                <View style={cameraStyles.sideOverlay} />
 63              </View>
 64              <View style={cameraStyles.topBottomOverlay} />
 65            </View>
 66          </View>
 67        ) : null
 68      ) : (
 69        <TextInput
 70          style={[styles.input, { marginTop: 10 }]}
 71          placeholder="Enter Produce ID"
 72          value={value}
 73          onChangeText={onChange}
 74        />
 75      )}
 76    </View>
 77  );
 78}
 79
 80const cameraStyles = StyleSheet.create({
 81  overlay: {
 82    ...StyleSheet.absoluteFillObject,
 83    justifyContent: "center",
 84    alignItems: "center",
 85  },
 86  topBottomOverlay: {
 87    flex: 1,
 88    width: "100%",
 89    backgroundColor: "rgba(0,0,0,0.5)",
 90  },
 91  middleRow: {
 92    flexDirection: "row",
 93  },
 94  sideOverlay: {
 95    flex: 1,
 96    backgroundColor: "rgba(0,0,0,0.5)",
 97  },
 98  scanArea: {
 99    width: SCAN_AREA_SIZE,
100    height: SCAN_AREA_SIZE,
101    borderWidth: 2,
102    borderColor: colors.midGreen,
103  },
104});