@test-web/react-native-sdk 1.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.
- package/README.md +58 -0
- package/android/build.gradle +50 -0
- package/android/src/main/AndroidManifest.xml +24 -0
- package/android/src/main/java/com/yourcompany/sdk/YourSDKModule.java +40 -0
- package/android/src/main/java/com/yourcompany/sdk/YourSDKPackage.java +24 -0
- package/ios/YourSDK-Bridging-Header.h +1 -0
- package/ios/YourSDK-Info.plist +30 -0
- package/ios/YourSDK.podspec +19 -0
- package/ios/YourSDKModule.h +5 -0
- package/ios/YourSDKModule.m +32 -0
- package/ios/YourSDKModule.swift +22 -0
- package/package.json +38 -0
- package/src/apis/index.ts +32 -0
- package/src/components/common/CustomOverlay.tsx +44 -0
- package/src/components/common/Footer.tsx +30 -0
- package/src/components/common/Header.tsx +29 -0
- package/src/components/common/Loader.tsx +23 -0
- package/src/components/index.tsx +6 -0
- package/src/components/ui/Button.tsx +41 -0
- package/src/components/ui/ThemedText.tsx +42 -0
- package/src/components/ui/index.tsx +2 -0
- package/src/context/IDMConfigurationContext.tsx +44 -0
- package/src/context/KeyboardContext.tsx +61 -0
- package/src/context/ThemeContext.tsx +34 -0
- package/src/context/themes.ts +134 -0
- package/src/hooks/useOrientation.ts +25 -0
- package/src/index.tsx +110 -0
- package/src/native/NativeModule.ts +10 -0
- package/src/screens/BackDocumentAdvice.tsx +52 -0
- package/src/screens/BarcodeAdvice.tsx +52 -0
- package/src/screens/BarcodeCapture.tsx +66 -0
- package/src/screens/CameraPermission.tsx +74 -0
- package/src/screens/DocumentCaptureBack.tsx +65 -0
- package/src/screens/DocumentCaptureFront.tsx +65 -0
- package/src/screens/FrontDocumentAdvice.tsx +52 -0
- package/src/screens/LocationPermission.tsx +74 -0
- package/src/screens/MrzAdvice.tsx +52 -0
- package/src/screens/MrzCapture.tsx +64 -0
- package/src/screens/NoCameraFound.tsx +64 -0
- package/src/screens/RetakeSelfie.tsx +56 -0
- package/src/screens/SelectDocuments.tsx +250 -0
- package/src/screens/SelfieAdvice.tsx +35 -0
- package/src/screens/SelfieCapture.tsx +56 -0
- package/src/screens/ThankYou.tsx +23 -0
- package/src/screens/VerifyIdentity.tsx +54 -0
- package/src/screens/index.tsx +17 -0
- package/src/styles/BarcodeAdviceStyles.ts +45 -0
- package/src/styles/DocumentAdviceStyles.ts +44 -0
- package/src/styles/DocumentCaptureStyles.ts +55 -0
- package/src/styles/PermissionStyle.ts +61 -0
- package/src/styles/RetakeStyles.ts +67 -0
- package/src/styles/ScannerStyles.ts +28 -0
- package/src/styles/SelectDocumentsStyles.ts +90 -0
- package/src/styles/SelfieAdviceStyles.ts +61 -0
- package/src/styles/SelfieCaptureStyles.ts +48 -0
- package/src/styles/ThankYouStyles.ts +31 -0
- package/src/styles/VerifyIdentityStyles.ts +86 -0
- package/src/types/IDMConf.ts +28 -0
- package/src/types/index.ts +12 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/metadata_new.json +1 -0
- package/src/utils/performance.ts +176 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# React Native IDM Scan SDK
|
|
2
|
+
|
|
3
|
+
Complete identity verification SDK with 18 screens, 10 themes, and optimized performance.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ 18 verification screens
|
|
8
|
+
✅ 10 pre-built themes
|
|
9
|
+
✅ Camera & location permissions
|
|
10
|
+
✅ Document scanning
|
|
11
|
+
✅ Selfie capture
|
|
12
|
+
✅ Responsive design
|
|
13
|
+
✅ TypeScript support
|
|
14
|
+
✅ 60-80% optimized performance
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install test-react-native-sdk
|
|
20
|
+
npm install @react-navigation/native @react-navigation/native-stack
|
|
21
|
+
npm install react-native-screens react-native-safe-area-context
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**iOS:**
|
|
25
|
+
```bash
|
|
26
|
+
cd ios && pod install && cd ..
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import React from 'react';
|
|
33
|
+
import { IDMScan } from 'test-react-native-sdk';
|
|
34
|
+
|
|
35
|
+
export default function App() {
|
|
36
|
+
return <IDMScan idmConf={{ theme: 'light' }} />;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Themes
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { IDMScan, themes } from 'test-react-native-sdk';
|
|
44
|
+
|
|
45
|
+
<IDMScan idmConf={{ theme: themes.ocean }} />
|
|
46
|
+
<IDMScan idmConf={{ theme: themes.dark }} />
|
|
47
|
+
<IDMScan idmConf={{ theme: themes.sunset }} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Available: `light`, `dark`, `ocean`, `sunset`, `forest`, `pastel`, `highContrast`, `professional`, `sakura`, `midnight`
|
|
51
|
+
|
|
52
|
+
## Documentation
|
|
53
|
+
|
|
54
|
+
See [SETUP.md](./SETUP.md) for complete installation and integration guide.
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
repositories {
|
|
3
|
+
google()
|
|
4
|
+
mavenCentral()
|
|
5
|
+
}
|
|
6
|
+
dependencies {
|
|
7
|
+
classpath 'com.android.tools.build:gradle:7.4.2'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
apply plugin: 'com.android.library'
|
|
12
|
+
|
|
13
|
+
def safeExtGet(prop, fallback) {
|
|
14
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
android {
|
|
18
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 33)
|
|
19
|
+
|
|
20
|
+
defaultConfig {
|
|
21
|
+
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
22
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 33)
|
|
23
|
+
versionCode 1
|
|
24
|
+
versionName "1.0.0"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
buildTypes {
|
|
28
|
+
release {
|
|
29
|
+
minifyEnabled false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
lintOptions {
|
|
34
|
+
disable 'GradleCompatible'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
compileOptions {
|
|
38
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
39
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
repositories {
|
|
44
|
+
mavenCentral()
|
|
45
|
+
google()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
dependencies {
|
|
49
|
+
implementation 'com.facebook.react:react-native:+'
|
|
50
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.yourcompany.sdk">
|
|
3
|
+
|
|
4
|
+
<!-- Camera Permission -->
|
|
5
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
6
|
+
|
|
7
|
+
<!-- Location Permissions -->
|
|
8
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
9
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
10
|
+
|
|
11
|
+
<!-- Storage Permissions (for saving captured images) -->
|
|
12
|
+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
13
|
+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
|
14
|
+
android:maxSdkVersion="28" />
|
|
15
|
+
|
|
16
|
+
<!-- Internet Permission (for API calls when needed) -->
|
|
17
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
18
|
+
|
|
19
|
+
<!-- Camera Features -->
|
|
20
|
+
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
|
21
|
+
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
|
22
|
+
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
|
|
23
|
+
|
|
24
|
+
</manifest>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package com.yourcompany.sdk;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
4
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
5
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
6
|
+
import com.facebook.react.bridge.Promise;
|
|
7
|
+
|
|
8
|
+
public class YourSDKModule extends ReactContextBaseJavaModule {
|
|
9
|
+
private final ReactApplicationContext reactContext;
|
|
10
|
+
|
|
11
|
+
public YourSDKModule(ReactApplicationContext reactContext) {
|
|
12
|
+
super(reactContext);
|
|
13
|
+
this.reactContext = reactContext;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Override
|
|
17
|
+
public String getName() {
|
|
18
|
+
return "YourSDKModule";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@ReactMethod
|
|
22
|
+
public void initialize(String apiKey, Promise promise) {
|
|
23
|
+
try {
|
|
24
|
+
// Initialize your SDK with the API key
|
|
25
|
+
promise.resolve("SDK initialized successfully");
|
|
26
|
+
} catch (Exception e) {
|
|
27
|
+
promise.reject("INIT_ERROR", e.getMessage());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactMethod
|
|
32
|
+
public void performAction(String action, Promise promise) {
|
|
33
|
+
try {
|
|
34
|
+
// Perform custom native action
|
|
35
|
+
promise.resolve("Action completed: " + action);
|
|
36
|
+
} catch (Exception e) {
|
|
37
|
+
promise.reject("ACTION_ERROR", e.getMessage());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.yourcompany.sdk;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage;
|
|
4
|
+
import com.facebook.react.bridge.NativeModule;
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
7
|
+
|
|
8
|
+
import java.util.ArrayList;
|
|
9
|
+
import java.util.Collections;
|
|
10
|
+
import java.util.List;
|
|
11
|
+
|
|
12
|
+
public class YourSDKPackage implements ReactPackage {
|
|
13
|
+
@Override
|
|
14
|
+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
15
|
+
List<NativeModule> modules = new ArrayList<>();
|
|
16
|
+
modules.add(new YourSDKModule(reactContext));
|
|
17
|
+
return modules;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
22
|
+
return Collections.emptyList();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<!-- Camera Permission -->
|
|
6
|
+
<key>NSCameraUsageDescription</key>
|
|
7
|
+
<string>We need camera access to capture your selfie and scan your identity documents for verification purposes.</string>
|
|
8
|
+
|
|
9
|
+
<!-- Photo Library Permission (if needed) -->
|
|
10
|
+
<key>NSPhotoLibraryUsageDescription</key>
|
|
11
|
+
<string>We need access to your photo library to save captured images.</string>
|
|
12
|
+
|
|
13
|
+
<key>NSPhotoLibraryAddUsageDescription</key>
|
|
14
|
+
<string>We need permission to save captured images to your photo library.</string>
|
|
15
|
+
|
|
16
|
+
<!-- Location Permissions -->
|
|
17
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
18
|
+
<string>We need your location to verify your identity and prevent fraud.</string>
|
|
19
|
+
|
|
20
|
+
<key>NSLocationAlwaysUsageDescription</key>
|
|
21
|
+
<string>We need your location to verify your identity and prevent fraud.</string>
|
|
22
|
+
|
|
23
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
24
|
+
<string>We need your location to verify your identity and prevent fraud.</string>
|
|
25
|
+
|
|
26
|
+
<!-- Face ID Permission (if using biometric) -->
|
|
27
|
+
<key>NSFaceIDUsageDescription</key>
|
|
28
|
+
<string>We use Face ID to verify your identity securely.</string>
|
|
29
|
+
</dict>
|
|
30
|
+
</plist>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "YourSDK"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => "11.0" }
|
|
14
|
+
s.source = { :git => "https://github.com/yourcompany/react-native-sdk.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "**/*.{h,m,mm,swift}"
|
|
17
|
+
|
|
18
|
+
s.dependency "React-Core"
|
|
19
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#import "YourSDKModule.h"
|
|
2
|
+
|
|
3
|
+
@implementation YourSDKModule
|
|
4
|
+
|
|
5
|
+
RCT_EXPORT_MODULE(YourSDKModule)
|
|
6
|
+
|
|
7
|
+
RCT_EXPORT_METHOD(initialize:(NSString *)apiKey
|
|
8
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
9
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
10
|
+
{
|
|
11
|
+
@try {
|
|
12
|
+
// Initialize your SDK with the API key
|
|
13
|
+
resolve(@"SDK initialized successfully");
|
|
14
|
+
} @catch (NSException *exception) {
|
|
15
|
+
reject(@"INIT_ERROR", exception.reason, nil);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
RCT_EXPORT_METHOD(performAction:(NSString *)action
|
|
20
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
21
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
22
|
+
{
|
|
23
|
+
@try {
|
|
24
|
+
// Perform custom native action
|
|
25
|
+
NSString *result = [NSString stringWithFormat:@"Action completed: %@", action];
|
|
26
|
+
resolve(result);
|
|
27
|
+
} @catch (NSException *exception) {
|
|
28
|
+
reject(@"ACTION_ERROR", exception.reason, nil);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
@objc(YourSDKModule)
|
|
4
|
+
class YourSDKModule: NSObject {
|
|
5
|
+
|
|
6
|
+
@objc
|
|
7
|
+
static func requiresMainQueueSetup() -> Bool {
|
|
8
|
+
return false
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@objc
|
|
12
|
+
func initialize(_ apiKey: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
13
|
+
// Initialize your SDK with the API key
|
|
14
|
+
resolver("SDK initialized successfully")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@objc
|
|
18
|
+
func performAction(_ action: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
19
|
+
// Perform custom native action
|
|
20
|
+
resolver("Action completed: \(action)")
|
|
21
|
+
}
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@test-web/react-native-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Simple React Native SDK for client integration",
|
|
5
|
+
"main": "src/index.tsx",
|
|
6
|
+
"types": "src/index.tsx",
|
|
7
|
+
"files": [
|
|
8
|
+
"src",
|
|
9
|
+
"android",
|
|
10
|
+
"ios",
|
|
11
|
+
"*.podspec"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"typescript": "tsc --noEmit",
|
|
15
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"react-native",
|
|
19
|
+
"sdk"
|
|
20
|
+
],
|
|
21
|
+
"repository": "https://github.com/yourcompany/react-native-sdk",
|
|
22
|
+
"author": "Your Company <hello@yourcompany.com>",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"react": "*",
|
|
26
|
+
"react-native": "*",
|
|
27
|
+
"@react-navigation/native": "^6.0.0",
|
|
28
|
+
"@react-navigation/native-stack": "^6.0.0",
|
|
29
|
+
"react-native-screens": "^3.0.0",
|
|
30
|
+
"react-native-safe-area-context": "^4.0.0",
|
|
31
|
+
"react-native-vision-camera": "^3.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^18.2.0",
|
|
35
|
+
"@types/react-native": "^0.72.0",
|
|
36
|
+
"typescript": "^5.2.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IDMConf } from '../types/IDMConf';
|
|
2
|
+
|
|
3
|
+
export async function getUserData(): Promise<any> {
|
|
4
|
+
// Static implementation - replace with actual API call
|
|
5
|
+
return {
|
|
6
|
+
permissionGranted: true,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function generateAccessToken(conf: IDMConf): Promise<string> {
|
|
11
|
+
// Static implementation - replace with actual API call
|
|
12
|
+
return 'static-access-token';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function generateRequest(conf: IDMConf, requestData: any): Promise<any> {
|
|
16
|
+
// Static implementation - replace with actual API call
|
|
17
|
+
return {
|
|
18
|
+
verificationCode: 'static-verification-code',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function getConfiguration(conf: IDMConf, verificationCode: string): Promise<any> {
|
|
23
|
+
// Static implementation - replace with actual API call
|
|
24
|
+
return {
|
|
25
|
+
// Your configuration data
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function getCountries(conf: IDMConf): Promise<any> {
|
|
30
|
+
// Static implementation - replace with actual API call
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet, Dimensions } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const { width, height } = Dimensions.get('window');
|
|
5
|
+
|
|
6
|
+
interface CustomOverlayProps {
|
|
7
|
+
holeWidth: number;
|
|
8
|
+
holeHeight: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CustomOverlay: React.FC<CustomOverlayProps> = ({
|
|
12
|
+
holeWidth,
|
|
13
|
+
holeHeight,
|
|
14
|
+
}) => {
|
|
15
|
+
const holeY = (height - holeHeight) / 2;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View style={StyleSheet.absoluteFill} pointerEvents="box-none">
|
|
19
|
+
<View style={[styles.overlay, { height: holeY }]} />
|
|
20
|
+
<View style={{ flexDirection: 'row', height: holeHeight }}>
|
|
21
|
+
<View style={styles.overlay} />
|
|
22
|
+
<View
|
|
23
|
+
style={{
|
|
24
|
+
width: holeWidth,
|
|
25
|
+
borderWidth: 2,
|
|
26
|
+
borderColor: 'white',
|
|
27
|
+
borderRadius: 10,
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
<View style={styles.overlay} />
|
|
31
|
+
</View>
|
|
32
|
+
<View style={styles.overlay} />
|
|
33
|
+
</View>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const styles = StyleSheet.create({
|
|
38
|
+
overlay: {
|
|
39
|
+
flex: 1,
|
|
40
|
+
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export default CustomOverlay;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
4
|
+
|
|
5
|
+
function Footer() {
|
|
6
|
+
const { theme } = useTheme();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<View style={[styles.container, { backgroundColor: theme.colors.background }]}>
|
|
10
|
+
<Text style={[styles.text, { color: theme.colors.subtitle }]}>
|
|
11
|
+
Powered by IDMerit
|
|
12
|
+
</Text>
|
|
13
|
+
</View>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const styles = StyleSheet.create({
|
|
18
|
+
container: {
|
|
19
|
+
height: 50,
|
|
20
|
+
justifyContent: 'center',
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
borderTopWidth: 1,
|
|
23
|
+
borderTopColor: '#e0e0e0',
|
|
24
|
+
},
|
|
25
|
+
text: {
|
|
26
|
+
fontSize: 12,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export default memo(Footer);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
4
|
+
|
|
5
|
+
function Header() {
|
|
6
|
+
const { theme } = useTheme();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<View style={[styles.container, { backgroundColor: theme.colors.primary }]}>
|
|
10
|
+
<Text style={[styles.text, { color: theme.colors.buttonText }]}>
|
|
11
|
+
IDM Scan SDK
|
|
12
|
+
</Text>
|
|
13
|
+
</View>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
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);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { View, ActivityIndicator, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
4
|
+
|
|
5
|
+
function Loader() {
|
|
6
|
+
const { theme } = useTheme();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<View style={[styles.container, { backgroundColor: theme.colors.background }]}>
|
|
10
|
+
<ActivityIndicator size="large" color={theme.colors.primary} />
|
|
11
|
+
</View>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
container: {
|
|
17
|
+
flex: 1,
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default memo(Loader);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as Button } from './ui/Button';
|
|
2
|
+
export { default as ThemedText } from './ui/ThemedText';
|
|
3
|
+
export { default as Loader } from './common/Loader';
|
|
4
|
+
export { default as Header } from './common/Header';
|
|
5
|
+
export { default as Footer } from './common/Footer';
|
|
6
|
+
export { default as CustomOverlay } from './common/CustomOverlay';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { TouchableOpacity, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps {
|
|
5
|
+
title: string;
|
|
6
|
+
onPress: () => void;
|
|
7
|
+
style?: ViewStyle;
|
|
8
|
+
textStyle?: TextStyle;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function Button({ title, onPress, style, textStyle, disabled }: ButtonProps) {
|
|
13
|
+
return (
|
|
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
|
+
}
|
|
24
|
+
|
|
25
|
+
const styles = StyleSheet.create({
|
|
26
|
+
button: {
|
|
27
|
+
backgroundColor: '#007AFF',
|
|
28
|
+
paddingVertical: 12,
|
|
29
|
+
paddingHorizontal: 24,
|
|
30
|
+
borderRadius: 8,
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
justifyContent: 'center',
|
|
33
|
+
},
|
|
34
|
+
text: {
|
|
35
|
+
color: '#fff',
|
|
36
|
+
fontSize: 16,
|
|
37
|
+
fontWeight: '600',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export default memo(Button);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
|
2
|
+
import { Text, TextStyle, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../context/ThemeContext';
|
|
4
|
+
|
|
5
|
+
interface ThemedTextProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
style?: TextStyle;
|
|
8
|
+
type?: 'default' | 'title' | 'subtitle';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ThemedText({ children, style, type = 'default' }: ThemedTextProps) {
|
|
12
|
+
const { theme } = useTheme();
|
|
13
|
+
|
|
14
|
+
const textStyle = useMemo(
|
|
15
|
+
() => [
|
|
16
|
+
styles.default,
|
|
17
|
+
type === 'title' && styles.title,
|
|
18
|
+
type === 'subtitle' && styles.subtitle,
|
|
19
|
+
{ color: theme.colors.text },
|
|
20
|
+
style,
|
|
21
|
+
],
|
|
22
|
+
[theme.colors.text, type, style]
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return <Text style={textStyle}>{children}</Text>;
|
|
26
|
+
}
|
|
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,44 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, useMemo, useCallback, ReactNode } from 'react';
|
|
2
|
+
import { IDMConf } from '../types/IDMConf';
|
|
3
|
+
|
|
4
|
+
interface IDMContextType {
|
|
5
|
+
idmConf: IDMConf;
|
|
6
|
+
setIDMConf: (conf: IDMConf) => void;
|
|
7
|
+
updateIDMConf: (updates: Partial<IDMConf>) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const IDMContext = createContext<IDMContextType | undefined>(undefined);
|
|
11
|
+
|
|
12
|
+
interface IDMProviderProps {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
initialConf: IDMConf;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function IDMProvider({ children, initialConf }: IDMProviderProps) {
|
|
18
|
+
const [idmConf, setIDMConf] = useState<IDMConf>(initialConf);
|
|
19
|
+
|
|
20
|
+
// Optimized partial update function
|
|
21
|
+
const updateIDMConf = useCallback((updates: Partial<IDMConf>) => {
|
|
22
|
+
setIDMConf((prev) => ({ ...prev, ...updates }));
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
// Memoize context value to prevent unnecessary re-renders
|
|
26
|
+
const value = useMemo(
|
|
27
|
+
() => ({ idmConf, setIDMConf, updateIDMConf }),
|
|
28
|
+
[idmConf, updateIDMConf]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<IDMContext.Provider value={value}>
|
|
33
|
+
{children}
|
|
34
|
+
</IDMContext.Provider>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useIDM() {
|
|
39
|
+
const context = useContext(IDMContext);
|
|
40
|
+
if (!context) {
|
|
41
|
+
throw new Error('useIDM must be used within IDMProvider');
|
|
42
|
+
}
|
|
43
|
+
return context;
|
|
44
|
+
}
|