@sanctum-key/react-native-sdk 1.0.44 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -1 +1 @@
1
- {"version":3,"file":"VerificationProgressTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/VerificationProgressTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAM1D,UAAU,iCAAiC;IACzC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,4BAA4B,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,CA2QpF,CAAC"}
1
+ {"version":3,"file":"VerificationProgressTemplate.d.ts","sourceRoot":"","sources":["../../../../src/components/KYCElements/VerificationProgressTemplate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAM1D,UAAU,iCAAiC;IACzC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,eAAO,MAAM,4BAA4B,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,CAuRpF,CAAC"}
@@ -4,19 +4,25 @@ import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
4
4
  import { useI18n } from '../../hooks/useI18n';
5
5
  import kycService, { errorMessage } from '../../modules/api/KYCService';
6
6
  import { logger } from '../../utils/logger';
7
+ const MAX_RETRIES = 40; // 40 attempts * 3 seconds = exactly 2 minutes of polling
7
8
  export const VerificationProgressTemplate = () => {
8
9
  const { t } = useI18n();
9
10
  const { state, actions } = useTemplateKYCFlowContext();
10
11
  const [retryCount, setRetryCount] = useState(0);
11
12
  const [isRetrying, setIsRetrying] = useState(false);
12
- const [timeoutId, setTimeoutId] = useState(null);
13
+ // 🚨 BULLETPROOF REFS: Prevents memory leaks and duplicate polling loops
14
+ const timeoutIdRef = useRef(null);
13
15
  const isPollingRef = useRef(false);
16
+ const isMountedRef = useRef(true);
14
17
  const verification = state.verification;
15
18
  const isSuccess = verification.status === 'success';
16
19
  const isFailed = verification.status === 'failed';
17
- const getVerificationResult = async (currentRetryCount = 0, maxRetries = 60) => {
20
+ const getVerificationResult = async (currentRetryCount = 0) => {
21
+ // If component unmounted while waiting, stop everything
22
+ if (!isMountedRef.current)
23
+ return;
18
24
  try {
19
- logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
25
+ logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${MAX_RETRIES})`);
20
26
  const result = await kycService.getVerificationResult(state.session.session_id);
21
27
  logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));
22
28
  const rootStatus = (result?.status || '').toLowerCase();
@@ -28,20 +34,19 @@ export const VerificationProgressTemplate = () => {
28
34
  issues: [result?.message || result?.reason || 'Verification failed. Sent for manual review.']
29
35
  }
30
36
  });
31
- setIsRetrying(false);
32
- isPollingRef.current = false; // Release lock
37
+ if (isMountedRef.current)
38
+ setIsRetrying(false);
39
+ isPollingRef.current = false;
33
40
  return;
34
41
  }
35
42
  // 2. Safely Extract Nested Payload
36
- let vData = result?.data || result; // Fallback to root if .data is missing
37
- // Handle stringified JSON
43
+ let vData = result?.data || result;
38
44
  if (typeof vData === 'string') {
39
45
  try {
40
46
  vData = JSON.parse(vData);
41
47
  }
42
48
  catch (e) { }
43
49
  }
44
- // Handle backend dictionaries indexed by session_id
45
50
  if (vData && typeof vData === 'object' && vData[state.session.session_id]) {
46
51
  let nested = vData[state.session.session_id];
47
52
  if (nested && nested.data) {
@@ -54,19 +59,14 @@ export const VerificationProgressTemplate = () => {
54
59
  }
55
60
  const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase();
56
61
  const vDecision = (vData.decision || vData.outcome || vData.result || '').toLowerCase();
57
- // const processingError = vData.reason || vData.error || vData.issues || vData.error_message;
58
- const selfieMatch = vData.selfie_info?.is_match; // true, false, or null
62
+ const selfieMatch = vData.selfie_info?.is_match;
59
63
  logger.log(`Parsed Status: [${vStatus}], Decision: [${vDecision}], Selfie Match: [${selfieMatch}]`);
60
- // 4. Evaluate Failures First
61
- // 5. Evaluate Definitive Success
64
+ // SUCCESS CONDITION
62
65
  if (vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' ||
63
66
  vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear' ||
64
67
  (vStatus === 'completed' && selfieMatch === true)) {
65
- // 🚨 THE FIX: Prevent False Positives (Ghost Payloads)
66
- // If it says success, but the data object is completely empty, it is actually a failure.
67
68
  const hasActualData = vData && Object.keys(vData).length > 0;
68
69
  if (!hasActualData) {
69
- logger.warn('Backend returned success, but data payload is entirely empty.');
70
70
  actions.setVerificationState({
71
71
  status: 'failed',
72
72
  result: {
@@ -74,89 +74,105 @@ export const VerificationProgressTemplate = () => {
74
74
  issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']
75
75
  }
76
76
  });
77
- setIsRetrying(false);
77
+ if (isMountedRef.current)
78
+ setIsRetrying(false);
78
79
  isPollingRef.current = false;
79
80
  return;
80
81
  }
81
- // If we have data, proceed to actual success
82
82
  actions.setVerificationState({
83
83
  status: 'success',
84
- result: {
85
- ...result,
86
- referenceId: vData.verification_id || vData.session_id || state.session.session_id
87
- }
84
+ result: { ...result, referenceId: vData.verification_id || vData.session_id || state.session.session_id }
88
85
  });
89
- setIsRetrying(false);
86
+ if (isMountedRef.current)
87
+ setIsRetrying(false);
90
88
  isPollingRef.current = false;
91
89
  return;
92
90
  }
91
+ // PENDING/PROCESSING CONDITION
93
92
  if (vStatus === 'processing' || vStatus === 'pending' || vStatus === 'in_progress' ||
94
93
  vStatus === 'initiated' || (vStatus === 'completed' && selfieMatch === null) || !vStatus) {
95
- if (currentRetryCount < maxRetries) {
94
+ if (currentRetryCount < MAX_RETRIES) {
96
95
  const nextRetryCount = currentRetryCount + 1;
97
- setRetryCount(nextRetryCount);
98
- setIsRetrying(true);
99
- logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${maxRetries})`);
100
- if (timeoutId)
101
- clearTimeout(timeoutId);
102
- const newTimeoutId = setTimeout(() => {
103
- getVerificationResult(nextRetryCount, maxRetries);
96
+ if (isMountedRef.current) {
97
+ setRetryCount(nextRetryCount);
98
+ setIsRetrying(true);
99
+ }
100
+ logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);
101
+ if (timeoutIdRef.current)
102
+ clearTimeout(timeoutIdRef.current);
103
+ timeoutIdRef.current = setTimeout(() => {
104
+ getVerificationResult(nextRetryCount);
104
105
  }, 3000);
105
- setTimeoutId(newTimeoutId);
106
106
  }
107
107
  else {
108
108
  logger.error('Max retries reached, verification still processing');
109
- setIsRetrying(false);
110
- isPollingRef.current = false;
111
109
  actions.setVerificationState({
112
110
  status: 'failed',
113
111
  result: {
114
112
  referenceId: state.session.session_id,
115
- issues: ['Verification timed out. Please try again.']
113
+ issues: ['Verification timed out after maximum attempts. Please try again.']
116
114
  }
117
115
  });
116
+ if (isMountedRef.current)
117
+ setIsRetrying(false);
118
+ isPollingRef.current = false;
118
119
  }
119
120
  return;
120
121
  }
121
- // Fallback release if status is completely unknown
122
+ // UNKNOWN FALLBACK
122
123
  logger.warn(`Unknown verification status received: ${vStatus}`);
123
- setIsRetrying(false);
124
+ if (isMountedRef.current)
125
+ setIsRetrying(false);
124
126
  isPollingRef.current = false;
125
127
  }
126
128
  catch (error) {
127
129
  logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));
128
- if (currentRetryCount < maxRetries) {
130
+ if (currentRetryCount < MAX_RETRIES) {
129
131
  const nextRetryCount = currentRetryCount + 1;
130
- setRetryCount(nextRetryCount);
131
- setIsRetrying(true);
132
- logger.log(`getVerificationResult Error occurred, retrying in 3s... (${nextRetryCount}/${maxRetries})`);
133
- if (timeoutId)
134
- clearTimeout(timeoutId);
135
- const newTimeoutId = setTimeout(() => {
136
- getVerificationResult(nextRetryCount, maxRetries);
132
+ if (isMountedRef.current) {
133
+ setRetryCount(nextRetryCount);
134
+ setIsRetrying(true);
135
+ }
136
+ logger.log(`Error occurred, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);
137
+ if (timeoutIdRef.current)
138
+ clearTimeout(timeoutIdRef.current);
139
+ timeoutIdRef.current = setTimeout(() => {
140
+ getVerificationResult(nextRetryCount);
137
141
  }, 3000);
138
- setTimeoutId(newTimeoutId);
139
142
  }
140
143
  else {
141
- setIsRetrying(false);
142
- isPollingRef.current = false; // Release lock
143
144
  logger.error('Max retries reached after errors');
145
+ actions.setVerificationState({
146
+ status: 'failed',
147
+ result: {
148
+ referenceId: state.session.session_id,
149
+ issues: ['Connection failed multiple times. Please check your network and try again.']
150
+ }
151
+ });
152
+ if (isMountedRef.current)
153
+ setIsRetrying(false);
154
+ isPollingRef.current = false;
144
155
  }
145
156
  }
146
157
  };
158
+ // 1. Kick off polling when component mounts
147
159
  useEffect(() => {
160
+ isMountedRef.current = true;
148
161
  if (state.session.session_id && !isSuccess && !isFailed && !isPollingRef.current) {
149
- isPollingRef.current = true; // Lock the gate instantly
150
- getVerificationResult();
162
+ isPollingRef.current = true;
163
+ getVerificationResult(0); // Always start explicitly at 0
151
164
  }
152
165
  }, [state.session.session_id, isSuccess, isFailed]);
166
+ // 2. Strict cleanup on unmount ONLY
153
167
  useEffect(() => {
154
168
  return () => {
155
- if (timeoutId)
156
- clearTimeout(timeoutId);
157
- isPollingRef.current = false; // Reset lock on unmount
169
+ isMountedRef.current = false;
170
+ if (timeoutIdRef.current)
171
+ clearTimeout(timeoutIdRef.current);
172
+ isPollingRef.current = false;
158
173
  };
159
- }, [timeoutId]);
174
+ }, []);
175
+ // 3. Auto-submit on success
160
176
  useEffect(() => {
161
177
  let autoSubmitTimer;
162
178
  if (isSuccess) {
@@ -170,40 +186,49 @@ export const VerificationProgressTemplate = () => {
170
186
  clearTimeout(autoSubmitTimer);
171
187
  };
172
188
  }, [isSuccess, actions]);
189
+ // --- RENDER LOGIC ---
173
190
  if (isSuccess) {
174
191
  return (<View style={styles.container}>
175
192
  <Text style={styles.title}>{t('kyc.verificationProgress.steps.complete')}</Text>
176
193
  <Text style={styles.subtitle}>{t('kyc.verificationProgress.subtitle')}</Text>
194
+
177
195
  <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
178
196
  <Text style={styles.buttonText}>{t('common.continue')}</Text>
179
197
  </TouchableOpacity>
198
+
180
199
  {verification.result?.referenceId ? (<Text style={styles.refText}>{`Verification ID: ${verification.result.referenceId}`}</Text>) : null}
181
200
  </View>);
182
201
  }
183
202
  if (isFailed) {
184
203
  return (<View style={styles.container}>
185
204
  <Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>
205
+
186
206
  <View style={styles.issuesBox}>
187
207
  <Text style={styles.issuesTitle}>{t('common.error')}</Text>
188
208
  {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue, idx) => (<Text key={idx} style={styles.issueItem}>• {issue}</Text>))}
189
209
  </View>
210
+
190
211
  <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
191
212
  <Text style={styles.buttonText}>
192
213
  {state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}
193
214
  </Text>
194
215
  </TouchableOpacity>
216
+
195
217
  <TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>
196
218
  <Text style={styles.secondaryText}>
197
219
  {state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}
198
220
  </Text>
199
221
  </TouchableOpacity>
222
+
200
223
  {verification.result?.referenceId ? (<Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>) : null}
201
224
  </View>);
202
225
  }
203
226
  return (<View style={styles.container}>
204
227
  <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
205
228
  <Text style={styles.subtitle}>
206
- {isRetrying ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: 40 })}` : t('kyc.verificationProgress.estimatedTime')}
229
+ {isRetrying
230
+ ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: MAX_RETRIES })}`
231
+ : t('kyc.verificationProgress.estimatedTime')}
207
232
  </Text>
208
233
 
209
234
  <View style={styles.timeline}>
@@ -223,10 +248,10 @@ export const VerificationProgressTemplate = () => {
223
248
  <View style={styles.card}>
224
249
  <Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>
225
250
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>
226
-
251
+
227
252
  <Text style={styles.cardTitle}>{t('kyc.selfieCapture.title')}</Text>
228
253
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.analyzing')}</Text>
229
-
254
+
230
255
  <Text style={styles.cardTitle}>{t('kyc.verificationProgress.title')}</Text>
231
256
  <Text style={styles.cardLine}>
232
257
  {isRetrying ? `${t('kyc.verificationProgress.status.processing')}...` : t('kyc.verificationProgress.status.pending')}
@@ -1 +1 @@
1
- {"version":3,"file":"VerificationProgressTemplate.js","sourceRoot":"","sources":["../../../../src/components/KYCElements/VerificationProgressTemplate.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { View, Text, StyleSheet, TouchableOpacity } from 'react-native';\nimport { TemplateComponent } from '../../types/KYC.types';\nimport { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';\nimport { useI18n } from '../../hooks/useI18n';\nimport kycService, { errorMessage } from '../../modules/api/KYCService';\nimport { logger } from '../../utils/logger';\n\ninterface VerificationProgressTemplateProps {\n component: TemplateComponent;\n value: unknown;\n onValueChange: (data: unknown) => void;\n error?: string;\n language?: string;\n}\n\nexport const VerificationProgressTemplate: React.FC<VerificationProgressTemplateProps> = () => {\n const { t } = useI18n();\n const { state, actions } = useTemplateKYCFlowContext();\n const [retryCount, setRetryCount] = useState(0);\n const [isRetrying, setIsRetrying] = useState(false);\n const [timeoutId, setTimeoutId] = useState<number | null>(null);\n const isPollingRef = useRef(false);\n\n const verification = state.verification;\n const isSuccess = verification.status === 'success';\n const isFailed = verification.status === 'failed';\n\n const getVerificationResult = async (currentRetryCount = 0, maxRetries = 60) => {\n try {\n logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);\n const result: any = await kycService.getVerificationResult(state.session.session_id);\n \n logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));\n \n const rootStatus = (result?.status || '').toLowerCase();\n if (rootStatus === 'failed.' || rootStatus === 'failed' || rootStatus === 'rejected' || rootStatus === 'error') {\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: [result?.message || result?.reason || 'Verification failed. Sent for manual review.']\n } as any\n });\n setIsRetrying(false);\n isPollingRef.current = false; // Release lock\n return;\n }\n \n // 2. Safely Extract Nested Payload\n let vData = result?.data || result; // Fallback to root if .data is missing\n \n // Handle stringified JSON\n if (typeof vData === 'string') {\n try {\n vData = JSON.parse(vData);\n } catch (e) { }\n }\n \n // Handle backend dictionaries indexed by session_id\n if (vData && typeof vData === 'object' && vData[state.session.session_id]) {\n let nested = vData[state.session.session_id];\n if (nested && nested.data) {\n nested = typeof nested.data === 'string' ? JSON.parse(nested.data) : nested.data;\n }\n vData = nested;\n }\n \n if (!vData || typeof vData !== 'object') {\n throw new Error('Verification payload missing or invalid for current session');\n }\n \n const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase();\n const vDecision = (vData.decision || vData.outcome || vData.result || '').toLowerCase();\n // const processingError = vData.reason || vData.error || vData.issues || vData.error_message;\n const selfieMatch = vData.selfie_info?.is_match; // true, false, or null\n \n logger.log(`Parsed Status: [${vStatus}], Decision: [${vDecision}], Selfie Match: [${selfieMatch}]`);\n \n // 4. Evaluate Failures First\n // 5. Evaluate Definitive Success\n if (\n vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' ||\n vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear' ||\n (vStatus === 'completed' && selfieMatch === true)\n ) {\n \n // 🚨 THE FIX: Prevent False Positives (Ghost Payloads)\n // If it says success, but the data object is completely empty, it is actually a failure.\n const hasActualData = vData && Object.keys(vData).length > 0;\n \n if (!hasActualData) {\n logger.warn('Backend returned success, but data payload is entirely empty.');\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']\n } as any\n });\n setIsRetrying(false);\n isPollingRef.current = false;\n return;\n }\n\n // If we have data, proceed to actual success\n actions.setVerificationState({\n status: 'success',\n result: {\n ...result,\n referenceId: vData.verification_id || vData.session_id || state.session.session_id\n } as any\n });\n setIsRetrying(false);\n isPollingRef.current = false;\n return;\n }\n \n if (\n vStatus === 'processing' || vStatus === 'pending' || vStatus === 'in_progress' ||\n vStatus === 'initiated' || (vStatus === 'completed' && selfieMatch === null) || !vStatus\n ) {\n if (currentRetryCount < maxRetries) {\n const nextRetryCount = currentRetryCount + 1;\n setRetryCount(nextRetryCount);\n setIsRetrying(true);\n \n logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${maxRetries})`);\n \n if (timeoutId) clearTimeout(timeoutId);\n const newTimeoutId = setTimeout(() => {\n getVerificationResult(nextRetryCount, maxRetries);\n }, 3000); \n \n setTimeoutId(newTimeoutId as any);\n } else {\n logger.error('Max retries reached, verification still processing');\n setIsRetrying(false);\n isPollingRef.current = false;\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: ['Verification timed out. Please try again.']\n } as any\n });\n }\n return;\n }\n \n // Fallback release if status is completely unknown\n logger.warn(`Unknown verification status received: ${vStatus}`);\n setIsRetrying(false);\n isPollingRef.current = false;\n \n } catch (error: any) {\n logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));\n \n if (currentRetryCount < maxRetries) {\n const nextRetryCount = currentRetryCount + 1;\n setRetryCount(nextRetryCount);\n setIsRetrying(true);\n \n logger.log(`getVerificationResult Error occurred, retrying in 3s... (${nextRetryCount}/${maxRetries})`);\n \n if (timeoutId) clearTimeout(timeoutId);\n const newTimeoutId = setTimeout(() => {\n getVerificationResult(nextRetryCount, maxRetries);\n }, 3000);\n \n setTimeoutId(newTimeoutId as any);\n } else {\n setIsRetrying(false);\n isPollingRef.current = false; // Release lock\n logger.error('Max retries reached after errors');\n }\n }\n };\n\n useEffect(() => {\n if (state.session.session_id && !isSuccess && !isFailed && !isPollingRef.current) {\n isPollingRef.current = true; // Lock the gate instantly\n getVerificationResult();\n }\n }, [state.session.session_id, isSuccess, isFailed]);\n\n useEffect(() => {\n return () => {\n if (timeoutId) clearTimeout(timeoutId);\n isPollingRef.current = false; // Reset lock on unmount\n };\n }, [timeoutId]);\n\n useEffect(() => {\n let autoSubmitTimer: ReturnType<typeof setTimeout>;\n if (isSuccess) {\n logger.log(\"Verification successful. Initiating auto-submit countdown...\");\n autoSubmitTimer = setTimeout(() => {\n actions.submitVerification();\n }, 3000);\n }\n return () => {\n if (autoSubmitTimer) clearTimeout(autoSubmitTimer);\n };\n }, [isSuccess, actions]);\n\n if (isSuccess) {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.steps.complete')}</Text>\n <Text style={styles.subtitle}>{t('kyc.verificationProgress.subtitle')}</Text>\n <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>\n <Text style={styles.buttonText}>{t('common.continue')}</Text>\n </TouchableOpacity>\n {verification.result?.referenceId ? (\n <Text style={styles.refText}>{`Verification ID: ${verification.result.referenceId}`}</Text>\n ) : null}\n </View>\n );\n }\n\n if (isFailed) {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>\n <View style={styles.issuesBox}>\n <Text style={styles.issuesTitle}>{t('common.error')}</Text>\n {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (\n <Text key={idx} style={styles.issueItem}>• {issue}</Text>\n ))}\n </View>\n <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>\n <Text style={styles.buttonText}>\n {state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}\n </Text>\n </TouchableOpacity>\n <TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>\n <Text style={styles.secondaryText}>\n {state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}\n </Text>\n </TouchableOpacity>\n {verification.result?.referenceId ? (\n <Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>\n ) : null}\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>\n <Text style={styles.subtitle}>\n {isRetrying ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: 40 })}` : t('kyc.verificationProgress.estimatedTime')}\n </Text>\n\n <View style={styles.timeline}>\n <View style={[styles.dot, styles.done]}><Text style={styles.stepCheckmark}>✓</Text></View>\n <View style={styles.line} />\n <View style={[styles.dot, styles.active]}><Text style={styles.stepCheckmark}>2</Text></View>\n <View style={styles.line} />\n <View style={[styles.dot, styles.pending]}><Text style={styles.stepCheckmark}>3</Text></View>\n </View>\n\n <View style={styles.row}>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.status.completed')}</Text>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.analyzing')}</Text>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.verifying')}</Text>\n </View>\n\n <View style={styles.card}>\n <Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>\n <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>\n\n <Text style={styles.cardTitle}>{t('kyc.selfieCapture.title')}</Text>\n <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.analyzing')}</Text>\n\n <Text style={styles.cardTitle}>{t('kyc.verificationProgress.title')}</Text>\n <Text style={styles.cardLine}>\n {isRetrying ? `${t('kyc.verificationProgress.status.processing')}...` : t('kyc.verificationProgress.status.pending')}\n </Text>\n </View>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: { flex: 1, width: '100%', paddingHorizontal: 16, paddingVertical: 12 },\n title: { fontSize: 24, fontWeight: 'bold', color: '#111827', textAlign: 'center', marginTop: 12 },\n subtitle: { fontSize: 14, color: '#6B7280', textAlign: 'center', marginTop: 8 },\n timeline: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 24 },\n dot: { width: 38, height: 38, borderRadius: 34, justifyContent: 'center', alignItems: 'center' },\n stepCheckmark: { color: 'white', fontSize: 16, fontWeight: 'bold' },\n line: { flex: 1, height: 4, backgroundColor: '#E5E7EB' },\n done: { backgroundColor: '#10B981' },\n active: { backgroundColor: '#F59E0B' },\n pending: { backgroundColor: '#E5E7EB' },\n row: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 8 },\n stepLabel: { fontSize: 14, color: '#111827', fontWeight: '600' },\n card: { backgroundColor: 'white', padding: 16, borderRadius: 16, marginTop: 24 },\n cardTitle: { fontSize: 16, color: '#6B7280', marginTop: 8 },\n cardLine: { fontSize: 18, color: '#111827', fontWeight: '600', marginTop: 2 },\n button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 14 },\n primary: { backgroundColor: '#2DBD60' },\n buttonText: { color: 'white', fontSize: 16, fontWeight: '600' },\n refText: { marginTop: 12, textAlign: 'center', color: '#6B7280' },\n issuesBox: { backgroundColor: '#FEF2F2', borderRadius: 16, padding: 16, marginTop: 20 },\n issuesTitle: { color: '#991B1B', fontWeight: '700', marginBottom: 8 },\n issueItem: { color: '#991B1B', marginTop: 4 },\n secondary: { backgroundColor: '#F3F4F6', borderWidth: 1, borderColor: '#D1D5DB' },\n secondaryText: { color: '#374151', fontSize: 16, fontWeight: '600' },\n});"]}
1
+ {"version":3,"file":"VerificationProgressTemplate.js","sourceRoot":"","sources":["../../../../src/components/KYCElements/VerificationProgressTemplate.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { View, Text, StyleSheet, TouchableOpacity } from 'react-native';\nimport { TemplateComponent } from '../../types/KYC.types';\nimport { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';\nimport { useI18n } from '../../hooks/useI18n';\nimport kycService, { errorMessage } from '../../modules/api/KYCService';\nimport { logger } from '../../utils/logger';\n\ninterface VerificationProgressTemplateProps {\n component: TemplateComponent;\n value: unknown;\n onValueChange: (data: unknown) => void;\n error?: string;\n language?: string;\n}\n\nconst MAX_RETRIES = 40; // 40 attempts * 3 seconds = exactly 2 minutes of polling\n\nexport const VerificationProgressTemplate: React.FC<VerificationProgressTemplateProps> = () => {\n const { t } = useI18n();\n const { state, actions } = useTemplateKYCFlowContext();\n \n const [retryCount, setRetryCount] = useState(0);\n const [isRetrying, setIsRetrying] = useState(false);\n \n // 🚨 BULLETPROOF REFS: Prevents memory leaks and duplicate polling loops\n const timeoutIdRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isPollingRef = useRef(false);\n const isMountedRef = useRef(true); \n\n const verification = state.verification;\n const isSuccess = verification.status === 'success';\n const isFailed = verification.status === 'failed';\n\n const getVerificationResult = async (currentRetryCount = 0) => {\n // If component unmounted while waiting, stop everything\n if (!isMountedRef.current) return;\n\n try {\n logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${MAX_RETRIES})`);\n const result: any = await kycService.getVerificationResult(state.session.session_id);\n logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));\n\n const rootStatus = (result?.status || '').toLowerCase();\n if (rootStatus === 'failed.' || rootStatus === 'failed' || rootStatus === 'rejected' || rootStatus === 'error') {\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: [result?.message || result?.reason || 'Verification failed. Sent for manual review.']\n } as any\n });\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n return;\n }\n\n // 2. Safely Extract Nested Payload\n let vData = result?.data || result;\n \n if (typeof vData === 'string') {\n try { vData = JSON.parse(vData); } catch (e) { }\n }\n\n if (vData && typeof vData === 'object' && vData[state.session.session_id]) {\n let nested = vData[state.session.session_id];\n if (nested && nested.data) {\n nested = typeof nested.data === 'string' ? JSON.parse(nested.data) : nested.data;\n }\n vData = nested;\n }\n\n if (!vData || typeof vData !== 'object') {\n throw new Error('Verification payload missing or invalid for current session');\n }\n\n const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase();\n const vDecision = (vData.decision || vData.outcome || vData.result || '').toLowerCase();\n const selfieMatch = vData.selfie_info?.is_match;\n\n logger.log(`Parsed Status: [${vStatus}], Decision: [${vDecision}], Selfie Match: [${selfieMatch}]`);\n\n // SUCCESS CONDITION\n if (\n vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' ||\n vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear' ||\n (vStatus === 'completed' && selfieMatch === true)\n ) {\n const hasActualData = vData && Object.keys(vData).length > 0;\n if (!hasActualData) {\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']\n } as any\n });\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n return;\n }\n\n actions.setVerificationState({\n status: 'success',\n result: { ...result, referenceId: vData.verification_id || vData.session_id || state.session.session_id } as any\n });\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n return;\n }\n\n // PENDING/PROCESSING CONDITION\n if (\n vStatus === 'processing' || vStatus === 'pending' || vStatus === 'in_progress' ||\n vStatus === 'initiated' || (vStatus === 'completed' && selfieMatch === null) || !vStatus\n ) {\n if (currentRetryCount < MAX_RETRIES) {\n const nextRetryCount = currentRetryCount + 1;\n if (isMountedRef.current) {\n setRetryCount(nextRetryCount);\n setIsRetrying(true);\n }\n logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);\n \n if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = setTimeout(() => {\n getVerificationResult(nextRetryCount);\n }, 3000);\n } else {\n logger.error('Max retries reached, verification still processing');\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: ['Verification timed out after maximum attempts. Please try again.']\n } as any\n });\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n }\n return;\n }\n\n // UNKNOWN FALLBACK\n logger.warn(`Unknown verification status received: ${vStatus}`);\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n\n } catch (error: any) {\n logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));\n \n if (currentRetryCount < MAX_RETRIES) {\n const nextRetryCount = currentRetryCount + 1;\n if (isMountedRef.current) {\n setRetryCount(nextRetryCount);\n setIsRetrying(true);\n }\n logger.log(`Error occurred, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);\n \n if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = setTimeout(() => {\n getVerificationResult(nextRetryCount);\n }, 3000);\n } else {\n logger.error('Max retries reached after errors');\n actions.setVerificationState({\n status: 'failed',\n result: {\n referenceId: state.session.session_id,\n issues: ['Connection failed multiple times. Please check your network and try again.']\n } as any\n });\n if (isMountedRef.current) setIsRetrying(false);\n isPollingRef.current = false;\n }\n }\n };\n\n // 1. Kick off polling when component mounts\n useEffect(() => {\n isMountedRef.current = true;\n if (state.session.session_id && !isSuccess && !isFailed && !isPollingRef.current) {\n isPollingRef.current = true;\n getVerificationResult(0); // Always start explicitly at 0\n }\n }, [state.session.session_id, isSuccess, isFailed]);\n\n // 2. Strict cleanup on unmount ONLY\n useEffect(() => {\n return () => {\n isMountedRef.current = false;\n if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);\n isPollingRef.current = false;\n };\n }, []);\n\n // 3. Auto-submit on success\n useEffect(() => {\n let autoSubmitTimer: ReturnType<typeof setTimeout>;\n if (isSuccess) {\n logger.log(\"Verification successful. Initiating auto-submit countdown...\");\n autoSubmitTimer = setTimeout(() => {\n actions.submitVerification();\n }, 3000);\n }\n return () => {\n if (autoSubmitTimer) clearTimeout(autoSubmitTimer);\n };\n }, [isSuccess, actions]);\n\n // --- RENDER LOGIC ---\n\n if (isSuccess) {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.steps.complete')}</Text>\n <Text style={styles.subtitle}>{t('kyc.verificationProgress.subtitle')}</Text>\n \n <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>\n <Text style={styles.buttonText}>{t('common.continue')}</Text>\n </TouchableOpacity>\n \n {verification.result?.referenceId ? (\n <Text style={styles.refText}>{`Verification ID: ${verification.result.referenceId}`}</Text>\n ) : null}\n </View>\n );\n }\n\n if (isFailed) {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>\n \n <View style={styles.issuesBox}>\n <Text style={styles.issuesTitle}>{t('common.error')}</Text>\n {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (\n <Text key={idx} style={styles.issueItem}>• {issue}</Text>\n ))}\n </View>\n\n <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>\n <Text style={styles.buttonText}>\n {state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}\n </Text>\n </TouchableOpacity>\n\n <TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>\n <Text style={styles.secondaryText}>\n {state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}\n </Text>\n </TouchableOpacity>\n\n {verification.result?.referenceId ? (\n <Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>\n ) : null}\n </View>\n );\n }\n\n return (\n <View style={styles.container}>\n <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>\n <Text style={styles.subtitle}>\n {isRetrying\n ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: MAX_RETRIES })}`\n : t('kyc.verificationProgress.estimatedTime')}\n </Text>\n\n <View style={styles.timeline}>\n <View style={[styles.dot, styles.done]}><Text style={styles.stepCheckmark}>✓</Text></View>\n <View style={styles.line} />\n <View style={[styles.dot, styles.active]}><Text style={styles.stepCheckmark}>2</Text></View>\n <View style={styles.line} />\n <View style={[styles.dot, styles.pending]}><Text style={styles.stepCheckmark}>3</Text></View>\n </View>\n\n <View style={styles.row}>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.status.completed')}</Text>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.analyzing')}</Text>\n <Text style={styles.stepLabel}>{t('kyc.verificationProgress.steps.verifying')}</Text>\n </View>\n\n <View style={styles.card}>\n <Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>\n <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>\n \n <Text style={styles.cardTitle}>{t('kyc.selfieCapture.title')}</Text>\n <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.analyzing')}</Text>\n \n <Text style={styles.cardTitle}>{t('kyc.verificationProgress.title')}</Text>\n <Text style={styles.cardLine}>\n {isRetrying ? `${t('kyc.verificationProgress.status.processing')}...` : t('kyc.verificationProgress.status.pending')}\n </Text>\n </View>\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n container: { flex: 1, width: '100%', paddingHorizontal: 16, paddingVertical: 12 },\n title: { fontSize: 24, fontWeight: 'bold', color: '#111827', textAlign: 'center', marginTop: 12 },\n subtitle: { fontSize: 14, color: '#6B7280', textAlign: 'center', marginTop: 8 },\n timeline: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginTop: 24 },\n dot: { width: 38, height: 38, borderRadius: 34, justifyContent: 'center', alignItems: 'center' },\n stepCheckmark: { color: 'white', fontSize: 16, fontWeight: 'bold' },\n line: { flex: 1, height: 4, backgroundColor: '#E5E7EB' },\n done: { backgroundColor: '#10B981' },\n active: { backgroundColor: '#F59E0B' },\n pending: { backgroundColor: '#E5E7EB' },\n row: { flexDirection: 'row', justifyContent: 'space-between', marginTop: 8 },\n stepLabel: { fontSize: 14, color: '#111827', fontWeight: '600' },\n card: { backgroundColor: 'white', padding: 16, borderRadius: 16, marginTop: 24 },\n cardTitle: { fontSize: 16, color: '#6B7280', marginTop: 8 },\n cardLine: { fontSize: 18, color: '#111827', fontWeight: '600', marginTop: 2 },\n button: { paddingVertical: 14, borderRadius: 10, alignItems: 'center', marginTop: 14 },\n primary: { backgroundColor: '#2DBD60' },\n buttonText: { color: 'white', fontSize: 16, fontWeight: '600' },\n refText: { marginTop: 12, textAlign: 'center', color: '#6B7280' },\n issuesBox: { backgroundColor: '#FEF2F2', borderRadius: 16, padding: 16, marginTop: 20 },\n issuesTitle: { color: '#991B1B', fontWeight: '700', marginBottom: 8 },\n issueItem: { color: '#991B1B', marginTop: 4 },\n secondary: { backgroundColor: '#F3F4F6', borderWidth: 1, borderColor: '#D1D5DB' },\n secondaryText: { color: '#374151', fontSize: 16, fontWeight: '600' },\n});"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanctum-key/react-native-sdk",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "Sanctum Key React Native SDK",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -14,25 +14,33 @@ interface VerificationProgressTemplateProps {
14
14
  language?: string;
15
15
  }
16
16
 
17
+ const MAX_RETRIES = 40; // 40 attempts * 3 seconds = exactly 2 minutes of polling
18
+
17
19
  export const VerificationProgressTemplate: React.FC<VerificationProgressTemplateProps> = () => {
18
20
  const { t } = useI18n();
19
21
  const { state, actions } = useTemplateKYCFlowContext();
22
+
20
23
  const [retryCount, setRetryCount] = useState(0);
21
24
  const [isRetrying, setIsRetrying] = useState(false);
22
- const [timeoutId, setTimeoutId] = useState<number | null>(null);
25
+
26
+ // 🚨 BULLETPROOF REFS: Prevents memory leaks and duplicate polling loops
27
+ const timeoutIdRef = useRef<ReturnType<typeof setTimeout> | null>(null);
23
28
  const isPollingRef = useRef(false);
29
+ const isMountedRef = useRef(true);
24
30
 
25
31
  const verification = state.verification;
26
32
  const isSuccess = verification.status === 'success';
27
33
  const isFailed = verification.status === 'failed';
28
34
 
29
- const getVerificationResult = async (currentRetryCount = 0, maxRetries = 60) => {
35
+ const getVerificationResult = async (currentRetryCount = 0) => {
36
+ // If component unmounted while waiting, stop everything
37
+ if (!isMountedRef.current) return;
38
+
30
39
  try {
31
- logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${maxRetries + 1})`);
40
+ logger.log(`Starting verification check (attempt ${currentRetryCount + 1}/${MAX_RETRIES})`);
32
41
  const result: any = await kycService.getVerificationResult(state.session.session_id);
33
-
34
42
  logger.log('getVerificationResult raw result:', JSON.stringify(result, null, 2));
35
-
43
+
36
44
  const rootStatus = (result?.status || '').toLowerCase();
37
45
  if (rootStatus === 'failed.' || rootStatus === 'failed' || rootStatus === 'rejected' || rootStatus === 'error') {
38
46
  actions.setVerificationState({
@@ -42,22 +50,18 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
42
50
  issues: [result?.message || result?.reason || 'Verification failed. Sent for manual review.']
43
51
  } as any
44
52
  });
45
- setIsRetrying(false);
46
- isPollingRef.current = false; // Release lock
53
+ if (isMountedRef.current) setIsRetrying(false);
54
+ isPollingRef.current = false;
47
55
  return;
48
56
  }
49
-
57
+
50
58
  // 2. Safely Extract Nested Payload
51
- let vData = result?.data || result; // Fallback to root if .data is missing
52
-
53
- // Handle stringified JSON
59
+ let vData = result?.data || result;
60
+
54
61
  if (typeof vData === 'string') {
55
- try {
56
- vData = JSON.parse(vData);
57
- } catch (e) { }
62
+ try { vData = JSON.parse(vData); } catch (e) { }
58
63
  }
59
-
60
- // Handle backend dictionaries indexed by session_id
64
+
61
65
  if (vData && typeof vData === 'object' && vData[state.session.session_id]) {
62
66
  let nested = vData[state.session.session_id];
63
67
  if (nested && nested.data) {
@@ -65,132 +69,132 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
65
69
  }
66
70
  vData = nested;
67
71
  }
68
-
72
+
69
73
  if (!vData || typeof vData !== 'object') {
70
74
  throw new Error('Verification payload missing or invalid for current session');
71
75
  }
72
-
76
+
73
77
  const vStatus = (vData.verification_status || vData.status || vData.state || '').toLowerCase();
74
78
  const vDecision = (vData.decision || vData.outcome || vData.result || '').toLowerCase();
75
- // const processingError = vData.reason || vData.error || vData.issues || vData.error_message;
76
- const selfieMatch = vData.selfie_info?.is_match; // true, false, or null
77
-
79
+ const selfieMatch = vData.selfie_info?.is_match;
80
+
78
81
  logger.log(`Parsed Status: [${vStatus}], Decision: [${vDecision}], Selfie Match: [${selfieMatch}]`);
79
-
80
- // 4. Evaluate Failures First
81
- // 5. Evaluate Definitive Success
82
- if (
83
- vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' ||
84
- vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear' ||
85
- (vStatus === 'completed' && selfieMatch === true)
86
- ) {
87
-
88
- // 🚨 THE FIX: Prevent False Positives (Ghost Payloads)
89
- // If it says success, but the data object is completely empty, it is actually a failure.
90
- const hasActualData = vData && Object.keys(vData).length > 0;
91
-
92
- if (!hasActualData) {
93
- logger.warn('Backend returned success, but data payload is entirely empty.');
82
+
83
+ // SUCCESS CONDITION
84
+ if (
85
+ vStatus === 'approved' || vStatus === 'verified' || vStatus === 'success' ||
86
+ vDecision === 'approved' || vDecision === 'passed' || vDecision === 'clear' ||
87
+ (vStatus === 'completed' && selfieMatch === true)
88
+ ) {
89
+ const hasActualData = vData && Object.keys(vData).length > 0;
90
+ if (!hasActualData) {
91
+ actions.setVerificationState({
92
+ status: 'failed',
93
+ result: {
94
+ referenceId: state.session.session_id,
95
+ issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']
96
+ } as any
97
+ });
98
+ if (isMountedRef.current) setIsRetrying(false);
99
+ isPollingRef.current = false;
100
+ return;
101
+ }
102
+
94
103
  actions.setVerificationState({
95
- status: 'failed',
96
- result: {
97
- referenceId: state.session.session_id,
98
- issues: ['Document text could not be read clearly. Please retake the photo in better lighting.']
99
- } as any
104
+ status: 'success',
105
+ result: { ...result, referenceId: vData.verification_id || vData.session_id || state.session.session_id } as any
100
106
  });
101
- setIsRetrying(false);
107
+ if (isMountedRef.current) setIsRetrying(false);
102
108
  isPollingRef.current = false;
103
109
  return;
104
110
  }
105
111
 
106
- // If we have data, proceed to actual success
107
- actions.setVerificationState({
108
- status: 'success',
109
- result: {
110
- ...result,
111
- referenceId: vData.verification_id || vData.session_id || state.session.session_id
112
- } as any
113
- });
114
- setIsRetrying(false);
115
- isPollingRef.current = false;
116
- return;
117
- }
118
-
112
+ // PENDING/PROCESSING CONDITION
119
113
  if (
120
114
  vStatus === 'processing' || vStatus === 'pending' || vStatus === 'in_progress' ||
121
115
  vStatus === 'initiated' || (vStatus === 'completed' && selfieMatch === null) || !vStatus
122
116
  ) {
123
- if (currentRetryCount < maxRetries) {
117
+ if (currentRetryCount < MAX_RETRIES) {
124
118
  const nextRetryCount = currentRetryCount + 1;
125
- setRetryCount(nextRetryCount);
126
- setIsRetrying(true);
127
-
128
- logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${maxRetries})`);
129
-
130
- if (timeoutId) clearTimeout(timeoutId);
131
- const newTimeoutId = setTimeout(() => {
132
- getVerificationResult(nextRetryCount, maxRetries);
133
- }, 3000);
119
+ if (isMountedRef.current) {
120
+ setRetryCount(nextRetryCount);
121
+ setIsRetrying(true);
122
+ }
123
+ logger.log(`Verification still processing, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);
134
124
 
135
- setTimeoutId(newTimeoutId as any);
125
+ if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);
126
+ timeoutIdRef.current = setTimeout(() => {
127
+ getVerificationResult(nextRetryCount);
128
+ }, 3000);
136
129
  } else {
137
130
  logger.error('Max retries reached, verification still processing');
138
- setIsRetrying(false);
139
- isPollingRef.current = false;
140
131
  actions.setVerificationState({
141
132
  status: 'failed',
142
133
  result: {
143
134
  referenceId: state.session.session_id,
144
- issues: ['Verification timed out. Please try again.']
135
+ issues: ['Verification timed out after maximum attempts. Please try again.']
145
136
  } as any
146
137
  });
138
+ if (isMountedRef.current) setIsRetrying(false);
139
+ isPollingRef.current = false;
147
140
  }
148
141
  return;
149
142
  }
150
-
151
- // Fallback release if status is completely unknown
143
+
144
+ // UNKNOWN FALLBACK
152
145
  logger.warn(`Unknown verification status received: ${vStatus}`);
153
- setIsRetrying(false);
146
+ if (isMountedRef.current) setIsRetrying(false);
154
147
  isPollingRef.current = false;
155
-
148
+
156
149
  } catch (error: any) {
157
150
  logger.error('getVerificationResult error', JSON.stringify(errorMessage(error) || { message: error?.message || 'Unknown error' }, null, 2));
158
151
 
159
- if (currentRetryCount < maxRetries) {
152
+ if (currentRetryCount < MAX_RETRIES) {
160
153
  const nextRetryCount = currentRetryCount + 1;
161
- setRetryCount(nextRetryCount);
162
- setIsRetrying(true);
163
-
164
- logger.log(`getVerificationResult Error occurred, retrying in 3s... (${nextRetryCount}/${maxRetries})`);
154
+ if (isMountedRef.current) {
155
+ setRetryCount(nextRetryCount);
156
+ setIsRetrying(true);
157
+ }
158
+ logger.log(`Error occurred, retrying in 3s... (${nextRetryCount}/${MAX_RETRIES})`);
165
159
 
166
- if (timeoutId) clearTimeout(timeoutId);
167
- const newTimeoutId = setTimeout(() => {
168
- getVerificationResult(nextRetryCount, maxRetries);
160
+ if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);
161
+ timeoutIdRef.current = setTimeout(() => {
162
+ getVerificationResult(nextRetryCount);
169
163
  }, 3000);
170
-
171
- setTimeoutId(newTimeoutId as any);
172
164
  } else {
173
- setIsRetrying(false);
174
- isPollingRef.current = false; // Release lock
175
165
  logger.error('Max retries reached after errors');
166
+ actions.setVerificationState({
167
+ status: 'failed',
168
+ result: {
169
+ referenceId: state.session.session_id,
170
+ issues: ['Connection failed multiple times. Please check your network and try again.']
171
+ } as any
172
+ });
173
+ if (isMountedRef.current) setIsRetrying(false);
174
+ isPollingRef.current = false;
176
175
  }
177
176
  }
178
177
  };
179
178
 
179
+ // 1. Kick off polling when component mounts
180
180
  useEffect(() => {
181
+ isMountedRef.current = true;
181
182
  if (state.session.session_id && !isSuccess && !isFailed && !isPollingRef.current) {
182
- isPollingRef.current = true; // Lock the gate instantly
183
- getVerificationResult();
183
+ isPollingRef.current = true;
184
+ getVerificationResult(0); // Always start explicitly at 0
184
185
  }
185
186
  }, [state.session.session_id, isSuccess, isFailed]);
186
187
 
188
+ // 2. Strict cleanup on unmount ONLY
187
189
  useEffect(() => {
188
190
  return () => {
189
- if (timeoutId) clearTimeout(timeoutId);
190
- isPollingRef.current = false; // Reset lock on unmount
191
+ isMountedRef.current = false;
192
+ if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);
193
+ isPollingRef.current = false;
191
194
  };
192
- }, [timeoutId]);
195
+ }, []);
193
196
 
197
+ // 3. Auto-submit on success
194
198
  useEffect(() => {
195
199
  let autoSubmitTimer: ReturnType<typeof setTimeout>;
196
200
  if (isSuccess) {
@@ -204,14 +208,18 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
204
208
  };
205
209
  }, [isSuccess, actions]);
206
210
 
211
+ // --- RENDER LOGIC ---
212
+
207
213
  if (isSuccess) {
208
214
  return (
209
215
  <View style={styles.container}>
210
216
  <Text style={styles.title}>{t('kyc.verificationProgress.steps.complete')}</Text>
211
217
  <Text style={styles.subtitle}>{t('kyc.verificationProgress.subtitle')}</Text>
218
+
212
219
  <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
213
220
  <Text style={styles.buttonText}>{t('common.continue')}</Text>
214
221
  </TouchableOpacity>
222
+
215
223
  {verification.result?.referenceId ? (
216
224
  <Text style={styles.refText}>{`Verification ID: ${verification.result.referenceId}`}</Text>
217
225
  ) : null}
@@ -223,22 +231,26 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
223
231
  return (
224
232
  <View style={styles.container}>
225
233
  <Text style={styles.title}>{t('kyc.verificationProgress.status.failed')}</Text>
234
+
226
235
  <View style={styles.issuesBox}>
227
236
  <Text style={styles.issuesTitle}>{t('common.error')}</Text>
228
237
  {Array.isArray(verification.result?.issues) && verification.result.issues.map((issue: string, idx: number) => (
229
238
  <Text key={idx} style={styles.issueItem}>• {issue}</Text>
230
239
  ))}
231
240
  </View>
241
+
232
242
  <TouchableOpacity style={[styles.button, styles.primary]} onPress={() => actions.submitVerification()}>
233
243
  <Text style={styles.buttonText}>
234
244
  {state.currentLanguage === 'en' ? 'OK / Finish' : 'Terminer'}
235
245
  </Text>
236
246
  </TouchableOpacity>
247
+
237
248
  <TouchableOpacity style={[styles.button, styles.secondary]} onPress={() => actions.resetTemplate()}>
238
249
  <Text style={styles.secondaryText}>
239
250
  {state.currentLanguage === 'en' ? 'Start Over' : 'Recommencer'}
240
251
  </Text>
241
252
  </TouchableOpacity>
253
+
242
254
  {verification.result?.referenceId ? (
243
255
  <Text style={styles.refText}>{`Reference ID: ${verification.result.referenceId}`}</Text>
244
256
  ) : null}
@@ -250,7 +262,9 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
250
262
  <View style={styles.container}>
251
263
  <Text style={styles.title}>{t('kyc.verificationProgress.title')}</Text>
252
264
  <Text style={styles.subtitle}>
253
- {isRetrying ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: 40 })}` : t('kyc.verificationProgress.estimatedTime')}
265
+ {isRetrying
266
+ ? `${t('kyc.verificationProgress.retrying', { current: retryCount, max: MAX_RETRIES })}`
267
+ : t('kyc.verificationProgress.estimatedTime')}
254
268
  </Text>
255
269
 
256
270
  <View style={styles.timeline}>
@@ -270,10 +284,10 @@ export const VerificationProgressTemplate: React.FC<VerificationProgressTemplate
270
284
  <View style={styles.card}>
271
285
  <Text style={styles.cardTitle}>{t('kyc.idCardCapture.title')}</Text>
272
286
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.extracting')}</Text>
273
-
287
+
274
288
  <Text style={styles.cardTitle}>{t('kyc.selfieCapture.title')}</Text>
275
289
  <Text style={styles.cardLine}>{t('kyc.verificationProgress.steps.analyzing')}</Text>
276
-
290
+
277
291
  <Text style={styles.cardTitle}>{t('kyc.verificationProgress.title')}</Text>
278
292
  <Text style={styles.cardLine}>
279
293
  {isRetrying ? `${t('kyc.verificationProgress.status.processing')}...` : t('kyc.verificationProgress.status.pending')}