@transfergratis/react-native-sdk 0.1.5 → 0.1.7

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 (60) hide show
  1. package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
  2. package/build/components/KYCElements/CountrySelectionTemplate.js +7 -1
  3. package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
  4. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts +1 -1
  5. package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
  6. package/build/components/KYCElements/SelfieCaptureTemplate.js +32 -3
  7. package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
  8. package/build/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
  9. package/build/components/KYCElements/VerificationProgressTemplate.js +106 -5
  10. package/build/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
  11. package/build/components/TemplateKYCExample.d.ts +4 -1
  12. package/build/components/TemplateKYCExample.d.ts.map +1 -1
  13. package/build/components/TemplateKYCExample.js +4 -4
  14. package/build/components/TemplateKYCExample.js.map +1 -1
  15. package/build/components/TemplateKYCFlowRefactored.d.ts +3 -2
  16. package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
  17. package/build/components/TemplateKYCFlowRefactored.js +2 -2
  18. package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
  19. package/build/hooks/useTemplateKYCFlow.d.ts +5 -3
  20. package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
  21. package/build/hooks/useTemplateKYCFlow.js +89 -74
  22. package/build/hooks/useTemplateKYCFlow.js.map +1 -1
  23. package/build/index.d.ts +1 -0
  24. package/build/index.d.ts.map +1 -1
  25. package/build/index.js +2 -0
  26. package/build/index.js.map +1 -1
  27. package/build/modules/api/KYCService.d.ts +2 -1
  28. package/build/modules/api/KYCService.d.ts.map +1 -1
  29. package/build/modules/api/KYCService.js +17 -61
  30. package/build/modules/api/KYCService.js.map +1 -1
  31. package/build/modules/api/types.d.ts +25 -0
  32. package/build/modules/api/types.d.ts.map +1 -1
  33. package/build/modules/api/types.js.map +1 -1
  34. package/build/types/KYC.types.d.ts +2 -5
  35. package/build/types/KYC.types.d.ts.map +1 -1
  36. package/build/types/KYC.types.js.map +1 -1
  37. package/build/utils/cropByObb.js +4 -4
  38. package/build/utils/cropByObb.js.map +1 -1
  39. package/build/web/WebKYCEntry.d.ts +9 -0
  40. package/build/web/WebKYCEntry.d.ts.map +1 -0
  41. package/build/web/WebKYCEntry.js +156 -0
  42. package/build/web/WebKYCEntry.js.map +1 -0
  43. package/build/web/index.d.ts +2 -0
  44. package/build/web/index.d.ts.map +1 -0
  45. package/build/web/index.js +2 -0
  46. package/build/web/index.js.map +1 -0
  47. package/package.json +4 -4
  48. package/src/components/KYCElements/CountrySelectionTemplate.tsx +8 -1
  49. package/src/components/KYCElements/SelfieCaptureTemplate.tsx +37 -7
  50. package/src/components/KYCElements/VerificationProgressTemplate.tsx +129 -6
  51. package/src/components/TemplateKYCExample.tsx +6 -5
  52. package/src/components/TemplateKYCFlowRefactored.tsx +6 -2
  53. package/src/hooks/useTemplateKYCFlow.tsx +105 -77
  54. package/src/index.ts +3 -0
  55. package/src/modules/api/KYCService.ts +21 -74
  56. package/src/modules/api/types.ts +30 -3
  57. package/src/types/KYC.types.ts +4 -5
  58. package/src/utils/cropByObb.ts +5 -5
  59. package/src/web/WebKYCEntry.tsx +215 -0
  60. package/src/web/index.ts +1 -0
@@ -1,8 +1,9 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
3
3
  import { TemplateComponent } from '../../types/KYC.types';
4
4
  import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
5
5
  import { useI18n } from '../../hooks/useI18n';
6
+ import kycService from '../../modules/api/KYCService';
6
7
 
7
8
  interface VerificationProgressTemplateProps {
8
9
  component: TemplateComponent;
@@ -15,18 +16,124 @@ interface VerificationProgressTemplateProps {
15
16
  export const VerificationProgressTemplate: React.FC<VerificationProgressTemplateProps> = () => {
16
17
  const { t } = useI18n();
17
18
  const { state, actions } = useTemplateKYCFlowContext();
19
+ const [retryCount, setRetryCount] = useState(0);
20
+ const [isRetrying, setIsRetrying] = useState(false);
21
+ const [timeoutId, setTimeoutId] = useState<number | null>(null);
18
22
 
19
23
  const verification = state.verification;
20
24
 
21
25
  const isSuccess = verification.status === 'success';
22
26
  const isFailed = verification.status === 'failed';
23
27
 
28
+ // Fonction pour récupérer le résultat de vérification avec retry
29
+ const getVerificationResult = async (currentRetryCount = 0, maxRetries = 40) => {
30
+ try {
31
+ console.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
32
+
33
+ const result = await kycService.getVerificationResult(state.session.session_id);
34
+ const verificationResult = result[state.session.session_id].data;
35
+
36
+ console.log('getVerificationResult result', JSON.stringify(result, null, 2));
37
+
38
+ // Vérifier le statut de vérification
39
+ if (verificationResult.verification_status === null || verificationResult.verification_status === "processing" || verificationResult.verification_status === "pending") {
40
+ if (currentRetryCount < maxRetries) {
41
+ const nextRetryCount = currentRetryCount + 1;
42
+ setRetryCount(nextRetryCount);
43
+ setIsRetrying(true);
44
+
45
+ console.log(`Verification still processing, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
46
+
47
+ // Nettoyer le timeout précédent s'il existe
48
+ if (timeoutId) {
49
+ clearTimeout(timeoutId);
50
+ }
51
+
52
+ // Attendre 10 secondes avant de relancer
53
+ const newTimeoutId = setTimeout(() => {
54
+ getVerificationResult(nextRetryCount, maxRetries);
55
+ }, 10000);
56
+
57
+ setTimeoutId(newTimeoutId);
58
+ return; // Sortir de la fonction pour éviter de traiter le résultat
59
+ } else {
60
+ console.error('Max retries reached, verification still processing');
61
+ setIsRetrying(false);
62
+ return;
63
+ }
64
+ }
65
+
66
+ // Traiter le résultat final (success, failed, etc.)
67
+ if (verificationResult.verification_status === "completed" ||
68
+ verificationResult.verification_status === "approved") {
69
+ // Mettre à jour l'état avec le succès
70
+ actions.setVerificationState({
71
+ status: 'success',
72
+ result: result
73
+ });
74
+ } else if (verificationResult.verification_status === "failed" ||
75
+ verificationResult.verification_status === "rejected") {
76
+ // Mettre à jour l'état avec l'échec
77
+ actions.setVerificationState({
78
+ status: 'failed',
79
+ result: {
80
+ referenceId: verificationResult.verification_id,
81
+ issues: ['Verification failed']
82
+ } as any
83
+ });
84
+ }
85
+
86
+ setIsRetrying(false);
87
+
88
+ } catch (error) {
89
+ console.error('getVerificationResult error', error);
90
+
91
+ // En cas d'erreur, on peut aussi retry
92
+ if (currentRetryCount < maxRetries) {
93
+ const nextRetryCount = currentRetryCount + 1;
94
+ setRetryCount(nextRetryCount);
95
+ setIsRetrying(true);
96
+
97
+ console.log(`Error occurred, retrying in 10s... (${nextRetryCount}/${maxRetries})`);
98
+
99
+ // Nettoyer le timeout précédent s'il existe
100
+ if (timeoutId) {
101
+ clearTimeout(timeoutId);
102
+ }
103
+
104
+ const newTimeoutId = setTimeout(() => {
105
+ getVerificationResult(nextRetryCount, maxRetries);
106
+ }, 10000);
107
+
108
+ setTimeoutId(newTimeoutId);
109
+ } else {
110
+ setIsRetrying(false);
111
+ console.error('Max retries reached after errors');
112
+ }
113
+ }
114
+ };
115
+
116
+ useEffect(() => {
117
+ if (state.session.session_id) {
118
+ getVerificationResult();
119
+ }
120
+ }, [state.session.session_id]);
121
+
122
+ // Nettoyage des timeouts lors du démontage du composant
123
+ useEffect(() => {
124
+ return () => {
125
+ if (timeoutId) {
126
+ clearTimeout(timeoutId);
127
+ }
128
+ };
129
+ }, [timeoutId]);
130
+
24
131
  if (isSuccess) {
25
132
  return (
26
133
  <View style={styles.container}>
27
134
  <Text style={styles.title}>{t('kyc.verificationProgress.steps.complete')}</Text>
28
135
  <Text style={styles.subtitle}>{t('kyc.verificationProgress.subtitle')}</Text>
29
- <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.resetTemplate()}>
136
+ <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
30
137
  <Text style={styles.buttonText}>{t('common.continue')}</Text>
31
138
  </TouchableOpacity>
32
139
  {verification.result?.referenceId ? (
@@ -43,11 +150,11 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
43
150
  <Text style={styles.subtitle}>{t('errors.validationError')}</Text>
44
151
  <View style={styles.issuesBox}>
45
152
  <Text style={styles.issuesTitle}>{t('common.error')}</Text>
46
- {(verification.result?.issues || []).map((issue, idx) => (
153
+ {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (
47
154
  <Text key={idx} style={styles.issueItem}>• {issue}</Text>
48
155
  ))}
49
156
  </View>
50
- <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.goToComponent( state.template.components.find(c=>c.type!=='review_submit' && c.type!=='verification_progress')?.id || 0)}>
157
+ <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.goToComponent(state.template.components.find(c => c.type !== 'review_submit' && c.type !== 'verification_progress')?.id || 0)}>
51
158
  <Text style={styles.buttonText}>{t('common.retry')}</Text>
52
159
  </TouchableOpacity>
53
160
  <TouchableOpacity style={[styles.button, styles.secondary]}>
@@ -60,10 +167,21 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
60
167
  );
61
168
  }
62
169
 
170
+
171
+
172
+
173
+
174
+
175
+
63
176
  return (
64
177
  <View style={styles.container}>
65
178
  <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
66
- <Text style={styles.subtitle}>{t('kyc.verificationProgress.estimatedTime')}</Text>
179
+ <Text style={styles.subtitle}>
180
+ {isRetrying
181
+ ? `${t('kyc.verificationProgress.retrying')} (${retryCount}/10)`
182
+ : t('kyc.verificationProgress.estimatedTime')
183
+ }
184
+ </Text>
67
185
 
68
186
  <View style={styles.timeline}>
69
187
  <View style={[styles.dot, styles.done]}><Text style={styles.stepCheckmark}>✓</Text></View>
@@ -85,7 +203,12 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
85
203
  <Text style={styles.cardTitle}>{t('kyc.selfieCapture.title')}</Text>
86
204
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.analyzing')}</Text>
87
205
  <Text style={styles.cardTitle}>{t('kyc.verificationProgress.title')}</Text>
88
- <Text style={styles.cardLine}>{t('kyc.verificationProgress.status.pending')}</Text>
206
+ <Text style={styles.cardLine}>
207
+ {isRetrying
208
+ ? `${t('kyc.verificationProgress.status.processing')}...`
209
+ : t('kyc.verificationProgress.status.pending')
210
+ }
211
+ </Text>
89
212
  </View>
90
213
  </View>
91
214
  );
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { View, StyleSheet } from 'react-native';
3
3
  import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
4
- import { KYCTemplate } from '../types/KYC.types';
4
+ import { KYCTemplate, VerificationState } from '../types/KYC.types';
5
5
 
6
6
  // Template JSON basé sur votre exemple
7
7
  const advancedVerificationTemplate: KYCTemplate = {
@@ -56,7 +56,7 @@ const advancedVerificationTemplate: KYCTemplate = {
56
56
  buttonText: { en: "Confirm", fr: "Confirmer" }
57
57
  },
58
58
  config: {
59
- allowed_countries: ["CA", "FR", "CM", "US", "DE", "CI", "SN", "NG", "MA", "DZ"],
59
+ allowed_countries: ["CA", "FR", "CM", "US", "DE", "SN", "NG", "MA", "DZ","CI", "KE","GH"],
60
60
  default_country: "CA",
61
61
  required: true
62
62
  } as const
@@ -224,8 +224,8 @@ const advancedVerificationTemplate: KYCTemplate = {
224
224
  ]
225
225
  };
226
226
 
227
- export const TemplateKYCExample: React.FC<{ onComplete: (data: Record<number, any>) => void, onCancel: () => void, onError: (error: string) => void }> = ({ onComplete, onCancel, onError }) => {
228
- const handleComplete = (data: Record<number, any>) => {
227
+ export const TemplateKYCExample: React.FC<{ onComplete: (data: VerificationState) => void, onCancel: () => void, onError: (error: string) => void, language: string, API_KEY: string }> = ({ onComplete, onCancel, onError, language, API_KEY }) => {
228
+ const handleComplete = (data: VerificationState) => {
229
229
  console.log('KYC Template completed with data:', data);
230
230
  onComplete(data);
231
231
  // Ici vous pouvez envoyer les données à votre API
@@ -248,7 +248,8 @@ export const TemplateKYCExample: React.FC<{ onComplete: (data: Record<number, an
248
248
  onComplete={handleComplete}
249
249
  onError={handleError}
250
250
  onCancel={handleCancel}
251
- language="en" // ou "en" pour l'anglais
251
+ language={language} // ou "en" pour l'anglais
252
+ API_KEY={API_KEY}
252
253
  />
253
254
  </View>
254
255
  );
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { View, Text, StyleSheet, SafeAreaView, TouchableOpacity, ActivityIndicator, Dimensions } from 'react-native';
3
- import { KYCTemplate } from '../types/KYC.types';
3
+ import { KYCTemplate, VerificationState } from '../types/KYC.types';
4
4
  import { TemplateKYCFlowProvider, useTemplateKYCFlowContext } from '../hooks/useTemplateKYCFlow';
5
5
  import { useI18n } from '../hooks/useI18n';
6
6
  import { IDCardCapture } from './KYCElements/IDCardCapture';
@@ -14,10 +14,11 @@ import { VerificationProgressTemplate } from './KYCElements/VerificationProgress
14
14
 
15
15
  interface TemplateKYCFlowProps {
16
16
  template: KYCTemplate;
17
- onComplete?: (data: Record<number, unknown>) => void;
17
+ onComplete?: (data: VerificationState) => void;
18
18
  onError?: (error: string) => void;
19
19
  language?: string;
20
20
  onCancel?: () => void;
21
+ API_KEY?: string;
21
22
  }
22
23
 
23
24
  export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
@@ -26,13 +27,16 @@ export const TemplateKYCFlow: React.FC<TemplateKYCFlowProps> = ({
26
27
  onError,
27
28
  language = 'fr',
28
29
  onCancel,
30
+ API_KEY,
29
31
  }) => {
30
32
  return (
31
33
  <TemplateKYCFlowProvider
32
34
  template={template}
33
35
  onComplete={onComplete}
34
36
  onError={onError}
37
+ onCancel={onCancel}
35
38
  initialLanguage={language}
39
+ apiKey={API_KEY}
36
40
  >
37
41
  <TemplateKYCFlowContent onCancel={onCancel} />
38
42
  </TemplateKYCFlowProvider>
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useCallback, useMemo, createContext, useContext, ReactNode, useEffect } from 'react';
2
- import { KYCTemplate, TemplateState, TemplateActions, UseTemplateReturn, TemplateComponent } from '../types/KYC.types';
2
+ import { KYCTemplate, TemplateState, TemplateActions, UseTemplateReturn, TemplateComponent, GovernmentDocumentType, VerificationState } from '../types/KYC.types';
3
3
  import kycService, { authentification, truncateFields } from '../modules/api/KYCService';
4
4
  import useI18n from './useI18n';
5
5
 
@@ -22,9 +22,11 @@ const TemplateKYCFlowContext = createContext<TemplateKYCFlowContextType | undefi
22
22
  interface TemplateKYCFlowProviderProps {
23
23
  children: ReactNode;
24
24
  template: KYCTemplate;
25
- onComplete?: (data: Record<number, any>) => void;
25
+ onComplete?: (data: VerificationState) => void;
26
26
  onError?: (error: string) => void;
27
+ onCancel?: () => void;
27
28
  initialLanguage?: string;
29
+ apiKey?: string;
28
30
  }
29
31
 
30
32
  export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = ({
@@ -32,9 +34,11 @@ export const TemplateKYCFlowProvider: React.FC<TemplateKYCFlowProviderProps> = (
32
34
  template,
33
35
  onComplete,
34
36
  onError,
37
+ onCancel,
35
38
  initialLanguage = 'en',
39
+ apiKey,
36
40
  }) => {
37
- const hookResult = useTemplateKYCFlow(template, onComplete, onError, initialLanguage);
41
+ const hookResult = useTemplateKYCFlow(template, onComplete, onError, onCancel, initialLanguage, apiKey);
38
42
 
39
43
  return (
40
44
  <TemplateKYCFlowContext.Provider value={hookResult}>
@@ -54,9 +58,11 @@ export const useTemplateKYCFlowContext = (): TemplateKYCFlowContextType => {
54
58
 
55
59
  export const useTemplateKYCFlow = (
56
60
  template: KYCTemplate,
57
- onComplete?: (data: Record<number, any>) => void,
61
+ onComplete?: (data: VerificationState) => void,
58
62
  onError?: (error: string) => void,
63
+ onCancel?: () => void,
59
64
  initialLanguage: string = 'en',
65
+ apiKey?: string,
60
66
  ): UseTemplateReturn => {
61
67
 
62
68
  const { setLocale } = useI18n();
@@ -70,6 +76,80 @@ export const useTemplateKYCFlow = (
70
76
  return type === 'verification_progress';
71
77
  }, []);
72
78
 
79
+
80
+
81
+ const ensureReviewSubmitStep = useCallback((tpl: KYCTemplate): KYCTemplate => {
82
+ const hasReview = tpl.components.some(c => c.type === 'review_submit');
83
+ if (hasReview) return tpl;
84
+
85
+ const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
86
+ const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
87
+
88
+ const reviewComponent: TemplateComponent = {
89
+ id: lastId + 1,
90
+ type: 'review_submit',
91
+ order: lastOrder + 1,
92
+ labels: { en: 'Review & Submit', fr: 'Revoir & Soumettre' },
93
+ instructions: { en: 'Confirm and submit', fr: 'Confirmer et soumettre' },
94
+ ui: { buttonText: { en: 'Complete Verification', fr: 'Terminer la vérification' } },
95
+ // @ts-ignore - config unused for review component
96
+ config: {},
97
+ } as TemplateComponent;
98
+
99
+ return {
100
+ ...tpl,
101
+ components: [...tpl.components, reviewComponent],
102
+ };
103
+ }, []);
104
+
105
+ const ensureVerificationProgressStep = useCallback((tpl: KYCTemplate): KYCTemplate => {
106
+ const hasVerification = tpl.components.some(c => c.type === 'verification_progress');
107
+ if (hasVerification) return tpl;
108
+
109
+ const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
110
+ const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
111
+
112
+ const verificationComponent: TemplateComponent = {
113
+ id: lastId + 2,
114
+ type: 'verification_progress',
115
+ order: lastOrder + 2,
116
+ labels: { en: 'Verification', fr: 'Vérification' },
117
+ instructions: { en: 'We\'re reviewing your documents', fr: 'Nous analysons vos documents' },
118
+ ui: { buttonText: { en: '', fr: '' } },
119
+ // @ts-ignore - config unused for progress component
120
+ config: {},
121
+ } as TemplateComponent;
122
+
123
+ return {
124
+ ...tpl,
125
+ components: [...tpl.components, verificationComponent],
126
+ };
127
+ }, []);
128
+
129
+ const templateWithReview = useMemo(() => ensureReviewSubmitStep(template), [template, ensureReviewSubmitStep]);
130
+ const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep]);
131
+
132
+ // État du flux
133
+ const [state, setState] = useState<TemplateState>({
134
+ template: templateWithReviewAndVerification,
135
+ currentComponentIndex: 0,
136
+ completedComponents: [],
137
+ componentData: {},
138
+ errors: {},
139
+ isProcessing: false,
140
+ currentLanguage: initialLanguage,
141
+ showCustomStepper: true,
142
+ session: {
143
+ session_id: '',
144
+ token: '',
145
+ isInitialized: false,
146
+ isProcessing: false,
147
+ error: null,
148
+ },
149
+ verification: {
150
+ status: 'idle',
151
+ },
152
+ });
73
153
  const mapComponentTypeToAction = useCallback((type: TemplateComponent['type']): string | null => {
74
154
  switch (type) {
75
155
  case 'id_card':
@@ -134,14 +214,19 @@ export const useTemplateKYCFlow = (
134
214
  }
135
215
 
136
216
  if (action === 'selfie_capture') {
137
- const metatada: Record<string, any> = {};
217
+ const documents: Record<string, any> = {};
138
218
  if (rawData && typeof rawData === 'object') {
139
219
 
140
220
  Object.keys(rawData).forEach((key) => {
141
- metatada[key] = rawData[key];
221
+ documents[key] = rawData[key];
142
222
  });
143
223
  }
144
- return { ...base, metatada };
224
+ const idCardID = Object.keys(state.componentData).find((c: string) => c === "1");
225
+ if (idCardID) {
226
+ const _idCardData = state.componentData[idCardID];
227
+ return { ...base, documents, country: _idCardData?.country || '', documentType: _idCardData?.documentType as GovernmentDocumentType || 'identity_card' };
228
+ }
229
+ // return { ...base, documents };
145
230
  }
146
231
 
147
232
  if (action === 'location_permission') {
@@ -150,79 +235,12 @@ export const useTemplateKYCFlow = (
150
235
 
151
236
  // Default: wrap as metadata
152
237
  return { ...base, metadata: { ...(rawData || {}) } };
153
- }, []);
238
+ }, [state.componentData]);
154
239
  // Ensure the template contains a final review step
155
- const ensureReviewSubmitStep = useCallback((tpl: KYCTemplate): KYCTemplate => {
156
- const hasReview = tpl.components.some(c => c.type === 'review_submit');
157
- if (hasReview) return tpl;
158
240
 
159
- const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
160
- const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
161
-
162
- const reviewComponent: TemplateComponent = {
163
- id: lastId + 1,
164
- type: 'review_submit',
165
- order: lastOrder + 1,
166
- labels: { en: 'Review & Submit', fr: 'Revoir & Soumettre' },
167
- instructions: { en: 'Confirm and submit', fr: 'Confirmer et soumettre' },
168
- ui: { buttonText: { en: 'Complete Verification', fr: 'Terminer la vérification' } },
169
- // @ts-ignore - config unused for review component
170
- config: {},
171
- } as TemplateComponent;
172
241
 
173
- return {
174
- ...tpl,
175
- components: [...tpl.components, reviewComponent],
176
- };
177
- }, []);
178
242
 
179
- const ensureVerificationProgressStep = useCallback((tpl: KYCTemplate): KYCTemplate => {
180
- const hasVerification = tpl.components.some(c => c.type === 'verification_progress');
181
- if (hasVerification) return tpl;
182
243
 
183
- const lastOrder = tpl.components.reduce((acc, c) => Math.max(acc, c.order ?? 0), 0);
184
- const lastId = tpl.components.reduce((acc, c) => Math.max(acc, c.id), 0);
185
-
186
- const verificationComponent: TemplateComponent = {
187
- id: lastId + 2,
188
- type: 'verification_progress',
189
- order: lastOrder + 2,
190
- labels: { en: 'Verification', fr: 'Vérification' },
191
- instructions: { en: 'We\'re reviewing your documents', fr: 'Nous analysons vos documents' },
192
- ui: { buttonText: { en: '', fr: '' } },
193
- // @ts-ignore - config unused for progress component
194
- config: {},
195
- } as TemplateComponent;
196
-
197
- return {
198
- ...tpl,
199
- components: [...tpl.components, verificationComponent],
200
- };
201
- }, []);
202
-
203
- const templateWithReview = useMemo(() => ensureReviewSubmitStep(template), [template, ensureReviewSubmitStep]);
204
- const templateWithReviewAndVerification = useMemo(() => ensureVerificationProgressStep(templateWithReview), [templateWithReview, ensureVerificationProgressStep]);
205
- // État du flux
206
- const [state, setState] = useState<TemplateState>({
207
- template: templateWithReviewAndVerification,
208
- currentComponentIndex: 0,
209
- completedComponents: [],
210
- componentData: {},
211
- errors: {},
212
- isProcessing: false,
213
- currentLanguage: initialLanguage,
214
- showCustomStepper: true,
215
- session: {
216
- session_id: '',
217
- token: '',
218
- isInitialized: false,
219
- isProcessing: false,
220
- error: null,
221
- },
222
- verification: {
223
- status: 'idle',
224
- },
225
- });
226
244
 
227
245
  // Composant actuel
228
246
  const currentComponent = useMemo(() => {
@@ -534,7 +552,17 @@ export const useTemplateKYCFlow = (
534
552
  validateComponent: useCallback((componentId: number) => {
535
553
  return validateComponent(componentId);
536
554
  }, [validateComponent]),
555
+ // complet verification
556
+ submitVerification: useCallback(async () => {
557
+ setState(prev => ({ ...prev, isProcessing: true }));
558
+ try {
559
+ onComplete?.(state.verification);
537
560
 
561
+ } catch (error) {
562
+ setState(prev => ({ ...prev, isProcessing: false }));
563
+ }
564
+ }, [state.session.session_id, state.verification, onComplete]),
565
+
538
566
  // Soumettre le template complet
539
567
  submitTemplate: useCallback(async () => {
540
568
  // Allow submission when on the review step and all previous steps are valid
@@ -554,14 +582,14 @@ export const useTemplateKYCFlow = (
554
582
  if (!allValid) throw new Error('Certaines étapes ne sont pas complètes');
555
583
 
556
584
  // Appeler le callback de completion
557
- onComplete?.(state.componentData);
585
+ // onComplete?.(state.componentData);
558
586
 
559
587
  setState(prev => ({ ...prev, isProcessing: false }));
560
588
  } catch (error) {
561
589
  setState(prev => ({ ...prev, isProcessing: false }));
562
590
  onError?.(error instanceof Error ? error.message : 'Erreur lors de la soumission');
563
591
  }
564
- }, [state.template.components, state.currentComponentIndex, validateComponent, state.componentData, onComplete, onError]),
592
+ }, [state.template.components, state.verification, state.currentComponentIndex, validateComponent, state.componentData, onComplete, onError]),
565
593
 
566
594
  // Réinitialiser le template
567
595
  resetTemplate: useCallback(() => {
package/src/index.ts CHANGED
@@ -42,6 +42,9 @@ export { FileUploadTemplate } from './components/KYCElements/FileUploadTemplate'
42
42
  export { LocationCaptureTemplate } from './components/KYCElements/LocationCaptureTemplate';
43
43
  export { CountrySelectionTemplate } from './components/KYCElements/CountrySelectionTemplate';
44
44
 
45
+ // Export Web KYC Components
46
+ export { WebKYCEntry } from './web';
47
+
45
48
  // Export KYC Service
46
49
  export { default as KYCService } from './modules/api/KYCService';
47
50
 
@@ -1,7 +1,7 @@
1
1
  import axios from 'axios';
2
2
  import { GovernmentDocumentType, GovernmentDocumentTypeShorted, OrientationVideoResponse } from '../../types/KYC.types';
3
3
  import { ExtractMrzTextResponse } from '../../components/OverLay/type';
4
- import { SessionResponse, VerificationSessionRequest } from './types';
4
+ import { SessionResponse, VerificationResult, VerificationSessionRequest } from './types';
5
5
 
6
6
  export interface KYCRequest {
7
7
  userId: string;
@@ -42,12 +42,12 @@ export class KYCService {
42
42
  private baseURL: string;
43
43
  private apiKey: string;
44
44
  // Additional service base URLs (fixed as per current infra)
45
- private faceServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8000';
46
- private textExtractionServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8006';
47
- private mrzServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8002';
48
- private barcodeServiceURL = 'http://kyc-ecs-alb-278715158.us-east-2.elb.amazonaws.com:8000';
45
+ private faceServiceURL = 'https://kyc-engine.transfergratis.net:8000';
46
+ private textExtractionServiceURL = 'https://kyc-engine.transfergratis.net:8006';
47
+ private mrzServiceURL = 'https://kyc-engine.transfergratis.net:8002';
48
+ private barcodeServiceURL = 'https://kyc-engine.transfergratis.net:8000';
49
49
  private orientationServiceURL = 'http://18.188.180.154:8080';
50
- private backendServiceURL = 'http://16.170.133.50/api/v1';
50
+ private backendServiceURL = 'https://kyc-backend.transfergratis.net/api/v1';
51
51
 
52
52
  constructor(baseURL: string, apiKey: string) {
53
53
  this.baseURL = baseURL;
@@ -387,77 +387,15 @@ export class KYCService {
387
387
  ...({ session_id: session_id }),
388
388
  timestamp: new Date().toISOString()
389
389
  }
390
-
390
+ const url = `${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/`;
391
391
 
392
392
 
393
393
  const logPayload = truncateFields({ payloadData, session_id, step });
394
394
  console.log('verificationSession payload',
395
- JSON.stringify({ logPayload, token, path: `${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/` },
396
- null, 2));
397
-
398
- // return Promise.resolve({ success: true, message: 'Verification session successful' });
399
- // if (action === "document_upload") {
400
- // // Upload un document à la fois pour éviter les timeouts
401
- // const documents = data.documents;
402
- // const sides = Object.keys(documents);
403
- // const results = [];
404
-
405
- // for (const side of sides) {
406
- // console.log(`📤 Uploading ${side} document...`);
407
- // const startTime = Date.now();
408
-
409
- // const formData = new FormData();
410
- // formData.append('action', 'document_upload');
411
- // formData.append('session_id', session_id);
412
- // formData.append('timestamp', new Date().toISOString());
413
- // formData.append('side', side);
414
-
415
- // const fileUri = documents[side].dir;
416
- // const rnFile: any = {
417
- // uri: fileUri,
418
- // type: 'image/jpeg',
419
- // name: `id_card_${side}.jpg`
420
- // };
421
- // formData.append('front_image', rnFile);
422
-
423
- // // Ajouter MRZ si disponible
424
- // if (documents[side].mrz) {
425
- // formData.append('mrz', documents[side].mrz);
426
- // }
427
-
428
- // try {
429
- // const res = await axios.post<SessionResponse>(
430
- // `${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/`,
431
- // formData,
432
- // {
433
- // headers: {
434
- // 'Authorization': `Bearer ${token}`
435
- // // Pas de Content-Type, laissez axios le gérer
436
- // },
437
- // timeout: 30000, // 30 secondes max
438
- // maxContentLength: 50 * 1024 * 1024, // 50MB max
439
- // maxBodyLength: 50 * 1024 * 1024
440
- // }
441
- // );
442
-
443
- // const uploadTime = Date.now() - startTime;
444
- // console.log(`✅ ${side} uploaded in ${uploadTime}ms:`, res.data);
445
- // results.push({ side, result: res.data, uploadTime });
446
-
447
- // } catch (error) {
448
- // console.error(`❌ ${side} upload failed:`, error);
449
- // throw new Error(`Upload failed for ${side}: ${error}`);
450
- // }
451
- // }
452
-
453
- // return {
454
- // success: true,
455
- // message: 'All documents uploaded successfully',
456
- // results
457
- // };
458
- // }
459
-
460
- const res = await axios.post<SessionResponse>(`${this.backendServiceURL}/verification/api/kyc/sessions/${session_id}/steps/${step}/`,
395
+ JSON.stringify({ logPayload, token, path: url },
396
+ null, 2))
397
+
398
+ const res = await axios.post<SessionResponse>(url,
461
399
  payloadData,
462
400
  {
463
401
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }
@@ -471,6 +409,15 @@ export class KYCService {
471
409
  throw new Error(errorMessage(error));
472
410
  }
473
411
  }
412
+ // reultat de la verification
413
+ async getVerificationResult(session_id: string): Promise<VerificationResult> {
414
+ const token = await authentification();
415
+ const url = `${this.backendServiceURL}/verification/api/kyc/result/?session_id=${session_id}`;
416
+ const res = await axios.get<VerificationResult>(url,
417
+ { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } });
418
+ console.log('getVerificationResult res', JSON.stringify(res.data, null, 2));
419
+ return res.data;
420
+ }
474
421
  }
475
422
 
476
423
 
@@ -502,7 +449,7 @@ export const authentification = async () => {
502
449
  params.append('client_id', 'kyc_frontend');
503
450
  params.append('client_secret', 'ZCW4mGaJXWR0UuI40lM1pHNQmYLw2xvX');
504
451
  params.append('grant_type', 'client_credentials');
505
- const res = await axios.post(`http://16.170.133.50:7080/realms/kyc/protocol/openid-connect/token`,
452
+ const res = await axios.post(`https://keycloak.transfergratis.net/realms/kyc/protocol/openid-connect/token`,
506
453
  params,
507
454
  {
508
455
  headers: {