@test-web/react-native-sdk 2.2.0 → 2.4.0
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/android/build/.transforms/246c075ea944392e66db7aa639265547/results.bin +1 -0
- package/android/build/.transforms/246c075ea944392e66db7aa639265547/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/yourcompany/sdk/BuildConfig.dex +0 -0
- package/android/build/.transforms/246c075ea944392e66db7aa639265547/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/yourcompany/sdk/YourSDKModule.dex +0 -0
- package/android/build/.transforms/246c075ea944392e66db7aa639265547/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/yourcompany/sdk/YourSDKPackage.dex +0 -0
- package/android/build/.transforms/246c075ea944392e66db7aa639265547/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/952af5a0e7b5b2ac3d48ad66eccefd1f/results.bin +1 -0
- package/android/build/.transforms/952af5a0e7b5b2ac3d48ad66eccefd1f/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/generated/source/buildConfig/debug/com/yourcompany/sdk/BuildConfig.java +10 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +34 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/yourcompany/sdk/BuildConfig.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/yourcompany/sdk/YourSDKModule.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/yourcompany/sdk/YourSDKPackage.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +56 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +34 -0
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/yourcompany/sdk/BuildConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/yourcompany/sdk/YourSDKModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/yourcompany/sdk/YourSDKPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +61 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/package.json +1 -1
- package/src/apis/captureBarcode.ts +37 -0
- package/src/apis/captureMRZ.ts +39 -0
- package/src/apis/checkLiveness.ts +48 -0
- package/src/apis/index.ts +26 -75
- package/src/components/common/Footer.tsx +19 -22
- package/src/components/common/Header.tsx +22 -21
- package/src/components/common/Loader.tsx +9 -28
- package/src/components/ui/Button.tsx +23 -31
- package/src/components/ui/ThemedText.tsx +21 -32
- package/src/context/FailedCountContext.tsx +35 -0
- package/src/context/IDMConfigurationContext.tsx +12 -2
- package/src/context/themes.ts +20 -0
- package/src/index.tsx +41 -29
- package/src/screens/BackDocumentAdvice.tsx +13 -18
- package/src/screens/BarcodeAdvice.tsx +39 -19
- package/src/screens/BarcodeCapture.tsx +127 -158
- package/src/screens/DocumentCaptureBack.tsx +145 -102
- package/src/screens/DocumentCaptureFront.tsx +146 -113
- package/src/screens/FrontDocumentAdvice.tsx +13 -18
- package/src/screens/LocationPermission.tsx +124 -17
- package/src/screens/MrzAdvice.tsx +27 -13
- package/src/screens/MrzCapture.tsx +233 -206
- package/src/screens/SelectDocuments.tsx +57 -66
- package/src/screens/SelfieAdvice.tsx +2 -3
- package/src/screens/SelfieCapture.tsx +135 -103
- package/src/screens/ThankYou.tsx +25 -31
- package/src/screens/VerifyIdentity.tsx +1 -0
- package/src/styles/BarcodeAdviceStyles.ts +6 -6
- package/src/styles/DocumentCaptureBackStyle.ts +70 -0
- package/src/styles/DocumentCaptureFrontStyle.ts +70 -0
- package/src/styles/FooterStyles.ts +27 -0
- package/src/styles/HeaderStyles.ts +20 -0
- package/src/styles/LoaderStyles.ts +14 -0
- package/src/styles/ScannerStyles.ts +46 -9
- package/src/styles/ThankYouStyles.ts +8 -11
- package/src/types/index.ts +8 -0
- package/src/utils/MRZ_README.md +111 -0
- package/src/utils/imagesHelper.ts +264 -0
- package/src/utils/metadata_new.json +11373 -1
- package/src/utils/mrzExamples.ts +127 -0
- package/src/utils/mrzParser.ts +303 -0
- package/src/utils/mrzUtils.ts +70 -0
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { View, Text, StyleSheet } from 'react-native';
|
|
1
|
+
import { Image, StyleProp, View, ViewStyle } from 'react-native';
|
|
3
2
|
import { useTheme } from '../../context/ThemeContext';
|
|
3
|
+
import { useOrientation } from '../../hooks/useOrientation';
|
|
4
|
+
import { useIDM } from '../../context/IDMConfigurationContext';
|
|
5
|
+
import getStyles from '../../styles/HeaderStyles';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
interface HeaderProps {
|
|
8
|
+
style?: StyleProp<ViewStyle>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function Header({ style }: HeaderProps) {
|
|
6
12
|
const { theme } = useTheme();
|
|
13
|
+
const orientation = useOrientation();
|
|
14
|
+
const { idmConf } = useIDM();
|
|
15
|
+
const styles = getStyles(theme, orientation);
|
|
16
|
+
|
|
17
|
+
// Get logo from configuration - never show default logo
|
|
18
|
+
const logo = idmConf?.configuration?.logo;
|
|
19
|
+
|
|
20
|
+
// Only render if logo is available from configuration
|
|
21
|
+
if (!logo || !logo.startsWith('data:image')) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
7
24
|
|
|
8
25
|
return (
|
|
9
|
-
<View style={[styles.container,
|
|
10
|
-
<
|
|
11
|
-
IDM Scan SDK
|
|
12
|
-
</Text>
|
|
26
|
+
<View style={[styles.container, style]}>
|
|
27
|
+
<Image source={{ uri: logo }} style={styles.logo} resizeMode="contain" />
|
|
13
28
|
</View>
|
|
14
29
|
);
|
|
15
30
|
}
|
|
16
|
-
|
|
17
|
-
const styles = StyleSheet.create({
|
|
18
|
-
container: {
|
|
19
|
-
height: 60,
|
|
20
|
-
justifyContent: 'center',
|
|
21
|
-
alignItems: 'center',
|
|
22
|
-
},
|
|
23
|
-
text: {
|
|
24
|
-
fontSize: 18,
|
|
25
|
-
fontWeight: 'bold',
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
export default memo(Header);
|
|
@@ -1,37 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { View, ActivityIndicator, StyleSheet, Text } from 'react-native';
|
|
1
|
+
import { View, ActivityIndicator } from 'react-native';
|
|
3
2
|
import { useTheme } from '../../context/ThemeContext';
|
|
3
|
+
import { useOrientation } from '../../hooks/useOrientation';
|
|
4
|
+
import getStyles from '../../styles/LoaderStyles';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
message?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function Loader({ message }: LoaderProps) {
|
|
6
|
+
const Loader = () => {
|
|
10
7
|
const { theme } = useTheme();
|
|
8
|
+
const orientation = useOrientation();
|
|
9
|
+
const styles = getStyles(theme, orientation);
|
|
11
10
|
|
|
12
11
|
return (
|
|
13
|
-
<View style={
|
|
12
|
+
<View style={styles.loadingContainer}>
|
|
14
13
|
<ActivityIndicator size="large" color={theme.colors.primary} />
|
|
15
|
-
{message && (
|
|
16
|
-
<Text style={[styles.message, { color: theme.colors.text }]}>
|
|
17
|
-
{message}
|
|
18
|
-
</Text>
|
|
19
|
-
)}
|
|
20
14
|
</View>
|
|
21
15
|
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const styles = StyleSheet.create({
|
|
25
|
-
container: {
|
|
26
|
-
flex: 1,
|
|
27
|
-
justifyContent: 'center',
|
|
28
|
-
alignItems: 'center',
|
|
29
|
-
},
|
|
30
|
-
message: {
|
|
31
|
-
marginTop: 16,
|
|
32
|
-
fontSize: 16,
|
|
33
|
-
textAlign: 'center',
|
|
34
|
-
},
|
|
35
|
-
});
|
|
16
|
+
};
|
|
36
17
|
|
|
37
|
-
export default
|
|
18
|
+
export default Loader;
|
|
@@ -1,41 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { Pressable, StyleProp, Text, TextStyle, ViewStyle } from 'react-native';
|
|
2
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
3
3
|
|
|
4
4
|
interface ButtonProps {
|
|
5
5
|
title: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
style?: StyleProp<ViewStyle>;
|
|
7
|
+
textStyle?: StyleProp<TextStyle>;
|
|
8
|
+
onPress?: () => void;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function Button({ title,
|
|
13
|
-
|
|
14
|
-
<TouchableOpacity
|
|
15
|
-
style={[styles.button, style]}
|
|
16
|
-
onPress={onPress}
|
|
17
|
-
disabled={disabled}
|
|
18
|
-
activeOpacity={0.7}
|
|
19
|
-
>
|
|
20
|
-
<Text style={[styles.text, textStyle]}>{title}</Text>
|
|
21
|
-
</TouchableOpacity>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
12
|
+
export default function Button({ title, style, textStyle, onPress, disabled = false }: ButtonProps) {
|
|
13
|
+
const { theme } = useTheme();
|
|
24
14
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
paddingHorizontal: 24,
|
|
30
|
-
borderRadius: 8,
|
|
15
|
+
const defaultStyle: ViewStyle = {
|
|
16
|
+
backgroundColor: theme.colors.buttonBackground,
|
|
17
|
+
padding: theme.button.padding,
|
|
18
|
+
borderRadius: theme.button.borderRadius,
|
|
31
19
|
alignItems: 'center',
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
color:
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const defaultTextStyle: TextStyle = {
|
|
23
|
+
color: theme.colors.buttonText,
|
|
36
24
|
fontSize: 16,
|
|
37
|
-
fontWeight: '
|
|
38
|
-
}
|
|
39
|
-
});
|
|
25
|
+
fontWeight: 'bold',
|
|
26
|
+
};
|
|
40
27
|
|
|
41
|
-
|
|
28
|
+
return (
|
|
29
|
+
<Pressable style={[defaultStyle, style]} onPress={onPress} disabled={disabled}>
|
|
30
|
+
<Text style={[defaultTextStyle, textStyle]}>{title}</Text>
|
|
31
|
+
</Pressable>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -1,42 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Text, TextStyle, StyleSheet } from 'react-native';
|
|
1
|
+
import { Text, StyleProp, TextStyle } from 'react-native';
|
|
3
2
|
import { useTheme } from '../../context/ThemeContext';
|
|
4
3
|
|
|
5
4
|
interface ThemedTextProps {
|
|
5
|
+
type?: 'title' | 'subtitle' | 'default';
|
|
6
|
+
style?: StyleProp<TextStyle>;
|
|
6
7
|
children: React.ReactNode;
|
|
7
|
-
style?: TextStyle;
|
|
8
|
-
type?: 'default' | 'title' | 'subtitle';
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
function ThemedText({
|
|
10
|
+
export default function ThemedText({ type = 'default', style, children }: ThemedTextProps) {
|
|
12
11
|
const { theme } = useTheme();
|
|
13
12
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
const defaultStyles: { [key: string]: TextStyle } = {
|
|
14
|
+
title: {
|
|
15
|
+
fontSize: 24,
|
|
16
|
+
fontWeight: '300',
|
|
17
|
+
color: theme.colors.text,
|
|
18
|
+
},
|
|
19
|
+
subtitle: {
|
|
20
|
+
fontSize: 18,
|
|
21
|
+
fontWeight: '400',
|
|
22
|
+
color: theme.colors.subtitle,
|
|
23
|
+
},
|
|
24
|
+
default: {
|
|
25
|
+
fontSize: 16,
|
|
26
|
+
color: theme.colors.text,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
24
29
|
|
|
25
|
-
return <Text style={
|
|
30
|
+
return <Text style={[defaultStyles[type], style]}>{children}</Text>;
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
const styles = StyleSheet.create({
|
|
29
|
-
default: {
|
|
30
|
-
fontSize: 16,
|
|
31
|
-
},
|
|
32
|
-
title: {
|
|
33
|
-
fontSize: 28,
|
|
34
|
-
fontWeight: 'bold',
|
|
35
|
-
},
|
|
36
|
-
subtitle: {
|
|
37
|
-
fontSize: 18,
|
|
38
|
-
fontWeight: '500',
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
export default memo(ThemedText);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
// Define the context shape
|
|
4
|
+
interface FailedCountContextType {
|
|
5
|
+
failedCount: number;
|
|
6
|
+
setFailedCount: React.Dispatch<React.SetStateAction<number>>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Create the context
|
|
10
|
+
const FailedCountContext = createContext<FailedCountContextType | undefined>(undefined);
|
|
11
|
+
|
|
12
|
+
// Custom hook to consume the context
|
|
13
|
+
export const useFailedCount = () => {
|
|
14
|
+
const context = useContext(FailedCountContext);
|
|
15
|
+
if (!context) {
|
|
16
|
+
throw new Error('useFailedCount must be used within a FailedCountProvider');
|
|
17
|
+
}
|
|
18
|
+
return context;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Provider props interface
|
|
22
|
+
interface FailedCountProviderProps {
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Provider component
|
|
27
|
+
export const FailedCountProvider: React.FC<FailedCountProviderProps> = ({ children }) => {
|
|
28
|
+
const [failedCount, setFailedCount] = useState<number>(0);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<FailedCountContext.Provider value={{ failedCount, setFailedCount }}>
|
|
32
|
+
{children}
|
|
33
|
+
</FailedCountContext.Provider>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -17,9 +17,19 @@ interface IDMProviderProps {
|
|
|
17
17
|
export function IDMProvider({ children, initialConf }: IDMProviderProps) {
|
|
18
18
|
const [idmConf, setIDMConf] = useState<IDMConf>(initialConf);
|
|
19
19
|
|
|
20
|
-
// Optimized partial update function
|
|
20
|
+
// Optimized partial update function that preserves configuration
|
|
21
21
|
const updateIDMConf = useCallback((updates: Partial<IDMConf>) => {
|
|
22
|
-
setIDMConf((prev) =>
|
|
22
|
+
setIDMConf((prev) => {
|
|
23
|
+
// Ensure configuration is preserved during updates
|
|
24
|
+
const newConf = { ...prev, ...updates };
|
|
25
|
+
|
|
26
|
+
// If configuration exists in prev but not in updates, preserve it
|
|
27
|
+
if (prev.configuration && !updates.configuration) {
|
|
28
|
+
newConf.configuration = prev.configuration;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return newConf;
|
|
32
|
+
});
|
|
23
33
|
}, []);
|
|
24
34
|
|
|
25
35
|
// Memoize context value to prevent unnecessary re-renders
|
package/src/context/themes.ts
CHANGED
|
@@ -10,6 +10,8 @@ export const lightTheme: Theme = {
|
|
|
10
10
|
buttonText: '#ffffff',
|
|
11
11
|
buttonBackground: '#007bff',
|
|
12
12
|
},
|
|
13
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
14
|
+
button: { borderRadius: 8, padding: 12 },
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
// 🌑 Dark (default)
|
|
@@ -22,6 +24,8 @@ export const darkTheme: Theme = {
|
|
|
22
24
|
buttonText: '#111827',
|
|
23
25
|
buttonBackground: '#3b82f6',
|
|
24
26
|
},
|
|
27
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
28
|
+
button: { borderRadius: 8, padding: 12 },
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
// 🌅 Sunset (warm oranges)
|
|
@@ -34,6 +38,8 @@ export const sunsetTheme: Theme = {
|
|
|
34
38
|
buttonText: '#ffffff',
|
|
35
39
|
buttonBackground: '#f97316',
|
|
36
40
|
},
|
|
41
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
42
|
+
button: { borderRadius: 12, padding: 14 },
|
|
37
43
|
};
|
|
38
44
|
|
|
39
45
|
// 🌊 Ocean (blues & teal)
|
|
@@ -46,6 +52,8 @@ export const oceanTheme: Theme = {
|
|
|
46
52
|
buttonText: '#ffffff',
|
|
47
53
|
buttonBackground: '#0284c7',
|
|
48
54
|
},
|
|
55
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
56
|
+
button: { borderRadius: 16, padding: 14 },
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
// 🌿 Forest (greens)
|
|
@@ -58,6 +66,8 @@ export const forestTheme: Theme = {
|
|
|
58
66
|
buttonText: '#ffffff',
|
|
59
67
|
buttonBackground: '#3fa564',
|
|
60
68
|
},
|
|
69
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
70
|
+
button: { borderRadius: 20, padding: 16 },
|
|
61
71
|
};
|
|
62
72
|
|
|
63
73
|
// 🎨 Pastel (lavender & purple)
|
|
@@ -70,6 +80,8 @@ export const pastelTheme: Theme = {
|
|
|
70
80
|
buttonText: '#ffffff',
|
|
71
81
|
buttonBackground: '#a78bfa',
|
|
72
82
|
},
|
|
83
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
84
|
+
button: { borderRadius: 24, padding: 14 },
|
|
73
85
|
};
|
|
74
86
|
|
|
75
87
|
// ⚡ High Contrast (accessibility)
|
|
@@ -82,6 +94,8 @@ export const highContrastTheme: Theme = {
|
|
|
82
94
|
buttonText: '#000000',
|
|
83
95
|
buttonBackground: '#ffcc00',
|
|
84
96
|
},
|
|
97
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
98
|
+
button: { borderRadius: 0, padding: 14 },
|
|
85
99
|
};
|
|
86
100
|
|
|
87
101
|
// 💼 Professional (neutral + blue accent)
|
|
@@ -94,6 +108,8 @@ export const professionalTheme: Theme = {
|
|
|
94
108
|
buttonText: '#ffffff',
|
|
95
109
|
buttonBackground: '#2563eb',
|
|
96
110
|
},
|
|
111
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
112
|
+
button: { borderRadius: 6, padding: 12 },
|
|
97
113
|
};
|
|
98
114
|
|
|
99
115
|
// 🌸 Sakura (soft pink)
|
|
@@ -106,6 +122,8 @@ export const sakuraTheme: Theme = {
|
|
|
106
122
|
buttonText: '#ffffff',
|
|
107
123
|
buttonBackground: '#ec4899',
|
|
108
124
|
},
|
|
125
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
126
|
+
button: { borderRadius: 18, padding: 14 },
|
|
109
127
|
};
|
|
110
128
|
|
|
111
129
|
// 🌌 Midnight (deep purples)
|
|
@@ -118,6 +136,8 @@ export const midnightTheme: Theme = {
|
|
|
118
136
|
buttonText: '#1e1b4b',
|
|
119
137
|
buttonBackground: '#7c3aed',
|
|
120
138
|
},
|
|
139
|
+
fonts: { regular: 'System', bold: 'System-Bold' },
|
|
140
|
+
button: { borderRadius: 10, padding: 12 },
|
|
121
141
|
};
|
|
122
142
|
|
|
123
143
|
export const themes: Record<string, Theme> = {
|
package/src/index.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import { themes } from './context/themes';
|
|
|
23
23
|
import { IDMConf } from './types/IDMConf';
|
|
24
24
|
import { IDMProvider, useIDM } from './context/IDMConfigurationContext';
|
|
25
25
|
import { KeyboardProvider, useKeyboard } from './context/KeyboardContext';
|
|
26
|
+
import { FailedCountProvider } from './context/FailedCountContext';
|
|
26
27
|
import Footer from './components/common/Footer';
|
|
27
28
|
import Header from './components/common/Header';
|
|
28
29
|
import Loader from './components/common/Loader';
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
generateAccessToken,
|
|
32
33
|
generateRequest,
|
|
33
34
|
getConfiguration,
|
|
34
|
-
|
|
35
|
+
countryMetaData,
|
|
35
36
|
} from './apis';
|
|
36
37
|
|
|
37
38
|
const Stack = createNativeStackNavigator();
|
|
@@ -54,11 +55,13 @@ interface IDMScanProps {
|
|
|
54
55
|
|
|
55
56
|
export default function IDMScan({ idmConf }: IDMScanProps) {
|
|
56
57
|
return (
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
<FailedCountProvider>
|
|
59
|
+
<IDMProvider initialConf={idmConf}>
|
|
60
|
+
<KeyboardProvider>
|
|
61
|
+
<IDMScanContent />
|
|
62
|
+
</KeyboardProvider>
|
|
63
|
+
</IDMProvider>
|
|
64
|
+
</FailedCountProvider>
|
|
62
65
|
);
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -69,6 +72,7 @@ function IDMScanContent() {
|
|
|
69
72
|
const [currentRoute, setCurrentRoute] = useState<string | undefined>();
|
|
70
73
|
const [loading, setLoading] = useState(true);
|
|
71
74
|
const [error, setError] = useState<string | null>(null);
|
|
75
|
+
const [isActivityReady, setIsActivityReady] = useState(false);
|
|
72
76
|
|
|
73
77
|
// Memoize theme calculation
|
|
74
78
|
const theme = useMemo(
|
|
@@ -102,35 +106,40 @@ function IDMScanContent() {
|
|
|
102
106
|
if (!idmConf.userDetails) {
|
|
103
107
|
console.log('Fetching user data...');
|
|
104
108
|
const userData = await getUserDataAPI();
|
|
105
|
-
|
|
106
|
-
setIDMConf(updatedConf);
|
|
107
|
-
|
|
109
|
+
|
|
108
110
|
// Step 2: Generate access token if not provided
|
|
109
111
|
if (!idmConf.accessToken) {
|
|
110
112
|
console.log('Generating access token...');
|
|
111
|
-
const token = await generateAccessToken(
|
|
112
|
-
const confWithToken = { ...updatedConf, accessToken: token };
|
|
113
|
-
setIDMConf(confWithToken);
|
|
113
|
+
const token = await generateAccessToken({ ...idmConf, userDetails: userData });
|
|
114
114
|
|
|
115
115
|
// Step 3: Generate verification request
|
|
116
116
|
console.log('Generating verification request...');
|
|
117
|
-
const requestResult = await generateRequest(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
122
|
-
setIDMConf(confWithVerifyCode);
|
|
117
|
+
const requestResult = await generateRequest(
|
|
118
|
+
{ ...idmConf, userDetails: userData, accessToken: token },
|
|
119
|
+
idmConf.requestData
|
|
120
|
+
);
|
|
123
121
|
|
|
124
122
|
// Step 4: Get configuration
|
|
125
123
|
console.log('Fetching configuration...');
|
|
126
124
|
const fetchedConfig = await getConfiguration(
|
|
127
|
-
|
|
125
|
+
{ ...idmConf, userDetails: userData, accessToken: token, verificationCode: requestResult.verificationCode },
|
|
128
126
|
requestResult.verificationCode
|
|
129
127
|
);
|
|
128
|
+
|
|
129
|
+
// Update all at once to prevent state loss
|
|
130
130
|
setIDMConf({
|
|
131
|
-
...
|
|
131
|
+
...idmConf,
|
|
132
|
+
userDetails: userData,
|
|
133
|
+
accessToken: token,
|
|
134
|
+
verificationCode: requestResult.verificationCode,
|
|
132
135
|
configuration: fetchedConfig,
|
|
133
136
|
});
|
|
137
|
+
} else {
|
|
138
|
+
// Only update user data if token already exists
|
|
139
|
+
setIDMConf({
|
|
140
|
+
...idmConf,
|
|
141
|
+
userDetails: userData,
|
|
142
|
+
});
|
|
134
143
|
}
|
|
135
144
|
}
|
|
136
145
|
} catch (err: any) {
|
|
@@ -138,20 +147,23 @@ function IDMScanContent() {
|
|
|
138
147
|
setError(err.message || 'Failed to initialize SDK');
|
|
139
148
|
} finally {
|
|
140
149
|
setLoading(false);
|
|
150
|
+
// Add delay to ensure Activity is fully ready before showing permission screen
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
setIsActivityReady(true);
|
|
153
|
+
}, 1000);
|
|
141
154
|
}
|
|
142
155
|
};
|
|
143
156
|
|
|
144
157
|
initializeSDK();
|
|
145
158
|
}, []); // Run once on mount
|
|
146
159
|
|
|
147
|
-
//
|
|
160
|
+
// Load static country metadata when access token and verification code are available
|
|
148
161
|
useEffect(() => {
|
|
149
|
-
const
|
|
162
|
+
const loadCountriesData = () => {
|
|
150
163
|
if (idmConf.accessToken && idmConf.verificationCode && !idmConf.countryDetails) {
|
|
151
164
|
try {
|
|
152
|
-
console.log('
|
|
153
|
-
const
|
|
154
|
-
const countriesArray = Array.isArray(response) ? response : response?.data || [];
|
|
165
|
+
console.log('Loading countries from static metadata...');
|
|
166
|
+
const countriesArray = countryMetaData || [];
|
|
155
167
|
|
|
156
168
|
const mapped = countriesArray.map((singleCountry: any) => ({
|
|
157
169
|
label: singleCountry.country,
|
|
@@ -164,12 +176,12 @@ function IDMScanContent() {
|
|
|
164
176
|
countryDetails: mapped,
|
|
165
177
|
});
|
|
166
178
|
} catch (err: any) {
|
|
167
|
-
console.error('Error
|
|
179
|
+
console.error('Error loading countries:', err);
|
|
168
180
|
}
|
|
169
181
|
}
|
|
170
182
|
};
|
|
171
183
|
|
|
172
|
-
|
|
184
|
+
loadCountriesData();
|
|
173
185
|
}, [idmConf.accessToken, idmConf.verificationCode]);
|
|
174
186
|
|
|
175
187
|
// Determine initial route based on permissions
|
|
@@ -180,7 +192,7 @@ function IDMScanContent() {
|
|
|
180
192
|
return 'LocationPermission';
|
|
181
193
|
}, [idmConf.userDetails?.permissionGranted]);
|
|
182
194
|
|
|
183
|
-
if (loading) {
|
|
195
|
+
if (loading || !isActivityReady) {
|
|
184
196
|
return (
|
|
185
197
|
<ThemeProvider theme={theme}>
|
|
186
198
|
<Loader />
|
|
@@ -191,7 +203,7 @@ function IDMScanContent() {
|
|
|
191
203
|
if (error) {
|
|
192
204
|
return (
|
|
193
205
|
<ThemeProvider theme={theme}>
|
|
194
|
-
<Loader
|
|
206
|
+
<Loader />
|
|
195
207
|
</ThemeProvider>
|
|
196
208
|
);
|
|
197
209
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native';
|
|
2
|
-
import { Image, ScrollView
|
|
2
|
+
import { Image, ScrollView } from 'react-native';
|
|
3
3
|
import Button from '../components/ui/Button';
|
|
4
4
|
import ThemedText from '../components/ui/ThemedText';
|
|
5
5
|
import getStyles from '../styles/DocumentAdviceStyles';
|
|
6
6
|
import { useTheme } from '../context/ThemeContext';
|
|
7
7
|
import { useOrientation } from '../hooks/useOrientation';
|
|
8
|
+
import { useIDM } from '../context/IDMConfigurationContext';
|
|
8
9
|
import { useMemo } from 'react';
|
|
10
|
+
import { getCardScanImageBack } from '../utils/imagesHelper';
|
|
9
11
|
|
|
10
12
|
export default function BackDocumentAdvice() {
|
|
11
13
|
const { theme } = useTheme();
|
|
14
|
+
const { idmConf } = useIDM();
|
|
12
15
|
const orientation = useOrientation();
|
|
13
16
|
const navigation = useNavigation();
|
|
14
17
|
|
|
15
|
-
const styles = useMemo(
|
|
16
|
-
() => getStyles(theme, orientation),
|
|
17
|
-
[theme, orientation]
|
|
18
|
-
);
|
|
18
|
+
const styles = useMemo(() => getStyles(theme, orientation), [theme, orientation]);
|
|
19
19
|
|
|
20
20
|
const handleRedirect = () => {
|
|
21
21
|
navigation.navigate('DocumentCaptureBack' as never);
|
|
@@ -27,19 +27,14 @@ export default function BackDocumentAdvice() {
|
|
|
27
27
|
Capture Your ID Back
|
|
28
28
|
</ThemedText>
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
]}
|
|
40
|
-
>
|
|
41
|
-
<ThemedText>ID Back Image</ThemedText>
|
|
42
|
-
</View>
|
|
30
|
+
<Image
|
|
31
|
+
source={getCardScanImageBack(
|
|
32
|
+
idmConf?.selectedCountryDetails?.selectedMetaData?.type,
|
|
33
|
+
idmConf?.selectedCountryDetails?.selectedMetaData?.countryCode
|
|
34
|
+
)}
|
|
35
|
+
style={styles.idcard}
|
|
36
|
+
resizeMode="contain"
|
|
37
|
+
/>
|
|
43
38
|
|
|
44
39
|
<Button
|
|
45
40
|
title="Take a photo"
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native';
|
|
2
|
-
import {
|
|
2
|
+
import { Image, ScrollView } from 'react-native';
|
|
3
3
|
import Button from '../components/ui/Button';
|
|
4
4
|
import ThemedText from '../components/ui/ThemedText';
|
|
5
5
|
import getStyles from '../styles/BarcodeAdviceStyles';
|
|
6
6
|
import { useTheme } from '../context/ThemeContext';
|
|
7
7
|
import { useOrientation } from '../hooks/useOrientation';
|
|
8
|
-
import {
|
|
8
|
+
import { useIDM } from '../context/IDMConfigurationContext';
|
|
9
|
+
import { useEffect, useState, useMemo } from 'react';
|
|
9
10
|
|
|
10
11
|
export default function BarcodeAdvice() {
|
|
11
12
|
const { theme } = useTheme();
|
|
13
|
+
const { idmConf } = useIDM();
|
|
12
14
|
const orientation = useOrientation();
|
|
13
15
|
const navigation = useNavigation();
|
|
14
16
|
|
|
17
|
+
const [barcodeType, setBarcodeType] = useState<string | null>('PDF417 B');
|
|
18
|
+
|
|
19
|
+
// Memoize styles to avoid recalculation on every render
|
|
15
20
|
const styles = useMemo(
|
|
16
21
|
() => getStyles(theme, orientation),
|
|
17
22
|
[theme, orientation]
|
|
@@ -21,25 +26,40 @@ export default function BarcodeAdvice() {
|
|
|
21
26
|
navigation.navigate('BarcodeCapture' as never);
|
|
22
27
|
};
|
|
23
28
|
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const metadata = idmConf?.selectedCountryDetails?.selectedMetaData;
|
|
31
|
+
if (metadata?.barcode === 'PDF417F') {
|
|
32
|
+
setBarcodeType('PDF417F');
|
|
33
|
+
} else {
|
|
34
|
+
setBarcodeType('PDF417 B');
|
|
35
|
+
}
|
|
36
|
+
}, [idmConf]);
|
|
37
|
+
|
|
24
38
|
return (
|
|
25
39
|
<ScrollView contentContainerStyle={styles.container}>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
{barcodeType === 'PDF417 B' ? (
|
|
41
|
+
<ThemedText style={styles.maintitle} type="title">
|
|
42
|
+
Scan the barcode on the back of your ID
|
|
43
|
+
</ThemedText>
|
|
44
|
+
) : (
|
|
45
|
+
<ThemedText style={styles.maintitle} type="title">
|
|
46
|
+
Scan the barcode on the front of your ID
|
|
47
|
+
</ThemedText>
|
|
48
|
+
)}
|
|
49
|
+
|
|
50
|
+
{barcodeType === 'PDF417 B' ? (
|
|
51
|
+
<Image
|
|
52
|
+
source={require('../../assets/images/card-scan-back-icon.jpg')}
|
|
53
|
+
style={styles.idcard}
|
|
54
|
+
resizeMode="contain"
|
|
55
|
+
/>
|
|
56
|
+
) : (
|
|
57
|
+
<Image
|
|
58
|
+
source={require('../../assets/images/card-scan-front-icon.png')}
|
|
59
|
+
style={styles.idcard}
|
|
60
|
+
resizeMode="contain"
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
43
63
|
|
|
44
64
|
<Button
|
|
45
65
|
title="Scan"
|