@sanctum-key/react-native-sdk 1.0.7 → 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.
- package/README.md +4 -4
- package/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkModule.kt +6 -6
- package/android/src/main/java/kyc/transfergratis/com/TransfergratisSdkView.kt +2 -2
- package/build/package.json +5 -5
- package/build/src/App.d.ts +2 -2
- package/build/src/App.d.ts.map +1 -1
- package/build/src/App.js +2 -2
- package/build/src/App.js.map +1 -1
- package/build/src/{SanctumKeySdk.types.d.ts → TransfergratisSdk.types.d.ts} +3 -3
- package/build/src/TransfergratisSdk.types.d.ts.map +1 -0
- package/build/src/TransfergratisSdk.types.js +2 -0
- package/build/src/TransfergratisSdk.types.js.map +1 -0
- package/build/src/{SanctumKeySdkModule.d.ts → TransfergratisSdkModule.d.ts} +4 -4
- package/build/src/TransfergratisSdkModule.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkModule.js → TransfergratisSdkModule.js} +2 -2
- package/build/src/TransfergratisSdkModule.js.map +1 -0
- package/build/src/{SanctumKeySdkModule.web.d.ts → TransfergratisSdkModule.web.d.ts} +4 -4
- package/build/src/TransfergratisSdkModule.web.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkModule.web.js → TransfergratisSdkModule.web.js} +3 -3
- package/build/src/TransfergratisSdkModule.web.js.map +1 -0
- package/build/src/TransfergratisSdkView.d.ts +4 -0
- package/build/src/TransfergratisSdkView.d.ts.map +1 -0
- package/build/src/TransfergratisSdkView.js +7 -0
- package/build/src/TransfergratisSdkView.js.map +1 -0
- package/build/src/TransfergratisSdkView.web.d.ts +4 -0
- package/build/src/TransfergratisSdkView.web.d.ts.map +1 -0
- package/build/src/{SanctumKeySdkView.web.js → TransfergratisSdkView.web.js} +2 -2
- package/build/src/TransfergratisSdkView.web.js.map +1 -0
- package/build/src/api/axios.js +2 -2
- package/build/src/api/axios.js.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js +16 -144
- package/build/src/components/KYCElements/PhoneVerificationTemplate.js.map +1 -1
- package/build/src/components/NativeCameraView.js +1 -1
- package/build/src/components/NativeCameraView.js.map +1 -1
- package/build/src/config/KYCConfig.js +1 -1
- package/build/src/config/KYCConfig.js.map +1 -1
- package/build/src/config/allowedDomains.js +6 -6
- package/build/src/config/allowedDomains.js.map +1 -1
- package/build/src/index.d.ts +3 -3
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +3 -3
- package/build/src/index.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +2 -1
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +19 -25
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/modules/camera/NativeCameraModule.js +17 -17
- package/build/src/modules/camera/NativeCameraModule.js.map +1 -1
- package/expo-module.config.json +2 -2
- package/ios/TransfergratisSdk.podspec +2 -2
- package/ios/TransfergratisSdkModule.swift +12 -12
- package/package.json +5 -5
- package/src/App.tsx +2 -2
- package/src/{SanctumKeySdk.types.ts → TransfergratisSdk.types.ts} +2 -2
- package/src/{SanctumKeySdkModule.ts → TransfergratisSdkModule.ts} +3 -3
- package/src/{SanctumKeySdkModule.web.ts → TransfergratisSdkModule.web.ts} +3 -3
- package/src/TransfergratisSdkView.tsx +11 -0
- package/src/{SanctumKeySdkView.web.tsx → TransfergratisSdkView.web.tsx} +2 -2
- package/src/api/axios.ts +2 -2
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +24 -184
- package/src/components/NativeCameraView.tsx +1 -1
- package/src/config/KYCConfig.ts +1 -1
- package/src/config/allowedDomains.ts +6 -6
- package/src/i18n/README.md +1 -1
- package/src/index.ts +3 -3
- package/src/modules/api/KYCService.ts +20 -30
- package/src/modules/camera/NativeCameraModule.ts +17 -17
- package/build/src/SanctumKeySdk.types.d.ts.map +0 -1
- package/build/src/SanctumKeySdk.types.js +0 -2
- package/build/src/SanctumKeySdk.types.js.map +0 -1
- package/build/src/SanctumKeySdkModule.d.ts.map +0 -1
- package/build/src/SanctumKeySdkModule.js.map +0 -1
- package/build/src/SanctumKeySdkModule.web.d.ts.map +0 -1
- package/build/src/SanctumKeySdkModule.web.js.map +0 -1
- package/build/src/SanctumKeySdkView.d.ts +0 -4
- package/build/src/SanctumKeySdkView.d.ts.map +0 -1
- package/build/src/SanctumKeySdkView.js +0 -7
- package/build/src/SanctumKeySdkView.js.map +0 -1
- package/build/src/SanctumKeySdkView.web.d.ts +0 -4
- package/build/src/SanctumKeySdkView.web.d.ts.map +0 -1
- package/build/src/SanctumKeySdkView.web.js.map +0 -1
- package/src/SanctumKeySdkView.tsx +0 -11
|
@@ -15,13 +15,13 @@ export type ErrorEventPayload = {
|
|
|
15
15
|
message: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export type
|
|
18
|
+
export type TransfergratisSdkModuleEvents = {
|
|
19
19
|
onCameraCapture: (params: CameraCaptureEventPayload) => void;
|
|
20
20
|
onFileSelected: (params: FileSelectedEventPayload) => void;
|
|
21
21
|
onError: (params: ErrorEventPayload) => void;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
export type
|
|
24
|
+
export type TransfergratisSdkViewProps = {
|
|
25
25
|
instructions: string;
|
|
26
26
|
showCamera: boolean;
|
|
27
27
|
onCapture?: (event: { nativeEvent: { action: 'capture' | 'retake' } }) => void;
|
|
@@ -2,9 +2,9 @@ import { requireNativeModule } from 'expo-modules-core';
|
|
|
2
2
|
|
|
3
3
|
import { NativeModule } from 'expo';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { TransfergratisSdkModuleEvents } from './TransfergratisSdk.types';
|
|
6
6
|
|
|
7
|
-
declare class
|
|
7
|
+
declare class TransfergratisSdkModule extends NativeModule<TransfergratisSdkModuleEvents> {
|
|
8
8
|
PI: number;
|
|
9
9
|
testModule(): Promise<string>;
|
|
10
10
|
requestCameraPermission(): Promise<boolean>;
|
|
@@ -13,4 +13,4 @@ declare class SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// This call loads the native module object from the JSI.
|
|
16
|
-
export default requireNativeModule<
|
|
16
|
+
export default requireNativeModule<TransfergratisSdkModule>('TransfergratisSdk');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { registerWebModule } from 'expo-modules-core';
|
|
2
2
|
import { NativeModule } from 'expo';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { TransfergratisSdkModuleEvents } from './TransfergratisSdk.types';
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class TransfergratisSdkModule extends NativeModule<TransfergratisSdkModuleEvents> {
|
|
7
7
|
PI = Math.PI;
|
|
8
8
|
|
|
9
9
|
async requestCameraPermission(): Promise<boolean> {
|
|
@@ -28,4 +28,4 @@ class SanctumKeySdkModule extends NativeModule<SanctumKeySdkModuleEvents> {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export default registerWebModule(
|
|
31
|
+
export default registerWebModule(TransfergratisSdkModule, 'TransfergratisSdkModule');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { requireNativeView } from 'expo';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TransfergratisSdkViewProps } from './TransfergratisSdk.types';
|
|
5
|
+
|
|
6
|
+
const NativeView: React.ComponentType<TransfergratisSdkViewProps> =
|
|
7
|
+
requireNativeView('TransfergratisSdk');
|
|
8
|
+
|
|
9
|
+
export default function TransfergratisSdkView(props: TransfergratisSdkViewProps) {
|
|
10
|
+
return <NativeView {...props} />;
|
|
11
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { TransfergratisSdkViewProps } from './TransfergratisSdk.types';
|
|
4
4
|
|
|
5
|
-
export default function
|
|
5
|
+
export default function TransfergratisSdkView(props: TransfergratisSdkViewProps) {
|
|
6
6
|
return (
|
|
7
7
|
<div>
|
|
8
8
|
{/* <iframe
|
package/src/api/axios.ts
CHANGED
|
@@ -132,12 +132,12 @@ export default HttpClient;
|
|
|
132
132
|
|
|
133
133
|
// ml service api
|
|
134
134
|
export const mlService = new HttpClient({
|
|
135
|
-
baseURL: 'https://api.ml.
|
|
135
|
+
baseURL: 'https://api.ml.transfergratis.com',
|
|
136
136
|
apiKey: 'your-api-key',
|
|
137
137
|
});
|
|
138
138
|
// backedn service api
|
|
139
139
|
export const backendService = new HttpClient({
|
|
140
|
-
baseURL: 'https://api.backend.
|
|
140
|
+
baseURL: 'https://api.backend.transfergratis.com',
|
|
141
141
|
apiKey: 'your-api-key',
|
|
142
142
|
});
|
|
143
143
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { View, Text, StyleSheet, TextInput, TouchableOpacity, Alert, Pressable
|
|
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,12 +31,7 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
44
31
|
|
|
45
32
|
// State
|
|
46
33
|
const [step, setStep] = useState<VerificationStep>('phone');
|
|
47
|
-
|
|
48
|
-
// Split phone state into code and number
|
|
49
|
-
const [countryCode, setCountryCode] = useState('+254');
|
|
50
34
|
const [phone, setPhone] = useState('');
|
|
51
|
-
const [showCountryPicker, setShowCountryPicker] = useState(false);
|
|
52
|
-
|
|
53
35
|
const [otp, setOtp] = useState('');
|
|
54
36
|
const [localError, setLocalError] = useState<string | null>(null);
|
|
55
37
|
const [isSimulating, setIsSimulating] = useState(false);
|
|
@@ -80,12 +62,10 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
80
62
|
setLocalError(null);
|
|
81
63
|
setIsSimulating(true);
|
|
82
64
|
|
|
83
|
-
// Combine code and number for the API
|
|
84
|
-
const fullPhoneNumber = `${countryCode}${trimmedPhone}`;
|
|
85
|
-
|
|
86
65
|
try {
|
|
87
|
-
await kycService.sendWhatsAppVerificationCode(sessionId,
|
|
66
|
+
await kycService.sendWhatsAppVerificationCode(sessionId, trimmedPhone, auth);
|
|
88
67
|
setStep('otp');
|
|
68
|
+
// Auto-focus the OTP input shortly after switching steps
|
|
89
69
|
setTimeout(() => inputRef.current?.focus(), 100);
|
|
90
70
|
} catch (err: any) {
|
|
91
71
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send verification code');
|
|
@@ -103,19 +83,16 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
103
83
|
|
|
104
84
|
setLocalError(null);
|
|
105
85
|
setIsSimulating(true);
|
|
106
|
-
|
|
107
|
-
const fullPhoneNumber = `${countryCode}${phone.trim()}`;
|
|
108
86
|
|
|
109
87
|
try {
|
|
110
|
-
await kycService.verifyWhatsAppCode(sessionId, otp.trim(),
|
|
111
|
-
|
|
112
|
-
const data = { phone: fullPhoneNumber, otp, verified: true };
|
|
88
|
+
await kycService.verifyWhatsAppCode(sessionId, otp.trim(), auth);
|
|
89
|
+
const data = { phone, otp, verified: true };
|
|
113
90
|
onValueChange(data);
|
|
114
91
|
actions.nextComponent(data);
|
|
115
92
|
} catch (err: any) {
|
|
116
93
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.wrongCode') || 'Invalid verification code');
|
|
117
94
|
setLocalError(typeof msg === 'string' ? msg : JSON.stringify(msg));
|
|
118
|
-
setOtp('');
|
|
95
|
+
setOtp(''); // Clear the boxes on error so they can type again
|
|
119
96
|
inputRef.current?.focus();
|
|
120
97
|
} finally {
|
|
121
98
|
setIsSimulating(false);
|
|
@@ -123,13 +100,12 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
123
100
|
};
|
|
124
101
|
|
|
125
102
|
const onChangePhone = (text: string) => {
|
|
126
|
-
|
|
127
|
-
const cleaned = text.replace(/[^0-9]/g, '');
|
|
128
|
-
setPhone(cleaned);
|
|
103
|
+
setPhone(text);
|
|
129
104
|
if (localError) setLocalError(null);
|
|
130
105
|
};
|
|
131
106
|
|
|
132
107
|
const onChangeOtp = (text: string) => {
|
|
108
|
+
// Only allow numbers
|
|
133
109
|
const cleaned = text.replace(/[^0-9]/g, '');
|
|
134
110
|
setOtp(cleaned);
|
|
135
111
|
if (localError) setLocalError(null);
|
|
@@ -171,35 +147,22 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
171
147
|
<View style={styles.container}>
|
|
172
148
|
<Text style={styles.title}>{title}</Text>
|
|
173
149
|
<Text style={styles.instructions}>
|
|
174
|
-
{step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${
|
|
150
|
+
{step === 'phone' ? instructions : (t('kyc.enterCodeSent') || `Please enter the code sent to ${phone}`)}
|
|
175
151
|
</Text>
|
|
176
152
|
|
|
177
153
|
<View style={styles.contentContainer}>
|
|
178
154
|
{step === 'phone' ? (
|
|
179
155
|
<View style={styles.inputContainer}>
|
|
180
156
|
<Text style={styles.label}>{t('common.phone') || 'Phone Number'}</Text>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<Text style={styles.dropdownIcon}>▼</Text>
|
|
191
|
-
</TouchableOpacity>
|
|
192
|
-
|
|
193
|
-
<TextInput
|
|
194
|
-
style={styles.phoneInput}
|
|
195
|
-
placeholder="712 345 678"
|
|
196
|
-
value={phone}
|
|
197
|
-
onChangeText={onChangePhone}
|
|
198
|
-
keyboardType="phone-pad"
|
|
199
|
-
autoComplete="tel"
|
|
200
|
-
editable={!isSimulating}
|
|
201
|
-
/>
|
|
202
|
-
</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
|
+
/>
|
|
203
166
|
</View>
|
|
204
167
|
) : (
|
|
205
168
|
<View style={styles.inputContainer}>
|
|
@@ -207,6 +170,7 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
207
170
|
|
|
208
171
|
<View style={styles.otpWrapper}>
|
|
209
172
|
{renderOtpBoxes()}
|
|
173
|
+
{/* Hidden TextInput overlaid to handle native keyboard & pasting seamlessly */}
|
|
210
174
|
<TextInput
|
|
211
175
|
ref={inputRef}
|
|
212
176
|
style={styles.hiddenInput}
|
|
@@ -246,12 +210,11 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
246
210
|
if (isSimulating) return;
|
|
247
211
|
setLocalError(null);
|
|
248
212
|
setIsSimulating(true);
|
|
249
|
-
const fullPhoneNumber = `${countryCode}${phone.trim()}`;
|
|
250
213
|
try {
|
|
251
|
-
await kycService.sendWhatsAppVerificationCode(sessionId,
|
|
214
|
+
await kycService.sendWhatsAppVerificationCode(sessionId, phone.trim(), auth);
|
|
252
215
|
Alert.alert(
|
|
253
216
|
t('common.codeResent') || 'Code Resent',
|
|
254
|
-
t('common.codeResentMessage', { email:
|
|
217
|
+
t('common.codeResentMessage', { email: phone }) || 'Code resent to ' + phone
|
|
255
218
|
);
|
|
256
219
|
} catch (err: any) {
|
|
257
220
|
const msg = errorMessage(err) ?? err?.message ?? (t('errors.sendCodeFailed') || 'Failed to send code');
|
|
@@ -267,45 +230,6 @@ export const PhoneVerificationTemplate: React.FC<PhoneVerificationTemplateProps>
|
|
|
267
230
|
</TouchableOpacity>
|
|
268
231
|
)}
|
|
269
232
|
</View>
|
|
270
|
-
|
|
271
|
-
{/* 🚨 COUNTRY PICKER MODAL */}
|
|
272
|
-
<Modal
|
|
273
|
-
visible={showCountryPicker}
|
|
274
|
-
animationType="slide"
|
|
275
|
-
transparent={true}
|
|
276
|
-
onRequestClose={() => setShowCountryPicker(false)}
|
|
277
|
-
>
|
|
278
|
-
<TouchableOpacity
|
|
279
|
-
style={styles.modalOverlay}
|
|
280
|
-
activeOpacity={1}
|
|
281
|
-
onPress={() => setShowCountryPicker(false)}
|
|
282
|
-
>
|
|
283
|
-
<View style={styles.modalContent}>
|
|
284
|
-
<View style={styles.modalHeader}>
|
|
285
|
-
<Text style={styles.modalTitle}>Select Country</Text>
|
|
286
|
-
<TouchableOpacity onPress={() => setShowCountryPicker(false)}>
|
|
287
|
-
<Text style={styles.modalClose}>✕</Text>
|
|
288
|
-
</TouchableOpacity>
|
|
289
|
-
</View>
|
|
290
|
-
<FlatList
|
|
291
|
-
data={COUNTRY_CODES}
|
|
292
|
-
keyExtractor={(item) => item.code}
|
|
293
|
-
renderItem={({ item }) => (
|
|
294
|
-
<TouchableOpacity
|
|
295
|
-
style={styles.countryItem}
|
|
296
|
-
onPress={() => {
|
|
297
|
-
setCountryCode(item.code);
|
|
298
|
-
setShowCountryPicker(false);
|
|
299
|
-
}}
|
|
300
|
-
>
|
|
301
|
-
<Text style={styles.countryItemLabel}>{item.label}</Text>
|
|
302
|
-
{countryCode === item.code && <Text style={styles.checkMark}>✓</Text>}
|
|
303
|
-
</TouchableOpacity>
|
|
304
|
-
)}
|
|
305
|
-
/>
|
|
306
|
-
</View>
|
|
307
|
-
</TouchableOpacity>
|
|
308
|
-
</Modal>
|
|
309
233
|
</View>
|
|
310
234
|
);
|
|
311
235
|
};
|
|
@@ -348,37 +272,7 @@ const styles = StyleSheet.create({
|
|
|
348
272
|
marginBottom: 8,
|
|
349
273
|
marginLeft: 4,
|
|
350
274
|
},
|
|
351
|
-
|
|
352
|
-
// --- Phone Row Styles ---
|
|
353
|
-
phoneInputRow: {
|
|
354
|
-
flexDirection: 'row',
|
|
355
|
-
alignItems: 'center',
|
|
356
|
-
gap: 10, // Space between picker and input
|
|
357
|
-
},
|
|
358
|
-
countryPickerBtn: {
|
|
359
|
-
flexDirection: 'row',
|
|
360
|
-
alignItems: 'center',
|
|
361
|
-
justifyContent: 'space-between',
|
|
362
|
-
borderWidth: 1,
|
|
363
|
-
borderColor: '#e0e0e0',
|
|
364
|
-
paddingHorizontal: 12,
|
|
365
|
-
paddingVertical: 16,
|
|
366
|
-
borderRadius: 12,
|
|
367
|
-
backgroundColor: '#f8f9fa',
|
|
368
|
-
minWidth: 90,
|
|
369
|
-
},
|
|
370
|
-
countryPickerText: {
|
|
371
|
-
fontSize: 16,
|
|
372
|
-
color: '#333',
|
|
373
|
-
fontWeight: '600',
|
|
374
|
-
},
|
|
375
|
-
dropdownIcon: {
|
|
376
|
-
fontSize: 12,
|
|
377
|
-
color: '#666',
|
|
378
|
-
marginLeft: 8,
|
|
379
|
-
},
|
|
380
|
-
phoneInput: {
|
|
381
|
-
flex: 1, // Takes up remaining space
|
|
275
|
+
input: {
|
|
382
276
|
borderWidth: 1,
|
|
383
277
|
borderColor: '#e0e0e0',
|
|
384
278
|
padding: 16,
|
|
@@ -387,58 +281,6 @@ const styles = StyleSheet.create({
|
|
|
387
281
|
backgroundColor: '#f8f9fa',
|
|
388
282
|
color: '#333',
|
|
389
283
|
},
|
|
390
|
-
|
|
391
|
-
// --- Country Modal Styles ---
|
|
392
|
-
modalOverlay: {
|
|
393
|
-
flex: 1,
|
|
394
|
-
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
395
|
-
justifyContent: 'flex-end',
|
|
396
|
-
},
|
|
397
|
-
modalContent: {
|
|
398
|
-
backgroundColor: 'white',
|
|
399
|
-
borderTopLeftRadius: 24,
|
|
400
|
-
borderTopRightRadius: 24,
|
|
401
|
-
maxHeight: '60%',
|
|
402
|
-
paddingBottom: 40,
|
|
403
|
-
},
|
|
404
|
-
modalHeader: {
|
|
405
|
-
flexDirection: 'row',
|
|
406
|
-
justifyContent: 'space-between',
|
|
407
|
-
alignItems: 'center',
|
|
408
|
-
padding: 20,
|
|
409
|
-
borderBottomWidth: 1,
|
|
410
|
-
borderBottomColor: '#f0f0f0',
|
|
411
|
-
},
|
|
412
|
-
modalTitle: {
|
|
413
|
-
fontSize: 18,
|
|
414
|
-
fontWeight: '700',
|
|
415
|
-
color: '#1a1a1a',
|
|
416
|
-
},
|
|
417
|
-
modalClose: {
|
|
418
|
-
fontSize: 20,
|
|
419
|
-
color: '#666',
|
|
420
|
-
padding: 5,
|
|
421
|
-
},
|
|
422
|
-
countryItem: {
|
|
423
|
-
flexDirection: 'row',
|
|
424
|
-
justifyContent: 'space-between',
|
|
425
|
-
alignItems: 'center',
|
|
426
|
-
paddingVertical: 16,
|
|
427
|
-
paddingHorizontal: 24,
|
|
428
|
-
borderBottomWidth: 1,
|
|
429
|
-
borderBottomColor: '#f8f9fa',
|
|
430
|
-
},
|
|
431
|
-
countryItemLabel: {
|
|
432
|
-
fontSize: 16,
|
|
433
|
-
color: '#333',
|
|
434
|
-
},
|
|
435
|
-
checkMark: {
|
|
436
|
-
color: '#2DBD60',
|
|
437
|
-
fontSize: 18,
|
|
438
|
-
fontWeight: 'bold',
|
|
439
|
-
},
|
|
440
|
-
|
|
441
|
-
// --- OTP Styles ---
|
|
442
284
|
otpWrapper: {
|
|
443
285
|
position: 'relative',
|
|
444
286
|
width: '100%',
|
|
@@ -453,7 +295,7 @@ const styles = StyleSheet.create({
|
|
|
453
295
|
},
|
|
454
296
|
otpBox: {
|
|
455
297
|
width: '14%',
|
|
456
|
-
aspectRatio: 1,
|
|
298
|
+
aspectRatio: 1, // keeps it perfectly square
|
|
457
299
|
borderWidth: 1,
|
|
458
300
|
borderColor: '#e0e0e0',
|
|
459
301
|
borderRadius: 12,
|
|
@@ -481,10 +323,8 @@ const styles = StyleSheet.create({
|
|
|
481
323
|
left: 0,
|
|
482
324
|
width: '100%',
|
|
483
325
|
height: '100%',
|
|
484
|
-
opacity: 0,
|
|
326
|
+
opacity: 0, // completely invisible but handles native keyboard interactions perfectly
|
|
485
327
|
},
|
|
486
|
-
|
|
487
|
-
// --- General Styles ---
|
|
488
328
|
errorText: {
|
|
489
329
|
color: '#dc2626',
|
|
490
330
|
marginBottom: 16,
|
|
@@ -10,7 +10,7 @@ export interface NativeCameraViewProps {
|
|
|
10
10
|
onError?: (event: any) => void;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const NativeCameraViewComponent = requireNativeViewManager('
|
|
13
|
+
const NativeCameraViewComponent = requireNativeViewManager('TransfergratisSdk_TransfergratisSdkView');
|
|
14
14
|
|
|
15
15
|
export const NativeCameraView: React.FC<NativeCameraViewProps> = (props) => {
|
|
16
16
|
|
package/src/config/KYCConfig.ts
CHANGED
|
@@ -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.
|
|
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
|
-
'
|
|
16
|
-
'www.
|
|
17
|
-
'admin.
|
|
18
|
-
'dashboard.
|
|
19
|
-
'preweb.
|
|
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.
|
|
62
|
+
// Subdomain match (e.g., app.transfergratis.com matches transfergratis.com)
|
|
63
63
|
if (domain.endsWith('.' + allowedDomain)) {
|
|
64
64
|
return true;
|
|
65
65
|
}
|
package/src/i18n/README.md
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './
|
|
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
|
|
11
|
+
export { TemplateKYCExample as LaunchTransferGratisKYC } from './components/TemplateKYCExample';
|
|
12
12
|
// Backward compatibility for existing integrations using the typo.
|
|
13
|
-
export { TemplateKYCExample as
|
|
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.
|
|
64
|
-
private textExtractionServiceURL = 'https://kyc-engine.
|
|
65
|
-
private mrzServiceURL = 'https://kyc-engine.
|
|
66
|
-
private barcodeServiceURL = 'https://kyc-engine.
|
|
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) {
|
|
@@ -645,40 +645,30 @@ export class KYCService {
|
|
|
645
645
|
return res.data;
|
|
646
646
|
}
|
|
647
647
|
|
|
648
|
+
/** Verify WhatsApp code with OTP. POST /api/v1/accounts/verify-whatsapp-verification/ */
|
|
648
649
|
async verifyWhatsAppCode(
|
|
649
650
|
sessionId: string,
|
|
650
651
|
otp: string,
|
|
651
|
-
phoneNumber: string,
|
|
652
652
|
auth?: { apiKey?: string; token?: string }
|
|
653
653
|
): Promise<unknown> {
|
|
654
|
-
|
|
654
|
+
// Note: Verify this endpoint matches your exact Django/backend route
|
|
655
655
|
const url = `${KYCConfig.getBackendUrl()}/accounts/verify-whatsapp-verification/`;
|
|
656
656
|
const token = auth?.apiKey ? undefined : (auth?.token ?? await authentification());
|
|
657
657
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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}` }),
|
|
665
668
|
},
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
// 🚨 THE FIX: Spoof the Referer header for Django's CSRF middleware
|
|
671
|
-
'Referer': KYCConfig.getBackendUrl(),
|
|
672
|
-
|
|
673
|
-
...(auth?.apiKey ? { 'Authorization': `ApiKey ${auth.apiKey}` } : { 'Authorization': `Bearer ${token}` }),
|
|
674
|
-
},
|
|
675
|
-
}
|
|
676
|
-
);
|
|
677
|
-
return res.data;
|
|
678
|
-
} catch (error: any) {
|
|
679
|
-
console.error("WhatsApp Verify API Error: ", error.response?.data || error.message);
|
|
680
|
-
throw error;
|
|
681
|
-
}
|
|
669
|
+
}
|
|
670
|
+
);
|
|
671
|
+
return res.data;
|
|
682
672
|
}
|
|
683
673
|
}
|
|
684
674
|
|
|
@@ -729,7 +719,7 @@ export const authentification = async (): Promise<string> => {
|
|
|
729
719
|
const params = 'client_id=kyc_frontend&client_secret=QhgAmvKgmwODzsEp98dnA4PeUEMMaFHd&grant_type=client_credentials';
|
|
730
720
|
|
|
731
721
|
const res = await axios.post(
|
|
732
|
-
`https://keycloak.
|
|
722
|
+
`https://keycloak.transfergratis.net/realms/kyc/protocol/openid-connect/token`,
|
|
733
723
|
params,
|
|
734
724
|
{
|
|
735
725
|
headers: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NativeEventEmitter, Platform } from "react-native";
|
|
2
|
-
import
|
|
2
|
+
import TransfergratisSdkModule from "../../TransfergratisSdkModule";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export interface CameraCaptureResult {
|
|
@@ -23,11 +23,11 @@ export class NativeCameraModule {
|
|
|
23
23
|
*/
|
|
24
24
|
async testModule(): Promise<string> {
|
|
25
25
|
try {
|
|
26
|
-
if (!
|
|
27
|
-
console.warn('
|
|
26
|
+
if (!TransfergratisSdkModule) {
|
|
27
|
+
console.warn('TransfergratisSdk native module not available');
|
|
28
28
|
return 'Module not available';
|
|
29
29
|
}
|
|
30
|
-
return await
|
|
30
|
+
return await TransfergratisSdkModule.testModule();
|
|
31
31
|
} catch (error) {
|
|
32
32
|
console.error('Error testing module:', error);
|
|
33
33
|
return 'Test failed';
|
|
@@ -39,17 +39,17 @@ export class NativeCameraModule {
|
|
|
39
39
|
console.log('Platform:', Platform.OS);
|
|
40
40
|
|
|
41
41
|
// Vérifier que le module natif est disponible
|
|
42
|
-
if (
|
|
43
|
-
console.log('
|
|
42
|
+
if (TransfergratisSdkModule) {
|
|
43
|
+
console.log('TransfergratisSdk module found, creating event emitter');
|
|
44
44
|
try {
|
|
45
|
-
// this.eventEmitter = new NativeEventEmitter(
|
|
45
|
+
// this.eventEmitter = new NativeEventEmitter(TransfergratisSdkModule as unknown as NativeModule);
|
|
46
46
|
console.log('Event emitter created successfully');
|
|
47
47
|
} catch (error) {
|
|
48
48
|
console.error('Error creating event emitter:', error);
|
|
49
49
|
this.eventEmitter = null;
|
|
50
50
|
}
|
|
51
51
|
} else {
|
|
52
|
-
console.warn('
|
|
52
|
+
console.warn('TransfergratisSdk native module not available');
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -60,11 +60,11 @@ export class NativeCameraModule {
|
|
|
60
60
|
console.log('requestCameraPermission');
|
|
61
61
|
|
|
62
62
|
try {
|
|
63
|
-
if (!
|
|
64
|
-
console.warn('
|
|
63
|
+
if (!TransfergratisSdkModule) {
|
|
64
|
+
console.warn('TransfergratisSdk native module not available');
|
|
65
65
|
return false;
|
|
66
66
|
}
|
|
67
|
-
return await
|
|
67
|
+
return await TransfergratisSdkModule.requestCameraPermission();
|
|
68
68
|
} catch (error) {
|
|
69
69
|
console.error('Error requesting camera permission:', error);
|
|
70
70
|
return false;
|
|
@@ -76,8 +76,8 @@ export class NativeCameraModule {
|
|
|
76
76
|
*/
|
|
77
77
|
async openCameraWithInstructions(instructions: string): Promise<CameraCaptureResult> {
|
|
78
78
|
try {
|
|
79
|
-
if (!
|
|
80
|
-
console.warn('
|
|
79
|
+
if (!TransfergratisSdkModule) {
|
|
80
|
+
console.warn('TransfergratisSdk native module not available');
|
|
81
81
|
return {
|
|
82
82
|
success: false,
|
|
83
83
|
error: 'Native module not available'
|
|
@@ -92,7 +92,7 @@ export class NativeCameraModule {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
const result = await
|
|
95
|
+
const result = await TransfergratisSdkModule.openCameraWithInstructions(instructions);
|
|
96
96
|
return {
|
|
97
97
|
success: result.success,
|
|
98
98
|
path: result.path
|
|
@@ -111,14 +111,14 @@ export class NativeCameraModule {
|
|
|
111
111
|
*/
|
|
112
112
|
async openFilePicker(allowedTypes: string[] = ['*/*']): Promise<FilePickerResult> {
|
|
113
113
|
try {
|
|
114
|
-
if (!
|
|
115
|
-
console.warn('
|
|
114
|
+
if (!TransfergratisSdkModule) {
|
|
115
|
+
console.warn('TransfergratisSdk native module not available');
|
|
116
116
|
return {
|
|
117
117
|
success: false,
|
|
118
118
|
error: 'Native module not available'
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
-
const result = await
|
|
121
|
+
const result = await TransfergratisSdkModule.openFilePicker(allowedTypes);
|
|
122
122
|
return {
|
|
123
123
|
success: result.success,
|
|
124
124
|
uri: result.uri,
|