@sanctum-key/react-native-sdk 1.0.41 → 1.0.43

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -1 +1 @@
1
- {"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;AAqB5L,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8vBtD,CAAC"}
1
+ {"version":3,"file":"IDCardCapture.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/IDCardCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,iBAAiB,EAAoI,MAAM,uBAAuB,CAAC;AAqB5L,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0yBtD,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useMemo, useRef, useState } from 'react';
2
- import { View, Text, StyleSheet, Image, ScrollView, Platform, ActivityIndicator, TouchableOpacity, useWindowDimensions } from 'react-native';
2
+ import { View, Text, StyleSheet, Image, ScrollView, Platform, ActivityIndicator, TouchableOpacity, useWindowDimensions, Alert } from 'react-native';
3
3
  import { showAlert } from '../../utils/platformAlert';
4
4
  import { EnhancedCameraView } from '../EnhancedCameraView';
5
5
  import { GovernmentDocumentTypeShorted, GovernmentDocumentTypeBackend } from '../../types/KYC.types';
@@ -15,7 +15,7 @@ import { cropByObb, getObbConfidence, OBB_CONFIDENCE_THRESHOLD } from '../../uti
15
15
  import REGION_MAPPING from '../../config/region_mapping.json';
16
16
  import QRCode from 'react-native-qrcode-svg';
17
17
  import { cropImageWithBBoxWithTolerance } from '../../utils/cropByObb';
18
- import kycService, { authentification } from '../../modules/api/KYCService';
18
+ import kycService, { authentification, clearAuthToken } from '../../modules/api/KYCService';
19
19
  const ISO_TO_COUNTRY_NAME = {
20
20
  'KE': 'Kenya', 'CM': 'Cameroon', 'NG': 'Nigeria', 'CA': 'Canada',
21
21
  'FR': 'France', 'GH': 'Ghana', 'ZA': 'South Africa', 'GB': 'Britain',
@@ -397,6 +397,31 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
397
397
  setSilentCaptureResult(prev => ({ ...prev, isAnalyzing: false, success: false, error: 'Failed to process barcode. Please retake the photo.' }));
398
398
  }
399
399
  };
400
+ const handleExitKYCFlow = () => {
401
+ clearAuthToken();
402
+ // 2. Clear all local camera/capture states
403
+ setCapturedImages({});
404
+ if (onValueChange)
405
+ onValueChange({}); // Clear the parent's form state
406
+ setCurrentSide('front');
407
+ setScanPhase('image');
408
+ setSilentCaptureResult({ success: false, isAnalyzing: false, path: '', error: '' });
409
+ scannedBarcodeRef.current = null;
410
+ setPendingCAImage(null);
411
+ setIsProcessingCapture(false);
412
+ setProcessingImagePath(null);
413
+ // 3. Restart the flow
414
+ if (actions.resetTemplate) {
415
+ // This is the best method: it wipes the context and rebuilds the initial state
416
+ actions.resetTemplate();
417
+ }
418
+ else if (actions.goToComponent && state.template?.components?.length > 0) {
419
+ actions.goToComponent(state.template.components[0].id);
420
+ }
421
+ else {
422
+ console.warn("Could not restart flow. Check your KYC context actions.");
423
+ }
424
+ };
400
425
  const handleSilentCapture = async (result) => {
401
426
  if (isProcessingCaptureRef.current)
402
427
  return;
@@ -404,7 +429,6 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
404
429
  return;
405
430
  if (isAnalyzingRef.current)
406
431
  return;
407
- // USE REFS TO AVOID IOS NATIVE STALE CLOSURE
408
432
  const side = currentSideRef.current;
409
433
  const captured = capturedImagesRef.current;
410
434
  const docType = selectedDocTypeRef.current;
@@ -497,40 +521,51 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
497
521
  }
498
522
  catch (error) {
499
523
  clearTimeout(watchdog);
500
- const rawMessage = (error?.message || '').toLowerCase();
524
+ const rawMessage = (typeof error === 'string' ? error : (error?.message || '')).toLowerCase();
525
+ const statusCode = error?.response?.status || error?.status;
526
+ if (statusCode === 401 ||
527
+ statusCode === 403 ||
528
+ rawMessage.includes('401') ||
529
+ rawMessage.includes('unauthorized') ||
530
+ rawMessage.includes('token') ||
531
+ rawMessage.includes('unauthenticated')) {
532
+ setShowCamera(false);
533
+ setIsProcessingCapture(false);
534
+ setSilentCaptureResult(prev => ({ ...prev, isAnalyzing: false, success: false, error: '' }));
535
+ // Use React Native's native Alert to wait for the user's tap
536
+ Alert.alert(state.currentLanguage === 'en' ? 'Session Expired' : 'Session Expirée', state.currentLanguage === 'en'
537
+ ? 'Your secure session has expired. Please restart the process.'
538
+ : 'Votre session sécurisée a expiré. Veuillez recommencer.', [
539
+ {
540
+ text: state.currentLanguage === 'en' ? 'Restart' : 'Recommencer',
541
+ onPress: () => handleExitKYCFlow() // Redirects ONLY when they click the button
542
+ }
543
+ ], { cancelable: false } // Forces them to click the button
544
+ );
545
+ return;
546
+ }
501
547
  let hintMessage = '';
548
+ // 2. Business Logic Errors
502
549
  if (rawMessage.includes('pays sélectionné') || rawMessage.includes('country mismatch')) {
503
- hintMessage = state.currentLanguage === 'en'
504
- ? 'Does not match the selected country.'
505
- : 'Ne correspond pas au pays sélectionné.';
550
+ hintMessage = state.currentLanguage === 'en' ? 'Does not match the selected country.' : 'Ne correspond pas au pays sélectionné.';
506
551
  }
507
552
  else if (rawMessage.includes('impossible') || rawMessage.includes('unreadable')) {
508
- hintMessage = state.currentLanguage === 'en'
509
- ? 'Move to better lighting.'
510
- : 'Améliorez l\'éclairage.';
553
+ hintMessage = state.currentLanguage === 'en' ? 'Move to better lighting and ensure card is in frame.' : 'Améliorez l\'éclairage et assurez-vous que la carte est bien cadrée.';
511
554
  }
512
555
  else if (rawMessage.includes('card_not_fully_in_frame') || rawMessage.includes('frame')) {
513
- hintMessage = state.currentLanguage === 'en'
514
- ? 'Move closer to the document.'
515
- : 'Rapprochez-vous du document.';
556
+ hintMessage = state.currentLanguage === 'en' ? 'Move closer to the document.' : 'Rapprochez-vous du document.';
516
557
  }
517
558
  else if (rawMessage.includes('ne correspond pas au recto')) {
518
- hintMessage = state.currentLanguage === 'en'
519
- ? 'Please scan the same ID.'
520
- : 'Veuillez scanner la même pièce.';
559
+ hintMessage = state.currentLanguage === 'en' ? 'Please scan the same ID.' : 'Veuillez scanner la même pièce.';
521
560
  }
522
- // 2. If it's not a known logical error, assume it's a network/API failure
561
+ // 3. Fallback to Network/API failure
523
562
  else {
524
563
  const isNetworkError = error.isAxiosError || error.message === 'Network Error' || error.code === 'ECONNABORTED' || rawMessage.includes('network') || !error.response;
525
564
  if (isNetworkError) {
526
- hintMessage = state.currentLanguage === 'en'
527
- ? 'Poor connection. Retrying...'
528
- : 'Connexion faible. Nouvelle tentative...';
565
+ hintMessage = state.currentLanguage === 'en' ? 'Poor connection. Retrying...' : 'Connexion faible. Nouvelle tentative...';
529
566
  }
530
567
  else {
531
- hintMessage = state.currentLanguage === 'en'
532
- ? 'Analyzing...' // Generic fallback if an unknown API error occurs
533
- : 'Analyse en cours...';
568
+ hintMessage = state.currentLanguage === 'en' ? 'Analyzing...' : 'Analyse en cours...';
534
569
  }
535
570
  }
536
571
  setSilentCaptureResult(prev => ({ ...prev, isAnalyzing: false, success: false, error: hintMessage }));