@transfergratis/react-native-sdk 0.1.4 → 0.1.5
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/build/api/axios.d.ts +30 -0
- package/build/api/axios.d.ts.map +1 -0
- package/build/api/axios.js +92 -0
- package/build/api/axios.js.map +1 -0
- package/build/components/EnhancedCameraView.d.ts +1 -41
- package/build/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.js +75 -34
- package/build/components/EnhancedCameraView.js.map +1 -1
- package/build/components/EnhancedCameraView.web.d.ts +1 -41
- package/build/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/components/EnhancedCameraView.web.js +28 -4
- package/build/components/EnhancedCameraView.web.js.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts +2 -2
- package/build/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/CountrySelectionTemplate.js +71 -114
- package/build/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/FileUploadTemplate.js +7 -3
- package/build/components/KYCElements/FileUploadTemplate.js.map +1 -1
- package/build/components/KYCElements/IDCardCapture.d.ts +7 -2
- package/build/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/components/KYCElements/IDCardCapture.js +253 -104
- package/build/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/components/KYCElements/InitializationStep.d.ts +5 -0
- package/build/components/KYCElements/InitializationStep.d.ts.map +1 -0
- package/build/components/KYCElements/InitializationStep.js +41 -0
- package/build/components/KYCElements/InitializationStep.js.map +1 -0
- package/build/components/KYCElements/LocationCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/LocationCaptureTemplate.js +15 -13
- package/build/components/KYCElements/LocationCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCapture.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCapture.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureEnhanced.js.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts +2 -2
- package/build/components/KYCElements/OrientationVideoCaptureFinal.d.ts.map +1 -1
- package/build/components/KYCElements/OrientationVideoCaptureFinal.js.map +1 -1
- package/build/components/KYCElements/ReviewSubmitTemplate.d.ts +12 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.js +171 -0
- package/build/components/KYCElements/ReviewSubmitTemplate.js.map +1 -0
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts +6 -2
- package/build/components/KYCElements/SelfieCaptureTemplate.d.ts.map +1 -1
- package/build/components/KYCElements/SelfieCaptureTemplate.js +105 -35
- package/build/components/KYCElements/SelfieCaptureTemplate.js.map +1 -1
- package/build/components/KYCElements/VerificationProgressTemplate.d.ts +12 -0
- package/build/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -0
- package/build/components/KYCElements/VerificationProgressTemplate.js +93 -0
- package/build/components/KYCElements/VerificationProgressTemplate.js.map +1 -0
- package/build/components/OverLay/IdCard.d.ts +1 -1
- package/build/components/OverLay/IdCard.d.ts.map +1 -1
- package/build/components/OverLay/IdCard.js +10 -6
- package/build/components/OverLay/IdCard.js.map +1 -1
- package/build/components/OverLay/SelfieOverlay.d.ts +1 -1
- package/build/components/OverLay/SelfieOverlay.d.ts.map +1 -1
- package/build/components/OverLay/SelfieOverlay.js +5 -4
- package/build/components/OverLay/SelfieOverlay.js.map +1 -1
- package/build/components/OverLay/type.d.ts +71 -1
- package/build/components/OverLay/type.d.ts.map +1 -1
- package/build/components/OverLay/type.js.map +1 -1
- package/build/components/TemplateKYCExample.d.ts.map +1 -1
- package/build/components/TemplateKYCExample.js +72 -197
- package/build/components/TemplateKYCExample.js.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.d.ts.map +1 -1
- package/build/components/TemplateKYCFlowRefactored.js +63 -39
- package/build/components/TemplateKYCFlowRefactored.js.map +1 -1
- package/build/components/example/OrientationVideoExample.d.ts.map +1 -1
- package/build/components/example/OrientationVideoExample.js +1 -5
- package/build/components/example/OrientationVideoExample.js.map +1 -1
- package/build/config/countriesData.d.ts +3 -0
- package/build/config/countriesData.d.ts.map +1 -0
- package/build/config/countriesData.js +79 -0
- package/build/config/countriesData.js.map +1 -0
- package/build/config/region_mapping.d.ts +3 -0
- package/build/config/region_mapping.d.ts.map +1 -0
- package/build/config/region_mapping.js +687 -0
- package/build/config/region_mapping.js.map +1 -0
- package/build/hooks/useI18n.d.ts +11 -0
- package/build/hooks/useI18n.d.ts.map +1 -0
- package/build/hooks/useI18n.js +37 -0
- package/build/hooks/useI18n.js.map +1 -0
- package/build/hooks/useOrientationVideo.d.ts +1 -2
- package/build/hooks/useOrientationVideo.d.ts.map +1 -1
- package/build/hooks/useOrientationVideo.js +2 -1
- package/build/hooks/useOrientationVideo.js.map +1 -1
- package/build/hooks/useRealtimeVerifier.d.ts +28 -0
- package/build/hooks/useRealtimeVerifier.d.ts.map +1 -0
- package/build/hooks/useRealtimeVerifier.js +91 -0
- package/build/hooks/useRealtimeVerifier.js.map +1 -0
- package/build/hooks/useTemplateKYCFlow.d.ts +1 -0
- package/build/hooks/useTemplateKYCFlow.d.ts.map +1 -1
- package/build/hooks/useTemplateKYCFlow.js +337 -38
- package/build/hooks/useTemplateKYCFlow.js.map +1 -1
- package/build/i18n/en/index.d.ts +168 -0
- package/build/i18n/en/index.d.ts.map +1 -0
- package/build/i18n/en/index.js +195 -0
- package/build/i18n/en/index.js.map +1 -0
- package/build/i18n/fr/index.d.ts +168 -0
- package/build/i18n/fr/index.d.ts.map +1 -0
- package/build/i18n/fr/index.js +194 -0
- package/build/i18n/fr/index.js.map +1 -0
- package/build/i18n/index.d.ts +10 -0
- package/build/i18n/index.d.ts.map +1 -0
- package/build/i18n/index.js +56 -0
- package/build/i18n/index.js.map +1 -0
- package/build/i18n/types.d.ts +153 -0
- package/build/i18n/types.d.ts.map +1 -0
- package/build/i18n/types.js +3 -0
- package/build/i18n/types.js.map +1 -0
- package/build/i18n/usage-example.d.ts +4 -0
- package/build/i18n/usage-example.d.ts.map +1 -0
- package/build/i18n/usage-example.js +189 -0
- package/build/i18n/usage-example.js.map +1 -0
- package/build/modules/api/CardAuthentification.d.ts +22 -0
- package/build/modules/api/CardAuthentification.d.ts.map +1 -0
- package/build/modules/api/CardAuthentification.js +107 -0
- package/build/modules/api/CardAuthentification.js.map +1 -0
- package/build/modules/api/KYCService.d.ts +57 -1
- package/build/modules/api/KYCService.d.ts.map +1 -1
- package/build/modules/api/KYCService.js +348 -27
- package/build/modules/api/KYCService.js.map +1 -1
- package/build/modules/api/SelfieVerification.d.ts +3 -0
- package/build/modules/api/SelfieVerification.d.ts.map +1 -0
- package/build/modules/api/SelfieVerification.js +9 -0
- package/build/modules/api/SelfieVerification.js.map +1 -0
- package/build/modules/api/backendApi.d.ts +2 -0
- package/build/modules/api/backendApi.d.ts.map +1 -0
- package/build/modules/api/backendApi.js +6 -0
- package/build/modules/api/backendApi.js.map +1 -0
- package/build/modules/api/types.d.ts +20 -0
- package/build/modules/api/types.d.ts.map +1 -0
- package/build/modules/api/types.js +2 -0
- package/build/modules/api/types.js.map +1 -0
- package/build/types/KYC.types.d.ts +59 -7
- package/build/types/KYC.types.d.ts.map +1 -1
- package/build/types/KYC.types.js +9 -1
- package/build/types/KYC.types.js.map +1 -1
- package/build/utils/cropByObb.d.ts +11 -0
- package/build/utils/cropByObb.d.ts.map +1 -0
- package/build/utils/cropByObb.js +78 -0
- package/build/utils/cropByObb.js.map +1 -0
- package/build/utils/get-document-type-info.d.ts +13 -0
- package/build/utils/get-document-type-info.d.ts.map +1 -0
- package/build/utils/get-document-type-info.js +59 -0
- package/build/utils/get-document-type-info.js.map +1 -0
- package/build/utils/pathToBase64.d.ts +3 -0
- package/build/utils/pathToBase64.d.ts.map +1 -0
- package/build/utils/pathToBase64.js +47 -0
- package/build/utils/pathToBase64.js.map +1 -0
- package/build/utils/remove-duplicate.d.ts +2 -0
- package/build/utils/remove-duplicate.d.ts.map +1 -0
- package/build/utils/remove-duplicate.js +4 -0
- package/build/utils/remove-duplicate.js.map +1 -0
- package/package.json +3 -1
- package/src/api/axios.ts +144 -0
- package/src/components/EnhancedCameraView.tsx +96 -78
- package/src/components/EnhancedCameraView.web.tsx +41 -40
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +104 -136
- package/src/components/KYCElements/FileUploadTemplate.tsx +14 -8
- package/src/components/KYCElements/IDCardCapture.tsx +311 -115
- package/src/components/KYCElements/InitializationStep.tsx +53 -0
- package/src/components/KYCElements/LocationCaptureTemplate.tsx +17 -15
- package/src/components/KYCElements/OrientationVideoCapture.tsx +2 -2
- package/src/components/KYCElements/OrientationVideoCaptureEnhanced.tsx +2 -2
- package/src/components/KYCElements/OrientationVideoCaptureFinal.tsx +2 -2
- package/src/components/KYCElements/ReviewSubmitTemplate.tsx +201 -0
- package/src/components/KYCElements/SelfieCaptureTemplate.tsx +140 -53
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +123 -0
- package/src/components/OverLay/IdCard.tsx +17 -9
- package/src/components/OverLay/SelfieOverlay.tsx +6 -5
- package/src/components/OverLay/type.ts +64 -2
- package/src/components/TemplateKYCExample.tsx +76 -197
- package/src/components/TemplateKYCFlowRefactored.tsx +74 -46
- package/src/components/example/OrientationVideoExample.tsx +3 -7
- package/src/config/countriesData.ts +84 -0
- package/src/config/region_mapping.ts +688 -0
- package/src/hooks/useI18n.ts +53 -0
- package/src/hooks/useOrientationVideo.ts +2 -2
- package/src/hooks/useRealtimeVerifier.ts +128 -0
- package/src/hooks/useTemplateKYCFlow.tsx +375 -53
- package/src/i18n/README.md +288 -0
- package/src/i18n/en/index.ts +206 -0
- package/src/i18n/fr/index.ts +205 -0
- package/src/i18n/index.ts +65 -0
- package/src/i18n/types.ts +172 -0
- package/src/i18n/usage-example.tsx +202 -0
- package/src/modules/api/CardAuthentification.ts +114 -0
- package/src/modules/api/KYCService.ts +403 -30
- package/src/modules/api/SelfieVerification.ts +11 -0
- package/src/modules/api/backendApi.ts +8 -0
- package/src/modules/api/types.ts +24 -0
- package/src/types/KYC.types.ts +83 -14
- package/src/utils/cropByObb.ts +99 -0
- package/src/utils/get-document-type-info.ts +62 -0
- package/src/utils/pathToBase64.ts +47 -0
- package/src/utils/remove-duplicate.ts +3 -0
- package/src/types/nativewind.d.ts +0 -2
package/src/api/axios.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import axios, {
|
|
2
|
+
AxiosInstance,
|
|
3
|
+
AxiosRequestConfig,
|
|
4
|
+
InternalAxiosRequestConfig,
|
|
5
|
+
AxiosResponse,
|
|
6
|
+
} from 'axios';
|
|
7
|
+
|
|
8
|
+
export type ApiConfiguration = {
|
|
9
|
+
baseURL: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
authToken?: string;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type ApiErrorData = {
|
|
16
|
+
message?: string;
|
|
17
|
+
code?: string | number;
|
|
18
|
+
details?: unknown;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export class HttpClient {
|
|
22
|
+
private instance: AxiosInstance;
|
|
23
|
+
private apiKey?: string;
|
|
24
|
+
private authToken?: string;
|
|
25
|
+
|
|
26
|
+
constructor(configuration: ApiConfiguration) {
|
|
27
|
+
this.apiKey = configuration.apiKey;
|
|
28
|
+
this.authToken = configuration.authToken;
|
|
29
|
+
this.instance = axios.create({
|
|
30
|
+
baseURL: configuration.baseURL,
|
|
31
|
+
timeout: configuration.timeoutMs ?? 15000,
|
|
32
|
+
headers: {
|
|
33
|
+
Accept: 'application/json',
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
this.instance.interceptors.request.use(
|
|
39
|
+
(request: InternalAxiosRequestConfig) => {
|
|
40
|
+
const headers = request.headers ?? {};
|
|
41
|
+
if (this.apiKey && !headers['x-api-key']) {
|
|
42
|
+
headers['x-api-key'] = this.apiKey;
|
|
43
|
+
}
|
|
44
|
+
if (this.authToken && !headers.Authorization) {
|
|
45
|
+
headers.Authorization = `Bearer ${this.authToken}`;
|
|
46
|
+
}
|
|
47
|
+
request.headers = headers;
|
|
48
|
+
return request;
|
|
49
|
+
},
|
|
50
|
+
(error) => Promise.reject(error)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
this.instance.interceptors.response.use(
|
|
54
|
+
(response: AxiosResponse) => response,
|
|
55
|
+
(error) => {
|
|
56
|
+
if (!error.response) {
|
|
57
|
+
return Promise.reject({
|
|
58
|
+
message: 'Network error. Please check your connection.',
|
|
59
|
+
code: 'network_error',
|
|
60
|
+
details: error?.message,
|
|
61
|
+
} as ApiErrorData);
|
|
62
|
+
}
|
|
63
|
+
const { status, data } = error.response as AxiosResponse<ApiErrorData>;
|
|
64
|
+
if (status === 401) {
|
|
65
|
+
return Promise.reject({
|
|
66
|
+
message: data?.message || 'Unauthorized',
|
|
67
|
+
code: 401,
|
|
68
|
+
details: data,
|
|
69
|
+
} as ApiErrorData);
|
|
70
|
+
}
|
|
71
|
+
return Promise.reject({
|
|
72
|
+
message: data?.message || 'Request failed',
|
|
73
|
+
code: status,
|
|
74
|
+
details: data,
|
|
75
|
+
} as ApiErrorData);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setAuthToken(token?: string): void {
|
|
81
|
+
this.authToken = token;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setApiKey(key?: string): void {
|
|
85
|
+
this.apiKey = key;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setBaseURL(url: string): void {
|
|
89
|
+
this.instance.defaults.baseURL = url;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async get<T = unknown>(url: string, requestConfig?: AxiosRequestConfig): Promise<T> {
|
|
93
|
+
const res = await this.instance.get<T>(url, requestConfig);
|
|
94
|
+
return res.data as T;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async post<T = unknown, B = unknown>(
|
|
98
|
+
url: string,
|
|
99
|
+
body?: B,
|
|
100
|
+
requestConfig?: AxiosRequestConfig
|
|
101
|
+
): Promise<T> {
|
|
102
|
+
const res = await this.instance.post<T>(url, body, requestConfig);
|
|
103
|
+
return res.data as T;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async put<T = unknown, B = unknown>(
|
|
107
|
+
url: string,
|
|
108
|
+
body?: B,
|
|
109
|
+
requestConfig?: AxiosRequestConfig
|
|
110
|
+
): Promise<T> {
|
|
111
|
+
const res = await this.instance.put<T>(url, body, requestConfig);
|
|
112
|
+
return res.data as T;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async patch<T = unknown, B = unknown>(
|
|
116
|
+
url: string,
|
|
117
|
+
body?: B,
|
|
118
|
+
requestConfig?: AxiosRequestConfig
|
|
119
|
+
): Promise<T> {
|
|
120
|
+
const res = await this.instance.patch<T>(url, body, requestConfig);
|
|
121
|
+
return res.data as T;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async delete<T = unknown>(url: string, requestConfig?: AxiosRequestConfig): Promise<T> {
|
|
125
|
+
const res = await this.instance.delete<T>(url, requestConfig);
|
|
126
|
+
return res.data as T;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export default HttpClient;
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
// ml service api
|
|
134
|
+
export const mlService = new HttpClient({
|
|
135
|
+
baseURL: 'https://api.ml.transfergratis.com',
|
|
136
|
+
apiKey: 'your-api-key',
|
|
137
|
+
});
|
|
138
|
+
// backedn service api
|
|
139
|
+
export const backendService = new HttpClient({
|
|
140
|
+
baseURL: 'https://api.backend.transfergratis.com',
|
|
141
|
+
apiKey: 'your-api-key',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
|
|
@@ -1,39 +1,12 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { View, StyleSheet, TouchableOpacity, Text
|
|
2
|
+
import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
|
|
3
3
|
import { Camera, useCameraDevice } from 'react-native-vision-camera';
|
|
4
4
|
import VisionCameraModule from '../modules/camera/VisionCameraModule';
|
|
5
|
+
import { useI18n } from '../hooks/useI18n';
|
|
6
|
+
import { EnhancedCameraViewProps } from './OverLay/type';
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
|
|
6
|
-
export interface EnhancedCameraViewProps {
|
|
7
|
-
instructions?: string;
|
|
8
|
-
showCamera: boolean;
|
|
9
|
-
cameraType?: 'front' | 'back';
|
|
10
|
-
style?: ViewStyle;
|
|
11
|
-
onCapture?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
12
|
-
onError?: (event: { message: string }) => void;
|
|
13
|
-
onClose?: () => void;
|
|
14
|
-
enableFlash?: boolean;
|
|
15
|
-
enableHdr?: boolean;
|
|
16
|
-
quality?: 'low' | 'medium' | 'high';
|
|
17
|
-
showCaptureButton?: boolean;
|
|
18
|
-
showSwitchCamera?: boolean;
|
|
19
|
-
overlayComponent?: React.ReactNode;
|
|
20
|
-
bbox?: {
|
|
21
|
-
xMin: number;
|
|
22
|
-
yMin: number;
|
|
23
|
-
xMax: number;
|
|
24
|
-
yMax: number;
|
|
25
|
-
borderColor?: string;
|
|
26
|
-
borderWidth?: number;
|
|
27
|
-
cornerRadius?: number;
|
|
28
|
-
};
|
|
29
|
-
canFlip?: boolean;
|
|
30
|
-
// Video recording props
|
|
31
|
-
enableVideo?: boolean;
|
|
32
|
-
isRecording?: boolean;
|
|
33
|
-
onVideoRecordingStart?: () => void;
|
|
34
|
-
onVideoRecordingStop?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
35
|
-
videoDuration?: number;
|
|
36
|
-
}
|
|
37
10
|
|
|
38
11
|
export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
39
12
|
instructions = 'Position yourself in the frame and tap the capture button',
|
|
@@ -56,7 +29,10 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
56
29
|
onVideoRecordingStart,
|
|
57
30
|
onVideoRecordingStop,
|
|
58
31
|
videoDuration = 10,
|
|
32
|
+
onSilentCapture,
|
|
33
|
+
silentCaptureResult,
|
|
59
34
|
}) => {
|
|
35
|
+
const { t } = useI18n();
|
|
60
36
|
const camera = useRef<Camera>(null);
|
|
61
37
|
const [cameraType, setCameraType] = useState<'front' | 'back'>(initialCameraType);
|
|
62
38
|
const [hasPermission, setHasPermission] = useState(false);
|
|
@@ -64,6 +40,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
64
40
|
const [flash, setFlash] = useState<'off' | 'on' | 'auto'>('off');
|
|
65
41
|
|
|
66
42
|
const device = useCameraDevice(cameraType);
|
|
43
|
+
console.log({ setCameraType, setFlash });
|
|
67
44
|
|
|
68
45
|
// Check permissions on component mount
|
|
69
46
|
useEffect(() => {
|
|
@@ -78,14 +55,14 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
78
55
|
if (!hasAllPermissions) {
|
|
79
56
|
const granted = await VisionCameraModule.requestAllPermissions();
|
|
80
57
|
if (!granted) {
|
|
81
|
-
onError?.({ message: '
|
|
58
|
+
onError?.({ message: t('camera.permissionRequired') });
|
|
82
59
|
return;
|
|
83
60
|
}
|
|
84
61
|
}
|
|
85
62
|
setHasPermission(true);
|
|
86
63
|
} catch (error) {
|
|
87
64
|
console.error('Error checking permissions:', error);
|
|
88
|
-
onError?.({ message: '
|
|
65
|
+
onError?.({ message: t('camera.errorOccurred') });
|
|
89
66
|
}
|
|
90
67
|
};
|
|
91
68
|
|
|
@@ -96,13 +73,48 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
96
73
|
|
|
97
74
|
const onCameraError = useCallback((error: any) => {
|
|
98
75
|
console.error('Camera error:', error);
|
|
99
|
-
onError?.({ message: error.message || '
|
|
100
|
-
}, [onError]);
|
|
76
|
+
onError?.({ message: error.message || t('camera.errorOccurred') });
|
|
77
|
+
}, [onError, t]);
|
|
78
|
+
|
|
79
|
+
const captureSilentPhoto = useCallback(async () => {
|
|
80
|
+
if (!camera.current || !isInitialized) {
|
|
81
|
+
onError?.({ message: t('camera.notReady') });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log('silentCaptureResult', silentCaptureResult);
|
|
85
|
+
if (silentCaptureResult?.isAnalyzing || silentCaptureResult?.success) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const photo = await camera.current.takePhoto({
|
|
90
|
+
enableShutterSound: true,
|
|
91
|
+
flash: enableFlash ? flash : 'off',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const result = await VisionCameraModule.processPhotoResult(photo);
|
|
95
|
+
onSilentCapture?.(result);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
}, [isInitialized, onError, onSilentCapture]);
|
|
100
|
+
|
|
101
|
+
// Automatically take a silent photo every 5 seconds when ready
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (!showCamera || !isInitialized) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const intervalId = setInterval(() => {
|
|
108
|
+
captureSilentPhoto();
|
|
109
|
+
}, 5000);
|
|
110
|
+
|
|
111
|
+
return () => clearInterval(intervalId);
|
|
112
|
+
}, [showCamera, isInitialized, captureSilentPhoto]);
|
|
101
113
|
|
|
102
114
|
const capturePhoto = useCallback(async () => {
|
|
103
115
|
try {
|
|
104
116
|
if (!camera.current || !isInitialized) {
|
|
105
|
-
onError?.({ message: '
|
|
117
|
+
onError?.({ message: t('camera.notReady') });
|
|
106
118
|
return;
|
|
107
119
|
}
|
|
108
120
|
|
|
@@ -111,13 +123,13 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
111
123
|
flash: enableFlash ? flash : 'off',
|
|
112
124
|
});
|
|
113
125
|
|
|
114
|
-
const result =
|
|
126
|
+
const result = await VisionCameraModule.processPhotoResult(photo);
|
|
115
127
|
onCapture?.(result);
|
|
116
128
|
} catch (error) {
|
|
117
129
|
console.error('Error taking photo:', error);
|
|
118
130
|
onCapture?.({
|
|
119
131
|
success: false,
|
|
120
|
-
error: error instanceof Error ? error.message : '
|
|
132
|
+
error: error instanceof Error ? error.message : t('camera.failedToCapture'),
|
|
121
133
|
});
|
|
122
134
|
}
|
|
123
135
|
}, [isInitialized, quality, flash, enableFlash, onCapture, onError]);
|
|
@@ -125,7 +137,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
125
137
|
const startVideoRecording = useCallback(async () => {
|
|
126
138
|
try {
|
|
127
139
|
if (!camera.current || !isInitialized) {
|
|
128
|
-
onError?.({ message: '
|
|
140
|
+
onError?.({ message: t('camera.notReady') });
|
|
129
141
|
return;
|
|
130
142
|
}
|
|
131
143
|
|
|
@@ -140,7 +152,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
140
152
|
console.error('Recording error:', error);
|
|
141
153
|
onVideoRecordingStop?.({
|
|
142
154
|
success: false,
|
|
143
|
-
error: error.message || '
|
|
155
|
+
error: error.message || t('camera.failedToStartRecording'),
|
|
144
156
|
});
|
|
145
157
|
},
|
|
146
158
|
});
|
|
@@ -150,7 +162,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
150
162
|
console.error('Error starting video recording:', error);
|
|
151
163
|
onVideoRecordingStop?.({
|
|
152
164
|
success: false,
|
|
153
|
-
error: error instanceof Error ? error.message : '
|
|
165
|
+
error: error instanceof Error ? error.message : t('camera.failedToStartRecording'),
|
|
154
166
|
});
|
|
155
167
|
}
|
|
156
168
|
}, [isInitialized, onVideoRecordingStart, onVideoRecordingStop, onError]);
|
|
@@ -158,37 +170,37 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
158
170
|
const stopVideoRecording = useCallback(async () => {
|
|
159
171
|
try {
|
|
160
172
|
if (!camera.current) {
|
|
161
|
-
onError?.({ message: '
|
|
173
|
+
onError?.({ message: t('camera.notReady') });
|
|
162
174
|
return;
|
|
163
175
|
}
|
|
164
176
|
|
|
165
177
|
await camera.current.stopRecording();
|
|
166
178
|
} catch (error) {
|
|
167
179
|
console.error('Error stopping video recording:', error);
|
|
168
|
-
onError?.({ message: '
|
|
180
|
+
onError?.({ message: t('camera.failedToStopRecording') });
|
|
169
181
|
}
|
|
170
182
|
}, [onError]);
|
|
171
183
|
|
|
172
|
-
const switchCamera = useCallback(() => {
|
|
173
|
-
|
|
174
|
-
}, []);
|
|
184
|
+
// const switchCamera = useCallback(() => {
|
|
185
|
+
// setCameraType(current => current === 'front' ? 'back' : 'front');
|
|
186
|
+
// }, []);
|
|
175
187
|
|
|
176
|
-
const toggleFlash = useCallback(() => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}, []);
|
|
188
|
+
// const toggleFlash = useCallback(() => {
|
|
189
|
+
// setFlash(current => {
|
|
190
|
+
// switch (current) {
|
|
191
|
+
// case 'off': return 'on';
|
|
192
|
+
// case 'on': return 'auto';
|
|
193
|
+
// case 'auto': return 'off';
|
|
194
|
+
// default: return 'off';
|
|
195
|
+
// }
|
|
196
|
+
// });
|
|
197
|
+
// }, []);
|
|
186
198
|
|
|
187
199
|
if (!hasPermission) {
|
|
188
200
|
return (
|
|
189
201
|
<View style={[styles.container, style]}>
|
|
190
202
|
<Text style={styles.permissionMessage}>
|
|
191
|
-
|
|
203
|
+
{t('camera.permissionRequired')}
|
|
192
204
|
</Text>
|
|
193
205
|
</View>
|
|
194
206
|
);
|
|
@@ -198,7 +210,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
198
210
|
return (
|
|
199
211
|
<View style={[styles.container, style]}>
|
|
200
212
|
<Text style={styles.errorMessage}>
|
|
201
|
-
|
|
213
|
+
{t('camera.deviceNotAvailable')}
|
|
202
214
|
</Text>
|
|
203
215
|
</View>
|
|
204
216
|
);
|
|
@@ -235,20 +247,20 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
235
247
|
{/* Bounding box overlay */}
|
|
236
248
|
{bbox && (
|
|
237
249
|
<View style={styles.bboxOverlay}>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
<View
|
|
251
|
+
style={[
|
|
252
|
+
styles.bbox,
|
|
253
|
+
{
|
|
254
|
+
left: `${bbox.xMin}%`,
|
|
255
|
+
top: `${bbox.yMin}%`,
|
|
256
|
+
width: `${bbox.xMax - bbox.xMin}%`,
|
|
257
|
+
height: `${bbox.yMax - bbox.yMin}%`,
|
|
258
|
+
borderColor: bbox.borderColor || '#2DBD60',
|
|
259
|
+
borderWidth: bbox.borderWidth || 3,
|
|
260
|
+
borderRadius: bbox.cornerRadius || 8,
|
|
261
|
+
}
|
|
262
|
+
]}
|
|
263
|
+
/>
|
|
252
264
|
</View>
|
|
253
265
|
)}
|
|
254
266
|
|
|
@@ -256,16 +268,16 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
256
268
|
{/* Camera controls */}
|
|
257
269
|
<View style={styles.controlsContainer}>
|
|
258
270
|
{/* Flash button */}
|
|
259
|
-
{enableFlash && (
|
|
271
|
+
{/* {enableFlash && (
|
|
260
272
|
<TouchableOpacity style={styles.controlButton} onPress={toggleFlash}>
|
|
261
273
|
<Text style={styles.controlButtonText}>
|
|
262
274
|
{flash === 'off' ? '⚡' : flash === 'on' ? '⚡️' : '✨'}
|
|
263
275
|
</Text>
|
|
264
276
|
</TouchableOpacity>
|
|
265
|
-
)}
|
|
277
|
+
)} */}
|
|
266
278
|
|
|
267
279
|
{/* Capture button */}
|
|
268
|
-
{showCaptureButton && !enableVideo && (
|
|
280
|
+
{showCaptureButton && !enableVideo && silentCaptureResult?.success && (
|
|
269
281
|
<TouchableOpacity
|
|
270
282
|
style={styles.captureButton}
|
|
271
283
|
onPress={capturePhoto}
|
|
@@ -279,7 +291,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
279
291
|
)}
|
|
280
292
|
|
|
281
293
|
{/* Video recording button */}
|
|
282
|
-
{showCaptureButton && enableVideo && (
|
|
294
|
+
{showCaptureButton && enableVideo && silentCaptureResult?.success && (
|
|
283
295
|
<TouchableOpacity
|
|
284
296
|
style={[
|
|
285
297
|
styles.captureButton,
|
|
@@ -297,10 +309,16 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
297
309
|
)}
|
|
298
310
|
|
|
299
311
|
{/* Switch camera button */}
|
|
300
|
-
{showSwitchCamera && canFlip && (
|
|
312
|
+
{/* {showSwitchCamera && canFlip && (
|
|
301
313
|
<TouchableOpacity style={styles.controlButton} onPress={switchCamera}>
|
|
302
314
|
<Text style={styles.controlButtonText}>🔄</Text>
|
|
303
315
|
</TouchableOpacity>
|
|
316
|
+
)} */}
|
|
317
|
+
|
|
318
|
+
{silentCaptureResult?.isAnalyzing && (
|
|
319
|
+
<View style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 10, borderRadius: 10 }}>
|
|
320
|
+
<Text style={{ color: 'white', fontSize: 16, fontWeight: 'bold' }}>{t('camera.analyzing')}</Text>
|
|
321
|
+
</View>
|
|
304
322
|
)}
|
|
305
323
|
</View>
|
|
306
324
|
</View>
|
|
@@ -1,37 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { View, StyleSheet, TouchableOpacity, Text,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
instructions?: string;
|
|
6
|
-
showCamera: boolean;
|
|
7
|
-
cameraType?: 'front' | 'back';
|
|
8
|
-
style?: ViewStyle;
|
|
9
|
-
onCapture?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
10
|
-
onError?: (event: { message: string }) => void;
|
|
11
|
-
onClose?: () => void;
|
|
12
|
-
enableFlash?: boolean;
|
|
13
|
-
enableHdr?: boolean;
|
|
14
|
-
quality?: 'low' | 'medium' | 'high';
|
|
15
|
-
showCaptureButton?: boolean;
|
|
16
|
-
showSwitchCamera?: boolean;
|
|
17
|
-
overlayComponent?: React.ReactNode;
|
|
18
|
-
bbox?: {
|
|
19
|
-
xMin: number;
|
|
20
|
-
yMin: number;
|
|
21
|
-
xMax: number;
|
|
22
|
-
yMax: number;
|
|
23
|
-
borderColor?: string;
|
|
24
|
-
borderWidth?: number;
|
|
25
|
-
cornerRadius?: number;
|
|
26
|
-
};
|
|
27
|
-
canFlip?: boolean;
|
|
28
|
-
// Video recording props
|
|
29
|
-
enableVideo?: boolean;
|
|
30
|
-
isRecording?: boolean;
|
|
31
|
-
onVideoRecordingStart?: () => void;
|
|
32
|
-
onVideoRecordingStop?: (result: { success: boolean; path?: string; error?: string }) => void;
|
|
33
|
-
videoDuration?: number;
|
|
34
|
-
}
|
|
2
|
+
import { View, StyleSheet, TouchableOpacity, Text, Platform } from 'react-native';
|
|
3
|
+
import { EnhancedCameraViewProps } from './OverLay/type';
|
|
4
|
+
|
|
35
5
|
|
|
36
6
|
export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
37
7
|
instructions = 'Position yourself in the frame and tap the capture button',
|
|
@@ -54,6 +24,8 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
54
24
|
onVideoRecordingStart,
|
|
55
25
|
onVideoRecordingStop,
|
|
56
26
|
videoDuration = 10,
|
|
27
|
+
onSilentCapture,
|
|
28
|
+
silentCaptureResult,
|
|
57
29
|
}) => {
|
|
58
30
|
// Vérification de plateforme - ce composant est uniquement pour le web
|
|
59
31
|
if (Platform.OS !== 'web') {
|
|
@@ -98,7 +70,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
98
70
|
// Test camera permission
|
|
99
71
|
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
|
100
72
|
stream.getTracks().forEach(track => track.stop());
|
|
101
|
-
|
|
73
|
+
|
|
102
74
|
setHasPermission(true);
|
|
103
75
|
await startCamera();
|
|
104
76
|
} catch (error) {
|
|
@@ -150,6 +122,21 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
150
122
|
console.log('isInitialized', onInitialized, onCameraError);
|
|
151
123
|
|
|
152
124
|
const capturePhoto = useCallback(async () => {
|
|
125
|
+
try {
|
|
126
|
+
onCapture && onCapture({
|
|
127
|
+
success: true
|
|
128
|
+
})
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Error taking photo:', error);
|
|
131
|
+
onCapture?.({
|
|
132
|
+
success: false,
|
|
133
|
+
error: error instanceof Error ? error.message : 'Failed to capture photo',
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}, [isInitialized, onCapture, onError]);
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
const captureSilentPhoto = useCallback(async () => {
|
|
153
140
|
try {
|
|
154
141
|
if (!videoRef.current || !canvasRef.current || !isInitialized) {
|
|
155
142
|
onError?.({ message: 'Camera not ready' });
|
|
@@ -174,8 +161,8 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
174
161
|
|
|
175
162
|
// Convert to base64
|
|
176
163
|
const imageDataUrl = canvas.toDataURL('image/jpeg', 0.8);
|
|
177
|
-
|
|
178
|
-
|
|
164
|
+
|
|
165
|
+
onSilentCapture?.({
|
|
179
166
|
success: true,
|
|
180
167
|
path: imageDataUrl,
|
|
181
168
|
});
|
|
@@ -186,7 +173,21 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
186
173
|
error: error instanceof Error ? error.message : 'Failed to capture photo',
|
|
187
174
|
});
|
|
188
175
|
}
|
|
189
|
-
}, [isInitialized,
|
|
176
|
+
}, [isInitialized, onError, onSilentCapture]);
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// Automatically take a silent photo every 5 seconds when ready
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
if (!showCamera || !isInitialized) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const intervalId = setInterval(() => {
|
|
186
|
+
captureSilentPhoto();
|
|
187
|
+
}, 5000);
|
|
188
|
+
|
|
189
|
+
return () => clearInterval(intervalId);
|
|
190
|
+
}, [showCamera, isInitialized, captureSilentPhoto]);
|
|
190
191
|
|
|
191
192
|
const startVideoRecording = useCallback(async () => {
|
|
192
193
|
try {
|
|
@@ -211,12 +212,12 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
211
212
|
recorder.onstop = () => {
|
|
212
213
|
const blob = new Blob(chunks, { type: 'video/webm' });
|
|
213
214
|
const url = URL.createObjectURL(blob);
|
|
214
|
-
|
|
215
|
+
|
|
215
216
|
onVideoRecordingStop?.({
|
|
216
217
|
success: true,
|
|
217
218
|
path: url,
|
|
218
219
|
});
|
|
219
|
-
|
|
220
|
+
|
|
220
221
|
setRecordedChunks([]);
|
|
221
222
|
setIsRecordingVideo(false);
|
|
222
223
|
};
|
|
@@ -361,7 +362,7 @@ export const EnhancedCameraView: React.FC<EnhancedCameraViewProps> = ({
|
|
|
361
362
|
)}
|
|
362
363
|
|
|
363
364
|
{/* Capture button */}
|
|
364
|
-
{showCaptureButton && !enableVideo && (
|
|
365
|
+
{showCaptureButton && !enableVideo && silentCaptureResult?.success && (
|
|
365
366
|
<TouchableOpacity
|
|
366
367
|
style={styles.captureButton}
|
|
367
368
|
onPress={capturePhoto}
|