@sanctum-key/react-native-sdk 1.0.8 → 1.0.9

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 (96) hide show
  1. package/README.md +4 -4
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/AndroidManifest.xml +1 -1
  4. package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkModule.kt +6 -6
  5. package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkView.kt +2 -2
  6. package/build/package.json +5 -5
  7. package/build/src/App.d.ts +2 -2
  8. package/build/src/App.d.ts.map +1 -1
  9. package/build/src/App.js +2 -2
  10. package/build/src/App.js.map +1 -1
  11. package/build/src/{SanctumKeySdk.types.d.ts → TransfergratisSdk.types.d.ts} +3 -3
  12. package/build/src/TransfergratisSdk.types.d.ts.map +1 -0
  13. package/build/src/TransfergratisSdk.types.js +2 -0
  14. package/build/src/TransfergratisSdk.types.js.map +1 -0
  15. package/build/src/{SanctumKeySdkModule.d.ts → TransfergratisSdkModule.d.ts} +4 -4
  16. package/build/src/TransfergratisSdkModule.d.ts.map +1 -0
  17. package/build/src/{SanctumKeySdkModule.js → TransfergratisSdkModule.js} +2 -2
  18. package/build/src/TransfergratisSdkModule.js.map +1 -0
  19. package/build/src/{SanctumKeySdkModule.web.d.ts → TransfergratisSdkModule.web.d.ts} +4 -4
  20. package/build/src/TransfergratisSdkModule.web.d.ts.map +1 -0
  21. package/build/src/{SanctumKeySdkModule.web.js → TransfergratisSdkModule.web.js} +3 -3
  22. package/build/src/TransfergratisSdkModule.web.js.map +1 -0
  23. package/build/src/TransfergratisSdkView.d.ts +4 -0
  24. package/build/src/TransfergratisSdkView.d.ts.map +1 -0
  25. package/build/src/TransfergratisSdkView.js +7 -0
  26. package/build/src/TransfergratisSdkView.js.map +1 -0
  27. package/build/src/TransfergratisSdkView.web.d.ts +4 -0
  28. package/build/src/TransfergratisSdkView.web.d.ts.map +1 -0
  29. package/build/src/{SanctumKeySdkView.web.js → TransfergratisSdkView.web.js} +2 -2
  30. package/build/src/TransfergratisSdkView.web.js.map +1 -0
  31. package/build/src/api/axios.js +2 -2
  32. package/build/src/api/axios.js.map +1 -1
  33. package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
  34. package/build/src/components/EnhancedCameraView.js +12 -61
  35. package/build/src/components/EnhancedCameraView.js.map +1 -1
  36. package/build/src/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -1
  37. package/build/src/components/KYCElements/EmailVerificationTemplate.js +11 -32
  38. package/build/src/components/KYCElements/EmailVerificationTemplate.js.map +1 -1
  39. package/build/src/components/KYCElements/IDCardCapture.js +2 -1
  40. package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
  41. package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
  42. package/build/src/components/KYCElements/PhoneVerificationTemplate.js +22 -163
  43. package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
  44. package/build/src/components/NativeCameraView.js +1 -1
  45. package/build/src/components/NativeCameraView.js.map +1 -1
  46. package/build/src/config/KYCConfig.js +1 -1
  47. package/build/src/config/KYCConfig.js.map +1 -1
  48. package/build/src/config/allowedDomains.js +6 -6
  49. package/build/src/config/allowedDomains.js.map +1 -1
  50. package/build/src/index.d.ts +3 -3
  51. package/build/src/index.d.ts.map +1 -1
  52. package/build/src/index.js +3 -3
  53. package/build/src/index.js.map +1 -1
  54. package/build/src/modules/api/KYCService.d.ts +3 -3
  55. package/build/src/modules/api/KYCService.d.ts.map +1 -1
  56. package/build/src/modules/api/KYCService.js +25 -32
  57. package/build/src/modules/api/KYCService.js.map +1 -1
  58. package/build/src/modules/camera/NativeCameraModule.js +17 -17
  59. package/build/src/modules/camera/NativeCameraModule.js.map +1 -1
  60. package/expo-module.config.json +2 -2
  61. package/ios/TransfergratisSdk.podspec +2 -2
  62. package/ios/TransfergratisSdkModule.swift +12 -12
  63. package/package.json +5 -5
  64. package/src/App.tsx +2 -2
  65. package/src/{SanctumKeySdk.types.ts → TransfergratisSdk.types.ts} +2 -2
  66. package/src/{SanctumKeySdkModule.ts → TransfergratisSdkModule.ts} +3 -3
  67. package/src/{SanctumKeySdkModule.web.ts → TransfergratisSdkModule.web.ts} +3 -3
  68. package/src/TransfergratisSdkView.tsx +11 -0
  69. package/src/{SanctumKeySdkView.web.tsx → TransfergratisSdkView.web.tsx} +2 -2
  70. package/src/api/axios.ts +2 -2
  71. package/src/components/EnhancedCameraView.tsx +34 -99
  72. package/src/components/KYCElements/EmailVerificationTemplate.tsx +10 -36
  73. package/src/components/KYCElements/IDCardCapture.tsx +1 -1
  74. package/src/components/KYCElements/PhoneVerificationTemplate.tsx +30 -204
  75. package/src/components/NativeCameraView.tsx +1 -1
  76. package/src/config/KYCConfig.ts +1 -1
  77. package/src/config/allowedDomains.ts +6 -6
  78. package/src/i18n/README.md +1 -1
  79. package/src/index.ts +3 -3
  80. package/src/modules/api/KYCService.ts +26 -37
  81. package/src/modules/camera/NativeCameraModule.ts +17 -17
  82. package/build/src/SanctumKeySdk.types.d.ts.map +0 -1
  83. package/build/src/SanctumKeySdk.types.js +0 -2
  84. package/build/src/SanctumKeySdk.types.js.map +0 -1
  85. package/build/src/SanctumKeySdkModule.d.ts.map +0 -1
  86. package/build/src/SanctumKeySdkModule.js.map +0 -1
  87. package/build/src/SanctumKeySdkModule.web.d.ts.map +0 -1
  88. package/build/src/SanctumKeySdkModule.web.js.map +0 -1
  89. package/build/src/SanctumKeySdkView.d.ts +0 -4
  90. package/build/src/SanctumKeySdkView.d.ts.map +0 -1
  91. package/build/src/SanctumKeySdkView.js +0 -7
  92. package/build/src/SanctumKeySdkView.js.map +0 -1
  93. package/build/src/SanctumKeySdkView.web.d.ts +0 -4
  94. package/build/src/SanctumKeySdkView.web.d.ts.map +0 -1
  95. package/build/src/SanctumKeySdkView.web.js.map +0 -1
  96. package/src/SanctumKeySdkView.tsx +0 -11
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
- import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable, Modal, FlatList } from 'react-native';
2
+ import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable } from 'react-native';
3
3
  import { TemplateComponent, LocalizedText } from '../../types/KYC.types';
4
4
  import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
5
5
  import { useI18n } from '../../hooks/useI18n';
@@ -17,19 +17,6 @@ interface PhoneVerificationTemplateProps {
17
17
  type VerificationStep = 'phone' | 'otp';
18
18
  const CODE_LENGTH = 6;
19
19
 
20
- // Easily expand this list with any countries your app supports
21
- const COUNTRY_CODES = [
22
- { code: '+254', label: '🇰🇪 Kenya (+254)' },
23
- { code: '+255', label: '🇹🇿 Tanzania (+255)' },
24
- { code: '+256', label: '🇺🇬 Uganda (+256)' },
25
- { code: '+250', label: '🇷🇼 Rwanda (+250)' },
26
- { code: '+234', label: '🇳🇬 Nigeria (+234)' },
27
- { code: '+27', label: '🇿🇦 South Africa (+27)' },
28
- { code: '+44', label: '🇬🇧 UK (+44)' },
29
- { code: '+1', label: '🇺🇸 US/Canada (+1)' },
30
- { code: '+91', label: '🇮🇳 India (+91)' },
31
- ];
32
-
33
20
  export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps> = ({
34
21
  component,
35
22
  value,
@@ -44,16 +31,10 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
44
31
 
45
32
  // State
46
33
  const [step, setStep] = useState<VerificationStep>('phone');
47
- const [countryCode, setCountryCode] = useState('+254');
48
34
  const [phone, setPhone] = useState('');
49
- const [showCountryPicker, setShowCountryPicker] = useState(false);
50
-
51
35
  const [otp, setOtp] = useState('');
52
36
  const [localError, setLocalError] = useState<string | null>(null);
53
37
  const [isSimulating, setIsSimulating] = useState(false);
54
-
55
- // 🚨 NEW: Track actual focus state for visual feedback
56
- const [isInputFocused, setIsInputFocused] = useState(false);
57
38
 
58
39
  const inputRef = useRef<TextInput>(null);
59
40
 
@@ -71,21 +52,6 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
71
52
  }
72
53
  }, [otp]);
73
54
 
74
- // --- AUTO FOCUS LOGIC ---
75
- useEffect(() => {
76
- let focusTimer: ReturnType<typeof setTimeout>;
77
-
78
- if (step === 'otp' && !isSimulating) {
79
- focusTimer = setTimeout(() => {
80
- inputRef.current?.focus();
81
- }, 100);
82
- }
83
-
84
- return () => {
85
- if (focusTimer) clearTimeout(focusTimer);
86
- };
87
- }, [step, isSimulating]); // 🚨 Must watch both states
88
-
89
55
  const handleSendCode = async () => {
90
56
  const trimmedPhone = phone.trim();
91
57
  if (!trimmedPhone || trimmedPhone.length < 5) {
@@ -96,11 +62,11 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
96
62
  setLocalError(null);
97
63
  setIsSimulating(true);
98
64
 
99
- const fullPhoneNumber = `${countryCode}${trimmedPhone}`;
100
-
101
65
  try {
102
- await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
66
+ await kycService.sendWhatsAppVerificationCode(sessionId, trimmedPhone, auth);
103
67
  setStep('otp');
68
+ // Auto-focus the OTP input shortly after switching steps
69
+ setTimeout(() => inputRef.current?.focus(), 100);
104
70
  } catch (err: any) {
105
71
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
106
72
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -117,33 +83,29 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
117
83
 
118
84
  setLocalError(null);
119
85
  setIsSimulating(true);
120
-
121
- const fullPhoneNumber = `${countryCode}${phone.trim()}`;
122
86
 
123
87
  try {
124
- await kycService.verifyWhatsAppCode(sessionId, otp.trim(), fullPhoneNumber, auth);
125
-
126
- const data = { phone: fullPhoneNumber, otp, verified: true };
88
+ await kycService.verifyWhatsAppCode(sessionId, otp.trim(), auth);
89
+ const data = { phone, otp, verified: true };
127
90
  onValueChange(data);
128
91
  actions.nextComponent(data);
129
92
  } catch (err: any) {
130
93
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
131
94
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
132
- setOtp('');
133
- // Refocus so they can type immediately after an error
134
- inputRef.current?.focus();
95
+ setOtp(''); // Clear the boxes on error so they can type again
96
+ inputRef.current?.focus();
135
97
  } finally {
136
98
  setIsSimulating(false);
137
99
  }
138
100
  };
139
101
 
140
102
  const onChangePhone = (text: string) => {
141
- const cleaned = text.replace(/[^0-9]/g, '');
142
- setPhone(cleaned);
103
+ setPhone(text);
143
104
  if (localError) setLocalError(null);
144
105
  };
145
106
 
146
107
  const onChangeOtp = (text: string) => {
108
+ // Only allow numbers
147
109
  const cleaned = text.replace(/[^0-9]/g, '');
148
110
  setOtp(cleaned);
149
111
  if (localError) setLocalError(null);
@@ -161,20 +123,16 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
161
123
  <Pressable style={styles.otpBoxesContainer} onPress={() => inputRef.current?.focus()}>
162
124
  {boxes.map((_, index) => {
163
125
  const digit = otp[index] || '';
126
+ const isCurrent = index === otp.length;
164
127
  const isFilled = index < otp.length;
165
-
166
- // 🚨 NEW: Only highlight if the input is ACTUALLY focused.
167
- // Highlights the next empty box, or the last box if full.
168
- const isActiveIndex = index === otp.length || (index === CODE_LENGTH - 1 && otp.length === CODE_LENGTH);
169
- const isCurrent = isInputFocused && isActiveIndex;
170
128
 
171
129
  return (
172
130
  <View
173
131
  key={index}
174
132
  style={[
175
133
  styles.otpBox,
176
- isFilled && styles.otpBoxFilled,
177
- isCurrent && styles.otpBoxActive // Active overrides filled
134
+ isCurrent && styles.otpBoxActive,
135
+ isFilled && styles.otpBoxFilled
178
136
  ]}
179
137
  >
180
138
  <Text style={styles.otpBoxText}>{digit}</Text>
@@ -189,41 +147,30 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
189
147
  <View style={styles.container}>
190
148
  <Text style={styles.title}>{title}</Text>
191
149
  <Text style={styles.instructions}>
192
- {step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${countryCode} ${phone}`)}
150
+ {step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${phone}`)}
193
151
  </Text>
194
152
 
195
153
  <View style={styles.contentContainer}>
196
154
  {step === 'phone' ? (
197
155
  <View style={styles.inputContainer}>
198
156
  <Text style={styles.label}>{t('common.phone') || 'Phone Number'}</Text>
199
-
200
- <View style={styles.phoneInputRow}>
201
- <TouchableOpacity
202
- style={styles.countryPickerBtn}
203
- onPress={() => setShowCountryPicker(true)}
204
- disabled={isSimulating}
205
- >
206
- <Text style={styles.countryPickerText}>{countryCode}</Text>
207
- <Text style={styles.dropdownIcon}>▼</Text>
208
- </TouchableOpacity>
209
-
210
- <TextInput
211
- style={styles.phoneInput}
212
- placeholder="712 345 678"
213
- value={phone}
214
- onChangeText={onChangePhone}
215
- keyboardType="phone-pad"
216
- autoComplete="tel"
217
- editable={!isSimulating}
218
- />
219
- </View>
157
+ <TextInput
158
+ style={styles.input}
159
+ placeholder="+1234567890"
160
+ value={phone}
161
+ onChangeText={onChangePhone}
162
+ keyboardType="phone-pad"
163
+ autoComplete="tel"
164
+ editable={!isSimulating}
165
+ />
220
166
  </View>
221
167
  ) : (
222
168
  <View style={styles.inputContainer}>
223
169
  <Text style={styles.label}>{t('common.verificationCode') || 'Verification Code'}</Text>
224
170
 
225
171
  <View style={styles.otpWrapper}>
226
- {renderOtpBoxes()}
172
+ {renderOtpBoxes()}
173
+ {/* Hidden TextInput overlaid to handle native keyboard & pasting seamlessly */}
227
174
  <TextInput
228
175
  ref={inputRef}
229
176
  style={styles.hiddenInput}
@@ -234,8 +181,6 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
234
181
  editable={!isSimulating}
235
182
  textContentType="oneTimeCode"
236
183
  caretHidden={true}
237
- onFocus={() => setIsInputFocused(true)}
238
- onBlur={() => setIsInputFocused(false)}
239
184
  />
240
185
  </View>
241
186
 
@@ -265,15 +210,12 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
265
210
  if (isSimulating) return;
266
211
  setLocalError(null);
267
212
  setIsSimulating(true);
268
- const fullPhoneNumber = `${countryCode}${phone.trim()}`;
269
213
  try {
270
- await kycService.sendWhatsAppVerificationCode(sessionId, fullPhoneNumber, auth);
214
+ await kycService.sendWhatsAppVerificationCode(sessionId, phone.trim(), auth);
271
215
  Alert.alert(
272
216
  t('common.codeResent') || 'Code Resent',
273
- t('common.codeResentMessage', { email: fullPhoneNumber }) || 'Code resent to ' + fullPhoneNumber
217
+ t('common.codeResentMessage', { email: phone }) || 'Code resent to ' + phone
274
218
  );
275
- // Refocus after resending
276
- inputRef.current?.focus();
277
219
  } catch (err: any) {
278
220
  const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
279
221
  setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
@@ -288,51 +230,11 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
288
230
  </TouchableOpacity>
289
231
  )}
290
232
  </View>
291
-
292
- {/* COUNTRY PICKER MODAL */}
293
- <Modal
294
- visible={showCountryPicker}
295
- animationType="slide"
296
- transparent={true}
297
- onRequestClose={() => setShowCountryPicker(false)}
298
- >
299
- <TouchableOpacity
300
- style={styles.modalOverlay}
301
- activeOpacity={1}
302
- onPress={() => setShowCountryPicker(false)}
303
- >
304
- <View style={styles.modalContent}>
305
- <View style={styles.modalHeader}>
306
- <Text style={styles.modalTitle}>Select Country</Text>
307
- <TouchableOpacity onPress={() => setShowCountryPicker(false)}>
308
- <Text style={styles.modalClose}>✕</Text>
309
- </TouchableOpacity>
310
- </View>
311
- <FlatList
312
- data={COUNTRY_CODES}
313
- keyExtractor={(item) => item.code}
314
- renderItem={({ item }) => (
315
- <TouchableOpacity
316
- style={styles.countryItem}
317
- onPress={() => {
318
- setCountryCode(item.code);
319
- setShowCountryPicker(false);
320
- }}
321
- >
322
- <Text style={styles.countryItemLabel}>{item.label}</Text>
323
- {countryCode === item.code && <Text style={styles.checkMark}>✓</Text>}
324
- </TouchableOpacity>
325
- )}
326
- />
327
- </View>
328
- </TouchableOpacity>
329
- </Modal>
330
233
  </View>
331
234
  );
332
235
  };
333
236
 
334
237
  const styles = StyleSheet.create({
335
- // ... Keeping all previous styles identical for safety ...
336
238
  container: {
337
239
  padding: 24,
338
240
  backgroundColor: 'white',
@@ -370,35 +272,7 @@ const styles = StyleSheet.create({
370
272
  marginBottom: 8,
371
273
  marginLeft: 4,
372
274
  },
373
- phoneInputRow: {
374
- flexDirection: 'row',
375
- alignItems: 'center',
376
- gap: 10,
377
- },
378
- countryPickerBtn: {
379
- flexDirection: 'row',
380
- alignItems: 'center',
381
- justifyContent: 'space-between',
382
- borderWidth: 1,
383
- borderColor: '#e0e0e0',
384
- paddingHorizontal: 12,
385
- paddingVertical: 16,
386
- borderRadius: 12,
387
- backgroundColor: '#f8f9fa',
388
- minWidth: 90,
389
- },
390
- countryPickerText: {
391
- fontSize: 16,
392
- color: '#333',
393
- fontWeight: '600',
394
- },
395
- dropdownIcon: {
396
- fontSize: 12,
397
- color: '#666',
398
- marginLeft: 8,
399
- },
400
- phoneInput: {
401
- flex: 1,
275
+ input: {
402
276
  borderWidth: 1,
403
277
  borderColor: '#e0e0e0',
404
278
  padding: 16,
@@ -407,54 +281,6 @@ const styles = StyleSheet.create({
407
281
  backgroundColor: '#f8f9fa',
408
282
  color: '#333',
409
283
  },
410
- modalOverlay: {
411
- flex: 1,
412
- backgroundColor: 'rgba(0,0,0,0.5)',
413
- justifyContent: 'flex-end',
414
- },
415
- modalContent: {
416
- backgroundColor: 'white',
417
- borderTopLeftRadius: 24,
418
- borderTopRightRadius: 24,
419
- maxHeight: '60%',
420
- paddingBottom: 40,
421
- },
422
- modalHeader: {
423
- flexDirection: 'row',
424
- justifyContent: 'space-between',
425
- alignItems: 'center',
426
- padding: 20,
427
- borderBottomWidth: 1,
428
- borderBottomColor: '#f0f0f0',
429
- },
430
- modalTitle: {
431
- fontSize: 18,
432
- fontWeight: '700',
433
- color: '#1a1a1a',
434
- },
435
- modalClose: {
436
- fontSize: 20,
437
- color: '#666',
438
- padding: 5,
439
- },
440
- countryItem: {
441
- flexDirection: 'row',
442
- justifyContent: 'space-between',
443
- alignItems: 'center',
444
- paddingVertical: 16,
445
- paddingHorizontal: 24,
446
- borderBottomWidth: 1,
447
- borderBottomColor: '#f8f9fa',
448
- },
449
- countryItemLabel: {
450
- fontSize: 16,
451
- color: '#333',
452
- },
453
- checkMark: {
454
- color: '#2DBD60',
455
- fontSize: 18,
456
- fontWeight: 'bold',
457
- },
458
284
  otpWrapper: {
459
285
  position: 'relative',
460
286
  width: '100%',
@@ -469,7 +295,7 @@ const styles = StyleSheet.create({
469
295
  },
470
296
  otpBox: {
471
297
  width: '14%',
472
- aspectRatio: 1,
298
+ aspectRatio: 1, // keeps it perfectly square
473
299
  borderWidth: 1,
474
300
  borderColor: '#e0e0e0',
475
301
  borderRadius: 12,
@@ -497,7 +323,7 @@ const styles = StyleSheet.create({
497
323
  left: 0,
498
324
  width: '100%',
499
325
  height: '100%',
500
- opacity: 0,
326
+ opacity: 0, // completely invisible but handles native keyboard interactions perfectly
501
327
  },
502
328
  errorText: {
503
329
  color: '#dc2626',
@@ -10,7 +10,7 @@ export interface NativeCameraViewProps {
10
10
  onError?: (event: any) => void;
11
11
  }
12
12
 
13
- const NativeCameraViewComponent = requireNativeViewManager('SanctumKeySdk_SanctumKeySdkView');
13
+ const NativeCameraViewComponent = requireNativeViewManager('TransfergratisSdk_TransfergratisSdkView');
14
14
 
15
15
  export const NativeCameraView: React.FC<NativeCameraViewProps> = (props) => {
16
16
 
@@ -6,7 +6,7 @@ class KYCConfig {
6
6
 
7
7
  private backendUrls: Record<BackendEnvironment, string> = {
8
8
  PRODUCTION: 'https://service.sanctumkey.com/api/v1',
9
- TEST: 'https://kyc-backend.SanctumKey.net/api/v1',
9
+ TEST: 'https://kyc-backend.transfergratis.net/api/v1',
10
10
  };
11
11
 
12
12
  private constructor() { }
@@ -12,11 +12,11 @@ export interface AllowedDomainConfig {
12
12
  // Default configuration - can be overridden via environment variables
13
13
  const DEFAULT_CONFIG: AllowedDomainConfig = {
14
14
  domains: [
15
- 'SanctumKey.com',
16
- 'www.SanctumKey.com',
17
- 'admin.SanctumKey.com',
18
- 'dashboard.SanctumKey.com',
19
- 'preweb.SanctumKey.net',
15
+ 'transfergratis.com',
16
+ 'www.transfergratis.com',
17
+ 'admin.transfergratis.com',
18
+ 'dashboard.transfergratis.com',
19
+ 'preweb.transfergratis.net',
20
20
  // Add other trusted domains here
21
21
  ],
22
22
  enforceHttps: true,
@@ -59,7 +59,7 @@ export const isDomainAllowed = (domain: string): boolean => {
59
59
  return true;
60
60
  }
61
61
 
62
- // Subdomain match (e.g., app.SanctumKey.com matches SanctumKey.com)
62
+ // Subdomain match (e.g., app.transfergratis.com matches transfergratis.com)
63
63
  if (domain.endsWith('.' + allowedDomain)) {
64
64
  return true;
65
65
  }
@@ -1,4 +1,4 @@
1
- # 🌍 Système d'Internationalisation (i18n) - SanctumKey SDK
1
+ # 🌍 Système d'Internationalisation (i18n) - Transfergratis SDK
2
2
 
3
3
  Ce système d'internationalisation permet de traduire facilement votre application KYC en plusieurs langues.
4
4
 
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './SanctumKeySdk.types';
1
+ export * from './TransfergratisSdk.types';
2
2
 
3
3
 
4
4
  // Export KYC types
@@ -8,9 +8,9 @@ export * from './types/KYC.types';
8
8
  export * from './types/env.types';
9
9
 
10
10
 
11
- export { TemplateKYCExample as LaunchSanctumKeyKYC } from './components/TemplateKYCExample';
11
+ export { TemplateKYCExample as LaunchTransferGratisKYC } from './components/TemplateKYCExample';
12
12
  // Backward compatibility for existing integrations using the typo.
13
- export { TemplateKYCExample as LauchSanctumKeyKYC } from './components/TemplateKYCExample';
13
+ export { TemplateKYCExample as LauchTransferGratisKYC } from './components/TemplateKYCExample';
14
14
 
15
15
  // Export Template Flow Components
16
16
  export { TemplateKYCFlow } from './components/TemplateKYCFlowRefactored';
@@ -60,10 +60,10 @@ export class KYCService {
60
60
  private baseURL: string;
61
61
  private apiKey: string;
62
62
  // Additional service base URLs (fixed as per current infra)
63
- private faceServiceURL = 'https://kyc-engine.SanctumKey.net:8000';
64
- private textExtractionServiceURL = 'https://kyc-engine.SanctumKey.net:8006';
65
- private mrzServiceURL = 'https://kyc-engine.SanctumKey.net:8002';
66
- private barcodeServiceURL = 'https://kyc-engine.SanctumKey.net:8000';
63
+ private faceServiceURL = 'https://kyc-engine.transfergratis.net:8000';
64
+ private textExtractionServiceURL = 'https://kyc-engine.transfergratis.net:8006';
65
+ private mrzServiceURL = 'https://kyc-engine.transfergratis.net:8002';
66
+ private barcodeServiceURL = 'https://kyc-engine.transfergratis.net:8000';
67
67
  private orientationServiceURL = 'http://18.188.180.154:8080';
68
68
 
69
69
  constructor(baseURL: string, apiKey: string) {
@@ -620,7 +620,7 @@ export class KYCService {
620
620
  }
621
621
  }
622
622
 
623
- /** Send WhatsApp verification code. */
623
+ /** Send WhatsApp verification code. POST /api/v1/accounts/send-whatsapp-verification/ */
624
624
  async sendWhatsAppVerificationCode(
625
625
  sessionId: string,
626
626
  phoneNumber: string,
@@ -629,19 +629,15 @@ export class KYCService {
629
629
  const url = `${KYCConfig.getBackendUrl()}/accounts/send-whatsapp-verification/`;
630
630
  const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
631
631
 
632
- // 🚨 FORMATTING FIX: Strips the "+" sign (e.g., "+254712345" becomes "254712345")
633
- const formattedPhone = phoneNumber.replace(/[^0-9]/g, '');
634
-
635
632
  const res = await axios.post(
636
633
  url,
637
634
  {
638
635
  session_id: sessionId,
639
- phone_number: formattedPhone
636
+ phone_number: phoneNumber
640
637
  },
641
638
  {
642
639
  headers: {
643
640
  'Content-Type': 'application/json',
644
- 'Referer': KYCConfig.getBackendUrl(), // CSRF Protection
645
641
  ...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
646
642
  },
647
643
  }
@@ -649,39 +645,30 @@ export class KYCService {
649
645
  return res.data;
650
646
  }
651
647
 
652
- /** Verify WhatsApp code with OTP. */
648
+ /** Verify WhatsApp code with OTP. POST /api/v1/accounts/verify-whatsapp-verification/ */
653
649
  async verifyWhatsAppCode(
654
650
  sessionId: string,
655
651
  otp: string,
656
- phoneNumber: string,
657
652
  auth?: { apiKey?: string; token?: string }
658
653
  ): Promise<unknown> {
659
- const url = `${KYCConfig.getBackendUrl()}/accounts/verify-whatsapp-code/`;
654
+ // Note: Verify this endpoint matches your exact Django/backend route
655
+ const url = `${KYCConfig.getBackendUrl()}/accounts/verify-whatsapp-verification/`;
660
656
  const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
661
657
 
662
- const formattedPhone = phoneNumber.replace(/[^0-9]/g, '');
663
- const cleanOtp = otp.replace(/[^0-9]/g, '');
664
-
665
- try {
666
- const res = await axios.post(
667
- url,
668
- {
669
- session_id: sessionId,
670
- phone_number: formattedPhone,
671
- verification_code: cleanOtp
658
+ const res = await axios.post(
659
+ url,
660
+ {
661
+ session_id: sessionId,
662
+ otp: otp
663
+ }, // Adjust this payload if your backend also expects 'phone_number' here
664
+ {
665
+ headers: {
666
+ 'Content-Type': 'application/json',
667
+ ...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
672
668
  },
673
- {
674
- headers: {
675
- 'Content-Type': 'application/json',
676
- ...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
677
- },
678
- }
679
- );
680
- return res.data;
681
- } catch (error: any) {
682
- console.error("WhatsApp Verify API Error: ", error.response?.data || error.message);
683
- throw error;
684
- }
669
+ }
670
+ );
671
+ return res.data;
685
672
  }
686
673
  }
687
674
 
@@ -727,11 +714,12 @@ export const authentification = async (): Promise<string> => {
727
714
  activeAuthRequest = (async () => {
728
715
  logger.log('Authenticating: Fetching new Keycloak token...');
729
716
 
730
-
717
+ // 🚨 FIX: Do NOT use URLSearchParams in React Native with Axios.
718
+ // Use a raw URL-encoded string to guarantee Keycloak understands the payload.
731
719
  const params = 'client_id=kyc_frontend&client_secret=QhgAmvKgmwODzsEp98dnA4PeUEMMaFHd&grant_type=client_credentials';
732
720
 
733
721
  const res = await axios.post(
734
- `https://keycloak.SanctumKey.net/realms/kyc/protocol/openid-connect/token`,
722
+ `https://keycloak.transfergratis.net/realms/kyc/protocol/openid-connect/token`,
735
723
  params,
736
724
  {
737
725
  headers: {
@@ -759,6 +747,7 @@ export const authentification = async (): Promise<string> => {
759
747
  } catch (error: any) {
760
748
  cachedToken = null; // Clear bad cache
761
749
 
750
+ // 🚨 FIX: Extract Keycloak's exact error message so it doesn't log as {}
762
751
  const safeErrorMessage =
763
752
  error?.response?.data?.error_description ||
764
753
  error?.response?.data?.error ||