@test-web/react-native-sdk 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,8 @@ A fully dynamic, production-ready React Native SDK for identity verification wit
9
9
  - ✅ **18 Verification Screens** - Complete identity verification flow
10
10
  - ✅ **Document Scanning** - Support for ID cards, passports, driver licenses
11
11
  - ✅ **Selfie Capture** - Live selfie verification with camera integration
12
- - ✅ **MRZ & Barcode Scanning** - Machine-readable zone and barcode support
12
+ - ✅ **MRZ & Barcode Scanning** - Machine-readable zone and barcode support with Dynamsoft & ML Kit
13
+ - ✅ **Advanced Scanning** - Optional Dynamsoft barcode scanner and ML Kit text recognition
13
14
  - ✅ **10 Pre-built Themes** - Customizable UI themes
14
15
  - ✅ **Camera & Location Permissions** - Built-in permission handling
15
16
  - ✅ **TypeScript Support** - Full type definitions included
@@ -55,13 +56,27 @@ npm install react-native-vision-camera react-native-image-resizer react-native-f
55
56
  npm install react-native-device-info react-native-geolocation-service
56
57
  ```
57
58
 
58
- ### Step 4: Install iOS Pods (iOS only)
59
+ ### Step 4: Install Scanning Libraries (Optional but Recommended)
60
+
61
+ For enhanced barcode and MRZ scanning capabilities:
62
+
63
+ ```bash
64
+ # Dynamsoft Capture Vision for barcode scanning
65
+ npm install dynamsoft-capture-vision-react-native
66
+
67
+ # ML Kit for MRZ text recognition
68
+ npm install @react-native-ml-kit/text-recognition
69
+ ```
70
+
71
+ **Note:** Without these libraries, the SDK will use fallback simulation for barcode and MRZ scanning. For production use, we strongly recommend installing these libraries for accurate scanning.
72
+
73
+ ### Step 5: Install iOS Pods (iOS only)
59
74
 
60
75
  ```bash
61
76
  cd ios && pod install && cd ..
62
77
  ```
63
78
 
64
- ### Step 5: Rebuild Your App
79
+ ### Step 6: Rebuild Your App
65
80
 
66
81
  ```bash
67
82
  # For Android
@@ -155,6 +170,95 @@ platform :ios, '11.0'
155
170
 
156
171
  ---
157
172
 
173
+ ### Dynamsoft Barcode Scanner Setup (Optional)
174
+
175
+ If you installed `dynamsoft-capture-vision-react-native`, follow these additional steps:
176
+
177
+ #### Android Configuration
178
+
179
+ 1. Add to `android/app/build.gradle`:
180
+
181
+ ```gradle
182
+ android {
183
+ defaultConfig {
184
+ minSdkVersion 21
185
+ // Add this for Dynamsoft
186
+ ndk {
187
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ 2. Get your Dynamsoft license key from [Dynamsoft Customer Portal](https://www.dynamsoft.com/customer/license/trialLicense)
194
+
195
+ 3. Initialize the license in your app (before using the SDK):
196
+
197
+ ```typescript
198
+ import { DCVBarcodeReader } from 'dynamsoft-capture-vision-react-native';
199
+
200
+ // Initialize Dynamsoft license (do this once at app startup)
201
+ await DCVBarcodeReader.initLicense('YOUR_DYNAMSOFT_LICENSE_KEY');
202
+ ```
203
+
204
+ #### iOS Configuration
205
+
206
+ 1. Add to `ios/Podfile`:
207
+
208
+ ```ruby
209
+ platform :ios, '11.0'
210
+
211
+ target 'YourApp' do
212
+ # ... other pods
213
+
214
+ # Add this for Dynamsoft
215
+ pod 'DynamsoftCaptureVisionRouter', '~> 2.0'
216
+ pod 'DynamsoftBarcodeReader', '~> 10.0'
217
+ end
218
+ ```
219
+
220
+ 2. Run `pod install`:
221
+
222
+ ```bash
223
+ cd ios && pod install && cd ..
224
+ ```
225
+
226
+ **Note:** The SDK will automatically detect if Dynamsoft is available and use it for barcode scanning. If not installed, it will fall back to simulation mode.
227
+
228
+ ---
229
+
230
+ ### ML Kit Text Recognition Setup (Optional)
231
+
232
+ If you installed `@react-native-ml-kit/text-recognition`, follow these additional steps:
233
+
234
+ #### Android Configuration
235
+
236
+ ML Kit will be automatically configured on Android. No additional setup required.
237
+
238
+ #### iOS Configuration
239
+
240
+ 1. Add to `ios/Podfile`:
241
+
242
+ ```ruby
243
+ platform :ios, '11.0'
244
+
245
+ target 'YourApp' do
246
+ # ... other pods
247
+
248
+ # ML Kit is automatically linked
249
+ end
250
+ ```
251
+
252
+ 2. Run `pod install`:
253
+
254
+ ```bash
255
+ cd ios && pod install && cd ..
256
+ ```
257
+
258
+ **Note:** The SDK will automatically detect if ML Kit is available and use it for MRZ text recognition. If not installed, it will fall back to simulation mode.
259
+
260
+ ---
261
+
158
262
  ## 🚀 Usage
159
263
 
160
264
  ### Basic Implementation
@@ -257,6 +361,95 @@ export default function App() {
257
361
 
258
362
  ---
259
363
 
364
+ ## 📸 Scanning Capabilities
365
+
366
+ ### Barcode Scanning
367
+
368
+ The SDK supports barcode scanning with two modes:
369
+
370
+ #### 1. Production Mode (Recommended)
371
+
372
+ Install Dynamsoft Capture Vision for accurate barcode scanning:
373
+
374
+ ```bash
375
+ npm install dynamsoft-capture-vision-react-native
376
+ ```
377
+
378
+ **Supported Barcode Types:**
379
+ - PDF417 (Driver's License, ID Cards)
380
+ - QR Code
381
+ - Code 128
382
+ - Code 39
383
+ - EAN-13
384
+ - UPC-A
385
+ - And more...
386
+
387
+ **Initialize License:**
388
+
389
+ ```typescript
390
+ import { DCVBarcodeReader } from 'dynamsoft-capture-vision-react-native';
391
+
392
+ // At app startup
393
+ await DCVBarcodeReader.initLicense('YOUR_LICENSE_KEY');
394
+ ```
395
+
396
+ Get your free trial license from [Dynamsoft Customer Portal](https://www.dynamsoft.com/customer/license/trialLicense).
397
+
398
+ #### 2. Fallback Mode
399
+
400
+ Without Dynamsoft installed, the SDK will use simulation mode for testing purposes. This is useful for development but not recommended for production.
401
+
402
+ ### MRZ Scanning
403
+
404
+ The SDK supports MRZ (Machine Readable Zone) scanning with two modes:
405
+
406
+ #### 1. Production Mode (Recommended)
407
+
408
+ Install ML Kit Text Recognition for accurate MRZ scanning:
409
+
410
+ ```bash
411
+ npm install @react-native-ml-kit/text-recognition
412
+ ```
413
+
414
+ **Supported MRZ Types:**
415
+ - TD1 (ID Cards)
416
+ - TD2 (Travel Documents)
417
+ - TD3 (Passports)
418
+ - MRVA (Visa Type A)
419
+ - MRVB (Visa Type B)
420
+
421
+ The SDK automatically detects the MRZ type based on document metadata.
422
+
423
+ #### 2. Fallback Mode
424
+
425
+ Without ML Kit installed, the SDK will use simulation mode for testing purposes. This is useful for development but not recommended for production.
426
+
427
+ ### Scanning Flow
428
+
429
+ The SDK automatically determines which scanning methods are required based on document metadata:
430
+
431
+ ```typescript
432
+ // Example metadata from API
433
+ {
434
+ "document_flow": ["F", "B"], // Front and Back required
435
+ "barcode": "PDF417 B" // Barcode on back side
436
+ }
437
+ ```
438
+
439
+ **Flow:** Selfie → Front → Back → Barcode Scan → Complete
440
+
441
+ ```typescript
442
+ // Example metadata for passport
443
+ {
444
+ "document_flow": ["F"], // Front only
445
+ "barcode": "TD3" // MRZ scanning required
446
+ }
447
+ ```
448
+
449
+ **Flow:** Selfie → Front → MRZ Scan → Complete
450
+
451
+ ---
452
+
260
453
  ## 🔄 Dynamic Flow
261
454
 
262
455
  The SDK automatically determines the verification flow based on document metadata:
@@ -449,6 +642,86 @@ cd android && ./gradlew clean && cd ..
449
642
  - Ensure react-native-fs is installed
450
643
  - Check storage permissions
451
644
 
645
+ #### 7. Barcode Scanning Not Working
646
+
647
+ **Problem:** Barcode scanning shows simulation or doesn't detect barcodes.
648
+
649
+ **Solution:**
650
+ - Install `dynamsoft-capture-vision-react-native` for real barcode scanning
651
+ - Initialize Dynamsoft license key before using the SDK
652
+ - Ensure camera permissions are granted
653
+ - Test with a real PDF417 barcode (driver's license back)
654
+ - Check console logs for Dynamsoft initialization errors
655
+
656
+ #### 8. MRZ Scanning Not Working
657
+
658
+ **Problem:** MRZ scanning shows simulation or doesn't detect MRZ codes.
659
+
660
+ **Solution:**
661
+ - Install `@react-native-ml-kit/text-recognition` for real MRZ scanning
662
+ - Ensure camera permissions are granted
663
+ - Test with a real passport or ID card with MRZ
664
+ - Ensure good lighting and steady camera position
665
+ - Check console logs for ML Kit errors
666
+
667
+ ---
668
+
669
+ ## 🧪 Testing Scanning Features
670
+
671
+ ### Testing Barcode Scanning
672
+
673
+ #### With Dynamsoft (Production)
674
+
675
+ 1. Install Dynamsoft:
676
+ ```bash
677
+ npm install dynamsoft-capture-vision-react-native
678
+ ```
679
+
680
+ 2. Get a trial license from [Dynamsoft](https://www.dynamsoft.com/customer/license/trialLicense)
681
+
682
+ 3. Initialize in your app:
683
+ ```typescript
684
+ import { DCVBarcodeReader } from 'dynamsoft-capture-vision-react-native';
685
+
686
+ await DCVBarcodeReader.initLicense('YOUR_LICENSE_KEY');
687
+ ```
688
+
689
+ 4. Test with a real driver's license or ID card with PDF417 barcode
690
+
691
+ #### Without Dynamsoft (Development)
692
+
693
+ The SDK will automatically use simulation mode. After 3 seconds, it will generate a simulated barcode result.
694
+
695
+ ### Testing MRZ Scanning
696
+
697
+ #### With ML Kit (Production)
698
+
699
+ 1. Install ML Kit:
700
+ ```bash
701
+ npm install @react-native-ml-kit/text-recognition
702
+ ```
703
+
704
+ 2. Test with a real passport or ID card with MRZ zone
705
+
706
+ 3. Ensure good lighting and hold the document steady
707
+
708
+ #### Without ML Kit (Development)
709
+
710
+ The SDK will automatically use simulation mode. After 3 seconds, it will generate a simulated MRZ result.
711
+
712
+ ### Checking Scanner Status
713
+
714
+ The SDK logs which scanning mode is being used:
715
+
716
+ ```
717
+ // Console output examples:
718
+ "Dynamsoft Barcode Scanner initialized" // Production mode
719
+ "Dynamsoft not available, using fallback" // Simulation mode
720
+
721
+ "ML Kit text recognition initialized" // Production mode
722
+ "ML Kit not available, using fallback" // Simulation mode
723
+ ```
724
+
452
725
  ---
453
726
 
454
727
  ## 🎯 Advanced Usage
@@ -557,6 +830,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
557
830
  - ✅ **Flow Manager** - Smart navigation based on document type
558
831
  - ✅ **Better Error Handling** - Comprehensive error management
559
832
  - ✅ **Loading States** - User feedback throughout the flow
833
+ - ✅ **Dynamsoft Integration** - Professional barcode scanning (optional)
834
+ - ✅ **ML Kit Integration** - Accurate MRZ text recognition (optional)
835
+
836
+ ### Scanning Features
837
+ - **Dynamsoft Capture Vision** - Industry-leading barcode scanning for PDF417, QR codes, and more
838
+ - **ML Kit Text Recognition** - Google's ML Kit for accurate MRZ detection on passports and ID cards
839
+ - **Fallback Mode** - Simulation mode for development without external libraries
840
+ - **Auto-Detection** - SDK automatically uses available scanning libraries
560
841
 
561
842
  ### Breaking Changes from v1.x
562
843
  - `clientID`, `clientSecret`, `environment`, and `requestData` are now required
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@test-web/react-native-sdk",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Dynamic React Native SDK for document verification with API-driven configuration",
5
5
  "main": "src/index.tsx",
6
6
  "types": "src/index.tsx",
@@ -25,7 +25,8 @@
25
25
  "barcode",
26
26
  "mrz",
27
27
  "dynamic",
28
- "api-driven"
28
+ "api-driven",
29
+ "dynamsoft"
29
30
  ],
30
31
  "repository": "https://github.com/yourcompany/react-native-sdk",
31
32
  "author": "Your Company <hello@yourcompany.com>",
@@ -41,7 +42,9 @@
41
42
  "react-native-image-resizer": ">=1.0.0",
42
43
  "react-native-fs": ">=2.0.0",
43
44
  "react-native-device-info": ">=10.0.0",
44
- "react-native-geolocation-service": ">=5.0.0"
45
+ "react-native-geolocation-service": ">=5.0.0",
46
+ "dynamsoft-capture-vision-react-native": ">=3.0.0",
47
+ "@react-native-ml-kit/text-recognition": ">=1.1.0"
45
48
  },
46
49
  "peerDependenciesMeta": {
47
50
  "react-native-image-resizer": {
@@ -55,6 +58,12 @@
55
58
  },
56
59
  "react-native-geolocation-service": {
57
60
  "optional": true
61
+ },
62
+ "dynamsoft-capture-vision-react-native": {
63
+ "optional": true
64
+ },
65
+ "@react-native-ml-kit/text-recognition": {
66
+ "optional": true
58
67
  }
59
68
  },
60
69
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- export const SANDBOX_BASE_URL = 'https://sandbox-api.idmerit.com';
1
+ export const SANDBOX_BASE_URL = 'https://sandbox.idmvalidate.com';
2
2
  export const PRODUCTION_BASE_URL = 'https://api.idmerit.com';
3
3
 
4
4
  export const getBaseURL = (environment: 'sandbox' | 'production'): string => {
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState, useEffect, useRef } from 'react';
2
2
  import { View, Text, StyleSheet, Alert } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
4
  import { useTheme } from '../context/ThemeContext';
@@ -16,10 +16,46 @@ export default function BarcodeCapture() {
16
16
  const navigation = useNavigation();
17
17
  const [loading, setLoading] = useState(false);
18
18
  const [scannedData, setScannedData] = useState<string | null>(null);
19
+ const [isScanning, setIsScanning] = useState(true);
20
+ const scannerRef = useRef<any>(null);
19
21
 
20
- // Handle barcode scan
21
- const handleBarcodeScan = async (barcodeText: string) => {
22
- if (loading || !barcodeText) return;
22
+ // Initialize Dynamsoft Barcode Scanner
23
+ useEffect(() => {
24
+ let isMounted = true;
25
+
26
+ const initializeScanner = async () => {
27
+ try {
28
+ // Try to import Dynamsoft Capture Vision
29
+ const { DCVCameraView, DBRRuntimeSettings } = require('dynamsoft-capture-vision-react-native');
30
+
31
+ // License initialization would go here
32
+ // await DCVBarcodeReader.initLicense('YOUR_LICENSE_KEY');
33
+
34
+ console.log('Dynamsoft Barcode Scanner initialized');
35
+ } catch (error) {
36
+ console.warn('Dynamsoft not available, using fallback:', error);
37
+ // Fallback to simulation if Dynamsoft not installed
38
+ if (isMounted) {
39
+ simulateBarcodeScan();
40
+ }
41
+ }
42
+ };
43
+
44
+ initializeScanner();
45
+
46
+ return () => {
47
+ isMounted = false;
48
+ setIsScanning(false);
49
+ };
50
+ // eslint-disable-next-line react-hooks/exhaustive-deps
51
+ }, []);
52
+
53
+ // Handle barcode scan result
54
+ const handleBarcodeScanned = async (barcodeText: string) => {
55
+ if (loading || !barcodeText || !isScanning) return;
56
+
57
+ setIsScanning(false);
58
+ setScannedData(barcodeText);
23
59
 
24
60
  try {
25
61
  setLoading(true);
@@ -42,61 +78,103 @@ export default function BarcodeCapture() {
42
78
  // Navigate to ThankYou
43
79
  navigation.navigate('ThankYou' as never);
44
80
  } else {
45
- Alert.alert('Error', result.errorMessage || 'Failed to process barcode');
46
- setLoading(false);
81
+ Alert.alert('Error', result.errorMessage || 'Failed to process barcode', [
82
+ {
83
+ text: 'Retry',
84
+ onPress: () => {
85
+ setIsScanning(true);
86
+ setScannedData(null);
87
+ setLoading(false);
88
+ },
89
+ },
90
+ ]);
47
91
  }
48
92
  } catch (error: any) {
49
93
  console.error('Error processing barcode:', error);
50
- Alert.alert('Error', 'Failed to process barcode');
51
- setLoading(false);
94
+ Alert.alert('Error', 'Failed to process barcode', [
95
+ {
96
+ text: 'Retry',
97
+ onPress: () => {
98
+ setIsScanning(true);
99
+ setScannedData(null);
100
+ setLoading(false);
101
+ },
102
+ },
103
+ ]);
52
104
  }
53
105
  };
54
106
 
55
- // Simulate barcode scanning (replace with actual barcode scanner library)
56
- useEffect(() => {
57
- // TODO: Integrate actual barcode scanning library (e.g., react-native-vision-camera with barcode plugin)
58
- // For now, simulate scanning after 3 seconds
107
+ // Fallback simulation if Dynamsoft not available
108
+ const simulateBarcodeScan = () => {
59
109
  const timer = setTimeout(() => {
60
- const simulatedBarcode = 'SIMULATED_BARCODE_DATA_' + Date.now();
61
- setScannedData(simulatedBarcode);
62
- handleBarcodeScan(simulatedBarcode);
110
+ if (isScanning) {
111
+ const simulatedBarcode = 'SIMULATED_PDF417_' + Date.now();
112
+ handleBarcodeScanned(simulatedBarcode);
113
+ }
63
114
  }, 3000);
64
115
 
65
116
  return () => clearTimeout(timer);
66
- // eslint-disable-next-line react-hooks/exhaustive-deps
67
- }, []);
117
+ };
68
118
 
69
- return (
70
- <View style={styles.container}>
71
- <Text style={styles.topLabel}>
72
- Fill the box with the barcode{'\n'}until it turns green
73
- </Text>
119
+ // Render Dynamsoft Camera View
120
+ const renderBarcodeScanner = () => {
121
+ try {
122
+ const { DCVCameraView } = require('dynamsoft-capture-vision-react-native');
74
123
 
75
- {/* Camera placeholder - Replace with actual camera view */}
76
- <View style={[StyleSheet.absoluteFill, { backgroundColor: '#000' }]}>
77
- <Text
78
- style={{
79
- color: '#fff',
80
- textAlign: 'center',
81
- marginTop: 200,
82
- fontSize: 16,
124
+ return (
125
+ <DCVCameraView
126
+ ref={scannerRef}
127
+ style={StyleSheet.absoluteFill}
128
+ scanRegionVisible={true}
129
+ overlayVisible={true}
130
+ onBarcodeScanned={(results: any) => {
131
+ if (results && results.length > 0 && isScanning) {
132
+ const barcodeText = results[0].barcodeText || results[0].text;
133
+ handleBarcodeScanned(barcodeText);
134
+ }
83
135
  }}
84
- >
85
- {loading ? 'Processing...' : 'Scanning for barcode...'}
86
- </Text>
87
- {scannedData && (
136
+ />
137
+ );
138
+ } catch (error) {
139
+ console.warn('Dynamsoft camera view not available:', error);
140
+
141
+ // Fallback UI
142
+ return (
143
+ <View style={[StyleSheet.absoluteFill, { backgroundColor: '#000' }]}>
88
144
  <Text
89
145
  style={{
90
- color: '#0f0',
146
+ color: '#fff',
91
147
  textAlign: 'center',
92
- marginTop: 20,
93
- fontSize: 12,
148
+ marginTop: 200,
149
+ fontSize: 16,
94
150
  }}
95
151
  >
96
- Detected: {scannedData.substring(0, 30)}...
152
+ {loading ? 'Processing...' : 'Scanning for barcode...'}
97
153
  </Text>
98
- )}
99
- </View>
154
+ {scannedData && (
155
+ <Text
156
+ style={{
157
+ color: '#0f0',
158
+ textAlign: 'center',
159
+ marginTop: 20,
160
+ fontSize: 12,
161
+ }}
162
+ >
163
+ Detected: {scannedData.substring(0, 30)}...
164
+ </Text>
165
+ )}
166
+ </View>
167
+ );
168
+ }
169
+ };
170
+
171
+ return (
172
+ <View style={styles.container}>
173
+ <Text style={styles.topLabel}>
174
+ Fill the box with the barcode{'\n'}until it turns green
175
+ </Text>
176
+
177
+ {renderBarcodeScanner()}
100
178
 
101
179
  {/* Barcode overlay box */}
102
180
  <View
@@ -112,7 +190,7 @@ export default function BarcodeCapture() {
112
190
  }}
113
191
  />
114
192
 
115
- {loading && <Loader />}
193
+ {loading && <Loader message="Processing barcode..." />}
116
194
  </View>
117
195
  );
118
196
  }
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState, useEffect, useRef } from 'react';
2
2
  import { View, Text, StyleSheet, Alert } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
4
  import { useTheme } from '../context/ThemeContext';
@@ -17,6 +17,11 @@ export default function MrzCapture() {
17
17
  const navigation = useNavigation();
18
18
  const [loading, setLoading] = useState(false);
19
19
  const [scannedData, setScannedData] = useState<string | null>(null);
20
+ const [isScanning, setIsScanning] = useState(true);
21
+ const [hasPermission, setHasPermission] = useState(false);
22
+ const [device, setDevice] = useState<any>(null);
23
+ const cameraRef = useRef<any>(null);
24
+ const frameProcessorRef = useRef<any>(null);
20
25
 
21
26
  // Get MRZ engine type from metadata
22
27
  const getMRZEngine = () => {
@@ -27,9 +32,84 @@ export default function MrzCapture() {
27
32
  return flowManager.getMRZEngine();
28
33
  };
29
34
 
30
- // Handle MRZ scan
31
- const handleMRZScan = async (mrzCode: string) => {
32
- if (loading || !mrzCode) return;
35
+ // Initialize camera with ML Kit
36
+ useEffect(() => {
37
+ let isMounted = true;
38
+
39
+ const initializeCamera = async () => {
40
+ try {
41
+ const { Camera, useCameraDevice, useCameraPermission } = require('react-native-vision-camera');
42
+
43
+ const { hasPermission: hasPerm, requestPermission } = useCameraPermission();
44
+
45
+ if (!hasPerm) {
46
+ const granted = await requestPermission();
47
+ if (!granted) {
48
+ navigation.navigate('CameraPermission' as never);
49
+ return;
50
+ }
51
+ }
52
+
53
+ if (isMounted) {
54
+ setHasPermission(true);
55
+
56
+ const backDevice = useCameraDevice('back');
57
+ if (!backDevice) {
58
+ navigation.navigate('NoCameraFound' as never);
59
+ return;
60
+ }
61
+
62
+ setDevice(backDevice);
63
+ }
64
+ } catch (error) {
65
+ console.warn('Camera initialization failed:', error);
66
+ if (isMounted) {
67
+ simulateMRZScan();
68
+ }
69
+ }
70
+ };
71
+
72
+ initializeCamera();
73
+
74
+ return () => {
75
+ isMounted = false;
76
+ setIsScanning(false);
77
+ };
78
+ // eslint-disable-next-line react-hooks/exhaustive-deps
79
+ }, []);
80
+
81
+ // Process MRZ with ML Kit Text Recognition
82
+ const processMRZWithMLKit = async (frame: any) => {
83
+ if (!isScanning) return;
84
+
85
+ try {
86
+ const { recognizeText } = require('@react-native-ml-kit/text-recognition');
87
+
88
+ const result = await recognizeText(frame);
89
+
90
+ if (result && result.text) {
91
+ // Check if text contains MRZ pattern
92
+ const lines = result.text.split('\n');
93
+ const mrzLines = lines.filter((line: string) =>
94
+ line.length >= 30 && /^[A-Z0-9<]+$/.test(line)
95
+ );
96
+
97
+ if (mrzLines.length >= 2) {
98
+ const mrzCode = mrzLines.join('\n');
99
+ handleMRZScanned(mrzCode);
100
+ }
101
+ }
102
+ } catch (error) {
103
+ console.warn('ML Kit text recognition error:', error);
104
+ }
105
+ };
106
+
107
+ // Handle MRZ scan result
108
+ const handleMRZScanned = async (mrzCode: string) => {
109
+ if (loading || !mrzCode || !isScanning) return;
110
+
111
+ setIsScanning(false);
112
+ setScannedData(mrzCode);
33
113
 
34
114
  try {
35
115
  setLoading(true);
@@ -53,36 +133,72 @@ export default function MrzCapture() {
53
133
  // Navigate to ThankYou
54
134
  navigation.navigate('ThankYou' as never);
55
135
  } else {
56
- Alert.alert('Error', result.errorMessage || 'Failed to process MRZ');
57
- setLoading(false);
136
+ Alert.alert('Error', result.errorMessage || 'Failed to process MRZ', [
137
+ {
138
+ text: 'Retry',
139
+ onPress: () => {
140
+ setIsScanning(true);
141
+ setScannedData(null);
142
+ setLoading(false);
143
+ },
144
+ },
145
+ ]);
58
146
  }
59
147
  } catch (error: any) {
60
148
  console.error('Error processing MRZ:', error);
61
- Alert.alert('Error', 'Failed to process MRZ');
62
- setLoading(false);
149
+ Alert.alert('Error', 'Failed to process MRZ', [
150
+ {
151
+ text: 'Retry',
152
+ onPress: () => {
153
+ setIsScanning(true);
154
+ setScannedData(null);
155
+ setLoading(false);
156
+ },
157
+ },
158
+ ]);
63
159
  }
64
160
  };
65
161
 
66
- // Simulate MRZ scanning (replace with actual MRZ scanner library)
67
- useEffect(() => {
68
- // TODO: Integrate actual MRZ scanning library (e.g., @react-native-ml-kit/text-recognition)
69
- // For now, simulate scanning after 3 seconds
162
+ // Fallback simulation if ML Kit not available
163
+ const simulateMRZScan = () => {
70
164
  const timer = setTimeout(() => {
71
- const simulatedMRZ =
72
- 'P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<<\nL898902C36UTO7408122F1204159ZE184226B<<<<<10';
73
- setScannedData(simulatedMRZ);
74
- handleMRZScan(simulatedMRZ);
165
+ if (isScanning) {
166
+ const simulatedMRZ =
167
+ 'P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<<\nL898902C36UTO7408122F1204159ZE184226B<<<<<10';
168
+ handleMRZScanned(simulatedMRZ);
169
+ }
75
170
  }, 3000);
76
171
 
77
172
  return () => clearTimeout(timer);
78
- // eslint-disable-next-line react-hooks/exhaustive-deps
79
- }, []);
173
+ };
80
174
 
81
- return (
82
- <View style={styles.container}>
83
- <Text style={styles.topLabel}>Align the MRZ code in the box</Text>
175
+ // Render camera with frame processor
176
+ const renderCamera = () => {
177
+ try {
178
+ const { Camera } = require('react-native-vision-camera');
179
+
180
+ if (hasPermission && device) {
181
+ return (
182
+ <Camera
183
+ ref={cameraRef}
184
+ style={StyleSheet.absoluteFill}
185
+ device={device}
186
+ isActive={isScanning}
187
+ frameProcessor={(frame) => {
188
+ 'worklet';
189
+ if (isScanning) {
190
+ processMRZWithMLKit(frame);
191
+ }
192
+ }}
193
+ />
194
+ );
195
+ }
196
+ } catch (error) {
197
+ console.warn('Camera render failed:', error);
198
+ }
84
199
 
85
- {/* Camera placeholder - Replace with actual camera view */}
200
+ // Fallback UI
201
+ return (
86
202
  <View style={[StyleSheet.absoluteFill, { backgroundColor: '#000' }]}>
87
203
  <Text
88
204
  style={{
@@ -108,6 +224,14 @@ export default function MrzCapture() {
108
224
  </Text>
109
225
  )}
110
226
  </View>
227
+ );
228
+ };
229
+
230
+ return (
231
+ <View style={styles.container}>
232
+ <Text style={styles.topLabel}>Align the MRZ code in the box</Text>
233
+
234
+ {renderCamera()}
111
235
 
112
236
  {/* MRZ overlay box */}
113
237
  <View
@@ -123,7 +247,7 @@ export default function MrzCapture() {
123
247
  }}
124
248
  />
125
249
 
126
- {loading && <Loader />}
250
+ {loading && <Loader message="Processing MRZ..." />}
127
251
  </View>
128
252
  );
129
253
  }
@@ -72,17 +72,37 @@ const getUserData = async (): Promise<UserData> => {
72
72
  try {
73
73
  // Try to import geolocation if available
74
74
  const Geolocation = require('react-native-geolocation-service');
75
- location = await new Promise((resolve, reject) => {
76
- Geolocation.getCurrentPosition(
77
- resolve,
78
- reject,
79
- {
80
- enableHighAccuracy: true,
81
- timeout: 15000,
82
- maximumAge: 10000,
83
- }
84
- );
85
- });
75
+
76
+ // Check if Geolocation is properly imported and has the method
77
+ if (Geolocation && typeof Geolocation.getCurrentPosition === 'function') {
78
+ location = await new Promise((resolve, reject) => {
79
+ Geolocation.getCurrentPosition(
80
+ resolve,
81
+ reject,
82
+ {
83
+ enableHighAccuracy: true,
84
+ timeout: 15000,
85
+ maximumAge: 10000,
86
+ }
87
+ );
88
+ });
89
+ } else if (Geolocation && Geolocation.default && typeof Geolocation.default.getCurrentPosition === 'function') {
90
+ // Try default export
91
+ location = await new Promise((resolve, reject) => {
92
+ Geolocation.default.getCurrentPosition(
93
+ resolve,
94
+ reject,
95
+ {
96
+ enableHighAccuracy: true,
97
+ timeout: 15000,
98
+ maximumAge: 10000,
99
+ }
100
+ );
101
+ });
102
+ } else {
103
+ console.warn('Geolocation library not properly configured');
104
+ location = null;
105
+ }
86
106
  } catch (err) {
87
107
  console.warn('Location fetch error:', err);
88
108
  location = null;