@test-web/react-native-sdk 1.0.0 → 2.0.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.
Files changed (125) hide show
  1. package/README.md +824 -26
  2. package/assets/images/Chrome-logo.svg +1 -0
  3. package/assets/images/Firefox-logo.png +0 -0
  4. package/assets/images/IDM-logo.jpg +0 -0
  5. package/assets/images/MRZOverlay.png +0 -0
  6. package/assets/images/Safari-logo.png +0 -0
  7. package/assets/images/aadhar.png +0 -0
  8. package/assets/images/camera-bg.png +0 -0
  9. package/assets/images/card-overlay-back.png +0 -0
  10. package/assets/images/card-overlay.png +0 -0
  11. package/assets/images/card-scan-back-icon.jpg +0 -0
  12. package/assets/images/card-scan-front-icon.png +0 -0
  13. package/assets/images/card-scan-icon-aadhaar-1.png +0 -0
  14. package/assets/images/card-scan-icon-aadhaar-back.png +0 -0
  15. package/assets/images/card-scan-icon-aadhaar-scan-qr.png +0 -0
  16. package/assets/images/card-scan-icon-aadhaar.png +0 -0
  17. package/assets/images/card-scan-icon-can-pr.png +0 -0
  18. package/assets/images/card-scan-icon-default-back.png +0 -0
  19. package/assets/images/card-scan-icon-dl.png +0 -0
  20. package/assets/images/card-scan-icon-greencard-back.jpg +0 -0
  21. package/assets/images/card-scan-icon-greencard.jpg +0 -0
  22. package/assets/images/card-scan-icon-hc.png +0 -0
  23. package/assets/images/card-scan-icon-ni-argentina-back.jpg +0 -0
  24. package/assets/images/card-scan-icon-ni-argentina-old.png +0 -0
  25. package/assets/images/card-scan-icon-ni-argentina.jpg +0 -0
  26. package/assets/images/card-scan-icon-ni-barcode.jpg +0 -0
  27. package/assets/images/card-scan-icon-ni-brazil-back.jpg +0 -0
  28. package/assets/images/card-scan-icon-ni-brazil.jpg +0 -0
  29. package/assets/images/card-scan-icon-ni-dominican-republic-back.png +0 -0
  30. package/assets/images/card-scan-icon-ni-dominican-republic-front.png +0 -0
  31. package/assets/images/card-scan-icon-ni-dominican-republic-mrz.png +0 -0
  32. package/assets/images/card-scan-icon-ni-dominicanaRepublic-back.jpg +0 -0
  33. package/assets/images/card-scan-icon-ni-france-back.png +0 -0
  34. package/assets/images/card-scan-icon-ni-france-front.png +0 -0
  35. package/assets/images/card-scan-icon-ni-france-scan-mrz.png +0 -0
  36. package/assets/images/card-scan-icon-ni-germany-back.jpg +0 -0
  37. package/assets/images/card-scan-icon-ni-germany.jpg +0 -0
  38. package/assets/images/card-scan-icon-ni-paraguay-back.png +0 -0
  39. package/assets/images/card-scan-icon-ni-paraguay-front.png +0 -0
  40. package/assets/images/card-scan-icon-ni-paraguay-scan-mrz.png +0 -0
  41. package/assets/images/card-scan-icon-ni-uae-back.png +0 -0
  42. package/assets/images/card-scan-icon-ni-uae-front.png +0 -0
  43. package/assets/images/card-scan-icon-ni-uae-scan-mrz.png +0 -0
  44. package/assets/images/card-scan-icon-ni-uganda-front.png +0 -0
  45. package/assets/images/card-scan-icon-ni-uganda-scan-mrz.png +0 -0
  46. package/assets/images/card-scan-icon-ni-ukrain-back.png +0 -0
  47. package/assets/images/card-scan-icon-ni-ukrain-front.png +0 -0
  48. package/assets/images/card-scan-icon-ni-ukrain-scan-mrz.png +0 -0
  49. package/assets/images/card-scan-icon-ni.png +0 -0
  50. package/assets/images/card-scan-icon-old.jpg +0 -0
  51. package/assets/images/card-scan-icon-pan.png +0 -0
  52. package/assets/images/card-scan-icon-passport-card-back.jpg +0 -0
  53. package/assets/images/card-scan-icon-passport-card.jpg +0 -0
  54. package/assets/images/card-scan-icon-passport-old.png +0 -0
  55. package/assets/images/card-scan-icon-passport.png +0 -0
  56. package/assets/images/card-scan-icon-pr.png +0 -0
  57. package/assets/images/card-scan-icon.jpg +0 -0
  58. package/assets/images/check.png +0 -0
  59. package/assets/images/chrome-animation-GPS-permissions-setting.gif +0 -0
  60. package/assets/images/chrome-animation-camera-permissions-setting.gif +0 -0
  61. package/assets/images/denied.png +0 -0
  62. package/assets/images/dl.png +0 -0
  63. package/assets/images/driver-license.png +0 -0
  64. package/assets/images/firefox-animation-permissions-setting.gif +0 -0
  65. package/assets/images/flashlight_on.png +0 -0
  66. package/assets/images/gallery.png +0 -0
  67. package/assets/images/greencard.png +0 -0
  68. package/assets/images/header.jpg +0 -0
  69. package/assets/images/health-card.png +0 -0
  70. package/assets/images/ic_camera_front_white_36px.svg +4 -0
  71. package/assets/images/ic_camera_rear_white_36px.svg +4 -0
  72. package/assets/images/ic_fullscreen_exit_white_48px.svg +4 -0
  73. package/assets/images/ic_fullscreen_white_48px.svg +4 -0
  74. package/assets/images/ic_photo_camera_white_48px.svg +5 -0
  75. package/assets/images/id-card.png +0 -0
  76. package/assets/images/idcardimg.png +0 -0
  77. package/assets/images/idmval-barcode.png +0 -0
  78. package/assets/images/information.png +0 -0
  79. package/assets/images/loader.gif +0 -0
  80. package/assets/images/loading.svg +1 -0
  81. package/assets/images/logo.jpg +0 -0
  82. package/assets/images/logo.png +0 -0
  83. package/assets/images/mrz-back.png +0 -0
  84. package/assets/images/mrz-ni.png +0 -0
  85. package/assets/images/mrz.png +0 -0
  86. package/assets/images/mrz1.png +0 -0
  87. package/assets/images/mrz_old.png +0 -0
  88. package/assets/images/mrz_small.png +0 -0
  89. package/assets/images/national-id.png +0 -0
  90. package/assets/images/nationalID.png +0 -0
  91. package/assets/images/no-wifi.png +0 -0
  92. package/assets/images/passport-card.png +0 -0
  93. package/assets/images/passport.png +0 -0
  94. package/assets/images/permit-card.png +0 -0
  95. package/assets/images/photo-overlay.png +0 -0
  96. package/assets/images/placeholder.jpg +0 -0
  97. package/assets/images/qr-code.png +0 -0
  98. package/assets/images/right-checkmark.jpg +0 -0
  99. package/assets/images/selfie.jpg +0 -0
  100. package/assets/images/showing-sec.png +0 -0
  101. package/assets/images/spinner.gif +0 -0
  102. package/assets/images/splash-icon.png +0 -0
  103. package/assets/images/take-selfie.jpg +0 -0
  104. package/assets/images/torch_off.png +0 -0
  105. package/assets/images/warning-icon.jpg +0 -0
  106. package/assets/images/warning-stick.jpg +0 -0
  107. package/assets/images/wrong-checkmark.jpg +0 -0
  108. package/package.json +44 -8
  109. package/src/apis/index.ts +338 -17
  110. package/src/components/common/Loader.tsx +16 -2
  111. package/src/config/apiConfig.ts +6 -0
  112. package/src/index.tsx +123 -7
  113. package/src/screens/BarcodeCapture.tsx +154 -24
  114. package/src/screens/DocumentCaptureBack.tsx +133 -24
  115. package/src/screens/DocumentCaptureFront.tsx +146 -24
  116. package/src/screens/MrzCapture.tsx +205 -16
  117. package/src/screens/SelectDocuments.tsx +37 -56
  118. package/src/screens/SelfieCapture.tsx +114 -18
  119. package/src/screens/ThankYou.tsx +34 -1
  120. package/src/services/getUserData.ts +111 -0
  121. package/src/types/IDMConf.ts +81 -7
  122. package/src/utils/base64.ts +25 -0
  123. package/src/utils/flowManager.ts +138 -0
  124. package/src/utils/imageProcessor.ts +96 -0
  125. package/src/utils/index.ts +18 -0
@@ -0,0 +1,111 @@
1
+ import { Platform, PermissionsAndroid } from 'react-native';
2
+
3
+ interface UserData {
4
+ permissionGranted: boolean;
5
+ location: any | null;
6
+ ipAddress: string | null;
7
+ deviceInfo: any;
8
+ }
9
+
10
+ /**
11
+ * Gets user data including location, device info, and IP address
12
+ * Handles permission requests for Android
13
+ */
14
+ const getUserData = async (): Promise<UserData> => {
15
+ let permissionGranted = true;
16
+ let location: any | null = null;
17
+ let ipAddress: string | null = null;
18
+
19
+ // Get device info (requires react-native-device-info)
20
+ let deviceInfo: any = {
21
+ brand: 'Unknown',
22
+ model: 'Unknown',
23
+ systemName: Platform.OS,
24
+ systemVersion: Platform.Version.toString(),
25
+ uniqueId: 'unknown',
26
+ };
27
+
28
+ try {
29
+ // Try to import device info if available
30
+ const DeviceInfo = require('react-native-device-info');
31
+ deviceInfo = {
32
+ brand: DeviceInfo.getBrand(),
33
+ model: DeviceInfo.getModel(),
34
+ systemName: DeviceInfo.getSystemName(),
35
+ systemVersion: DeviceInfo.getSystemVersion(),
36
+ uniqueId: await DeviceInfo.getUniqueId(),
37
+ };
38
+ } catch (error) {
39
+ console.warn('react-native-device-info not available:', error);
40
+ }
41
+
42
+ // Android: Check location permission
43
+ if (Platform.OS === 'android') {
44
+ try {
45
+ const alreadyGranted = await PermissionsAndroid.check(
46
+ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
47
+ );
48
+
49
+ if (!alreadyGranted) {
50
+ const granted = await PermissionsAndroid.request(
51
+ PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
52
+ {
53
+ title: 'Location Permission',
54
+ message: 'This app needs access to your location.',
55
+ buttonPositive: 'OK',
56
+ buttonNegative: 'Cancel',
57
+ }
58
+ );
59
+
60
+ if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
61
+ permissionGranted = false;
62
+ }
63
+ }
64
+ } catch (err) {
65
+ console.warn('Permission check error:', err);
66
+ permissionGranted = false;
67
+ }
68
+ }
69
+
70
+ // Get location if permission granted
71
+ if (permissionGranted) {
72
+ try {
73
+ // Try to import geolocation if available
74
+ const Geolocation = require('react-native-geolocation-service');
75
+ location = await new Promise((resolve, reject) => {
76
+ Geolocation.getCurrentPosition(
77
+ resolve,
78
+ reject,
79
+ {
80
+ enableHighAccuracy: true,
81
+ timeout: 15000,
82
+ maximumAge: 10000,
83
+ }
84
+ );
85
+ });
86
+ } catch (err) {
87
+ console.warn('Location fetch error:', err);
88
+ location = null;
89
+ }
90
+ }
91
+
92
+ // Get IP address
93
+ try {
94
+ const response = await fetch('https://api.ipify.org?format=json');
95
+ if (response.ok) {
96
+ const data = await response.json();
97
+ ipAddress = data.ip;
98
+ }
99
+ } catch (err) {
100
+ console.warn('IP fetch error:', err);
101
+ }
102
+
103
+ return {
104
+ permissionGranted,
105
+ location,
106
+ ipAddress,
107
+ deviceInfo,
108
+ };
109
+ };
110
+
111
+ export default getUserData;
@@ -1,13 +1,58 @@
1
1
  export interface IDMConf {
2
- theme?: string | any;
2
+ clientID: string;
3
+ clientSecret: string;
4
+ environment: 'sandbox' | 'production';
5
+ requestData: RequestData;
6
+ theme?: 'light' | 'dark' | any;
3
7
  userDetails?: UserDetails;
4
8
  accessToken?: string;
5
9
  verificationCode?: string;
6
- requestData?: any;
7
- configuration?: any;
10
+ configuration?: Configuration;
8
11
  countryDetails?: CountryDetail[];
9
- selectedCountryDetails?: any;
10
- requestConfiguration?: any;
12
+ selectedCountryDetails?: SelectedCountryDetail;
13
+ requestConfiguration?: RequestConfiguration;
14
+ }
15
+
16
+ export interface RequestData {
17
+ requestID: string;
18
+ name?: string;
19
+ dateOfBirth?: string;
20
+ countryCode?: string;
21
+ mobile?: string;
22
+ callbackURL?: string;
23
+ redirectURL?: string;
24
+ }
25
+
26
+ export interface Configuration {
27
+ logo?: string;
28
+ hideFooter?: boolean;
29
+ skipInputName?: boolean;
30
+ enableLiveVideo?: boolean;
31
+ defaultWebTemplate?: boolean;
32
+ tenantName?: string;
33
+ geoLocationRequired?: boolean;
34
+ showEndUserVerificationHistory?: boolean;
35
+ enableLiveVideoMode?: boolean;
36
+ showFooterTenantName?: boolean;
37
+ verificationCode?: string | null | boolean;
38
+ }
39
+
40
+ export interface RequestConfiguration {
41
+ requestID?: string | null;
42
+ callbackURL?: string | null;
43
+ uniqueID?: string | null;
44
+ status?: string | null;
45
+ documentType?: string | null;
46
+ barcodeType?: string | null;
47
+ skipBarcode?: boolean | null;
48
+ skipLiveness?: boolean | null;
49
+ enableCardBackCapture?: boolean | null;
50
+ qrCode?: string;
51
+ redirectURL?: string | null;
52
+ verificationLink?: string | null;
53
+ country?: string | null;
54
+ countryCode?: string | null;
55
+ liveVideo?: boolean | null;
11
56
  }
12
57
 
13
58
  export interface UserDetails {
@@ -17,12 +62,41 @@ export interface UserDetails {
17
62
  latitude: number;
18
63
  longitude: number;
19
64
  };
65
+ } | null;
66
+ ipAddress?: string | null;
67
+ deviceInfo?: {
68
+ brand: string;
69
+ model: string;
70
+ systemName: string;
71
+ systemVersion: string;
72
+ uniqueId: string;
20
73
  };
21
74
  [key: string]: any;
22
75
  }
23
76
 
24
77
  export interface CountryDetail {
25
78
  label: string;
26
- value: string;
27
- metadata: any[];
79
+ value: string | number;
80
+ metadata: DocumentMetadata[];
81
+ }
82
+
83
+ export interface SelectedCountryDetail extends CountryDetail {
84
+ selectedMetaData?: DocumentMetadata;
85
+ }
86
+
87
+ export interface DocumentMetadata {
88
+ id: number;
89
+ country: string;
90
+ countryCode: string;
91
+ type: string; // DL, PP, NI, PC, GC, etc.
92
+ barcode: string; // PDF417 B, PDF417F, TD3, TD2, TD1, None
93
+ dateFormat: string;
94
+ distance: number;
95
+ comparedText: string | null;
96
+ alternateText: string;
97
+ live: boolean;
98
+ selected: boolean;
99
+ countryEuropean: boolean;
100
+ engineLanguage: boolean;
101
+ document_flow: string[]; // ["F"], ["F", "B"], etc.
28
102
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Encodes a string to base64
3
+ * @param str - The string to encode
4
+ * @returns Base64 encoded string
5
+ */
6
+ export const base64Encode = (str: string): string => {
7
+ if (typeof btoa !== 'undefined') {
8
+ return btoa(str);
9
+ }
10
+ // Fallback for environments without btoa
11
+ return Buffer.from(str, 'utf-8').toString('base64');
12
+ };
13
+
14
+ /**
15
+ * Decodes a base64 string
16
+ * @param str - The base64 string to decode
17
+ * @returns Decoded string
18
+ */
19
+ export const base64Decode = (str: string): string => {
20
+ if (typeof atob !== 'undefined') {
21
+ return atob(str);
22
+ }
23
+ // Fallback for environments without atob
24
+ return Buffer.from(str, 'base64').toString('utf-8');
25
+ };
@@ -0,0 +1,138 @@
1
+ import { DocumentMetadata } from '../types/IDMConf';
2
+
3
+ export type FlowStep = 'F' | 'B'; // Front, Back
4
+ export type BarcodeType = 'PDF417 B' | 'PDF417F' | 'TD3' | 'TD2' | 'TD1' | 'None' | 'NONE';
5
+
6
+ /**
7
+ * Determines the next screen in the verification flow based on metadata
8
+ */
9
+ export class FlowManager {
10
+ private metadata: DocumentMetadata;
11
+ private completedSteps: Set<FlowStep>;
12
+
13
+ constructor(metadata: DocumentMetadata) {
14
+ this.metadata = metadata;
15
+ this.completedSteps = new Set();
16
+ }
17
+
18
+ /**
19
+ * Mark a step as completed
20
+ */
21
+ markStepCompleted(step: FlowStep): void {
22
+ this.completedSteps.add(step);
23
+ }
24
+
25
+ /**
26
+ * Get the next screen to navigate to after capturing front document
27
+ */
28
+ getNextScreenAfterFront(): string {
29
+ this.markStepCompleted('F');
30
+
31
+ const { document_flow, barcode } = this.metadata;
32
+
33
+ // Check if back capture is required
34
+ if (document_flow && document_flow.includes('B') && !this.completedSteps.has('B')) {
35
+ return 'BackDocumentAdvice';
36
+ }
37
+
38
+ // Check for barcode/MRZ requirements
39
+ return this.getNextScreenForBarcode(barcode);
40
+ }
41
+
42
+ /**
43
+ * Get the next screen to navigate to after capturing back document
44
+ */
45
+ getNextScreenAfterBack(): string {
46
+ this.markStepCompleted('B');
47
+
48
+ const { barcode } = this.metadata;
49
+ return this.getNextScreenForBarcode(barcode);
50
+ }
51
+
52
+ /**
53
+ * Determine next screen based on barcode type
54
+ */
55
+ private getNextScreenForBarcode(barcode: string): string {
56
+ const barcodeUpper = barcode?.toUpperCase() || 'NONE';
57
+
58
+ if (barcodeUpper.includes('PDF417')) {
59
+ return 'BarcodeAdvice';
60
+ }
61
+
62
+ if (['TD3', 'TD2', 'TD1'].includes(barcodeUpper)) {
63
+ return 'MrzAdvice';
64
+ }
65
+
66
+ // No barcode/MRZ required, go to thank you
67
+ return 'ThankYou';
68
+ }
69
+
70
+ /**
71
+ * Check if back capture is required
72
+ */
73
+ requiresBackCapture(): boolean {
74
+ const { document_flow } = this.metadata;
75
+ return document_flow && document_flow.includes('B') || false;
76
+ }
77
+
78
+ /**
79
+ * Check if barcode scan is required
80
+ */
81
+ requiresBarcodeCapture(): boolean {
82
+ const { barcode } = this.metadata;
83
+ const barcodeUpper = barcode?.toUpperCase() || 'NONE';
84
+ return barcodeUpper.includes('PDF417');
85
+ }
86
+
87
+ /**
88
+ * Check if MRZ scan is required
89
+ */
90
+ requiresMRZCapture(): boolean {
91
+ const { barcode } = this.metadata;
92
+ const barcodeUpper = barcode?.toUpperCase() || 'NONE';
93
+ return ['TD3', 'TD2', 'TD1'].includes(barcodeUpper);
94
+ }
95
+
96
+ /**
97
+ * Get all required steps for this document
98
+ */
99
+ getRequiredSteps(): string[] {
100
+ const steps: string[] = [];
101
+ const { document_flow, barcode } = this.metadata;
102
+
103
+ if (document_flow) {
104
+ if (document_flow.includes('F')) steps.push('FrontCapture');
105
+ if (document_flow.includes('B')) steps.push('BackCapture');
106
+ }
107
+
108
+ const barcodeUpper = barcode?.toUpperCase() || 'NONE';
109
+ if (barcodeUpper.includes('PDF417')) {
110
+ steps.push('BarcodeCapture');
111
+ } else if (['TD3', 'TD2', 'TD1'].includes(barcodeUpper)) {
112
+ steps.push('MRZCapture');
113
+ }
114
+
115
+ return steps;
116
+ }
117
+
118
+ /**
119
+ * Get MRZ engine type based on barcode type
120
+ */
121
+ getMRZEngine(): string {
122
+ const { barcode } = this.metadata;
123
+ const barcodeUpper = barcode?.toUpperCase() || 'NONE';
124
+
125
+ if (barcodeUpper === 'TD3') return 'TD3';
126
+ if (barcodeUpper === 'TD2') return 'TD2';
127
+ if (barcodeUpper === 'TD1') return 'TD1';
128
+
129
+ return 'TD3'; // Default
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Helper function to create a FlowManager instance
135
+ */
136
+ export const createFlowManager = (metadata: DocumentMetadata): FlowManager => {
137
+ return new FlowManager(metadata);
138
+ };
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Image processing utilities for document capture
3
+ * Handles image resizing and base64 conversion
4
+ */
5
+
6
+ interface ResizeOptions {
7
+ width?: number;
8
+ height?: number;
9
+ quality?: number;
10
+ format?: 'JPEG' | 'PNG';
11
+ }
12
+
13
+ /**
14
+ * Resize and convert image to base64
15
+ * Requires react-native-image-resizer and react-native-fs
16
+ */
17
+ export const processImageToBase64 = async (
18
+ imagePath: string,
19
+ options: ResizeOptions = {}
20
+ ): Promise<string> => {
21
+ const {
22
+ width = 810,
23
+ height = 1080,
24
+ quality = 70,
25
+ format = 'JPEG',
26
+ } = options;
27
+
28
+ try {
29
+ // Try to import required libraries
30
+ const ImageResizer = require('react-native-image-resizer');
31
+ const RNFS = require('react-native-fs');
32
+
33
+ // Ensure path has file:// prefix
34
+ const fullPath = imagePath.startsWith('file://') ? imagePath : `file://${imagePath}`;
35
+
36
+ try {
37
+ // Resize the image
38
+ const resizedImage = await ImageResizer.createResizedImage(
39
+ fullPath,
40
+ width,
41
+ height,
42
+ format,
43
+ quality,
44
+ 0,
45
+ undefined,
46
+ false
47
+ );
48
+
49
+ // Convert to base64
50
+ const base64Image = await RNFS.readFile(resizedImage.uri, 'base64');
51
+ return base64Image;
52
+ } catch (resizeError: any) {
53
+ console.warn('Image resizing failed, using original image:', resizeError.message);
54
+
55
+ // Fallback: use original image
56
+ const base64Image = await RNFS.readFile(fullPath, 'base64');
57
+ return base64Image;
58
+ }
59
+ } catch (error: any) {
60
+ console.error('Image processing error:', error);
61
+ throw new Error(`Failed to process image: ${error.message}`);
62
+ }
63
+ };
64
+
65
+ /**
66
+ * Validate image path
67
+ */
68
+ export const validateImagePath = (path: string | undefined): boolean => {
69
+ if (!path) {
70
+ console.error('No image path provided');
71
+ return false;
72
+ }
73
+ return true;
74
+ };
75
+
76
+ /**
77
+ * Get image dimensions (if needed)
78
+ */
79
+ export const getImageDimensions = async (
80
+ imagePath: string
81
+ ): Promise<{ width: number; height: number }> => {
82
+ try {
83
+ const Image = require('react-native').Image;
84
+
85
+ return new Promise((resolve, reject) => {
86
+ Image.getSize(
87
+ imagePath,
88
+ (width: number, height: number) => resolve({ width, height }),
89
+ (error: any) => reject(error)
90
+ );
91
+ });
92
+ } catch (error: any) {
93
+ console.error('Failed to get image dimensions:', error);
94
+ throw error;
95
+ }
96
+ };
@@ -17,3 +17,21 @@ export {
17
17
  BatchUpdater,
18
18
  createStableRef,
19
19
  } from './performance';
20
+
21
+ // Base64 utilities
22
+ export { base64Encode, base64Decode } from './base64';
23
+
24
+ // Document type labels
25
+ export const DOCUMENT_LABELS: Record<string, string> = {
26
+ DL: "Driver's License",
27
+ PP: 'Passport',
28
+ NI: 'National ID',
29
+ PC: 'Passport Card',
30
+ GC: 'Green Card',
31
+ HC: 'Health Card',
32
+ };
33
+
34
+ export const getDocumentLabel = (type: string): string => {
35
+ return DOCUMENT_LABELS[type] || type;
36
+ };
37
+