@sanctum-key/react-native-sdk 1.0.60 → 1.0.62
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 +34 -0
- package/android/build/.transforms/ac63f648699cdd4b91e6ee06476f2a70/results.bin +1 -0
- package/android/build/.transforms/ac63f648699cdd4b91e6ee06476f2a70/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +9 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +45 -25
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +9 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +34 -12
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$BarcodeRegion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$6$1.class → SanctumKeySdkModule$definition$1$7$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$1$6$2.class → SanctumKeySdkModule$definition$1$7$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$5.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$3.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$4.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$2.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$6.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$4.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$8.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunction$6.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunction$9.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$2.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$3.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$3.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$4.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$4.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$5.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$5.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$6.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$6.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$AsyncFunctionWithPromise$7.class → SanctumKeySdkModule$definition$lambda$24$$inlined$AsyncFunctionWithPromise$7.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$$inlined$View$1.class → SanctumKeySdkModule$definition$lambda$24$$inlined$View$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$1.class → SanctumKeySdkModule$definition$lambda$24$lambda$23$$inlined$Prop$1.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/{SanctumKeySdkModule$definition$lambda$16$lambda$15$$inlined$Prop$2.class → SanctumKeySdkModule$definition$lambda$24$lambda$23$$inlined$Prop$2.class} +0 -0
- package/android/build/tmp/kotlin-classes/debug/kyc/sanctumkey/com/SanctumKeySdkModule.class +0 -0
- package/android/src/main/AndroidManifest.xml +9 -0
- package/android/src/main/java/kyc/sanctumkey/com/SanctumKeySdkModule.kt +147 -0
- package/build/package.json +1 -1
- package/build/src/SanctumKeySdkModule.d.ts +2 -0
- package/build/src/SanctumKeySdkModule.d.ts.map +1 -1
- package/build/src/SanctumKeySdkModule.js.map +1 -1
- package/build/src/SanctumKeySdkModule.web.d.ts +2 -0
- package/build/src/SanctumKeySdkModule.web.d.ts.map +1 -1
- package/build/src/SanctumKeySdkModule.web.js +14 -0
- package/build/src/SanctumKeySdkModule.web.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +1 -1
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.js +27 -17
- package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +46 -28
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/OverLay/IdCard.d.ts +1 -1
- package/build/src/components/OverLay/IdCard.d.ts.map +1 -1
- package/build/src/components/OverLay/IdCard.js +47 -14
- package/build/src/components/OverLay/IdCard.js.map +1 -1
- package/build/src/components/OverLay/type.d.ts +2 -0
- package/build/src/components/OverLay/type.d.ts.map +1 -1
- package/build/src/components/OverLay/type.js.map +1 -1
- package/build/src/components/Svgs/scanningLine.d.ts +4 -1
- package/build/src/components/Svgs/scanningLine.d.ts.map +1 -1
- package/build/src/components/Svgs/scanningLine.js +15 -11
- package/build/src/components/Svgs/scanningLine.js.map +1 -1
- package/build/src/components/TemplateKYCExample.d.ts +4 -1
- package/build/src/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/src/components/TemplateKYCExample.js +2 -2
- package/build/src/components/TemplateKYCExample.js.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.d.ts +4 -2
- package/build/src/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/src/components/TemplateKYCFlowRefactored.js +157 -8
- package/build/src/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/src/config/region_mapping.d.ts.map +1 -1
- package/build/src/config/region_mapping.js +28 -0
- package/build/src/config/region_mapping.js.map +1 -1
- package/build/src/config/region_mapping.json +28 -0
- package/build/src/index.d.ts +2 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +2 -0
- package/build/src/index.js.map +1 -1
- package/build/src/security/deviceSecurity.d.ts +30 -0
- package/build/src/security/deviceSecurity.d.ts.map +1 -0
- package/build/src/security/deviceSecurity.js +55 -0
- package/build/src/security/deviceSecurity.js.map +1 -0
- package/build/src/utils/logger.d.ts.map +1 -1
- package/build/src/utils/logger.js +5 -0
- package/build/src/utils/logger.js.map +1 -1
- package/ios/SanctumKeySdkModule.swift +93 -0
- package/package.json +1 -1
- package/src/SanctumKeySdkModule.ts +2 -0
- package/src/SanctumKeySdkModule.web.ts +16 -0
- package/src/components/KYCElements/CountrySelection.tsx +3 -1
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +73 -24
- package/src/components/KYCElements/IDCardCapture.tsx +53 -30
- package/src/components/OverLay/IdCard.tsx +72 -15
- package/src/components/OverLay/type.ts +4 -2
- package/src/components/Svgs/scanningLine.tsx +19 -12
- package/src/components/TemplateKYCExample.tsx +8 -1
- package/src/components/TemplateKYCFlowRefactored.tsx +202 -16
- package/src/config/region_mapping.json +28 -0
- package/src/config/region_mapping.ts +28 -0
- package/src/index.ts +9 -1
- package/src/security/deviceSecurity.ts +106 -0
- package/src/utils/logger.ts +5 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useMemo, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FlatList, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import { TemplateComponent, CountrySelectionConfig, LocalizedText, Country, IDCardConfig } from '../../types/KYC.types';
|
|
4
4
|
import { countryMapping } from '../../config/region_mapping';
|
|
5
5
|
import { useTemplateKYCFlowContext } from '../../hooks/useTemplateKYCFlow';
|
|
@@ -208,24 +208,71 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
|
|
|
208
208
|
const renderCountrySelection = () => {
|
|
209
209
|
return (
|
|
210
210
|
<>
|
|
211
|
-
<TextInput
|
|
212
|
-
|
|
213
|
-
{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
211
|
+
<TextInput
|
|
212
|
+
style={styles.searchBar}
|
|
213
|
+
placeholder={state.currentLanguage === "en" ? "Search countries" : "Rechercher un pays"}
|
|
214
|
+
placeholderTextColor="#64748B"
|
|
215
|
+
value={searchQuery}
|
|
216
|
+
onChangeText={setSearchQuery}
|
|
217
|
+
autoCorrect={false}
|
|
218
|
+
autoCapitalize="none"
|
|
219
|
+
clearButtonMode="while-editing"
|
|
220
|
+
returnKeyType="search"
|
|
221
|
+
accessibilityRole="search"
|
|
222
|
+
accessibilityLabel={state.currentLanguage === "en" ? "Search countries" : "Rechercher un pays"}
|
|
223
|
+
accessibilityHint={state.currentLanguage === "en" ? "Filters the country list as you type" : "Filtre la liste des pays pendant la saisie"}
|
|
224
|
+
/>
|
|
225
|
+
<FlatList
|
|
226
|
+
style={styles.listContainer}
|
|
227
|
+
contentContainerStyle={[
|
|
228
|
+
styles.listContent,
|
|
229
|
+
filteredCountries.length === 0 && styles.emptyListContent,
|
|
230
|
+
]}
|
|
231
|
+
data={filteredCountries}
|
|
232
|
+
keyExtractor={(country) => country.code!}
|
|
233
|
+
renderItem={({ item: country }) => {
|
|
234
|
+
const isSelected = selectedCountryCode === country.code;
|
|
235
|
+
const countryName = state.currentLanguage === "en" ? country.name_en : country.name;
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<TouchableOpacity
|
|
239
|
+
style={[styles.option, isSelected && styles.selectedOption]}
|
|
240
|
+
onPress={() => handleCountrySelect(country.code!)}
|
|
241
|
+
activeOpacity={0.7}
|
|
242
|
+
accessible
|
|
243
|
+
accessibilityRole="radio"
|
|
244
|
+
accessibilityState={{ selected: isSelected }}
|
|
245
|
+
accessibilityLabel={`${countryName}, ${country.code}`}
|
|
246
|
+
accessibilityHint={state.currentLanguage === "en" ? "Select this issuing country" : "Sélectionner ce pays émetteur"}
|
|
247
|
+
>
|
|
248
|
+
<Text style={styles.flag} accessible={false}>{country.flag}</Text>
|
|
249
|
+
<View style={styles.optionContent}>
|
|
250
|
+
<Text style={[styles.optionName, isSelected && styles.selectedOptionName]}>{countryName}</Text>
|
|
251
|
+
<Text style={styles.optionCode}>{country.code}</Text>
|
|
252
|
+
</View>
|
|
253
|
+
{isSelected && (
|
|
254
|
+
<View style={[styles.checkmark, { backgroundColor: component.ui.themeColor as string || '#2DBD60' }]} accessible={false}>
|
|
255
|
+
<Text style={styles.checkmarkText}>✓</Text>
|
|
256
|
+
</View>
|
|
257
|
+
)}
|
|
258
|
+
</TouchableOpacity>
|
|
259
|
+
);
|
|
260
|
+
}}
|
|
261
|
+
ListEmptyComponent={
|
|
262
|
+
<Text style={styles.emptyText} accessibilityRole="text">
|
|
263
|
+
{state.currentLanguage === "en" ? "No matching countries found." : "Aucun pays trouvé."}
|
|
264
|
+
</Text>
|
|
265
|
+
}
|
|
266
|
+
showsVerticalScrollIndicator
|
|
267
|
+
persistentScrollbar={Platform.OS === 'android'}
|
|
268
|
+
keyboardShouldPersistTaps="handled"
|
|
269
|
+
keyboardDismissMode={Platform.OS === 'ios' ? 'interactive' : 'on-drag'}
|
|
270
|
+
nestedScrollEnabled
|
|
271
|
+
initialNumToRender={12}
|
|
272
|
+
maxToRenderPerBatch={12}
|
|
273
|
+
windowSize={7}
|
|
274
|
+
accessibilityRole="list"
|
|
275
|
+
/>
|
|
229
276
|
</>
|
|
230
277
|
);
|
|
231
278
|
};
|
|
@@ -341,14 +388,16 @@ export const CountrySelectionTemplate: React.FC<CountrySelectionTemplateProps> =
|
|
|
341
388
|
};
|
|
342
389
|
|
|
343
390
|
const styles = StyleSheet.create({
|
|
344
|
-
root: { flex: 1, maxWidth: 760, width: '100%' },
|
|
345
|
-
container: { backgroundColor: 'white', margin: 10, borderRadius: 10, paddingVertical: 16, paddingHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.35, shadowRadius: 4.84, elevation: 10 },
|
|
391
|
+
root: { flex: 1, minHeight: 0, maxWidth: 760, width: '100%' },
|
|
392
|
+
container: { flex: 1, minHeight: 0, backgroundColor: 'white', margin: 10, borderRadius: 10, paddingVertical: 16, paddingHorizontal: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.35, shadowRadius: 4.84, elevation: 10 },
|
|
346
393
|
progressContainer: { marginBottom: 16, alignItems: 'center' },
|
|
347
394
|
progressText: { fontSize: 14, color: '#666', fontWeight: '500' },
|
|
348
395
|
title: { fontSize: 24, fontWeight: 'bold', color: '#333', marginBottom: 8, textAlign: 'center' },
|
|
349
396
|
description: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 24, lineHeight: 22 },
|
|
350
397
|
searchBar: { height: 52, backgroundColor: '#F1F5F9', borderRadius: 12, paddingHorizontal: 16, fontSize: 16, color: '#1E293B', marginBottom: 16, borderWidth: 1, borderColor: '#CBD5E1', fontWeight: '500' },
|
|
351
|
-
listContainer: {
|
|
398
|
+
listContainer: { flex: 1, minHeight: 120, marginBottom: 12 },
|
|
399
|
+
listContent: { paddingBottom: 8 },
|
|
400
|
+
emptyListContent: { flexGrow: 1, justifyContent: 'center' },
|
|
352
401
|
option: { flexDirection: 'row', alignItems: 'center', padding: 16, backgroundColor: '#F8F9FA', borderRadius: 12, marginBottom: 12, borderWidth: 2, borderColor: '#E9ECEF', minHeight: 64 },
|
|
353
402
|
selectedOption: { borderColor: '#2DBD60', backgroundColor: '#F0F9F0' },
|
|
354
403
|
flag: { fontSize: 32, marginRight: 16 },
|
|
@@ -360,7 +409,7 @@ const styles = StyleSheet.create({
|
|
|
360
409
|
checkmarkText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
|
|
361
410
|
infoBox: { backgroundColor: '#F9FAFB', padding: 12, borderRadius: 12, marginBottom: 16 },
|
|
362
411
|
infoText: { fontSize: 14, color: '#666', lineHeight: 20 },
|
|
363
|
-
buttonContainer: { flexDirection: 'row', marginTop:
|
|
412
|
+
buttonContainer: { flexDirection: 'row', marginTop: 12, gap: 12 },
|
|
364
413
|
errorText: { color: '#dc2626', fontSize: 14, marginTop: 8, textAlign: 'center' },
|
|
365
414
|
emptyText: { textAlign: 'center', color: '#64748B', fontSize: 16, marginTop: 24, fontWeight: '500' }
|
|
366
|
-
});
|
|
415
|
+
});
|
|
@@ -99,6 +99,23 @@ const isUsableBarcodeText = (value: unknown, allowShortBarcode: boolean): value
|
|
|
99
99
|
return !isDecoderError && trimmed.length > 0 && (allowShortBarcode || value.length > 50);
|
|
100
100
|
};
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Keep barcode extraction payloads aligned with extract_mrz_text responses.
|
|
104
|
+
* The barcode formatter historically returned its decoded fields under
|
|
105
|
+
* `data`; downstream consumers expect all machine-readable document data
|
|
106
|
+
* under `parsed_data` regardless of whether it came from MRZ or a barcode.
|
|
107
|
+
*/
|
|
108
|
+
const normalizeBarcodePayload = (payload: unknown): unknown => {
|
|
109
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return payload;
|
|
110
|
+
|
|
111
|
+
const record = payload as Record<string, unknown>;
|
|
112
|
+
if (Object.prototype.hasOwnProperty.call(record, 'parsed_data')) return record;
|
|
113
|
+
if (!Object.prototype.hasOwnProperty.call(record, 'data')) return record;
|
|
114
|
+
|
|
115
|
+
const { data, ...metadata } = record;
|
|
116
|
+
return { ...metadata, data: data };
|
|
117
|
+
};
|
|
118
|
+
|
|
102
119
|
interface IDCardCaptureProps {
|
|
103
120
|
component: TemplateComponent;
|
|
104
121
|
value?: Record<string, IIDCardPayload>;
|
|
@@ -497,7 +514,26 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({ component, value =
|
|
|
497
514
|
const isLandscape = screenWidth > screenHeight;
|
|
498
515
|
let xMin, xMax, yMin, yMax;
|
|
499
516
|
|
|
500
|
-
if (
|
|
517
|
+
if (scanPhase === 'barcode') {
|
|
518
|
+
// Keep the barcode target deliberately compact so users move close
|
|
519
|
+
// enough for dense PDF417 and linear bars to remain individually sharp.
|
|
520
|
+
// Pixel caps prevent the guide from becoming oversized on tablets.
|
|
521
|
+
const guideWidthPx = Math.min(
|
|
522
|
+
screenWidth * (isLandscape ? 0.68 : 0.82),
|
|
523
|
+
isLandscape ? 620 : 440,
|
|
524
|
+
);
|
|
525
|
+
const guideHeightPx = Math.min(
|
|
526
|
+
guideWidthPx / (isLandscape ? 4.2 : 3.2),
|
|
527
|
+
screenHeight * (isLandscape ? 0.34 : 0.12),
|
|
528
|
+
);
|
|
529
|
+
const guideWidthPercent = (guideWidthPx / screenWidth) * 100;
|
|
530
|
+
const guideHeightPercent = (guideHeightPx / screenHeight) * 100;
|
|
531
|
+
|
|
532
|
+
xMin = (100 - guideWidthPercent) / 2;
|
|
533
|
+
xMax = xMin + guideWidthPercent;
|
|
534
|
+
yMin = (100 - guideHeightPercent) / 2;
|
|
535
|
+
yMax = yMin + guideHeightPercent;
|
|
536
|
+
} else if (Platform.OS === 'web') {
|
|
501
537
|
const boxWidthPercent = isLandscape ? 0.40 : 0.85;
|
|
502
538
|
xMin = isLandscape ? 30 : 7.5;
|
|
503
539
|
xMax = xMin + (boxWidthPercent * 100);
|
|
@@ -624,7 +660,13 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({ component, value =
|
|
|
624
660
|
|
|
625
661
|
try {
|
|
626
662
|
let imagePathForUpload = capturePath;
|
|
627
|
-
|
|
663
|
+
// Barcode mode has a deliberately tighter visual guide, but this method
|
|
664
|
+
// saves the verified document image. If OBB bounds are unavailable, keep
|
|
665
|
+
// using the original full-card fallback rather than cropping to the
|
|
666
|
+
// barcode-only window.
|
|
667
|
+
const overlayBbox = scanPhaseRef.current === 'barcode'
|
|
668
|
+
? { xMin: 5, yMin: 34, xMax: 95, yMax: 66 }
|
|
669
|
+
: cameraConfig.overlay.bbox;
|
|
628
670
|
|
|
629
671
|
// Prefer the backend-detected card bounds. Front verification returns the
|
|
630
672
|
// detect_face OBB-derived bbox; back verification returns extract_mrz's
|
|
@@ -705,7 +747,7 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({ component, value =
|
|
|
705
747
|
setTimeout(() => {
|
|
706
748
|
if (cameraGenerationRef.current !== captureGeneration) return;
|
|
707
749
|
setShowCamera(false); actions.showCustomStepper(true);
|
|
708
|
-
setSilentCaptureResult(prev => ({ ...prev, isAnalyzing: false }));
|
|
750
|
+
setSilentCaptureResult(prev => ({ ...prev, success: false, isAnalyzing: false, error: '' }));
|
|
709
751
|
isProcessingCaptureRef.current = false;
|
|
710
752
|
setIsProcessingCapture(false); setProcessingImagePath(null);
|
|
711
753
|
scanPhaseRef.current = 'image';
|
|
@@ -780,10 +822,11 @@ export const IDCardCapture: React.FC<IDCardCaptureProps> = ({ component, value =
|
|
|
780
822
|
let parsedDictionary;
|
|
781
823
|
|
|
782
824
|
if (isHIC && barcodeString.length < 50) {
|
|
783
|
-
parsedDictionary = {
|
|
825
|
+
parsedDictionary = { parsed_data: { card_number: barcodeString, barcode_type: "1D" } };
|
|
784
826
|
} else {
|
|
785
827
|
const token = await authentification();
|
|
786
|
-
|
|
828
|
+
const formattedBarcode = await kycService.formatBarcodeData({ textInput: barcodeString, token }, env);
|
|
829
|
+
parsedDictionary = normalizeBarcodePayload(formattedBarcode);
|
|
787
830
|
}
|
|
788
831
|
if (isStaleBarcode()) return;
|
|
789
832
|
if (!parsedDictionary) throw new Error("Could not parse the barcode data.");
|
|
@@ -1117,10 +1160,11 @@ const handleSilentCapture = async (
|
|
|
1117
1160
|
if (isValidScan) {
|
|
1118
1161
|
let parsedDictionary;
|
|
1119
1162
|
if (isHIC && barcodeData.length < 50) {
|
|
1120
|
-
parsedDictionary = {
|
|
1163
|
+
parsedDictionary = { parsed_data: { card_number: barcodeData, barcode_type: "1D" } };
|
|
1121
1164
|
} else {
|
|
1122
1165
|
const token = await authentification();
|
|
1123
|
-
|
|
1166
|
+
const formattedBarcode = await kycService.formatBarcodeData({ textInput: barcodeData, token }, env);
|
|
1167
|
+
parsedDictionary = normalizeBarcodePayload(formattedBarcode);
|
|
1124
1168
|
}
|
|
1125
1169
|
if (isStaleFrame()) {
|
|
1126
1170
|
clearTimeout(watchdog);
|
|
@@ -1327,7 +1371,8 @@ const handleSilentCapture = async (
|
|
|
1327
1371
|
overlayComponent={
|
|
1328
1372
|
<IdCardOverlay
|
|
1329
1373
|
xMin={cameraConfig.overlay.bbox.xMin} yMin={cameraConfig.overlay.bbox.yMin} xMax={cameraConfig.overlay.bbox.xMax} yMax={cameraConfig.overlay.bbox.yMax}
|
|
1330
|
-
instructions={cameraConfig.overlay.guideText} cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0 as number} isSuccess={silentCaptureResult.success
|
|
1374
|
+
instructions={cameraConfig.overlay.guideText} cornerOpacity={cameraConfig.overlay.bbox.cornerRadius || 0 as number} isSuccess={silentCaptureResult.success} language={state.currentLanguage}
|
|
1375
|
+
mode={scanPhase === 'barcode' ? 'barcode' : 'document'}
|
|
1331
1376
|
stepperProps={{
|
|
1332
1377
|
back: () => {
|
|
1333
1378
|
if (currentSide === 'back') {
|
|
@@ -1342,21 +1387,6 @@ const handleSilentCapture = async (
|
|
|
1342
1387
|
/>
|
|
1343
1388
|
}
|
|
1344
1389
|
/>
|
|
1345
|
-
{scanPhase === 'barcode' && !isBusy && (
|
|
1346
|
-
<View style={styles.barcodePromptContainer}>
|
|
1347
|
-
<View style={styles.barcodePromptContent}>
|
|
1348
|
-
<View style={styles.barcodeIconContainer}><Text style={styles.barcodeIcon}>✓</Text></View>
|
|
1349
|
-
<View style={styles.barcodeTextContainer}>
|
|
1350
|
-
<Text style={styles.barcodePromptTitle}>{state.currentLanguage === 'en' ? 'Image Verified' : 'Image Vérifiée'}</Text>
|
|
1351
|
-
<Text style={styles.barcodePromptDesc}>
|
|
1352
|
-
{state.currentLanguage === 'en'
|
|
1353
|
-
? 'Proceed to scan the barcode. Move closer but ensure it is fully visible in the frame.'
|
|
1354
|
-
: 'Procédez au scan du code-barres. Rapprochez-vous, mais assurez-vous qu\'il soit entièrement visible dans le cadre.'}
|
|
1355
|
-
</Text>
|
|
1356
|
-
</View>
|
|
1357
|
-
</View>
|
|
1358
|
-
</View>
|
|
1359
|
-
)}
|
|
1360
1390
|
{!isBusy && silentCaptureResult.isAnalyzing && (
|
|
1361
1391
|
<View style={styles.topAnalyzingPillContainer}>
|
|
1362
1392
|
<View style={styles.topAnalyzingPill}>
|
|
@@ -1622,13 +1652,6 @@ const styles = StyleSheet.create({
|
|
|
1622
1652
|
qrCodeWrapper: { padding: 20, backgroundColor: '#FFFFFF', borderRadius: 20, borderWidth: 2, borderColor: '#E2E8F0', marginBottom: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.05, shadowRadius: 10 },
|
|
1623
1653
|
listeningContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#F0FDF4', paddingVertical: 12, paddingHorizontal: 20, borderRadius: 12, marginBottom: 24, borderWidth: 1, borderColor: '#BBF7D0' },
|
|
1624
1654
|
listeningText: { marginLeft: 12, color: '#166534', fontSize: 14, fontWeight: '600' },
|
|
1625
|
-
barcodePromptContainer: { position: 'absolute', top: Platform.OS === 'android' ? 60 : 75, left: 0, right: 0, alignItems: 'center', zIndex: 150, paddingHorizontal: 24, },
|
|
1626
|
-
barcodePromptContent: { flexDirection: 'row', alignItems: 'center', backgroundColor: 'rgba(15, 23, 42, 0.85)', paddingVertical: 14, paddingHorizontal: 20, borderRadius: 16, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.15)', shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.3, shadowRadius: 12, elevation: 10, maxWidth: 400, ...Platform.select({ web: { backdropFilter: 'blur(8px)' } as any, ios: { backdropFilter: 'blur(8px)' } as any, }), },
|
|
1627
|
-
barcodeIconContainer: { width: 36, height: 36, borderRadius: 18, backgroundColor: 'rgba(45, 189, 96, 0.2)', justifyContent: 'center', alignItems: 'center', marginRight: 14, borderWidth: 1, borderColor: 'rgba(45, 189, 96, 0.5)', },
|
|
1628
|
-
barcodeIcon: { fontSize: 16, color: '#2DBD60', fontWeight: 'bold', },
|
|
1629
|
-
barcodeTextContainer: { flex: 1, },
|
|
1630
|
-
barcodePromptTitle: { color: '#2DBD60', fontSize: 16, fontWeight: '700', marginBottom: 4, },
|
|
1631
|
-
barcodePromptDesc: { color: '#F8FAFC', fontSize: 14, fontWeight: '500', lineHeight: 20, },
|
|
1632
1655
|
storeLinksContainer: { width: '100%', alignItems: 'center', marginBottom: 24, paddingTop: 16, borderTopWidth: 1, borderTopColor: '#E2E8F0' },
|
|
1633
1656
|
storeLinksTitle: { fontSize: 14, color: '#64748B', fontWeight: '600', marginBottom: 12 },
|
|
1634
1657
|
storeButtonsRow: { flexDirection: 'row', gap: 12, width: '100%', justifyContent: 'center' },
|
|
@@ -28,6 +28,7 @@ const IdCardOverlay = ({
|
|
|
28
28
|
stepperProps,
|
|
29
29
|
isSuccess,
|
|
30
30
|
language = 'en',
|
|
31
|
+
mode = 'document',
|
|
31
32
|
xMin: xMinPercent = 5,
|
|
32
33
|
xMax: xMaxPercent = 95,
|
|
33
34
|
yMin: yMinPercent = 34,
|
|
@@ -63,18 +64,29 @@ const IdCardOverlay = ({
|
|
|
63
64
|
|
|
64
65
|
const docTypeFormatted = formatDocType(stepperProps?.selectedDocumentType);
|
|
65
66
|
const sideText = getSideText(stepperProps?.side);
|
|
67
|
+
const isBarcodeMode = mode === 'barcode';
|
|
66
68
|
|
|
67
|
-
const bottomTitle =
|
|
68
|
-
?
|
|
69
|
-
:
|
|
69
|
+
const bottomTitle = isBarcodeMode
|
|
70
|
+
? (language === 'en' ? 'Center the barcode in the yellow guide' : 'Centrez le code-barres dans le guide jaune')
|
|
71
|
+
: (language === 'en'
|
|
72
|
+
? `Position the ${sideText} of your ${docTypeFormatted}`
|
|
73
|
+
: `Positionnez le ${sideText} de votre ${docTypeFormatted}`);
|
|
70
74
|
|
|
71
|
-
const bottomSubtitle =
|
|
72
|
-
?
|
|
73
|
-
|
|
75
|
+
const bottomSubtitle = isBarcodeMode
|
|
76
|
+
? (language === 'en'
|
|
77
|
+
? 'Move closer until it almost fills the guide. Keep both ends visible.'
|
|
78
|
+
: 'Rapprochez-vous jusqu’à presque remplir le guide. Gardez les deux extrémités visibles.')
|
|
79
|
+
: (language === 'en'
|
|
80
|
+
? 'Ensure all details are clear and readable.'
|
|
81
|
+
: 'Assurez-vous que tous les détails sont lisibles.');
|
|
74
82
|
|
|
75
|
-
const helperText =
|
|
76
|
-
?
|
|
77
|
-
|
|
83
|
+
const helperText = isBarcodeMode
|
|
84
|
+
? (language === 'en'
|
|
85
|
+
? 'Barcode only • Keep level • Hold steady'
|
|
86
|
+
: 'Code-barres uniquement • Bien droit • Restez stable')
|
|
87
|
+
: (language === 'en'
|
|
88
|
+
? 'No glare • All corners visible • Hold steady'
|
|
89
|
+
: 'Pas de reflets • Coins visibles • Maintenez stable');
|
|
78
90
|
|
|
79
91
|
// --- SVG Constants ---
|
|
80
92
|
const CORNER_SIZE = 40;
|
|
@@ -117,8 +129,8 @@ const IdCardOverlay = ({
|
|
|
117
129
|
/>
|
|
118
130
|
</Mask>
|
|
119
131
|
<LinearGradient id="scanBorderGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
120
|
-
<Stop offset="0%" stopColor=
|
|
121
|
-
<Stop offset="100%" stopColor=
|
|
132
|
+
<Stop offset="0%" stopColor={isBarcodeMode ? '#FDE047' : '#4ADE80'} />
|
|
133
|
+
<Stop offset="100%" stopColor={isBarcodeMode ? '#F59E0B' : '#22C55E'} />
|
|
122
134
|
</LinearGradient>
|
|
123
135
|
</Defs>
|
|
124
136
|
|
|
@@ -133,11 +145,26 @@ const IdCardOverlay = ({
|
|
|
133
145
|
height={boxHeight}
|
|
134
146
|
rx={BORDER_RADIUS}
|
|
135
147
|
ry={BORDER_RADIUS}
|
|
136
|
-
stroke={isSuccess ? '#2DBD60' :
|
|
137
|
-
strokeWidth={isSuccess ? 3 : 1.5}
|
|
148
|
+
stroke={isSuccess ? '#2DBD60' : (isBarcodeMode ? 'rgba(250, 204, 21, 0.8)' : 'rgba(255,255,255,0.25)')}
|
|
149
|
+
strokeWidth={isSuccess || isBarcodeMode ? 3 : 1.5}
|
|
138
150
|
fill="transparent"
|
|
139
151
|
/>
|
|
140
152
|
|
|
153
|
+
{isBarcodeMode && (
|
|
154
|
+
<Rect
|
|
155
|
+
x={xMin + 8}
|
|
156
|
+
y={yMin + 8}
|
|
157
|
+
width={Math.max(0, boxWidth - 16)}
|
|
158
|
+
height={Math.max(0, boxHeight - 16)}
|
|
159
|
+
rx={Math.max(4, BORDER_RADIUS - 6)}
|
|
160
|
+
ry={Math.max(4, BORDER_RADIUS - 6)}
|
|
161
|
+
stroke="rgba(253, 224, 71, 0.45)"
|
|
162
|
+
strokeWidth={1}
|
|
163
|
+
strokeDasharray="8 7"
|
|
164
|
+
fill="transparent"
|
|
165
|
+
/>
|
|
166
|
+
)}
|
|
167
|
+
|
|
141
168
|
{/* Professional Corner Guides */}
|
|
142
169
|
<AnimatedG opacity={cornerOpacity || 1}>
|
|
143
170
|
{/* Top Left */}
|
|
@@ -177,7 +204,21 @@ const IdCardOverlay = ({
|
|
|
177
204
|
|
|
178
205
|
{/* Scanning animation */}
|
|
179
206
|
{!isSuccess && (
|
|
180
|
-
<ScanningLine
|
|
207
|
+
<ScanningLine
|
|
208
|
+
yMin={yMin}
|
|
209
|
+
yMax={yMax}
|
|
210
|
+
screenWidth={container.width}
|
|
211
|
+
height={container.height}
|
|
212
|
+
xMin={isBarcodeMode ? xMin : 0}
|
|
213
|
+
xMax={isBarcodeMode ? xMax : undefined}
|
|
214
|
+
color={isBarcodeMode ? '#FACC15' : '#22C55E'}
|
|
215
|
+
/>
|
|
216
|
+
)}
|
|
217
|
+
|
|
218
|
+
{isBarcodeMode && (
|
|
219
|
+
<View style={[styles.barcodeFrameLabel, { left: xMin, top: Math.max(8, yMin - 34) }]} pointerEvents="none">
|
|
220
|
+
<Text style={styles.barcodeFrameLabelText}>{language === 'en' ? 'BARCODE TARGET' : 'ZONE CODE-BARRES'}</Text>
|
|
221
|
+
</View>
|
|
181
222
|
)}
|
|
182
223
|
|
|
183
224
|
{/* Top UI Zone */}
|
|
@@ -287,4 +328,20 @@ const styles = StyleSheet.create({
|
|
|
287
328
|
fontSize: 12,
|
|
288
329
|
fontWeight: '500',
|
|
289
330
|
},
|
|
290
|
-
|
|
331
|
+
barcodeFrameLabel: {
|
|
332
|
+
position: 'absolute',
|
|
333
|
+
zIndex: 12,
|
|
334
|
+
backgroundColor: 'rgba(15, 23, 42, 0.82)',
|
|
335
|
+
borderWidth: 1,
|
|
336
|
+
borderColor: 'rgba(250, 204, 21, 0.55)',
|
|
337
|
+
borderRadius: 6,
|
|
338
|
+
paddingHorizontal: 8,
|
|
339
|
+
paddingVertical: 4,
|
|
340
|
+
},
|
|
341
|
+
barcodeFrameLabelText: {
|
|
342
|
+
color: '#FDE047',
|
|
343
|
+
fontSize: 10,
|
|
344
|
+
fontWeight: '800',
|
|
345
|
+
letterSpacing: 1.2,
|
|
346
|
+
},
|
|
347
|
+
});
|
|
@@ -15,7 +15,9 @@ export interface IdCardOverlayProps {
|
|
|
15
15
|
orientation?: 'center' | 'left' | 'right';
|
|
16
16
|
isAnalyzing?: boolean;
|
|
17
17
|
isSuccess?: boolean;
|
|
18
|
-
language: string
|
|
18
|
+
language: string;
|
|
19
|
+
/** Changes the guide geometry and copy for the dedicated barcode phase. */
|
|
20
|
+
mode?: 'document' | 'barcode';
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
|
|
@@ -93,4 +95,4 @@ export interface EnhancedCameraViewProps {
|
|
|
93
95
|
export interface CheckTemplateTypeResponse {
|
|
94
96
|
template_path: string;
|
|
95
97
|
lpips_score: number;
|
|
96
|
-
}
|
|
98
|
+
}
|
|
@@ -7,12 +7,18 @@ interface ScanningLineProps {
|
|
|
7
7
|
yMax: number;
|
|
8
8
|
screenWidth: number;
|
|
9
9
|
height: number;
|
|
10
|
+
xMin?: number;
|
|
11
|
+
xMax?: number;
|
|
12
|
+
color?: string;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
const ScanningLine = ({ yMin, yMax, screenWidth, height }: ScanningLineProps): React.ReactElement => {
|
|
15
|
+
const ScanningLine = ({ yMin, yMax, screenWidth, height, xMin = 0, xMax, color = '#22C55E' }: ScanningLineProps): React.ReactElement => {
|
|
13
16
|
const animatedValue = useRef(new Animated.Value(0)).current;
|
|
14
17
|
|
|
15
18
|
const boxHeight = yMax - yMin;
|
|
19
|
+
const lineWidth = Math.max(0, (xMax ?? screenWidth) - xMin);
|
|
20
|
+
const glowHeight = Math.min(40, Math.max(12, boxHeight * 0.3));
|
|
21
|
+
const scanEnd = Math.max(yMin, yMax - glowHeight - 4);
|
|
16
22
|
|
|
17
23
|
useEffect(() => {
|
|
18
24
|
const startAnimation = () => {
|
|
@@ -36,7 +42,7 @@ const ScanningLine = ({ yMin, yMax, screenWidth, height }: ScanningLineProps): R
|
|
|
36
42
|
|
|
37
43
|
const translateY = animatedValue.interpolate({
|
|
38
44
|
inputRange: [0, 0.5, 1],
|
|
39
|
-
outputRange: [yMin,
|
|
45
|
+
outputRange: [yMin, scanEnd, yMin],
|
|
40
46
|
});
|
|
41
47
|
|
|
42
48
|
return (
|
|
@@ -44,32 +50,33 @@ const ScanningLine = ({ yMin, yMax, screenWidth, height }: ScanningLineProps): R
|
|
|
44
50
|
style={[
|
|
45
51
|
styles.container,
|
|
46
52
|
{
|
|
47
|
-
|
|
53
|
+
left: xMin,
|
|
54
|
+
width: lineWidth,
|
|
48
55
|
height: height,
|
|
49
56
|
transform: [{ translateY }],
|
|
50
57
|
},
|
|
51
58
|
]}
|
|
52
59
|
pointerEvents="none"
|
|
53
60
|
>
|
|
54
|
-
<Svg height="4" width={
|
|
61
|
+
<Svg height="4" width={lineWidth}>
|
|
55
62
|
<Defs>
|
|
56
63
|
<LinearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
57
64
|
<Stop offset="0%" stopColor="transparent" stopOpacity="0" />
|
|
58
|
-
<Stop offset="50%" stopColor=
|
|
65
|
+
<Stop offset="50%" stopColor={color} stopOpacity="1" />
|
|
59
66
|
<Stop offset="100%" stopColor="transparent" stopOpacity="0" />
|
|
60
67
|
</LinearGradient>
|
|
61
68
|
</Defs>
|
|
62
|
-
<Rect x="0" y="0" width={
|
|
69
|
+
<Rect x="0" y="0" width={lineWidth} height="4" fill="url(#grad)" />
|
|
63
70
|
</Svg>
|
|
64
71
|
|
|
65
|
-
<Svg height=
|
|
72
|
+
<Svg height={glowHeight} width={lineWidth} style={{ marginTop: -2 }}>
|
|
66
73
|
<Defs>
|
|
67
74
|
<LinearGradient id="glow" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
68
|
-
<Stop offset="0%" stopColor=
|
|
69
|
-
<Stop offset="100%" stopColor=
|
|
75
|
+
<Stop offset="0%" stopColor={color} stopOpacity="0.4" />
|
|
76
|
+
<Stop offset="100%" stopColor={color} stopOpacity="0" />
|
|
70
77
|
</LinearGradient>
|
|
71
|
-
|
|
72
|
-
<Rect x="0" y="0" width={
|
|
78
|
+
</Defs>
|
|
79
|
+
<Rect x="0" y="0" width={lineWidth} height={glowHeight} fill="url(#glow)" />
|
|
73
80
|
</Svg>
|
|
74
81
|
</Animated.View>
|
|
75
82
|
);
|
|
@@ -84,4 +91,4 @@ const styles = StyleSheet.create({
|
|
|
84
91
|
},
|
|
85
92
|
});
|
|
86
93
|
|
|
87
|
-
export default ScanningLine;
|
|
94
|
+
export default ScanningLine;
|
|
@@ -4,6 +4,7 @@ import { TemplateKYCFlow } from './TemplateKYCFlowRefactored';
|
|
|
4
4
|
import { KYCTemplate, VerificationState } from '../types/KYC.types';
|
|
5
5
|
import { KycEnvironment, BackendEnvironment } from '../types/env.types';
|
|
6
6
|
import { sdkLogger } from '../utils/logger'; // 🚨 IMPORT SDK LOGGER
|
|
7
|
+
import type { DeviceSecurityCheckResult, DeviceSecurityPolicy } from '../security/deviceSecurity';
|
|
7
8
|
|
|
8
9
|
const advancedVerificationTemplate: KYCTemplate = {
|
|
9
10
|
id: 1,
|
|
@@ -60,6 +61,8 @@ export interface TemplateKYCExampleProps {
|
|
|
60
61
|
onSessionSave?: (sessionId: string) => void;
|
|
61
62
|
kyc_session_id?: string;
|
|
62
63
|
templateConfig?: Record<string, string>;
|
|
64
|
+
deviceSecurityPolicy?: DeviceSecurityPolicy;
|
|
65
|
+
onDeviceSecurityCheck?: (result: DeviceSecurityCheckResult) => void;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
export function TemplateKYCExample({
|
|
@@ -80,6 +83,8 @@ export function TemplateKYCExample({
|
|
|
80
83
|
onSessionSave,
|
|
81
84
|
kyc_session_id,
|
|
82
85
|
templateConfig,
|
|
86
|
+
deviceSecurityPolicy,
|
|
87
|
+
onDeviceSecurityCheck,
|
|
83
88
|
}: TemplateKYCExampleProps): JSX.Element {
|
|
84
89
|
|
|
85
90
|
const handleComplete = (data: VerificationState) => {
|
|
@@ -167,8 +172,10 @@ export function TemplateKYCExample({
|
|
|
167
172
|
referenceId={referenceId}
|
|
168
173
|
onSessionSave={onSessionSave}
|
|
169
174
|
kyc_session_id={kyc_session_id}
|
|
175
|
+
deviceSecurityPolicy={deviceSecurityPolicy}
|
|
176
|
+
onDeviceSecurityCheck={onDeviceSecurityCheck}
|
|
170
177
|
/>
|
|
171
178
|
</View>
|
|
172
179
|
</SafeAreaView>
|
|
173
180
|
);
|
|
174
|
-
}
|
|
181
|
+
}
|