diff --git a/App.tsx b/App.tsx index 0093817..b4d2f79 100644 --- a/App.tsx +++ b/App.tsx @@ -1,11 +1,13 @@ import React, { useState } from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { Provider } from 'react-redux'; import QRScannerScreen from './screens/QRScannerScreen'; import HistoryScreen from './screens/HistoryScreen'; import SettingsScreen from './screens/SettingsScreen'; import { QRCodeContext } from './types'; import CustomTabBar from './components/CustomTabBar'; +import store from './store'; import { withAuthenticator } from '@aws-amplify/ui-react-native'; import { Amplify } from 'aws-amplify'; @@ -19,7 +21,6 @@ Amplify.configure(config); const Tab = createBottomTabNavigator(); const App: React.FC = () => { - const [qrCodes, setQrCodes] = useState<{ data: string, bookmarked: boolean, scanResult: { secureConnection: boolean, virusTotalCheck: boolean, redirects: number } }[]>([]); const [scannedData, setScannedData] = useState(''); const clearScanData = () => { @@ -27,22 +28,22 @@ const App: React.FC = () => { }; return ( - - - } - > - - - {(props) => } - - - - - + + + + } + > + + + {(props) => } + + + + + + ); }; diff --git a/actions/qrCodeActions.ts b/actions/qrCodeActions.ts new file mode 100644 index 0000000..ef6a525 --- /dev/null +++ b/actions/qrCodeActions.ts @@ -0,0 +1,6 @@ +import { createAction } from '@reduxjs/toolkit'; +import { QRCode } from '../types'; + +export const addQRCode = createAction('qrCodes/addQRCode'); +export const toggleBookmark = createAction('qrCodes/toggleBookmark'); +export const deleteQRCode = createAction('qrCodes/deleteQRCode'); diff --git a/api/qrCodeAPI.tsx b/api/qrCodeAPI.tsx new file mode 100644 index 0000000..45a50bb --- /dev/null +++ b/api/qrCodeAPI.tsx @@ -0,0 +1,31 @@ +import axios from 'axios'; + +const API_BASE_URL = 'http://192.168.10.247:8080/v1/api/qrcodetypes'; + +export const detectQRCodeType = async (data: string) => { + console.log('API Call - Detect QR Code Type:', data); + const response = await axios.post(`${API_BASE_URL}/detect`, { data }); + console.log('API Response - QR Code Type:', response.data); + return response.data; +}; + +export const verifyURL = async (data: string) => { + console.log('API Call - Verify URL:', data); + const response = await axios.post(`${API_BASE_URL}/verifyURL`, { data }); + console.log('API Response - Verify URL:', response.data); + return response.data; +}; + +export const virusTotalCheck = async (data: string) => { + console.log('API Call - Virus Total Check:', data); + const response = await axios.post(`${API_BASE_URL}/virusTotalCheck`, { data }); + console.log('API Response - Virus Total Check:', response.data); + return response.data; +}; + +export const checkRedirects = async (data: string) => { + console.log('API Call - Check Redirects:', data); + const response = await axios.post(`${API_BASE_URL}/checkRedirects`, { data }); + console.log('API Response - Check Redirects:', response.data); + return response.data; +}; diff --git a/components/ScannedDataBox.tsx b/components/ScannedDataBox.tsx index 305a1ff..afcd238 100644 --- a/components/ScannedDataBox.tsx +++ b/components/ScannedDataBox.tsx @@ -2,43 +2,33 @@ import React, { useEffect, useState } from 'react'; import { View, Text, StyleSheet, Image, TouchableOpacity, Modal } from 'react-native'; import QRCode from 'react-native-qrcode-svg'; import { Ionicons } from '@expo/vector-icons'; +import * as Sharing from 'expo-sharing'; +import { WebView } from 'react-native-webview'; // Define Props for ScannedDataBox component interface ScannedDataBoxProps { data: string; dataType: string; clearScanData: () => void; + scanResult: { + secureConnection: boolean; + virusTotalCheck: boolean; + redirects: number; + }; } -// Define ScanResult interface -interface ScanResult { - secureConnection: boolean; - virusTotalCheck: boolean; - redirects: number; -} - -const ScannedDataBox: React.FC = ({ data, dataType, clearScanData }) => { - const [scanResult, setScanResult] = useState(null); +const ScannedDataBox: React.FC = ({ data, dataType, clearScanData, scanResult }) => { const [isModalVisible, setIsModalVisible] = useState(false); + const [isWebViewVisible, setIsWebViewVisible] = useState(false); + console.log("ScannedDataBox -> Data", data); + console.log("DataType", dataType); - console.log("ScannedDataBox -> Data:", data); - console.log("DataType:", dataType); - - // Set scan result based on data useEffect(() => { - setScanResult({ - secureConnection: data.includes('https'), // Example logic - virusTotalCheck: !data.includes('danger'), // Example logic - redirects: data.includes('redirect') ? 1 : 0, // Example logic - }); console.log("Scan result set:", scanResult); }, [data]); // Determine the result text based on scan result const getResultText = () => { - if (!scanResult) { - return 'UNKNOWN'; - } if (!scanResult.secureConnection && !scanResult.virusTotalCheck) { return 'DANGEROUS'; } else if (scanResult.redirects > 0) { @@ -62,6 +52,18 @@ const ScannedDataBox: React.FC = ({ data, dataType, clearSc } }; + const shareQRCodeData = async () => { + try { + await Sharing.shareAsync(data); + } catch (error) { + console.error('Error sharing QR code data:', error); + } + }; + + const openWebView = () => { + setIsWebViewVisible(true); + }; + return ( {/* Close button */} @@ -90,17 +92,17 @@ const ScannedDataBox: React.FC = ({ data, dataType, clearSc {/* Display scan checks */} Checks - Secure Connection: {scanResult?.secureConnection ? '✔️' : '✘'} - Virus Total Check: {scanResult?.virusTotalCheck ? '✔️' : '✘'} - Redirects: {scanResult ? scanResult.redirects : 'N/A'} + Secure Connection: {scanResult.secureConnection ? '✔️' : '✘'} + Virus Total Check: {scanResult.virusTotalCheck ? '✔️' : '✘'} + Redirects: {scanResult.redirects} {/* Action buttons */} - + Share - + Open @@ -139,6 +141,28 @@ const ScannedDataBox: React.FC = ({ data, dataType, clearSc + setIsWebViewVisible(false)} + > + + + true} + /> + setIsWebViewVisible(false)}> + Close + + + + ); }; @@ -279,6 +303,13 @@ const styles = StyleSheet.create({ fontSize: 12, color: '#fff', }, + webViewContainer: { + width: '100%', + height: '80%', + backgroundColor: 'white', + borderRadius: 7.5, + overflow: 'hidden' + }, }); export default ScannedDataBox; diff --git a/components/SecureWebView.tsx b/components/SecureWebView.tsx new file mode 100644 index 0000000..c088be8 --- /dev/null +++ b/components/SecureWebView.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { WebView } from 'react-native-webview'; + +// Define the SecureWebView component +const SecureWebView = ({ url }) => { + return ( + { + // Implement additional URL filtering logic here if needed + return true; // Return true to allow the URL to be loaded + }} + /> + ); +}; + +export default SecureWebView; diff --git a/package-lock.json b/package-lock.json index 2081c51..3c7e8f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@react-native-community/netinfo": "11.3.1", "@react-navigation/bottom-tabs": "^6.5.20", "@react-navigation/native": "^6.1.17", + "@reduxjs/toolkit": "^2.2.6", "aws-amplify": "^6.3.8", "axios": "^1.7.2", "expo": "~51.0.17", @@ -23,6 +24,7 @@ "expo-dev-client": "~4.0.19", "expo-image-manipulator": "^12.0.5", "expo-image-picker": "~15.0.7", + "expo-sharing": "~12.0.1", "expo-status-bar": "~1.12.1", "react": "18.2.0", "react-native": "^0.74.3", @@ -30,7 +32,10 @@ "react-native-qrcode-svg": "^6.3.1", "react-native-safe-area-context": "4.10.1", "react-native-screens": "3.31.1", - "react-native-svg": "15.2.0" + "react-native-svg": "15.2.0", + "react-native-webview": "^13.10.4", + "react-redux": "^9.1.2", + "redux": "^5.0.1" }, "devDependencies": { "@babel/core": "^7.20.0", @@ -7351,6 +7356,29 @@ "nanoid": "^3.1.23" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.6.tgz", + "integrity": "sha512-kH0r495c5z1t0g796eDQAkYbEQ3a1OLYN9o8jQQVZyKyw367pfRGS+qZLkHYvFHiUUdafpoSlQ2QYObIApjPWA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rnx-kit/chromium-edge-launcher": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@rnx-kit/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz", @@ -8747,6 +8775,11 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", @@ -11438,6 +11471,14 @@ "invariant": "^2.2.4" } }, + "node_modules/expo-sharing": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-12.0.1.tgz", + "integrity": "sha512-wBT+WeXwapj/9NWuLJO01vi9bdlchYu/Q/xD8slL/Ls4vVYku8CPqzkTtDFcjLrjtlJqyeHsdQXwKLvORmBIew==", + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-status-bar": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.12.1.tgz", @@ -12257,10 +12298,9 @@ } }, "node_modules/immer": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz", - "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==", - "license": "MIT", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -16259,6 +16299,27 @@ "react-native": "*" } }, + "node_modules/react-native-webview": { + "version": "13.10.4", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.10.4.tgz", + "integrity": "sha512-kRn70M7vyBS3IDaX2KqyF66ovUkrBS6LiHOgrEmRdZFO0i3hYY0wldEv1fJuKvgQIPMfo7GtGAjozFrk2vQdBw==", + "dependencies": { + "escape-string-regexp": "2.0.0", + "invariant": "2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-webview/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/react-native-svg-transformer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/react-native-svg-transformer/-/react-native-svg-transformer-1.4.0.tgz", @@ -16373,6 +16434,28 @@ "async-limiter": "~1.0.0" } }, + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -16436,6 +16519,19 @@ "node": ">=0.10.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -16569,6 +16665,11 @@ "path-parse": "^1.0.5" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -18428,7 +18529,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } diff --git a/package.json b/package.json index 1819e43..4dbde49 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@react-navigation/bottom-tabs": "^6.5.20", "@react-navigation/native": "^6.1.17", "aws-amplify": "^6.3.8", + "@reduxjs/toolkit": "^2.2.6", "axios": "^1.7.2", "expo": "~51.0.17", "expo-camera": "~15.0.13", @@ -28,10 +29,14 @@ "react-native": "^0.74.3", "react-native-get-random-values": "^1.11.0", "react-native-qrcode-svg": "^6.3.1", - "react-native-safe-area-context": "4.10.1", + "react-native-safe-area-context": "^4.10.4", "react-native-screens": "3.31.1", "react-native-svg": "15.2.0", - "expo-dev-client": "~4.0.19" + "expo-dev-client": "~4.0.19", + "react-native-webview": "^13.10.4", + "react-redux": "^9.1.2", + "redux": "^5.0.1", + "expo-sharing": "~12.0.1" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/reducers/qrCodesReducer.ts b/reducers/qrCodesReducer.ts new file mode 100644 index 0000000..6a4b458 --- /dev/null +++ b/reducers/qrCodesReducer.ts @@ -0,0 +1,30 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { QRCode } from '../types'; + +const qrCodesSlice = createSlice({ + name: 'qrCodes', + initialState: [] as QRCode[], + reducers: { + addQRCode(state, action: PayloadAction) { + state.push(action.payload); + console.log('Added QR code to state:', action.payload); + }, + toggleBookmark(state, action: PayloadAction) { + const index = state.length - 1 - action.payload; + if (state[index]) { + state[index].bookmarked = !state[index].bookmarked; + console.log('Toggled bookmark for QR code at index:', index); + } + }, + deleteQRCode(state, action: PayloadAction) { + const index = state.length - 1 - (action.payload as number); + if (state[index]) { + console.log('Deleting QR code at index:', index); + state.splice(index, 1); + } + }, + }, +}); + +export const { addQRCode, toggleBookmark, deleteQRCode } = qrCodesSlice.actions; +export default qrCodesSlice.reducer; diff --git a/screens/HistoryScreen.tsx b/screens/HistoryScreen.tsx index 804a8bb..f840103 100644 --- a/screens/HistoryScreen.tsx +++ b/screens/HistoryScreen.tsx @@ -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(null); const [selectedScanResult, setSelectedScanResult] = useState(null); - const [selectedType, setSelectedType] = useState(null); // Add state for selectedType + const [selectedType, setSelectedType] = useState(null); const [showBookmarks, setShowBookmarks] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false); const [indexToDelete, setIndexToDelete] = useState(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 ( {/* Header for toggling between History and Bookmarks */} - { - setShowBookmarks(false); - clearSelectedData(); - }}> + { setShowBookmarks(false); clearSelectedData(); }}> History - { - setShowBookmarks(true); - clearSelectedData(); - }}> + { setShowBookmarks(true); clearSelectedData(); }}> Bookmarks @@ -121,7 +91,7 @@ const HistoryScreen: React.FC = () => { })} - toggleBookmark(index)}> + dispatch(toggleBookmark(index))}> confirmDelete(index)}> @@ -146,7 +116,7 @@ const HistoryScreen: React.FC = () => { Are you sure? If bookmarked, this will be removed from both History and Bookmarks. - + dispatch(deleteQRCode(indexToDelete))}> Yes, Delete setIsModalVisible(false)}> diff --git a/screens/QRScannerScreen.tsx b/screens/QRScannerScreen.tsx index 09b1c6c..f30ff06 100644 --- a/screens/QRScannerScreen.tsx +++ b/screens/QRScannerScreen.tsx @@ -7,12 +7,16 @@ 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'; // Assuming you have actions defined for Redux +import { detectQRCodeType, verifyURL, checkRedirects } from '../api/qrCodeAPI'; // Import utility functions // Main Function -const QRScannerScreen: React.FC = () => { +const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanData }) => { const navigation = useNavigation(); // call Navigation bar - const [showSplash, setShowSplash] = useState(true); // call splash screen + const dispatch = useDispatch(); // Use dispatch for Redux actions + const [showSplash, setShowSplash] = useState(true); // call splash screen const qrCodeContext = useContext(QRCodeContext); // From ./types.ts const { qrCodes, setQrCodes } = qrCodeContext || { qrCodes: [], setQrCodes: () => {} }; @@ -22,6 +26,11 @@ const QRScannerScreen: React.FC = () => { const [dataType, setDataType] = useState(''); // State for data type const [enableTorch, setEnableTorch] = useState(false); // State for torch + // Add state variables for scan results + const [secureConnection, setSecureConnection] = useState(null); + const [virusTotalCheck, setVirusTotalCheck] = useState(null); + const [redirects, setRedirects] = useState(null); + // Request Camera Permission and initialize the app useEffect(() => { const initializeApp = async () => { @@ -46,23 +55,31 @@ const QRScannerScreen: React.FC = () => { const handlePayload = async (payload: string) => { setScanned(true); console.log("Scanning Completed. Payload is:", payload); - const type = await sendToAPIServer(payload); + + const type = await detectQRCodeType(payload); + const secureConnectionResult = await verifyURL(payload); + const redirectResult = await checkRedirects(payload); + + setSecureConnection(secureConnectionResult.isSecure); + setVirusTotalCheck(!secureConnectionResult.isMalicious); // Assuming you have virusTotalCheck logic integrated here + setRedirects(redirectResult.redirects); const qrCode = { data: payload, type, scanResult: { - secureConnection: true, // Placeholder, replace with actual logic - virusTotalCheck: true, // Placeholder, replace with actual logic - redirects: 0 // Placeholder, replace with actual logic - } + secureConnection: secureConnectionResult.isSecure, + virusTotalCheck: !secureConnectionResult.isMalicious, + redirects: redirectResult.redirects + }, + bookmarked: false // by default }; setScannedData(payload); console.log("Payload received:", payload); console.log("Type received from server:", type); setDataType(type); - setQrCodes([...qrCodes, qrCode]); + dispatch(addQRCode(qrCode)); // Dispatch action to save QR code data console.log("QR code data added to history"); }; @@ -181,7 +198,16 @@ const QRScannerScreen: React.FC = () => { {scannedData !== '' && ( - + )} diff --git a/store.ts b/store.ts new file mode 100644 index 0000000..3ae4b7b --- /dev/null +++ b/store.ts @@ -0,0 +1,11 @@ +import { configureStore } from '@reduxjs/toolkit'; +import qrCodesReducer from './reducers/qrCodesReducer'; + +const store = configureStore({ + reducer: { + qrCodes: qrCodesReducer, + }, +}); + +export type RootState = ReturnType; +export default store; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b9567f6..0e6371f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,4 @@ { - "extends": "expo/tsconfig.base", - "compilerOptions": { - "strict": true - } + "compilerOptions": {}, + "extends": "expo/tsconfig.base" } diff --git a/types.ts b/types.ts index e0dc258..5d76e36 100644 --- a/types.ts +++ b/types.ts @@ -1,7 +1,8 @@ -import { createContext } from "react"; +import { createContext } from 'react'; export interface QRCode { data: string; + type: string; bookmarked: boolean; scanResult: { secureConnection: boolean; @@ -10,12 +11,7 @@ export interface QRCode { }; } -interface QRCodeContextProps { +export const QRCodeContext = createContext<{ qrCodes: QRCode[]; - setQrCodes: (codes: QRCode[]) => void; - setCurrentScannedData?: (data: string) => void; - toggleBookmark?: (index: number) => void; - deleteQRCode?: (index: number) => void; -} - -export const QRCodeContext = createContext(null); + setQrCodes: React.Dispatch>; +} | null>(null); \ No newline at end of file