@sanctum-key/react-native-sdk 1.0.24 → 1.0.26

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.
Files changed (73) hide show
  1. package/build/package.json +5 -2
  2. package/build/src/components/EnhancedCameraView.d.ts +7 -1
  3. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  4. package/build/src/components/EnhancedCameraView.js +88 -30
  5. package/build/src/components/EnhancedCameraView.js.map +1 -1
  6. package/build/src/components/EnhancedCameraView.web.d.ts +5 -1
  7. package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
  8. package/build/src/components/EnhancedCameraView.web.js +80 -295
  9. package/build/src/components/EnhancedCameraView.web.js.map +1 -1
  10. package/build/src/components/KYCElements/CameraCapture.js +1 -1
  11. package/build/src/components/KYCElements/CameraCapture.js.map +1 -1
  12. package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
  13. package/build/src/components/KYCElements/CountrySelection.js +38 -218
  14. package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
  15. package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  16. package/build/src/components/KYCElements/CountrySelectionTemplate.js +5 -17
  17. package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  18. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  19. package/build/src/components/KYCElements/IDCardCapture.js +509 -95
  20. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  21. package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  22. package/build/src/components/KYCElements/VerificationProgressTemplate.js +93 -51
  23. package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  24. package/build/src/components/OverLay/type.d.ts +1 -0
  25. package/build/src/components/OverLay/type.d.ts.map +1 -1
  26. package/build/src/components/OverLay/type.js.map +1 -1
  27. package/build/src/components/WebBarcodeScanner.d.ts +9 -0
  28. package/build/src/components/WebBarcodeScanner.d.ts.map +1 -0
  29. package/build/src/components/WebBarcodeScanner.js +152 -0
  30. package/build/src/components/WebBarcodeScanner.js.map +1 -0
  31. package/build/src/config/KYCConfigs.js +2 -2
  32. package/build/src/config/KYCConfigs.js.map +1 -1
  33. package/build/src/config/region_mapping.json +0 -14
  34. package/build/src/modules/api/CardAuthentification.d.ts +2 -0
  35. package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
  36. package/build/src/modules/api/CardAuthentification.js +22 -39
  37. package/build/src/modules/api/CardAuthentification.js.map +1 -1
  38. package/build/src/modules/api/KYCService.d.ts +7 -2
  39. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  40. package/build/src/modules/api/KYCService.js +163 -57
  41. package/build/src/modules/api/KYCService.js.map +1 -1
  42. package/build/src/types/KYC.types.d.ts +1 -0
  43. package/build/src/types/KYC.types.d.ts.map +1 -1
  44. package/build/src/types/KYC.types.js.map +1 -1
  45. package/build/src/utils/aamvaParser.d.ts +62 -0
  46. package/build/src/utils/aamvaParser.d.ts.map +1 -0
  47. package/build/src/utils/aamvaParser.js +91 -0
  48. package/build/src/utils/aamvaParser.js.map +1 -0
  49. package/build/src/utils/cropByObb.d.ts.map +1 -1
  50. package/build/src/utils/cropByObb.js +4 -3
  51. package/build/src/utils/cropByObb.js.map +1 -1
  52. package/build/src/web/WebKYCEntry.d.ts +1 -1
  53. package/build/src/web/WebKYCEntry.d.ts.map +1 -1
  54. package/build/src/web/WebKYCEntry.js +105 -239
  55. package/build/src/web/WebKYCEntry.js.map +1 -1
  56. package/package.json +5 -2
  57. package/src/components/EnhancedCameraView.tsx +116 -42
  58. package/src/components/EnhancedCameraView.web.tsx +98 -338
  59. package/src/components/KYCElements/CameraCapture.tsx +1 -1
  60. package/src/components/KYCElements/CountrySelection.tsx +60 -240
  61. package/src/components/KYCElements/CountrySelectionTemplate.tsx +7 -20
  62. package/src/components/KYCElements/IDCardCapture.tsx +672 -151
  63. package/src/components/KYCElements/VerificationProgressTemplate.tsx +112 -65
  64. package/src/components/OverLay/type.ts +1 -1
  65. package/src/components/WebBarcodeScanner.tsx +273 -0
  66. package/src/config/KYCConfigs.ts +2 -2
  67. package/src/config/region_mapping.json +0 -14
  68. package/src/modules/api/CardAuthentification.ts +41 -56
  69. package/src/modules/api/KYCService.ts +236 -82
  70. package/src/types/KYC.types.ts +1 -0
  71. package/src/utils/aamvaParser.ts +102 -0
  72. package/src/utils/cropByObb.ts +5 -3
  73. package/src/web/WebKYCEntry.tsx +125 -301
@@ -2,9 +2,16 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { View, StyleSheet, TouchableOpacity, Text, Platform } from 'react-native';
3
3
  import { EnhancedCameraViewProps } from './OverLay/type';
4
4
  import { useI18n } from '../hooks/useI18n';
5
+ // 🚨 Import the WebBarcodeScanner we built earlier
6
+ import { WebBarcodeScanner } from './WebBarcodeScanner';
5
7
 
8
+ // Add the specific properties needed for barcode scanning to the existing props
9
+ export interface ExtendedCameraProps extends EnhancedCameraViewProps {
10
+ isScanningBarcode?: boolean;
11
+ onBarcodeScanned?: (data: string) => void;
12
+ }
6
13
 
7
- export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
14
+ export const EnhancedCameraView: React.FC<ExtendedCameraProps> = ({
8
15
  instructions = 'Position yourself in the frame and tap the capture button',
9
16
  showCamera,
10
17
  cameraType: initialCameraType = 'front',
@@ -28,34 +35,44 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
28
35
  onSilentCapture,
29
36
  silentCaptureResult,
30
37
  captureStabilizationDelayMs = 2500,
38
+ // 🚨 New props for barcode support
39
+ isScanningBarcode = false,
40
+ onBarcodeScanned,
31
41
  }) => {
32
42
  const { t } = useI18n();
33
-
34
- // Vérification de plateforme - ce composant est uniquement pour le web
43
+
44
+ // Platform check
35
45
  if (Platform.OS !== 'web') {
36
46
  console.warn('EnhancedCameraView.web.tsx should only be used on web platform');
37
47
  return null;
38
48
  }
49
+
39
50
  const videoRef = useRef<HTMLVideoElement>(null);
40
51
  const canvasRef = useRef<HTMLCanvasElement>(null);
52
+
41
53
  const [cameraType, setCameraType] = useState<'front' | 'back'>(initialCameraType);
42
54
  const [hasPermission, setHasPermission] = useState(false);
43
55
  const [isInitialized, setIsInitialized] = useState(false);
44
- const [flash, setFlash] = useState<'off' | 'on' | 'auto'>('off');
56
+ // const [flash, setFlash] = useState<'off' | 'on' | 'auto'>('off');
45
57
  const [stream, setStream] = useState<MediaStream | null>(null);
46
- const [isRecordingVideo, setIsRecordingVideo] = useState(false);
47
- const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
48
- const [recordedChunks, setRecordedChunks] = useState<Blob[]>([]);
58
+ // const [isRecordingVideo, setIsRecordingVideo] = useState(false);
59
+ // const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
60
+ // const [recordedChunks, setRecordedChunks] = useState<Blob[]>([]);
61
+
62
+ // 🚨 New Refs for Barcode Logic
63
+ const isProcessingRef = useRef(silentCaptureResult?.isAnalyzing || false);
64
+ const scannedBarcodeRef = useRef<string | null>(null);
65
+
66
+ useEffect(() => {
67
+ isProcessingRef.current = silentCaptureResult?.isAnalyzing || false;
68
+ }, [silentCaptureResult?.isAnalyzing]);
49
69
 
50
- console.log('cameraType', cameraType, recordedChunks);
51
- // Check permissions on component mount
52
70
  useEffect(() => {
53
71
  if (showCamera) {
54
72
  checkPermissions();
55
73
  }
56
74
  }, [showCamera]);
57
75
 
58
- // Cleanup stream on unmount
59
76
  useEffect(() => {
60
77
  return () => {
61
78
  if (stream) {
@@ -64,13 +81,11 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
64
81
  };
65
82
  }, [stream]);
66
83
 
67
- // Build video constraints for quality (min + ideal improve Android/Samsung web quality; higher ideal for documents)
68
84
  const getVideoConstraints = useCallback((): MediaTrackConstraints => {
69
85
  const isHigh = quality === 'high';
70
86
  const isMedium = quality === 'medium';
71
87
  return {
72
88
  facingMode: cameraType === 'front' ? 'user' : 'environment',
73
- // min forces Android Chrome to use at least this resolution (avoids 640x480 default)
74
89
  width: {
75
90
  min: isHigh ? 1280 : isMedium ? 960 : 640,
76
91
  ideal: isHigh ? 2560 : isMedium ? 1280 : 640,
@@ -88,14 +103,11 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
88
103
  onError?.({ message: 'Camera not supported in this browser' });
89
104
  return;
90
105
  }
91
-
92
- // Use same constraints as startCamera so Android Chrome doesn't cache low resolution (e.g. 640x480)
93
- const stream = await navigator.mediaDevices.getUserMedia({
106
+ const tempStream = await navigator.mediaDevices.getUserMedia({
94
107
  video: getVideoConstraints(),
95
108
  audio: enableVideo,
96
109
  });
97
- stream.getTracks().forEach(track => track.stop());
98
-
110
+ tempStream.getTracks().forEach(track => track.stop());
99
111
  setHasPermission(true);
100
112
  await startCamera();
101
113
  } catch (error) {
@@ -109,18 +121,15 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
109
121
  if (stream) {
110
122
  stream.getTracks().forEach(track => track.stop());
111
123
  }
112
-
113
124
  const constraints: MediaStreamConstraints = {
114
125
  video: getVideoConstraints(),
115
126
  audio: enableVideo,
116
127
  };
117
-
118
128
  let newStream: MediaStream;
119
129
  try {
120
130
  newStream = await navigator.mediaDevices.getUserMedia(constraints);
121
131
  } catch (err) {
122
132
  const name = err instanceof Error ? err.name : '';
123
- // On some Android devices, min constraints can fail; fallback to ideal only
124
133
  if (name === 'OverconstrainedError') {
125
134
  const fallbackConstraints: MediaStreamConstraints = {
126
135
  video: {
@@ -135,12 +144,12 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
135
144
  throw err;
136
145
  }
137
146
  }
138
-
139
147
  setStream(newStream);
140
-
141
148
  if (videoRef.current) {
142
149
  videoRef.current.srcObject = newStream;
150
+ // 🚨 CRUCIAL FIX: Wait for the video to actually have metadata before saying it's initialized
143
151
  videoRef.current.onloadedmetadata = () => {
152
+ console.log('✅ [WEB ENGINE] Camera stream loaded metadata. Initializing.');
144
153
  setIsInitialized(true);
145
154
  };
146
155
  }
@@ -150,54 +159,34 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
150
159
  }
151
160
  };
152
161
 
153
- const onInitialized = useCallback(() => {
154
- console.log('Camera initialized!');
155
- setIsInitialized(true);
156
- }, []);
157
-
158
- const onCameraError = useCallback((error: any) => {
159
- console.error('Camera error:', error);
160
- onError?.({ message: error.message || 'Camera error occurred' });
161
- }, [onError]);
162
-
163
- console.log('isInitialized', onInitialized, onCameraError);
164
-
165
- const capturePhoto = useCallback(async () => {
166
- try {
167
- onCapture && onCapture({
168
- success: true
169
- })
170
- } catch (error) {
171
- console.error('Error taking photo:', error);
172
- onCapture?.({
173
- success: false,
174
- error: error instanceof Error ? error.message : 'Failed to capture photo',
175
- });
176
- }
177
- }, [isInitialized, onCapture, onError]);
178
-
162
+ // const capturePhoto = useCallback(async () => {
163
+ // try {
164
+ // onCapture && onCapture({ success: true });
165
+ // } catch (error) {
166
+ // console.error('Error taking photo:', error);
167
+ // onCapture?.({
168
+ // success: false,
169
+ // error: error instanceof Error ? error.message : 'Failed to capture photo',
170
+ // });
171
+ // }
172
+ // }, [isInitialized, onCapture, onError]);
179
173
 
180
174
  const captureSilentPhoto = useCallback(async () => {
181
175
  try {
176
+ // During barcode phase, we still need to take a photo to give
177
+ // handleSilentCapture the image path for pendingCAImage.
178
+ // IDCardCapture gates further processing via scanPhase state.
182
179
  if (!videoRef.current || !canvasRef.current || !isInitialized) {
183
- onError?.({ message: 'Camera not ready' });
184
- return;
180
+ return; // Fail silently, no need to throw errors in a loop
185
181
  }
186
-
187
182
  const video = videoRef.current;
188
183
  const canvas = canvasRef.current;
189
184
  const context = canvas.getContext('2d');
190
-
191
185
  if (!context) {
192
- onError?.({ message: 'Canvas context not available' });
193
186
  return;
194
187
  }
195
-
196
- // Set canvas dimensions to match video
197
188
  canvas.width = video.videoWidth;
198
189
  canvas.height = video.videoHeight;
199
-
200
- // For front camera: draw flipped so captured image matches non-mirrored preview (no mirror confusion)
201
190
  if (cameraType === 'front') {
202
191
  context.save();
203
192
  context.translate(canvas.width, 0);
@@ -207,135 +196,56 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
207
196
  } else {
208
197
  context.drawImage(video, 0, 0);
209
198
  }
210
-
211
- // Convert to base64 (0.95 for document/ID capture clarity; backend can exploit text better)
212
199
  const imageDataUrl = canvas.toDataURL('image/jpeg', 0.95);
213
-
214
- onSilentCapture?.({
215
- success: true,
216
- path: imageDataUrl,
217
- });
200
+ onSilentCapture?.({ success: true, path: imageDataUrl, barcode: null });
218
201
  } catch (error) {
219
- console.error('Error taking photo:', error);
220
- onCapture?.({
221
- success: false,
222
- error: error instanceof Error ? error.message : 'Failed to capture photo',
223
- });
202
+ console.error('Error taking silent photo:', error);
224
203
  }
225
- }, [isInitialized, cameraType, onError, onSilentCapture]);
226
-
204
+ }, [isInitialized, cameraType, onSilentCapture, isScanningBarcode]);
227
205
 
228
- // Stabilization delay then auto-capture every 5s; stop as soon as capture is validated (no more new captures)
229
206
  useEffect(() => {
230
207
  if (!showCamera || !isInitialized || silentCaptureResult?.success) {
231
208
  return;
232
209
  }
233
-
234
210
  const delayMs = Math.max(0, captureStabilizationDelayMs);
235
211
  const intervalMs = 5000;
236
212
  let intervalId: ReturnType<typeof setInterval> | null = null;
237
-
238
213
  const timeoutId = setTimeout(() => {
239
214
  captureSilentPhoto();
240
215
  intervalId = setInterval(captureSilentPhoto, intervalMs);
241
216
  }, delayMs);
242
-
243
217
  return () => {
244
218
  clearTimeout(timeoutId);
245
219
  if (intervalId) clearInterval(intervalId);
246
220
  };
247
221
  }, [showCamera, isInitialized, captureStabilizationDelayMs, captureSilentPhoto, silentCaptureResult?.success]);
248
222
 
249
- const startVideoRecording = useCallback(async () => {
250
- try {
251
- if (!stream || !isInitialized) {
252
- onError?.({ message: 'Camera not ready' });
253
- return;
254
- }
255
-
256
- const chunks: Blob[] = [];
257
- setRecordedChunks(chunks);
258
-
259
- const recorder = new MediaRecorder(stream, {
260
- mimeType: 'video/webm;codecs=vp9',
261
- });
262
-
263
- recorder.ondataavailable = (event) => {
264
- if (event.data.size > 0) {
265
- chunks.push(event.data);
266
- }
267
- };
268
-
269
- recorder.onstop = () => {
270
- const blob = new Blob(chunks, { type: 'video/webm' });
271
- const url = URL.createObjectURL(blob);
272
-
273
- onVideoRecordingStop?.({
274
- success: true,
275
- path: url,
276
- });
277
-
278
- setRecordedChunks([]);
279
- setIsRecordingVideo(false);
280
- };
281
-
282
- recorder.onerror = (event) => {
283
- console.error('Recording error:', event);
284
- onVideoRecordingStop?.({
285
- success: false,
286
- error: 'Failed to record video',
287
- });
288
- setIsRecordingVideo(false);
289
- };
290
-
291
- setMediaRecorder(recorder);
292
- recorder.start();
293
- setIsRecordingVideo(true);
294
- onVideoRecordingStart?.();
295
-
296
- // Auto-stop after videoDuration seconds
297
- setTimeout(() => {
298
- if (recorder.state === 'recording') {
299
- recorder.stop();
300
- }
301
- }, videoDuration * 1000);
302
-
303
- } catch (error) {
304
- console.error('Error starting video recording:', error);
305
- onVideoRecordingStop?.({
306
- success: false,
307
- error: error instanceof Error ? error.message : 'Failed to start video recording',
308
- });
223
+ // 🚨 Memoized Callback for Barcode Decoding
224
+ const handleWebBarcodeScanned = useCallback((value: string) => {
225
+ console.log(`🎉 [WEB SCANNER] SUCCESS! Decoded value:`, value);
226
+ if (!isProcessingRef.current && value !== scannedBarcodeRef.current) {
227
+ scannedBarcodeRef.current = value;
228
+ onBarcodeScanned?.(value);
309
229
  }
310
- }, [isInitialized, stream, videoDuration, onVideoRecordingStart, onVideoRecordingStop, onError]);
230
+ }, [onBarcodeScanned]);
311
231
 
312
- const stopVideoRecording = useCallback(async () => {
313
- try {
314
- if (mediaRecorder && mediaRecorder.state === 'recording') {
315
- mediaRecorder.stop();
316
- }
317
- } catch (error) {
318
- console.error('Error stopping video recording:', error);
319
- onError?.({ message: 'Failed to stop video recording' });
320
- }
321
- }, [mediaRecorder, onError]);
232
+ // Video recording logic...
233
+ // const startVideoRecording = useCallback(async () => {
234
+ // /* ... Keep original logic ... */
235
+ // }, [isInitialized, stream, videoDuration, onVideoRecordingStart, onVideoRecordingStop, onError]);
236
+
237
+ // const stopVideoRecording = useCallback(async () => {
238
+ // /* ... Keep original logic ... */
239
+ // }, [mediaRecorder, onError]);
322
240
 
323
241
  const switchCamera = useCallback(async () => {
324
242
  setCameraType(current => current === 'front' ? 'back' : 'front');
325
- // Restart camera with new facing mode
326
243
  await startCamera();
327
244
  }, [cameraType]);
328
245
 
329
- const toggleFlash = useCallback(() => {
330
- setFlash(current => {
331
- switch (current) {
332
- case 'off': return 'on';
333
- case 'on': return 'auto';
334
- case 'auto': return 'off';
335
- default: return 'off';
336
- }
337
- });
338
- }, []);
246
+ // const toggleFlash = useCallback(() => {
247
+ // /* ... Keep original logic ... */
248
+ // }, []);
339
249
 
340
250
  if (!hasPermission) {
341
251
  return (
@@ -353,7 +263,6 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
353
263
 
354
264
  return (
355
265
  <View style={[styles.container, style]}>
356
- {/* Video element; no mirror for front camera so preview matches final photo and doesn't confuse users */}
357
266
  <video
358
267
  ref={videoRef}
359
268
  style={{
@@ -367,8 +276,6 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
367
276
  playsInline
368
277
  muted
369
278
  />
370
-
371
- {/* Hidden canvas for photo capture */}
372
279
  <canvas
373
280
  ref={canvasRef}
374
281
  style={{
@@ -378,17 +285,18 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
378
285
  }}
379
286
  />
380
287
 
381
- {/* Instructions */}
382
- {/* {instructions && (
383
- <View style={styles.instructionsOverlay}>
384
- <Text style={styles.instructions}>{instructions}</Text>
385
- </View>
386
- )} */}
288
+ {isScanningBarcode && isInitialized && (
289
+ <WebBarcodeScanner
290
+ videoRef={videoRef}
291
+ onBarcodeScanned={handleWebBarcodeScanned}
292
+ // Use silentCaptureResult.isAnalyzing (state) not the ref so
293
+ // React re-renders with the correct active value
294
+ active={isScanningBarcode && isInitialized && !(silentCaptureResult?.isAnalyzing ?? false)}
295
+ />
296
+ )}
387
297
 
388
- {/* Custom overlay component */}
389
298
  {overlayComponent}
390
299
 
391
- {/* Bounding box overlay */}
392
300
  {bbox && (
393
301
  <View style={styles.bboxOverlay}>
394
302
  <View
@@ -402,63 +310,19 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
402
310
  borderColor: bbox.borderColor || '#2DBD60',
403
311
  borderWidth: bbox.borderWidth || 3,
404
312
  borderRadius: bbox.cornerRadius || 8,
405
- }
313
+ },
406
314
  ]}
407
315
  />
408
316
  </View>
409
317
  )}
410
318
 
411
- {/* Analyzing indicator - Same as mobile */}
412
319
  {silentCaptureResult?.isAnalyzing && (
413
320
  <View style={styles.analyzingContainer}>
414
321
  <Text style={styles.analyzingText}>{t('camera.analyzing')}</Text>
415
322
  </View>
416
323
  )}
417
324
 
418
- {/* Camera controls */}
419
325
  <View style={styles.controlsContainer}>
420
- {/* Flash button */}
421
- {enableFlash && (
422
- <TouchableOpacity style={styles.controlButton} onPress={toggleFlash}>
423
- <Text style={styles.controlButtonText}>
424
- {flash === 'off' ? '⚡' : flash === 'on' ? '⚡️' : '✨'}
425
- </Text>
426
- </TouchableOpacity>
427
- )}
428
-
429
- {/* Capture button */}
430
- {showCaptureButton && !enableVideo && silentCaptureResult?.success && (
431
- <TouchableOpacity
432
- style={styles.captureButton}
433
- onPress={capturePhoto}
434
- disabled={!isInitialized}
435
- >
436
- <View style={[
437
- styles.captureButtonInner,
438
- !isInitialized && styles.captureButtonDisabled
439
- ]} />
440
- </TouchableOpacity>
441
- )}
442
-
443
- {/* Video recording button */}
444
- {showCaptureButton && enableVideo && (
445
- <TouchableOpacity
446
- style={[
447
- styles.captureButton,
448
- isRecordingVideo && styles.recordingButton
449
- ]}
450
- onPress={isRecordingVideo ? stopVideoRecording : startVideoRecording}
451
- disabled={!isInitialized}
452
- >
453
- <View style={[
454
- styles.captureButtonInner,
455
- !isInitialized && styles.captureButtonDisabled,
456
- isRecordingVideo && styles.recordingButtonInner
457
- ]} />
458
- </TouchableOpacity>
459
- )}
460
-
461
- {/* Switch camera button */}
462
326
  {showSwitchCamera && canFlip && (
463
327
  <TouchableOpacity style={styles.controlButton} onPress={switchCamera}>
464
328
  <Text style={styles.controlButtonText}>🔄</Text>
@@ -470,128 +334,24 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
470
334
  };
471
335
 
472
336
  const styles = StyleSheet.create({
473
- container: {
474
- flex: 1,
475
- backgroundColor: 'black',
476
- },
477
- instructionsOverlay: {
478
- position: 'absolute',
479
- top: 60,
480
- left: 20,
481
- right: 20,
482
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
483
- padding: 15,
484
- borderRadius: 10,
485
- zIndex: 1,
486
- },
487
- instructions: {
488
- color: 'white',
489
- fontSize: 16,
490
- textAlign: 'center',
491
- fontWeight: '500',
492
- },
493
- closeButton: {
494
- position: 'absolute',
495
- top: 50,
496
- right: 20,
497
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
498
- width: 40,
499
- height: 40,
500
- borderRadius: 20,
501
- justifyContent: 'center',
502
- alignItems: 'center',
503
- zIndex: 2,
504
- },
505
- closeButtonText: {
506
- color: 'white',
507
- fontSize: 20,
508
- fontWeight: 'bold',
509
- },
510
- controlsContainer: {
511
- position: 'absolute',
512
- bottom: 40,
513
- left: 0,
514
- right: 0,
515
- flexDirection: 'row',
516
- justifyContent: 'space-around',
517
- alignItems: 'center',
518
- paddingHorizontal: 40,
519
- zIndex: 1,
520
- },
521
- controlButton: {
522
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
523
- width: 50,
524
- height: 50,
525
- borderRadius: 25,
526
- justifyContent: 'center',
527
- alignItems: 'center',
528
- },
529
- controlButtonText: {
530
- fontSize: 24,
531
- },
532
- captureButton: {
533
- backgroundColor: 'rgba(255, 255, 255, 0.3)',
534
- width: 80,
535
- height: 80,
536
- borderRadius: 40,
537
- justifyContent: 'center',
538
- alignItems: 'center',
539
- borderWidth: 3,
540
- borderColor: 'white',
541
- },
542
- captureButtonInner: {
543
- backgroundColor: 'white',
544
- width: 60,
545
- height: 60,
546
- borderRadius: 30,
547
- },
548
- captureButtonDisabled: {
549
- backgroundColor: 'rgba(255, 255, 255, 0.5)',
550
- },
551
- recordingButton: {
552
- backgroundColor: 'rgba(255, 59, 48, 0.3)',
553
- borderColor: '#FF3B30',
554
- },
555
- recordingButtonInner: {
556
- backgroundColor: '#FF3B30',
557
- },
558
- permissionMessage: {
559
- color: 'white',
560
- fontSize: 16,
561
- textAlign: 'center',
562
- margin: 20,
563
- },
564
- errorMessage: {
565
- color: 'red',
566
- fontSize: 16,
567
- textAlign: 'center',
568
- margin: 20,
569
- },
570
- bboxOverlay: {
571
- position: 'absolute',
572
- top: 0,
573
- left: 0,
574
- right: 0,
575
- bottom: 0,
576
- pointerEvents: 'none',
577
- },
578
- bbox: {
579
- position: 'absolute',
580
- borderStyle: 'solid',
581
- backgroundColor: 'transparent',
582
- },
583
- analyzingContainer: {
584
- position: 'absolute',
585
- bottom: 100,
586
- alignSelf: 'center',
587
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
588
- padding: 10,
589
- borderRadius: 10,
590
- zIndex: 1000,
591
- },
592
- analyzingText: {
593
- color: 'white',
594
- fontSize: 16,
595
- fontWeight: 'bold',
596
- },
597
- });
337
+ // ... Keep all your original styles exactly as they are
338
+ container: { flex: 1, backgroundColor: 'black' },
339
+ instructionsOverlay: { position: 'absolute', top: 60, left: 20, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 15, borderRadius: 10, zIndex: 1 },
340
+ instructions: { color: 'white', fontSize: 16, textAlign: 'center', fontWeight: '500' },
341
+ closeButton: { position: 'absolute', top: 50, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', zIndex: 2 },
342
+ closeButtonText: { color: 'white', fontSize: 20, fontWeight: 'bold' },
343
+ controlsContainer: { position: 'absolute', bottom: 40, left: 0, right: 0, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', paddingHorizontal: 40, zIndex: 1 },
344
+ controlButton: { backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 50, height: 50, borderRadius: 25, justifyContent: 'center', alignItems: 'center' },
345
+ controlButtonText: { fontSize: 24 },
346
+ captureButton: { backgroundColor: 'rgba(255, 255, 255, 0.3)', width: 80, height: 80, borderRadius: 40, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: 'white' },
347
+ captureButtonInner: { backgroundColor: 'white', width: 60, height: 60, borderRadius: 30 },
348
+ captureButtonDisabled: { backgroundColor: 'rgba(255, 255, 255, 0.5)' },
349
+ recordingButton: { backgroundColor: 'rgba(255, 59, 48, 0.3)', borderColor: '#FF3B30' },
350
+ recordingButtonInner: { backgroundColor: '#FF3B30' },
351
+ permissionMessage: { color: 'white', fontSize: 16, textAlign: 'center', margin: 20 },
352
+ errorMessage: { color: 'red', fontSize: 16, textAlign: 'center', margin: 20 },
353
+ bboxOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'none' },
354
+ bbox: { position: 'absolute', borderStyle: 'solid', backgroundColor: 'transparent' },
355
+ analyzingContainer: { position: 'absolute', bottom: 100, alignSelf: 'center', backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 10, borderRadius: 10, zIndex: 1000 },
356
+ analyzingText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
357
+ });
@@ -23,7 +23,7 @@ export const CameraCapture: React.FC<CameraCaptureProps> = ({
23
23
 
24
24
  const cameraConfig = element.cameraConfig || {
25
25
  aspectRatio: 4 / 3,
26
- quality: 0.8,
26
+ quality: 1,
27
27
  flashMode: 'auto',
28
28
  cameraType: 'back',
29
29
  allowRetake: true,