Integrate Redux for state management, replace useState with Redux store

This commit is contained in:
2024-07-07 15:57:29 +08:00
parent 47d1867cab
commit cdac16a723
11 changed files with 196 additions and 129 deletions

View File

@@ -1,18 +1,19 @@
import React, { useContext, useState, useEffect } from 'react';
import { View, Text, StyleSheet, FlatList, TouchableOpacity, Image, BackHandler, Modal } from 'react-native';
import { QRCodeContext, QRCode } from '../types'; // Import QRCode type
import { useDispatch, useSelector } from 'react-redux';
import ScannedDataBox from '../components/ScannedDataBox';
import { Ionicons } from '@expo/vector-icons';
import { RootState } from '../store';
import { QRCode } from '../types';
import { toggleBookmark, deleteQRCode } from '../actions/qrCodeActions';
const HistoryScreen: React.FC = () => {
const qrCodeContext = useContext(QRCodeContext);
const qrCodes = qrCodeContext?.qrCodes || [];
const setQrCodes = qrCodeContext?.setQrCodes || (() => {});
const dispatch = useDispatch();
const qrCodes = useSelector((state: RootState) => state.qrCodes);
const [selectedData, setSelectedData] = useState<string | null>(null);
const [selectedScanResult, setSelectedScanResult] = useState<any | null>(null);
const [selectedType, setSelectedType] = useState<string | null>(null); // Add state for selectedType
const [selectedType, setSelectedType] = useState<string | null>(null);
const [showBookmarks, setShowBookmarks] = useState<boolean>(false);
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [indexToDelete, setIndexToDelete] = useState<number | null>(null);
@@ -28,42 +29,17 @@ const HistoryScreen: React.FC = () => {
return false;
};
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
backAction
);
const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction);
return () => backHandler.remove();
}, [selectedData]);
const toggleBookmark = (index: number) => {
setQrCodes((prev: QRCode[]) => {
const originalIndex = prev.length - 1 - index; // Compute the original index
const newQrCodes = [...prev];
newQrCodes[originalIndex].bookmarked = !newQrCodes[originalIndex].bookmarked;
console.log('Toggled bookmark for QR code at index:', originalIndex);
return newQrCodes;
});
};
const filteredQrCodes = showBookmarks ? qrCodes.filter(qr => qr.bookmarked) : qrCodes.slice().reverse();
const deleteQRCode = () => {
if (indexToDelete !== null) {
setQrCodes((prev: QRCode[]) => {
const originalIndex = prev.length - 1 - indexToDelete; // Compute the original index
console.log('Deleting QR code at index:', originalIndex);
return prev.filter((_, i) => i !== originalIndex);
});
setIndexToDelete(null);
setIsModalVisible(false);
}
};
const filteredQrCodes = (showBookmarks ? qrCodes.filter(qr => qr.bookmarked) : qrCodes.slice().reverse());
const handleItemPress = (item: any) => {
const handleItemPress = (item: QRCode) => {
setSelectedData(item.data);
setSelectedScanResult(item.scanResult);
setSelectedType(item.type); // Set the selected type
setSelectedType(item.type);
console.log('Selected QR code data:', item.data);
console.log('Selected QR code type:', item.type);
};
@@ -77,23 +53,17 @@ const HistoryScreen: React.FC = () => {
const clearSelectedData = () => {
setSelectedData(null);
setSelectedScanResult(null);
setSelectedType(null); // Clear the selected type
setSelectedType(null);
};
return (
<View style={styles.container}>
{/* Header for toggling between History and Bookmarks */}
<View style={styles.headerContainer}>
<TouchableOpacity onPress={() => {
setShowBookmarks(false);
clearSelectedData();
}}>
<TouchableOpacity onPress={() => { setShowBookmarks(false); clearSelectedData(); }}>
<Text style={!showBookmarks ? styles.headerTextActive : styles.headerTextInactive}>History</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
setShowBookmarks(true);
clearSelectedData();
}}>
<TouchableOpacity onPress={() => { setShowBookmarks(true); clearSelectedData(); }}>
<Text style={showBookmarks ? styles.headerTextActive : styles.headerTextInactive}>Bookmarks</Text>
</TouchableOpacity>
</View>
@@ -121,7 +91,7 @@ const HistoryScreen: React.FC = () => {
})}</Text>
</View>
<View style={styles.itemRight}>
<TouchableOpacity onPress={() => toggleBookmark(index)}>
<TouchableOpacity onPress={() => dispatch(toggleBookmark(index))}>
<Ionicons name={item.bookmarked ? "bookmark" : "bookmark-outline"} size={24} color={item.bookmarked ? "#2196F3" : "#ff69b4"} />
</TouchableOpacity>
<TouchableOpacity onPress={() => confirmDelete(index)}>
@@ -146,7 +116,7 @@ const HistoryScreen: React.FC = () => {
<Text style={styles.modalTitle}>Are you sure?</Text>
<Text style={styles.modalText}>If bookmarked, this will be removed from both History and Bookmarks.</Text>
<View style={styles.modalButtons}>
<TouchableOpacity style={styles.modalButton} onPress={deleteQRCode}>
<TouchableOpacity style={styles.modalButton} onPress={() => dispatch(deleteQRCode(indexToDelete))}>
<Text style={styles.modalButtonText}>Yes, Delete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.modalButton} onPress={() => setIsModalVisible(false)}>

View File

@@ -1,20 +1,18 @@
import React, { useState, useEffect, useContext } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert, Image } from 'react-native';
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert } from 'react-native';
import { Camera, CameraView, scanFromURLAsync } from 'expo-camera';
import { QRCodeContext } from '../types';
import axios from 'axios'; // For URL calls
import { Ionicons } from '@expo/vector-icons'; // For icons
import { useNavigation } from '@react-navigation/native';
import * as ImagePicker from 'expo-image-picker';
import ScannedDataBox from '../components/ScannedDataBox';
import { useDispatch } from 'react-redux';
import { addQRCode } from '../actions/qrCodeActions';
// Main Function
const QRScannerScreen: React.FC = () => {
const navigation = useNavigation(); // call Navigation bar
const [showSplash, setShowSplash] = useState<boolean>(true); // call splash screen
const qrCodeContext = useContext(QRCodeContext); // From ./types.ts
const { qrCodes, setQrCodes } = qrCodeContext || { qrCodes: [], setQrCodes: () => {} };
const dispatch = useDispatch();
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanned, setScanned] = useState<boolean>(false);
@@ -22,35 +20,31 @@ const QRScannerScreen: React.FC = () => {
const [dataType, setDataType] = useState<string>(''); // State for data type
const [enableTorch, setEnableTorch] = useState<boolean>(false); // State for torch
// Request Camera Permission and initialize the app
useEffect(() => {
const initializeApp = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
setShowSplash(false);
console.log("Camera permissions initialized");
};
initializeApp();
}, []);
// Clear Scan Data
const clearScanDataInternal = () => {
setScannedData('');
setScanned(false);
setDataType('');
console.log("Scan data cleared");
};
// Handle QR Code Payload
const handlePayload = async (payload: string) => {
setScanned(true);
console.log("Scanning Completed. Payload is:", payload);
console.log("Scanning Competed payload is :", payload);
const type = await sendToAPIServer(payload);
const qrCode = {
data: payload,
type,
bookmarked: false,
scanResult: {
secureConnection: true, // Placeholder, replace with actual logic
virusTotalCheck: true, // Placeholder, replace with actual logic
@@ -59,14 +53,12 @@ const QRScannerScreen: React.FC = () => {
};
setScannedData(payload);
console.log("Payload received:", payload);
console.log("Type received from server:", type);
console.log("handlePayload -> payload", payload);
console.log("handlePayload -> type", type);
setDataType(type);
setQrCodes([...qrCodes, qrCode]);
console.log("QR code data added to history");
dispatch(addQRCode(qrCode));
};
// Send QR Code Data to Backend Server
const sendToAPIServer = async (payload: string): Promise<string> => {
console.log('Sending QR code data to backend:', payload);
@@ -86,23 +78,17 @@ const QRScannerScreen: React.FC = () => {
}
};
// Toggle Torch (Flashlight)
const toggleTorch = () => {
setEnableTorch((prev) => !prev);
console.log("Torch toggled:", enableTorch ? "off" : "on");
};
// Handle Test Scan
const handleTestScan = () => {
handlePayload('TEST123');
console.log("Test scan executed");
};
// Read QR Code from Image
const readQRFromImage = async () => {
clearScanDataInternal();
console.log("Reading QR code from image");
console.log("readingQRFromImage");
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false, // Don't ask user to crop images
@@ -115,11 +101,10 @@ const QRScannerScreen: React.FC = () => {
if (scannedResult && scannedResult[0] && scannedResult[0].data) {
handlePayload(scannedResult[0].data);
// Not sure why scannedResult.data is undefined but access as array work, KIV
console.log('QR code data from image:', scannedResult[0].data);
console.log('readingQRFromImage -> scannedResult[0].data:', scannedResult[0].data);
} else {
setScannedData("No QR Code Found");
setTimeout(() => setScannedData(""), 4000);
console.log("No QR code found in the selected image");
}
} catch (error) {
console.error('Error scanning QR code from image:', error);
@@ -128,11 +113,9 @@ const QRScannerScreen: React.FC = () => {
}
};
// Clear scan data when screen is focused
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
clearScanDataInternal();
console.log("Screen focused, scan data cleared");
});
return unsubscribe;
}, [navigation]);