@sanctum-key/react-native-sdk 1.0.27 → 1.0.28

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 (26) hide show
  1. package/build/package.json +1 -1
  2. package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
  3. package/build/src/components/KYCElements/IDCardCapture.js +156 -48
  4. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  5. package/build/src/components/TemplateKYCExample.d.ts +2 -1
  6. package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
  7. package/build/src/components/TemplateKYCExample.js +2 -2
  8. package/build/src/components/TemplateKYCExample.js.map +1 -1
  9. package/build/src/components/TemplateKYCFlowRefactored.d.ts +1 -0
  10. package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  11. package/build/src/components/TemplateKYCFlowRefactored.js +2 -2
  12. package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
  13. package/build/src/hooks/useTemplateKYCFlow.d.ts +1 -0
  14. package/build/src/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  15. package/build/src/hooks/useTemplateKYCFlow.js +31 -17
  16. package/build/src/hooks/useTemplateKYCFlow.js.map +1 -1
  17. package/build/src/modules/api/KYCService.d.ts +8 -0
  18. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  19. package/build/src/modules/api/KYCService.js +30 -0
  20. package/build/src/modules/api/KYCService.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/components/KYCElements/IDCardCapture.tsx +198 -77
  23. package/src/components/TemplateKYCExample.tsx +7 -3
  24. package/src/components/TemplateKYCFlowRefactored.tsx +3 -0
  25. package/src/hooks/useTemplateKYCFlow.tsx +65 -34
  26. package/src/modules/api/KYCService.ts +41 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.27",
3
+ "version": "1.0.28",
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;AAsB5L,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;AAUD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAg/BtD,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;AAsB5L,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;AAUD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0jCtD,CAAC"}
@@ -47,6 +47,58 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
47
47
  const [scanPhase, setScanPhase] = useState('image');
48
48
  const [pendingCAImage, setPendingCAImage] = useState(null);
49
49
  const scannedBarcodeRef = useRef(null);
50
+ // 🚨 NEW: State for the expiring link code
51
+ const [generatedCode, setGeneratedCode] = useState(null);
52
+ const [isGeneratingCode, setIsGeneratingCode] = useState(false);
53
+ const [codeTimeLeft, setCodeTimeLeft] = useState(0);
54
+ // 🚨 NEW: Countdown Timer Effect
55
+ useEffect(() => {
56
+ if (codeTimeLeft <= 0) {
57
+ if (generatedCode)
58
+ setGeneratedCode(null); // Clear the code when timer hits 0
59
+ return;
60
+ }
61
+ const timer = setInterval(() => {
62
+ setCodeTimeLeft((prev) => prev - 1);
63
+ }, 1000);
64
+ return () => clearInterval(timer);
65
+ }, [codeTimeLeft, generatedCode]);
66
+ // 🚨 NEW: Formatting helper
67
+ const formatTime = (seconds) => {
68
+ const m = Math.floor(seconds / 60);
69
+ const s = seconds % 60;
70
+ return `${m}:${s.toString().padStart(2, '0')}`;
71
+ };
72
+ const handleGenerateCode = async () => {
73
+ if (isGeneratingCode)
74
+ return;
75
+ setIsGeneratingCode(true);
76
+ try {
77
+ const apiKey = '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';
78
+ if (!apiKey) {
79
+ showAlert('Error', 'API Key is missing.');
80
+ setIsGeneratingCode(false);
81
+ return;
82
+ }
83
+ // 🚨 Pass the apiKey as the strictly required second parameter
84
+ const res = await kycService.generateReferralCode({ session_id: state.session.session_id }, apiKey);
85
+ // Extract the code from the response
86
+ const newCode = res.code || res.referral_code || res?.data?.code || res?.data?.referral_code;
87
+ if (newCode) {
88
+ setGeneratedCode(newCode);
89
+ setCodeTimeLeft(300); // 300 seconds = 5 minutes
90
+ }
91
+ else {
92
+ showAlert('Error', 'Failed to parse code from server response.');
93
+ }
94
+ }
95
+ catch (error) {
96
+ showAlert('Error', error.message || 'Failed to generate code');
97
+ }
98
+ finally {
99
+ setIsGeneratingCode(false);
100
+ }
101
+ };
50
102
  useEffect(() => {
51
103
  if (typeof window !== 'undefined' && window.location)
52
104
  setCurrentUrl(window.location.href);
@@ -814,62 +866,71 @@ export const IDCardCapture = ({ component, value = {}, onValueChange, error, lan
814
866
  </View>
815
867
 
816
868
  {showQRModal && Platform.OS === 'web' && (<View style={styles.qrModalOverlay}>
817
- <View style={styles.qrModalContainer}>
818
- <View style={styles.qrModalHeader}>
819
- <Text style={styles.qrModalTitle}>
820
- {state.currentLanguage === 'en' ? 'Continue on your phone' : 'Continuer sur votre téléphone'}
821
- </Text>
822
- <Text style={styles.qrModalText}>
823
- {state.currentLanguage === 'en'
869
+ <View style={styles.qrModalContainer}>
870
+ <View style={styles.qrModalHeader}>
871
+ <Text style={styles.qrModalTitle}>
872
+ {state.currentLanguage === 'en' ? 'Continue on your phone' : 'Continuer sur votre téléphone'}
873
+ </Text>
874
+ <Text style={styles.qrModalText}>
875
+ {state.currentLanguage === 'en'
824
876
  ? "Scan the QR code to download our mobile app and complete the scanning process securely."
825
877
  : "Scannez le code QR pour télécharger notre application et terminer la numérisation en toute sécurité."}
826
- </Text>
827
- </View>
878
+ </Text>
879
+ </View>
828
880
 
829
- <View style={styles.qrToggleContainer}>
830
- <TouchableOpacity style={[styles.qrToggleButton, qrPlatform === 'android' && styles.qrToggleButtonActive]} onPress={() => setQrPlatform('android')}>
831
- <Text style={[styles.qrToggleText, qrPlatform === 'android' && styles.qrToggleTextActive]}>
832
- Android
833
- </Text>
834
- </TouchableOpacity>
835
- <TouchableOpacity style={[styles.qrToggleButton, qrPlatform === 'ios' && styles.qrToggleButtonActive]} onPress={() => setQrPlatform('ios')}>
836
- <Text style={[styles.qrToggleText, qrPlatform === 'ios' && styles.qrToggleTextActive]}>
837
- iOS (Apple)
838
- </Text>
839
- </TouchableOpacity>
840
- </View>
881
+ <View style={styles.qrToggleContainer}>
882
+ <TouchableOpacity style={[styles.qrToggleButton, qrPlatform === 'android' && styles.qrToggleButtonActive]} onPress={() => setQrPlatform('android')}>
883
+ <Text style={[styles.qrToggleText, qrPlatform === 'android' && styles.qrToggleTextActive]}>
884
+ Android
885
+ </Text>
886
+ </TouchableOpacity>
887
+ <TouchableOpacity style={[styles.qrToggleButton, qrPlatform === 'ios' && styles.qrToggleButtonActive]} onPress={() => setQrPlatform('ios')}>
888
+ <Text style={[styles.qrToggleText, qrPlatform === 'ios' && styles.qrToggleTextActive]}>
889
+ iOS (Apple)
890
+ </Text>
891
+ </TouchableOpacity>
892
+ </View>
841
893
 
842
- <View style={styles.qrCodeWrapper}>
843
- <QRCode value={qrPlatform === 'android'
894
+ <View style={styles.qrCodeWrapper}>
895
+ <QRCode value={qrPlatform === 'android'
844
896
  ? 'https://play.google.com/store/apps/details?id=transfergratis.com&hl=en_CA&gl=US'
845
- : 'https://apps.apple.com/ca/app/transfergratis-money-transfer/id1605411731'} size={200} // Slightly reduced to accommodate the toggle switch
846
- backgroundColor="#FFFFFF" color="#0F172A"/>
847
- </View>
897
+ : 'https://apps.apple.com/ca/app/transfergratis-money-transfer/id1605411731'} size={180} backgroundColor="#FFFFFF" color="#0F172A"/>
898
+ </View>
848
899
 
849
- {isWebScanningRestricted && (<View style={styles.storeLinksContainer}>
850
- <Text style={styles.storeLinksTitle}>
851
- {state.currentLanguage === 'en' ? 'Or click to open directly:' : 'Ou cliquez pour ouvrir directement :'}
852
- </Text>
853
- <View style={styles.storeButtonsRow}>
854
- <TouchableOpacity style={styles.storeButton} onPress={() => window.open('https://play.google.com/store/apps/details?id=transfergratis.com&hl=en_CA&gl=US', '_blank')}>
855
- <Text style={styles.storeButtonText}>Google Play</Text>
856
- </TouchableOpacity>
857
- <TouchableOpacity style={styles.storeButton} onPress={() => window.open('https://apps.apple.com/ca/app/transfergratis-money-transfer/id1605411731', '_blank')}>
858
- <Text style={styles.storeButtonText}>App Store</Text>
859
- </TouchableOpacity>
860
- </View>
861
- </View>)}
900
+ <View style={styles.linkCodeSection}>
901
+ <Text style={styles.linkCodeHeader}>
902
+ {state.currentLanguage === 'en' ? 'Use code below to proceed on the Sanctum Key App.' : 'Vous avez déjà l\'application ? Liez-la :'}
903
+ </Text>
904
+
905
+ {generatedCode && codeTimeLeft > 0 ? (<View style={styles.activeCodeContainer}>
906
+ <Text style={styles.activeCodeText}>{generatedCode}</Text>
907
+ <Text style={styles.timerText}>
908
+ {state.currentLanguage === 'en' ? `Expires in ${formatTime(codeTimeLeft)}` : `Expire dans ${formatTime(codeTimeLeft)}`}
909
+ </Text>
910
+ </View>) : (<TouchableOpacity style={styles.generateCodeButton} onPress={handleGenerateCode} disabled={isGeneratingCode}>
911
+ {isGeneratingCode ? (<ActivityIndicator size="small" color="#0F172A"/>) : (<Text style={styles.generateCodeButtonText}>
912
+ {state.currentLanguage === 'en' ? 'Generate 5-Digit Link Code' : 'Générer un code à 5 chiffres'}
913
+ </Text>)}
914
+ </TouchableOpacity>)}
915
+ </View>
862
916
 
863
- <View style={styles.listeningContainer}>
864
- <ActivityIndicator size="small" color="#2DBD60"/>
865
- <Text style={styles.listeningText}>
866
- {state.currentLanguage === 'en' ? "Waiting for you to complete on mobile..." : "En attente de votre complétion sur mobile..."}
867
- </Text>
868
- </View>
917
+ {isWebScanningRestricted && (<View style={styles.storeLinksContainer}>
918
+ <Text style={styles.storeLinksTitle}>
919
+ {state.currentLanguage === 'en' ? 'Or click to open directly:' : 'Ou cliquez pour ouvrir directement :'}
920
+ </Text>
921
+ <View style={styles.storeButtonsRow}>
922
+ <TouchableOpacity style={styles.storeButton} onPress={() => window.open('https://play.google.com/store/apps/details?id=transfergratis.com&hl=en_CA&gl=US', '_blank')}>
923
+ <Text style={styles.storeButtonText}>Google Play</Text>
924
+ </TouchableOpacity>
925
+ <TouchableOpacity style={styles.storeButton} onPress={() => window.open('https://apps.apple.com/ca/app/transfergratis-money-transfer/id1605411731', '_blank')}>
926
+ <Text style={styles.storeButtonText}>App Store</Text>
927
+ </TouchableOpacity>
928
+ </View>
929
+ </View>)}
869
930
 
870
- <Button title={state.currentLanguage === 'en' ? "Cancel & Stay on Laptop" : "Annuler et rester sur l'ordinateur"} onPress={() => setShowQRModal(false)} variant="outline" fullWidth/>
871
- </View>
872
- </View>)}
931
+ <Button title={state.currentLanguage === 'en' ? "Cancel & Stay on Laptop" : "Annuler et rester sur l'ordinateur"} onPress={() => setShowQRModal(false)} variant="outline" fullWidth/>
932
+ </View>
933
+ </View>)}
873
934
  </View>);
874
935
  };
875
936
  const styles = StyleSheet.create({
@@ -986,5 +1047,52 @@ const styles = StyleSheet.create({
986
1047
  qrToggleTextActive: {
987
1048
  color: '#0F172A', // Active text color
988
1049
  },
1050
+ linkCodeSection: {
1051
+ width: '100%',
1052
+ alignItems: 'center',
1053
+ backgroundColor: '#F8FAFC', // Very light slate
1054
+ borderRadius: 16,
1055
+ padding: 16,
1056
+ marginBottom: 20,
1057
+ borderWidth: 1,
1058
+ borderColor: '#E2E8F0',
1059
+ },
1060
+ linkCodeHeader: {
1061
+ fontSize: 13,
1062
+ color: '#475569',
1063
+ fontWeight: '600',
1064
+ marginBottom: 12,
1065
+ },
1066
+ generateCodeButton: {
1067
+ backgroundColor: '#E2E8F0',
1068
+ paddingVertical: 12,
1069
+ paddingHorizontal: 20,
1070
+ borderRadius: 10,
1071
+ width: '100%',
1072
+ alignItems: 'center',
1073
+ justifyContent: 'center',
1074
+ height: 44, // Fixed height to prevent jumping during loading state
1075
+ },
1076
+ generateCodeButtonText: {
1077
+ color: '#0F172A',
1078
+ fontWeight: '700',
1079
+ fontSize: 14,
1080
+ },
1081
+ activeCodeContainer: {
1082
+ alignItems: 'center',
1083
+ width: '100%',
1084
+ },
1085
+ activeCodeText: {
1086
+ fontSize: 32,
1087
+ fontWeight: '900',
1088
+ color: '#2DBD60',
1089
+ letterSpacing: 4,
1090
+ marginBottom: 4,
1091
+ },
1092
+ timerText: {
1093
+ fontSize: 12,
1094
+ color: '#EF4444', // Red to indicate urgency
1095
+ fontWeight: '600',
1096
+ },
989
1097
  });
990
1098
  //# sourceMappingURL=IDCardCapture.js.map