@transfergratis/react-native-sdk 0.1.23 → 0.1.25
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/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +12 -5
- package/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +61 -59
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-transfergratis-react-native-sdk.jar +0 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +12 -5
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/transfergratis-react-native-sdk-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +26 -34
- package/android/src/main/AndroidManifest.xml +13 -5
- package/build/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.js +26 -3
- package/build/components/EnhancedCameraView.js.map +1 -1
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +21 -0
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts +12 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js +283 -0
- package/build/components/KYCElements/AdditionalDocumentsTemplate.js.map +1 -0
- package/build/components/KYCElements/CameraCapture.d.ts.map +1 -1
- package/build/components/KYCElements/CameraCapture.js +4 -3
- package/build/components/KYCElements/CameraCapture.js.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts +5 -2
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.js +360 -101
- package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/EmailVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js +193 -0
- package/build/components/KYCElements/EmailVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/FileUpload.d.ts.map +1 -1
- package/build/components/KYCElements/FileUpload.js +5 -4
- package/build/components/KYCElements/FileUpload.js.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.js +5 -4
- package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +356 -227
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.js +78 -37
- package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js +5 -4
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js +5 -4
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -0
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js +5 -4
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PersonalInformationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js +120 -0
- package/build/components/KYCElements/PersonalInformationTemplate.js.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts +12 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js +185 -0
- package/build/components/KYCElements/PhoneVerificationTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCapture.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCapture.js +4 -3
- package/build/components/KYCElements/SelfieCapture.js.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +189 -42
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/WelcomeTemplate.d.ts +12 -0
- package/build/components/KYCElements/WelcomeTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/WelcomeTemplate.js +243 -0
- package/build/components/KYCElements/WelcomeTemplate.js.map +1 -0
- package/build/components/TemplateKYCExample.d.ts +8 -2
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +10 -97
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts +6 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +108 -11
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/components/example/DynamicTemplateExample.d.ts +10 -0
- package/build/components/example/DynamicTemplateExample.d.ts.map +1 -0
- package/build/components/example/DynamicTemplateExample.js +241 -0
- package/build/components/example/DynamicTemplateExample.js.map +1 -0
- package/build/config/KYCConfig.d.ts +14 -0
- package/build/config/KYCConfig.d.ts.map +1 -0
- package/build/config/KYCConfig.js +26 -0
- package/build/config/KYCConfig.js.map +1 -0
- package/build/config/allowedDomains.d.ts +30 -0
- package/build/config/allowedDomains.d.ts.map +1 -0
- package/build/config/allowedDomains.js +112 -0
- package/build/config/allowedDomains.js.map +1 -0
- package/build/hooks/useOrientationVideo.d.ts +2 -1
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +3 -3
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useTemplateKYCFlow.d.ts +6 -1
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +317 -34
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/hooks/useTemplateLoader.d.ts +14 -0
- package/build/hooks/useTemplateLoader.d.ts.map +1 -0
- package/build/hooks/useTemplateLoader.js +85 -0
- package/build/hooks/useTemplateLoader.js.map +1 -0
- package/build/i18n/en/index.d.ts +49 -0
- package/build/i18n/en/index.d.ts.map +1 -1
- package/build/i18n/en/index.js +50 -1
- package/build/i18n/en/index.js.map +1 -1
- package/build/i18n/fr/index.d.ts +35 -0
- package/build/i18n/fr/index.d.ts.map +1 -1
- package/build/i18n/fr/index.js +36 -1
- package/build/i18n/fr/index.js.map +1 -1
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -0
- package/build/index.js.map +1 -1
- package/build/modules/api/CardAuthentification.d.ts +24 -3
- package/build/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/modules/api/CardAuthentification.js +69 -10
- package/build/modules/api/CardAuthentification.js.map +1 -1
- package/build/modules/api/KYCService.d.ts +7 -7
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +108 -39
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -1
- package/build/modules/api/SelfieVerification.d.ts.map +1 -1
- package/build/modules/api/SelfieVerification.js +17 -1
- package/build/modules/api/SelfieVerification.js.map +1 -1
- package/build/modules/api/TemplateService.d.ts +44 -0
- package/build/modules/api/TemplateService.d.ts.map +1 -0
- package/build/modules/api/TemplateService.js +145 -0
- package/build/modules/api/TemplateService.js.map +1 -0
- package/build/types/KYC.types.d.ts +265 -4
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js +15 -0
- package/build/types/KYC.types.js.map +1 -1
- package/build/types/env.types.d.ts +13 -0
- package/build/types/env.types.d.ts.map +1 -0
- package/build/types/env.types.js +2 -0
- package/build/types/env.types.js.map +1 -0
- package/build/utils/cropByObb.d.ts +1 -0
- package/build/utils/cropByObb.d.ts.map +1 -1
- package/build/utils/cropByObb.js +70 -0
- package/build/utils/cropByObb.js.map +1 -1
- package/build/utils/deviceDetection.d.ts +6 -0
- package/build/utils/deviceDetection.d.ts.map +1 -0
- package/build/utils/deviceDetection.js +12 -0
- package/build/utils/deviceDetection.js.map +1 -0
- package/build/utils/platformAlert.d.ts +20 -0
- package/build/utils/platformAlert.d.ts.map +1 -0
- package/build/utils/platformAlert.js +67 -0
- package/build/utils/platformAlert.js.map +1 -0
- package/build/utils/template-transformer.d.ts +10 -0
- package/build/utils/template-transformer.d.ts.map +1 -0
- package/build/utils/template-transformer.js +365 -0
- package/build/utils/template-transformer.js.map +1 -0
- package/build/web/WebKYCEntry.d.ts.map +1 -1
- package/build/web/WebKYCEntry.js +158 -32
- package/build/web/WebKYCEntry.js.map +1 -1
- package/package.json +1 -1
- package/plugin/build/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.js +3 -4
- package/plugin/src/withVisionCamera.ts +3 -4
- package/src/components/EnhancedCameraView.tsx +31 -2
- package/src/components/EnhancedCameraView.web.tsx +24 -0
- package/src/components/KYCElements/AdditionalDocumentsTemplate.tsx +346 -0
- package/src/components/KYCElements/CameraCapture.tsx +4 -3
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +410 -113
- package/src/components/KYCElements/EmailVerificationTemplate.tsx +264 -0
- package/src/components/KYCElements/FileUpload.tsx +5 -4
- package/src/components/KYCElements/FileUploadTemplate.tsx +5 -4
- package/src/components/KYCElements/IDCardCapture.tsx +397 -254
- package/src/components/KYCElements/LocationCaptureTemplate.tsx +95 -44
- package/src/components/KYCElements/OrientationVideoCapture.tsx +6 -3
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +6 -3
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +6 -3
- package/src/components/KYCElements/PersonalInformationTemplate.tsx +158 -0
- package/src/components/KYCElements/PhoneVerificationTemplate.tsx +253 -0
- package/src/components/KYCElements/SelfieCapture.tsx +4 -3
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +201 -44
- package/src/components/KYCElements/WelcomeTemplate.tsx +289 -0
- package/src/components/TemplateKYCExample.tsx +37 -108
- package/src/components/TemplateKYCFlowRefactored.tsx +148 -12
- package/src/components/example/DynamicTemplateExample.tsx +289 -0
- package/src/config/KYCConfig.ts +34 -0
- package/src/config/allowedDomains.ts +133 -0
- package/src/hooks/useOrientationVideo.ts +5 -4
- package/src/hooks/useTemplateKYCFlow.tsx +347 -32
- package/src/hooks/useTemplateLoader.ts +102 -0
- package/src/i18n/en/index.ts +53 -2
- package/src/i18n/fr/index.ts +37 -1
- package/src/index.ts +14 -0
- package/src/modules/api/CardAuthentification.ts +76 -11
- package/src/modules/api/KYCService.ts +129 -45
- package/src/modules/api/SelfieVerification.ts +25 -3
- package/src/modules/api/TemplateService.ts +167 -0
- package/src/types/KYC.types.ts +331 -3
- package/src/types/env.types.ts +13 -0
- package/src/utils/cropByObb.ts +83 -3
- package/src/utils/deviceDetection.ts +11 -0
- package/src/utils/platformAlert.ts +86 -0
- package/src/utils/template-transformer.ts +445 -0
- package/src/web/WebKYCEntry.tsx +199 -50
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Platform, Alert } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface AlertButton {
|
|
4
|
+
text?: string;
|
|
5
|
+
onPress?: () => void;
|
|
6
|
+
style?: 'default' | 'cancel' | 'destructive';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Platform-aware alert helper that works on both native and web platforms
|
|
11
|
+
* On web, uses window.confirm/window.alert since Alert.alert is not supported
|
|
12
|
+
* On native, uses the standard Alert.alert
|
|
13
|
+
*/
|
|
14
|
+
export const showAlert = (
|
|
15
|
+
title: string,
|
|
16
|
+
message?: string,
|
|
17
|
+
buttons?: AlertButton[]
|
|
18
|
+
): void => {
|
|
19
|
+
if (Platform.OS === 'web') {
|
|
20
|
+
// Web implementation using native browser dialogs
|
|
21
|
+
const fullMessage = message ? `${title}\n\n${message}` : title;
|
|
22
|
+
|
|
23
|
+
if (buttons && buttons.length > 1) {
|
|
24
|
+
|
|
25
|
+
// Multiple buttons - use confirm dialog
|
|
26
|
+
const confirmed = window.confirm(fullMessage);
|
|
27
|
+
|
|
28
|
+
if (confirmed) {
|
|
29
|
+
// Find and call the primary/positive button callback
|
|
30
|
+
const confirmButton = buttons.find(
|
|
31
|
+
btn => btn.style !== 'cancel' && btn.onPress
|
|
32
|
+
);
|
|
33
|
+
confirmButton?.onPress?.();
|
|
34
|
+
} else {
|
|
35
|
+
// Find and call the cancel button callback
|
|
36
|
+
const cancelButton = buttons.find(btn => btn.style === 'cancel');
|
|
37
|
+
cancelButton?.onPress?.();
|
|
38
|
+
}
|
|
39
|
+
} else if (buttons && buttons.length === 1) {
|
|
40
|
+
// Single button - use alert dialog
|
|
41
|
+
window.alert(fullMessage);
|
|
42
|
+
buttons[0]?.onPress?.();
|
|
43
|
+
} else {
|
|
44
|
+
// No buttons - just show alert
|
|
45
|
+
window.alert(fullMessage);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// Native implementation - use standard Alert.alert
|
|
49
|
+
Alert.alert(title, message, buttons);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Simplified confirm dialog for yes/no scenarios
|
|
55
|
+
*/
|
|
56
|
+
export const showConfirm = (
|
|
57
|
+
title: string,
|
|
58
|
+
message: string,
|
|
59
|
+
onConfirm: () => void,
|
|
60
|
+
onCancel?: () => void
|
|
61
|
+
): void => {
|
|
62
|
+
showAlert(title, message, [
|
|
63
|
+
{
|
|
64
|
+
text: 'Cancel',
|
|
65
|
+
style: 'cancel',
|
|
66
|
+
onPress: onCancel,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
text: 'OK',
|
|
70
|
+
onPress: onConfirm,
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Simple alert with just an OK button
|
|
77
|
+
*/
|
|
78
|
+
export const showSimpleAlert = (title: string, message?: string, onPress?: () => void): void => {
|
|
79
|
+
showAlert(title, message, [
|
|
80
|
+
{
|
|
81
|
+
text: 'OK',
|
|
82
|
+
onPress,
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
};
|
|
86
|
+
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BackendKYCTemplate,
|
|
3
|
+
BackendTemplateComponent,
|
|
4
|
+
KYCTemplate,
|
|
5
|
+
TemplateComponent,
|
|
6
|
+
LocalizedText,
|
|
7
|
+
ComponentUI,
|
|
8
|
+
IDCardConfig,
|
|
9
|
+
LocationConfig,
|
|
10
|
+
SelfieConfig,
|
|
11
|
+
FileUploadConfig,
|
|
12
|
+
CountrySelectionConfig,
|
|
13
|
+
ComponentConfig,
|
|
14
|
+
WelcomeConfig,
|
|
15
|
+
GovernmentDocumentType,
|
|
16
|
+
GovernmentIdConfig,
|
|
17
|
+
} from '../types/KYC.types';
|
|
18
|
+
import { logger } from './logger';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hash a string to a number (simple hash function)
|
|
22
|
+
*/
|
|
23
|
+
function hashStringToNumber(str: string): number {
|
|
24
|
+
let hash = 0;
|
|
25
|
+
for (let i = 0; i < str.length; i++) {
|
|
26
|
+
const char = str.charCodeAt(i);
|
|
27
|
+
hash = ((hash << 5) - hash) + char;
|
|
28
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
29
|
+
}
|
|
30
|
+
return Math.abs(hash);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Map backend component types to SDK component types
|
|
35
|
+
*/
|
|
36
|
+
const COMPONENT_TYPE_MAPPING: Record<string, TemplateComponent['type']> = {
|
|
37
|
+
'welcome': 'welcome',
|
|
38
|
+
'government-id': 'id_card',
|
|
39
|
+
'selfie-capture': 'selfie',
|
|
40
|
+
'location-capture': 'location',
|
|
41
|
+
'review-submit': 'review_submit',
|
|
42
|
+
'verification-progress': 'verification_progress',
|
|
43
|
+
'file-upload': 'file_upload',
|
|
44
|
+
'country-selection': 'country_selection',
|
|
45
|
+
'email-verification': 'email_verification',
|
|
46
|
+
'phone-verification': 'phone_verification',
|
|
47
|
+
'personal-information': 'personal_information',
|
|
48
|
+
'additional-documents': 'additional_documents',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Transform backend translations to SDK labels and instructions
|
|
53
|
+
*/
|
|
54
|
+
function transformTranslations(
|
|
55
|
+
translations: BackendTemplateComponent['translations'],
|
|
56
|
+
defaultLanguage: string = 'en'
|
|
57
|
+
): { labels: LocalizedText; instructions: LocalizedText } {
|
|
58
|
+
const labels: LocalizedText = { en: '', fr: '' };
|
|
59
|
+
const instructions: LocalizedText = { en: '', fr: '' };
|
|
60
|
+
|
|
61
|
+
// Extract title as label
|
|
62
|
+
if (translations.en?.title) labels.en = translations.en.title;
|
|
63
|
+
if (translations.fr?.title) labels.fr = translations.fr.title;
|
|
64
|
+
|
|
65
|
+
// Extract instructions
|
|
66
|
+
if (translations.en?.instructions) instructions.en = translations.en.instructions;
|
|
67
|
+
if (translations.fr?.instructions) instructions.fr = translations.fr.instructions;
|
|
68
|
+
|
|
69
|
+
// Fallback to description if instructions not available
|
|
70
|
+
if (!instructions.en && translations.en?.description) {
|
|
71
|
+
instructions.en = translations.en.description;
|
|
72
|
+
}
|
|
73
|
+
if (!instructions.fr && translations.fr?.description) {
|
|
74
|
+
instructions.fr = translations.fr.description;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Support other languages
|
|
78
|
+
Object.keys(translations).forEach((lang) => {
|
|
79
|
+
if (lang !== 'en' && lang !== 'fr' && translations[lang]) {
|
|
80
|
+
labels[lang] = translations[lang]?.title || '';
|
|
81
|
+
instructions[lang] = translations[lang]?.instructions || translations[lang]?.description || '';
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return { labels, instructions };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Transform UI configuration
|
|
90
|
+
*/
|
|
91
|
+
function transformUI(translations: BackendTemplateComponent['translations']): ComponentUI {
|
|
92
|
+
const buttonText: LocalizedText = { en: '', fr: '' };
|
|
93
|
+
|
|
94
|
+
if (translations.en?.buttonText) buttonText.en = translations.en.buttonText;
|
|
95
|
+
if (translations.fr?.buttonText) buttonText.fr = translations.fr.buttonText;
|
|
96
|
+
|
|
97
|
+
// Support other languages
|
|
98
|
+
Object.keys(translations).forEach((lang) => {
|
|
99
|
+
if (lang !== 'en' && lang !== 'fr' && translations[lang]?.buttonText) {
|
|
100
|
+
buttonText[lang] = translations[lang]!.buttonText!;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
buttonText,
|
|
106
|
+
themeColor: '#2DBD60', // Default theme color
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Transform welcome config
|
|
112
|
+
*/
|
|
113
|
+
function transformWelcomeConfig(config: any): WelcomeConfig {
|
|
114
|
+
return {
|
|
115
|
+
subtitle: config.subtitle,
|
|
116
|
+
buttonText: config.buttonText,
|
|
117
|
+
requirements: config.requirements || [],
|
|
118
|
+
estimatedTime: config.estimatedTime,
|
|
119
|
+
consentOptions: config.consentOptions || {
|
|
120
|
+
showPrivacyPolicy: true,
|
|
121
|
+
showTermsOfService: true,
|
|
122
|
+
showMarketingConsent: false,
|
|
123
|
+
},
|
|
124
|
+
welcomeMessage: config.welcomeMessage,
|
|
125
|
+
showEstimatedTime: config.showEstimatedTime !== false,
|
|
126
|
+
} as WelcomeConfig;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Transform government ID config to IDCardConfig
|
|
131
|
+
*/
|
|
132
|
+
function transformGovernmentIdConfig(config: any): IDCardConfig {
|
|
133
|
+
const documentTypes: string[] = config.documentTypes || ['passport', 'nationalId'];
|
|
134
|
+
const sides: string[] = [];
|
|
135
|
+
|
|
136
|
+
if (config.requiredSides === 'front-back' || config.requiredSides === 'both') {
|
|
137
|
+
sides.push('front', 'back');
|
|
138
|
+
} else if (config.requiredSides === 'front') {
|
|
139
|
+
sides.push('front');
|
|
140
|
+
} else if (config.requiredSides === 'back') {
|
|
141
|
+
sides.push('back');
|
|
142
|
+
} else {
|
|
143
|
+
// Default to both sides
|
|
144
|
+
sides.push('front', 'back');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const idCardConfig: IDCardConfig = {
|
|
148
|
+
sides,
|
|
149
|
+
allowed_formats: ['jpg', 'jpeg', 'png'],
|
|
150
|
+
max_size_mb: 10,
|
|
151
|
+
document_types: documentTypes.map((dt: string) => {
|
|
152
|
+
const mapping: Record<string, any> = {
|
|
153
|
+
'passport': 'passport',
|
|
154
|
+
'nationalId': 'national_id',
|
|
155
|
+
'driversLicense': 'drivers_licence',
|
|
156
|
+
'identityCard': 'identity_card',
|
|
157
|
+
};
|
|
158
|
+
return mapping[dt] || dt;
|
|
159
|
+
}) as any[],
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Add bbox configs if available
|
|
163
|
+
if (config.cameraOverlay?.bbox) {
|
|
164
|
+
const bbox = config.cameraOverlay.bbox;
|
|
165
|
+
idCardConfig.bbox_configs = {} as Record<GovernmentDocumentType, {
|
|
166
|
+
xMin: number;
|
|
167
|
+
yMin: number;
|
|
168
|
+
xMax: number;
|
|
169
|
+
yMax: number;
|
|
170
|
+
borderColor?: string;
|
|
171
|
+
borderWidth?: number;
|
|
172
|
+
cornerRadius?: number;
|
|
173
|
+
}>;
|
|
174
|
+
documentTypes.forEach((dt: string) => {
|
|
175
|
+
const docType = dt as GovernmentDocumentType;
|
|
176
|
+
(idCardConfig.bbox_configs as any)[docType] = {
|
|
177
|
+
xMin: bbox.xMin || 20,
|
|
178
|
+
yMin: bbox.yMin || 140,
|
|
179
|
+
xMax: bbox.xMax || 370,
|
|
180
|
+
yMax: bbox.yMax || 340,
|
|
181
|
+
borderColor: bbox.borderColor || '#2DBD60',
|
|
182
|
+
borderWidth: bbox.borderWidth || 3,
|
|
183
|
+
cornerRadius: bbox.cornerRadius || 8,
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Store additional backend-specific config in a way that can be accessed
|
|
189
|
+
(idCardConfig as any).authenticationMethods = config.authenticationMethods;
|
|
190
|
+
(idCardConfig as any).documentTypesByCountry = config.documentTypesByCountry;
|
|
191
|
+
(idCardConfig as any).selectedCountries = config.selectedCountries;
|
|
192
|
+
(idCardConfig as any).instructionsByDocumentType = config.instructionsByDocumentType;
|
|
193
|
+
(idCardConfig as any).cameraSettings = config.cameraSettings;
|
|
194
|
+
(idCardConfig as any).validationRules = config.validationRules;
|
|
195
|
+
|
|
196
|
+
return idCardConfig;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Transform location capture config
|
|
201
|
+
*/
|
|
202
|
+
function transformLocationConfig(config: any): LocationConfig {
|
|
203
|
+
return {
|
|
204
|
+
accuracy: config.accuracy || 'high',
|
|
205
|
+
required: config.required !== false,
|
|
206
|
+
} as LocationConfig;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Transform selfie capture config
|
|
211
|
+
*/
|
|
212
|
+
function transformSelfieConfig(config: any): SelfieConfig {
|
|
213
|
+
return {
|
|
214
|
+
liveness_check: config.livenessEnabled !== false,
|
|
215
|
+
max_attempts: config.maxAttempts || 5,
|
|
216
|
+
orientations: config.orientations || ['center'],
|
|
217
|
+
} as SelfieConfig;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Transform component config based on type
|
|
222
|
+
*/
|
|
223
|
+
function transformComponentConfig(
|
|
224
|
+
type: TemplateComponent['type'],
|
|
225
|
+
backendConfig: any
|
|
226
|
+
): ComponentConfig {
|
|
227
|
+
switch (type) {
|
|
228
|
+
case 'welcome':
|
|
229
|
+
return transformWelcomeConfig(backendConfig);
|
|
230
|
+
case 'id_card':
|
|
231
|
+
return transformGovernmentIdConfig(backendConfig);
|
|
232
|
+
case 'location':
|
|
233
|
+
return transformLocationConfig(backendConfig);
|
|
234
|
+
case 'selfie':
|
|
235
|
+
return transformSelfieConfig(backendConfig);
|
|
236
|
+
case 'file_upload':
|
|
237
|
+
return {
|
|
238
|
+
allowed_formats: backendConfig.allowed_formats || ['jpg', 'jpeg', 'png', 'pdf'],
|
|
239
|
+
max_size_mb: backendConfig.max_size_mb || 10,
|
|
240
|
+
required: backendConfig.required !== false,
|
|
241
|
+
} as FileUploadConfig;
|
|
242
|
+
case 'country_selection':
|
|
243
|
+
return {
|
|
244
|
+
allowed_countries: backendConfig.allowed_countries || [],
|
|
245
|
+
default_country: backendConfig.default_country || '',
|
|
246
|
+
required: backendConfig.required !== false,
|
|
247
|
+
} as CountrySelectionConfig;
|
|
248
|
+
case 'email_verification':
|
|
249
|
+
return backendConfig as any;
|
|
250
|
+
case 'phone_verification':
|
|
251
|
+
return backendConfig as any;
|
|
252
|
+
case 'personal_information':
|
|
253
|
+
return backendConfig as any;
|
|
254
|
+
case 'additional_documents':
|
|
255
|
+
return backendConfig as any;
|
|
256
|
+
default:
|
|
257
|
+
return backendConfig as ComponentConfig;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Transform a single backend component to SDK component
|
|
263
|
+
*/
|
|
264
|
+
function transformComponent(
|
|
265
|
+
backendComponent: BackendTemplateComponent,
|
|
266
|
+
componentIndex: number
|
|
267
|
+
): TemplateComponent {
|
|
268
|
+
const mappedType = COMPONENT_TYPE_MAPPING[backendComponent.type];
|
|
269
|
+
|
|
270
|
+
if (!mappedType) {
|
|
271
|
+
logger.warn(`Unknown component type: ${backendComponent.type}, defaulting to initialization`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const componentId = hashStringToNumber(backendComponent.id);
|
|
275
|
+
const { labels, instructions } = transformTranslations(backendComponent.translations);
|
|
276
|
+
const ui = transformUI(backendComponent.translations);
|
|
277
|
+
const config = transformComponentConfig(mappedType || 'initialization', backendComponent.config);
|
|
278
|
+
|
|
279
|
+
// For components with multiple sides (like id_card), create nested structure
|
|
280
|
+
let finalLabels: LocalizedText | Record<string, LocalizedText> = labels;
|
|
281
|
+
let finalInstructions: LocalizedText | Record<string, LocalizedText> = instructions;
|
|
282
|
+
let finalUI: ComponentUI | Record<string, ComponentUI> = ui;
|
|
283
|
+
|
|
284
|
+
if (mappedType === 'id_card' && (backendComponent.config as GovernmentIdConfig).requiredSides === 'front-back') {
|
|
285
|
+
// Create separate labels/instructions for front and back
|
|
286
|
+
finalLabels = {
|
|
287
|
+
front: {
|
|
288
|
+
en: backendComponent.translations.en?.title || labels.en,
|
|
289
|
+
fr: backendComponent.translations.fr?.title || labels.fr,
|
|
290
|
+
},
|
|
291
|
+
back: {
|
|
292
|
+
en: `${labels.en} (Back)`,
|
|
293
|
+
fr: `${labels.fr} (Verso)`,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
finalInstructions = {
|
|
297
|
+
front: instructions,
|
|
298
|
+
back: instructions,
|
|
299
|
+
};
|
|
300
|
+
finalUI = {
|
|
301
|
+
front: ui,
|
|
302
|
+
back: ui,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
id: componentId,
|
|
308
|
+
type: mappedType || 'initialization',
|
|
309
|
+
order: backendComponent.order,
|
|
310
|
+
labels: finalLabels,
|
|
311
|
+
instructions: finalInstructions,
|
|
312
|
+
ui: finalUI,
|
|
313
|
+
config,
|
|
314
|
+
required: backendComponent.required !== false,
|
|
315
|
+
} as TemplateComponent;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Transform backend template to SDK template format
|
|
320
|
+
*/
|
|
321
|
+
export function transformBackendTemplateToSDK(
|
|
322
|
+
backendTemplate: BackendKYCTemplate
|
|
323
|
+
): KYCTemplate {
|
|
324
|
+
try {
|
|
325
|
+
// Validate backend template
|
|
326
|
+
if (!backendTemplate.id || !backendTemplate.name || !Array.isArray(backendTemplate.components)) {
|
|
327
|
+
throw new Error('Invalid backend template structure');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Sort components by order
|
|
331
|
+
const sortedComponents = [...backendTemplate.components].sort(
|
|
332
|
+
(a, b) => a.order - b.order
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
// Transform each component
|
|
336
|
+
const transformedComponents = sortedComponents.map((comp, index) =>
|
|
337
|
+
transformComponent(comp, index)
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
// Auto-create country_selection component before id_card if government-id has selection data
|
|
341
|
+
// Check if country_selection already exists in backend template
|
|
342
|
+
const hasCountrySelectionInBackend = sortedComponents.some(c => (c as any).type === 'country-selection');
|
|
343
|
+
|
|
344
|
+
if (!hasCountrySelectionInBackend) {
|
|
345
|
+
// Find the first government-id component with selection data
|
|
346
|
+
const govIdWithSelection = sortedComponents.find(backendComp =>
|
|
347
|
+
backendComp.type === 'government-id' &&
|
|
348
|
+
backendComp.config && (
|
|
349
|
+
(backendComp.config as any).selectedCountries ||
|
|
350
|
+
(backendComp.config as any).documentTypesByCountry
|
|
351
|
+
)
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
if (govIdWithSelection) {
|
|
355
|
+
// Find the corresponding transformed id_card component
|
|
356
|
+
const transformedIdCard = transformedComponents.find(c =>
|
|
357
|
+
hashStringToNumber(govIdWithSelection.id) === c.id
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
if (transformedIdCard) {
|
|
361
|
+
// Create a country_selection component before id_card
|
|
362
|
+
const countrySelectionComponent: TemplateComponent = {
|
|
363
|
+
id: hashStringToNumber(`${govIdWithSelection.id}-country-selection`),
|
|
364
|
+
type: 'country_selection',
|
|
365
|
+
order: transformedIdCard.order - 0.5, // Insert before id_card
|
|
366
|
+
labels: {
|
|
367
|
+
en: govIdWithSelection.translations.en?.title || 'Select Country and Document',
|
|
368
|
+
fr: govIdWithSelection.translations.fr?.title || 'Sélectionnez le pays et le document',
|
|
369
|
+
},
|
|
370
|
+
instructions: {
|
|
371
|
+
en: 'Please select your country and document type',
|
|
372
|
+
fr: 'Veuillez sélectionner votre pays et le type de document',
|
|
373
|
+
},
|
|
374
|
+
ui: {
|
|
375
|
+
themeColor: '#2DBD60',
|
|
376
|
+
buttonText: {
|
|
377
|
+
en: 'Continue',
|
|
378
|
+
fr: 'Continuer',
|
|
379
|
+
},
|
|
380
|
+
} as ComponentUI,
|
|
381
|
+
config: {
|
|
382
|
+
allowed_countries: (govIdWithSelection.config as any).selectedCountries || [],
|
|
383
|
+
default_country: '',
|
|
384
|
+
required: true,
|
|
385
|
+
} as CountrySelectionConfig,
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Insert country_selection before id_card in transformedComponents
|
|
389
|
+
const idCardIndex = transformedComponents.indexOf(transformedIdCard);
|
|
390
|
+
transformedComponents.splice(idCardIndex, 0, countrySelectionComponent);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Re-assign order values sequentially after insertion
|
|
396
|
+
transformedComponents.forEach((comp, index) => {
|
|
397
|
+
comp.order = index + 1;
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// Create SDK template
|
|
401
|
+
const sdkTemplate: KYCTemplate = {
|
|
402
|
+
id: hashStringToNumber(backendTemplate.id),
|
|
403
|
+
name: backendTemplate.name as LocalizedText,
|
|
404
|
+
description: backendTemplate.description || {
|
|
405
|
+
en: '',
|
|
406
|
+
fr: '',
|
|
407
|
+
},
|
|
408
|
+
version: backendTemplate.version || '1.0.0',
|
|
409
|
+
components: transformedComponents,
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
logger.log(`Template transformed: ${backendTemplate.id} -> ${sdkTemplate.id} with ${transformedComponents.length} components`);
|
|
413
|
+
|
|
414
|
+
return sdkTemplate;
|
|
415
|
+
} catch (error: any) {
|
|
416
|
+
logger.error('Error transforming template:', error);
|
|
417
|
+
throw new Error(`Failed to transform template: ${error.message}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Validate transformed template
|
|
423
|
+
*/
|
|
424
|
+
export function validateTransformedTemplate(template: KYCTemplate): boolean {
|
|
425
|
+
if (!template.id || !template.name || !Array.isArray(template.components)) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!template.name.en || !template.name.fr) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Validate each component
|
|
434
|
+
for (const component of template.components) {
|
|
435
|
+
if (!component.id || !component.type || typeof component.order !== 'number') {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (!component.labels || !component.instructions || !component.config) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return true;
|
|
445
|
+
}
|