diff --git a/src/screens/events/QRCodeScanningScreen.tsx b/src/screens/events/QRCodeScanningScreen.tsx index f7d17404..89589545 100644 --- a/src/screens/events/QRCodeScanningScreen.tsx +++ b/src/screens/events/QRCodeScanningScreen.tsx @@ -1,18 +1,31 @@ -import { View, Text, TouchableOpacity, Alert, Animated, Easing } from 'react-native'; +import { View, Text, TouchableOpacity, Animated, Easing, Dimensions } from 'react-native'; import React, { useEffect, useRef, useState } from 'react'; import { CameraView, Camera } from 'expo-camera'; import { SafeAreaView } from 'react-native-safe-area-context'; -import { GestureHandlerRootView, PinchGestureHandler, PinchGestureHandlerGestureEvent, State } from 'react-native-gesture-handler'; -import { MainStackParams } from '../../types/navigation'; import { Octicons } from '@expo/vector-icons'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; +import { MainStackParams } from '../../types/navigation'; + +const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); + +type BarCodeScannedResult = { + type: string; + data: string; + bounds?: { + origin: { x: number; y: number }; + size: { width: number; height: number }; + }; +}; const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps) => { const [hasCameraPermissions, setHasCameraPermissions] = useState(null); + const [boxColor, setBoxColor] = useState('#FFFFFF'); + const [validScanned, setValidScanned] = useState(false); const pulseAnim = useRef(new Animated.Value(1)).current; - const [qrData, setQrData] = useState<{ id: string; mode: string } | null>(null); - const cameraRef = useRef(null); - const timeoutRef = useRef(null); + const boxTop = useRef(new Animated.Value((screenHeight / 2) - 240)).current; + const boxLeft = useRef(new Animated.Value((screenWidth / 2) - 120)).current; + const boxWidth = useRef(new Animated.Value(240)).current; + const boxHeight = useRef(new Animated.Value(240)).current; useEffect(() => { const getBarCodeScannerPermissions = async () => { @@ -30,13 +43,13 @@ const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps pulse()); }; @@ -44,45 +57,57 @@ const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps { - const dataRegex: RegExp = /^tamu-shpe:\/\/event\?id=[a-zA-z0-9]+&mode=(sign-in|sign-out)$/i; - - if (dataRegex.test(data)) { - const linkVariables = data.split('?')[1].split('&'); - const id = linkVariables[0].split('=')[1]; - const mode = linkVariables[1].split('=')[1]; - if (id && (mode === 'sign-in' || mode === 'sign-out')) { - setQrData({ id, mode }); - - // Clear any existing timeout when valid data is found - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - - // Set a timeout to clear qrData after 3 seconds if no new valid QR codes are detected - timeoutRef.current = setTimeout(() => { - setQrData(null); - }, 5000); - } + const handleBarCodeScanned = ({ bounds, type, data }: BarCodeScannedResult) => { + if (validScanned) { + return; } - }; - useEffect(() => { - return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); + const dataRegex = /^tamu-shpe:\/\/event\?id=[a-zA-Z0-9]+&mode=(sign-in|sign-out)$/i; + if (dataRegex.test(data)) { + setValidScanned(true); + console.log('Data Received', `Bar code with type ${type} and data ${data} has been scanned!`); + if (bounds) { + setBoxColor('#FD652F'); + + Animated.parallel([ + Animated.timing(boxTop, { + toValue: bounds.origin.y, + duration: 90, + easing: Easing.inOut(Easing.ease), + useNativeDriver: false, + }), + Animated.timing(boxLeft, { + toValue: bounds.origin.x, + duration: 90, + easing: Easing.inOut(Easing.ease), + useNativeDriver: false, + }), + Animated.timing(boxWidth, { + toValue: bounds.size.width, + duration: 90, + easing: Easing.inOut(Easing.ease), + useNativeDriver: false, + }), + Animated.timing(boxHeight, { + toValue: bounds.size.height, + duration: 90, + easing: Easing.inOut(Easing.ease), + useNativeDriver: false, + }), + ]).start(); } - }; - }, []); - const handleConfirm = () => { - if (qrData) { - navigation.navigate("EventVerificationScreen", { id: qrData.id, mode: qrData.mode as "sign-in" | "sign-out" }); - setQrData(null); + setTimeout(() => { + const linkVariables = data.split('?')[1].split('&'); + const id = linkVariables[0].split('=')[1]; + const mode = linkVariables[1].split('=')[1]; + if (id && (mode === 'sign-in' || mode === 'sign-out')) { + navigation.navigate('EventVerificationScreen', { id, mode }); + } + }, 500); } }; - if (hasCameraPermissions === null) { return Requesting for camera permission; } @@ -91,68 +116,62 @@ const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps - - {/* Header */} - - - Scanner - - navigation.goBack()}> - - + + + + Scanner - - - navigation.goBack()}> + + + + + + {/* Pulsing Effect with Animated Transition */} + - {/* Pulsing Effect */} - - - - - - - - - + + + + + - - {/* Button for Sign In/Sign Out */} - {qrData && ( - - - - {qrData.mode === 'sign-in' ? 'Sign in to the event' : 'Sign out of the event'} - - - - )} - - - - Using Scanner - Scan the QRCode provided by the event host. - - - + + + + + Using Scanner + Scan the QRCode provided by the event host. + + ); };