@trustchex/react-native-sdk 1.374.0 → 1.409.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 (137) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +1 -21
  2. package/android/src/main/java/com/trustchex/reactnativesdk/mlkit/MLKitModule.kt +1 -1
  3. package/android/src/main/java/com/trustchex/reactnativesdk/opencv/OpenCVModule.kt +636 -301
  4. package/ios/Camera/TrustchexCameraView.swift +9 -20
  5. package/ios/MLKit/MLKitModule.swift +1 -1
  6. package/ios/OpenCV/OpenCVHelper.h +0 -7
  7. package/ios/OpenCV/OpenCVHelper.mm +0 -60
  8. package/ios/OpenCV/OpenCVModule.h +0 -4
  9. package/ios/OpenCV/OpenCVModule.mm +440 -358
  10. package/lib/module/Screens/Debug/BarcodeTestScreen.js +308 -0
  11. package/lib/module/Screens/Debug/MRZTestScreen.js +105 -13
  12. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +49 -29
  13. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +5 -0
  14. package/lib/module/Screens/Dynamic/IdentityDocumentScanningScreen.js +5 -0
  15. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +26 -6
  16. package/lib/module/Screens/Dynamic/VideoCallScreen.js +676 -0
  17. package/lib/module/Screens/Static/OTPVerificationScreen.js +6 -0
  18. package/lib/module/Screens/Static/QrCodeScanningScreen.js +7 -1
  19. package/lib/module/Screens/Static/ResultScreen.js +27 -13
  20. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +51 -51
  21. package/lib/module/Shared/Animations/video-call.json +1 -0
  22. package/lib/module/Shared/Components/DebugNavigationPanel.js +180 -14
  23. package/lib/module/Shared/Components/DebugOverlay.js +541 -0
  24. package/lib/module/Shared/Components/EIDScanner.js +1 -4
  25. package/lib/module/Shared/Components/IdentityDocumentCamera.constants.js +44 -0
  26. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +270 -0
  27. package/lib/module/Shared/Components/IdentityDocumentCamera.js +702 -1703
  28. package/lib/module/Shared/Components/IdentityDocumentCamera.types.js +3 -0
  29. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +273 -0
  30. package/lib/module/Shared/Components/NavigationManager.js +15 -3
  31. package/lib/module/Shared/Contexts/AppContext.js +1 -0
  32. package/lib/module/Shared/Libs/SignalingClient.js +128 -0
  33. package/lib/module/Shared/Libs/analytics.utils.js +4 -0
  34. package/lib/module/Shared/Libs/deeplink.utils.js +9 -1
  35. package/lib/module/Shared/Libs/http-client.js +9 -0
  36. package/lib/module/Shared/Libs/promise.utils.js +16 -2
  37. package/lib/module/Shared/Libs/status-bar.utils.js +21 -0
  38. package/lib/module/Shared/Services/DataUploadService.js +294 -0
  39. package/lib/module/Shared/Services/VideoSessionService.js +156 -0
  40. package/lib/module/Shared/Services/WebRTCService.js +510 -0
  41. package/lib/module/Shared/Types/analytics.types.js +2 -0
  42. package/lib/module/Translation/Resources/en.js +20 -0
  43. package/lib/module/Translation/Resources/tr.js +20 -0
  44. package/lib/module/Trustchex.js +10 -0
  45. package/lib/module/version.js +1 -1
  46. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts +3 -0
  47. package/lib/typescript/src/Screens/Debug/BarcodeTestScreen.d.ts.map +1 -0
  48. package/lib/typescript/src/Screens/Debug/MRZTestScreen.d.ts.map +1 -1
  49. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  50. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  51. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentScanningScreen.d.ts.map +1 -1
  52. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  53. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts +3 -0
  54. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -0
  55. package/lib/typescript/src/Screens/Static/OTPVerificationScreen.d.ts.map +1 -1
  56. package/lib/typescript/src/Screens/Static/QrCodeScanningScreen.d.ts.map +1 -1
  57. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  58. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  59. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  60. package/lib/typescript/src/Shared/Components/DebugOverlay.d.ts +30 -0
  61. package/lib/typescript/src/Shared/Components/DebugOverlay.d.ts.map +1 -0
  62. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  63. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.constants.d.ts +35 -0
  64. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.constants.d.ts.map +1 -0
  65. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts +3 -56
  66. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  67. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +88 -0
  68. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -0
  69. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.types.d.ts +116 -0
  70. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.types.d.ts.map +1 -0
  71. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +93 -0
  72. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -0
  73. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  74. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts +1 -0
  75. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts.map +1 -1
  76. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts +24 -0
  77. package/lib/typescript/src/Shared/Libs/SignalingClient.d.ts.map +1 -0
  78. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  79. package/lib/typescript/src/Shared/Libs/deeplink.utils.d.ts.map +1 -1
  80. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  81. package/lib/typescript/src/Shared/Libs/promise.utils.d.ts.map +1 -1
  82. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts +9 -0
  83. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -0
  84. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts +25 -0
  85. package/lib/typescript/src/Shared/Services/DataUploadService.d.ts.map +1 -0
  86. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts +33 -0
  87. package/lib/typescript/src/Shared/Services/VideoSessionService.d.ts.map +1 -0
  88. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts +58 -0
  89. package/lib/typescript/src/Shared/Services/WebRTCService.d.ts.map +1 -0
  90. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
  91. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  92. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +4 -1
  93. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  94. package/lib/typescript/src/Translation/Resources/en.d.ts +20 -0
  95. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  96. package/lib/typescript/src/Translation/Resources/tr.d.ts +20 -0
  97. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  98. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  99. package/lib/typescript/src/version.d.ts +1 -1
  100. package/package.json +29 -2
  101. package/src/Screens/Debug/BarcodeTestScreen.tsx +317 -0
  102. package/src/Screens/Debug/MRZTestScreen.tsx +107 -13
  103. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +59 -33
  104. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +6 -0
  105. package/src/Screens/Dynamic/IdentityDocumentScanningScreen.tsx +6 -0
  106. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +34 -6
  107. package/src/Screens/Dynamic/VideoCallScreen.tsx +764 -0
  108. package/src/Screens/Static/OTPVerificationScreen.tsx +6 -0
  109. package/src/Screens/Static/QrCodeScanningScreen.tsx +7 -1
  110. package/src/Screens/Static/ResultScreen.tsx +58 -23
  111. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +58 -72
  112. package/src/Shared/Animations/video-call.json +1 -0
  113. package/src/Shared/Components/DebugNavigationPanel.tsx +185 -9
  114. package/src/Shared/Components/DebugOverlay.tsx +656 -0
  115. package/src/Shared/Components/EIDScanner.tsx +1 -5
  116. package/src/Shared/Components/IdentityDocumentCamera.constants.ts +44 -0
  117. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +342 -0
  118. package/src/Shared/Components/IdentityDocumentCamera.tsx +1089 -2465
  119. package/src/Shared/Components/IdentityDocumentCamera.types.ts +136 -0
  120. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +364 -0
  121. package/src/Shared/Components/NavigationManager.tsx +14 -1
  122. package/src/Shared/Contexts/AppContext.ts +2 -0
  123. package/src/Shared/Libs/SignalingClient.ts +189 -0
  124. package/src/Shared/Libs/analytics.utils.ts +4 -0
  125. package/src/Shared/Libs/deeplink.utils.ts +12 -1
  126. package/src/Shared/Libs/http-client.ts +10 -0
  127. package/src/Shared/Libs/promise.utils.ts +16 -2
  128. package/src/Shared/Libs/status-bar.utils.ts +19 -0
  129. package/src/Shared/Services/DataUploadService.ts +395 -0
  130. package/src/Shared/Services/VideoSessionService.ts +190 -0
  131. package/src/Shared/Services/WebRTCService.ts +636 -0
  132. package/src/Shared/Types/analytics.types.ts +2 -0
  133. package/src/Shared/Types/identificationInfo.ts +5 -1
  134. package/src/Translation/Resources/en.ts +25 -0
  135. package/src/Translation/Resources/tr.ts +27 -0
  136. package/src/Trustchex.tsx +12 -2
  137. package/src/version.ts +1 -1
@@ -6,10 +6,16 @@ import AppContext from "../../Shared/Contexts/AppContext.js";
6
6
  import QrCodeScannerCamera from "../../Shared/Components/QrCodeScannerCamera.js";
7
7
  import { useNavigation } from '@react-navigation/native';
8
8
  import { handleDeepLink } from "../../Shared/Libs/deeplink.utils.js";
9
+ import { useKeepAwake } from "../../Shared/Libs/native-keep-awake.utils.js";
10
+ import { useStatusBarWhiteBackground } from "../../Shared/Libs/status-bar.utils.js";
9
11
  import { jsx as _jsx } from "react/jsx-runtime";
10
12
  const QrCodeScanningScreen = () => {
13
+ useKeepAwake();
11
14
  const appContext = React.useContext(AppContext);
12
15
  const navigation = useNavigation();
16
+
17
+ // Configure status bar for white background
18
+ useStatusBarWhiteBackground();
13
19
  const onQrCodeScanned = data => {
14
20
  const [bUrl, sId] = handleDeepLink({
15
21
  url: data
@@ -25,7 +31,7 @@ const QrCodeScanningScreen = () => {
25
31
  } else {
26
32
  appContext.identificationInfo.sessionId = sId;
27
33
  }
28
- navigation.navigate('VerificationSessionCheckScreen');
34
+ navigation.goBack();
29
35
  }
30
36
  };
31
37
  const onClose = () => {
@@ -9,6 +9,7 @@ import RNFS from 'react-native-fs';
9
9
  import NativeProgressBar from "../../Shared/Components/NativeProgressBar.js";
10
10
  import LottieView from 'lottie-react-native';
11
11
  import { runWithRetry } from "../../Shared/Libs/promise.utils.js";
12
+ import { useStatusBarWhiteBackground } from "../../Shared/Libs/status-bar.utils.js";
12
13
  import NavigationManager from "../../Shared/Components/NavigationManager.js";
13
14
  import mrzUtils from "../../Shared/Libs/mrz.utils.js";
14
15
  import { useTranslation } from 'react-i18next';
@@ -35,6 +36,9 @@ const ResultScreen = () => {
35
36
 
36
37
  // Track screen view and exit
37
38
  useScreenTracking('result_screen');
39
+
40
+ // Configure status bar for white background
41
+ useStatusBarWhiteBackground();
38
42
  const formatDate = useCallback(dateStr => {
39
43
  if (!dateStr) return '';
40
44
  try {
@@ -64,12 +68,12 @@ const ResultScreen = () => {
64
68
  }, []);
65
69
  const apiUrl = useMemo(() => `${appContext.baseUrl}/api/app/mobile`, [appContext.baseUrl]);
66
70
  useEffect(() => {
67
- if (appContext.isDemoSession) {
71
+ if (appContext.isDemoSession || appContext.isTestVideoSession) {
68
72
  setShouldShowDemoData(true);
69
73
  // Generate device identifier for demo
70
74
  NativeDeviceInfo.generateHumanReadableIdentifier().then(setDeviceIdentifier);
71
75
  }
72
- }, [appContext.identificationInfo.identificationId, appContext.isDemoSession]);
76
+ }, [appContext.identificationInfo.identificationId, appContext.isDemoSession, appContext.isTestVideoSession]);
73
77
  const createIdentification = useCallback(async identificationId => {
74
78
  await httpClient.post(`${apiUrl}/identifications/${identificationId}`, null);
75
79
  }, [apiUrl]);
@@ -141,7 +145,12 @@ const ResultScreen = () => {
141
145
  nonce
142
146
  });
143
147
  }, [apiUrl, getGenderEnumType]);
144
- const uploadIdentificationMedia = useCallback(async (identificationId, scannedIdentityDocument, livenessDetection) => {
148
+ const uploadIdentificationMedia = useCallback(async (identificationId, scannedIdentityDocument, livenessDetection, skipIfAlreadyUploaded) => {
149
+ // Skip media upload if already uploaded during video call
150
+ if (skipIfAlreadyUploaded) {
151
+ console.log('[ResultScreen] Media already uploaded during video call, skipping');
152
+ return;
153
+ }
145
154
  const uploadFileOptions = {
146
155
  toUrl: `${apiUrl}/identifications/${identificationId}/media`,
147
156
  method: 'POST',
@@ -271,18 +280,23 @@ const ResultScreen = () => {
271
280
  if (!identificationId) {
272
281
  throw new Error('IdentificationId not found');
273
282
  }
283
+ const alreadyUploaded = !!identificationInfo.mediaUploadedDuringVideoCall;
274
284
  const sessionKey = await runWithRetry(() => getSessionKey(apiUrl, appContext.identificationInfo.sessionId));
275
- await runWithRetry(() => createIdentification(identificationId));
285
+ if (!alreadyUploaded) {
286
+ await runWithRetry(() => createIdentification(identificationId));
287
+ }
276
288
  setProgress(20);
277
289
  await runWithRetry(() => submitIdentificationConsent(identificationId, sessionKey));
278
290
  setProgress(30);
279
- const scannedIdentityDocument = identificationInfo.scannedDocument;
280
- if (scannedIdentityDocument && scannedIdentityDocument.documentType !== 'UNKNOWN') {
281
- await runWithRetry(() => submitIdentificationDocument(identificationId, scannedIdentityDocument, sessionKey));
291
+ if (!alreadyUploaded) {
292
+ const scannedIdentityDocument = identificationInfo.scannedDocument;
293
+ if (scannedIdentityDocument && scannedIdentityDocument.documentType !== 'UNKNOWN') {
294
+ await runWithRetry(() => submitIdentificationDocument(identificationId, scannedIdentityDocument, sessionKey));
295
+ }
296
+ setProgress(40);
297
+ const livenessDetection = identificationInfo.livenessDetection;
298
+ await runWithRetry(() => uploadIdentificationMedia(identificationId, scannedIdentityDocument, livenessDetection, false));
282
299
  }
283
- setProgress(40);
284
- const livenessDetection = identificationInfo.livenessDetection;
285
- await runWithRetry(() => uploadIdentificationMedia(identificationId, scannedIdentityDocument, livenessDetection));
286
300
  setProgress(90);
287
301
  await runWithRetry(() => finishIdentification(identificationId, sessionKey));
288
302
  setProgress(100);
@@ -313,12 +327,12 @@ const ResultScreen = () => {
313
327
  }
314
328
  }, [createIdentification, apiUrl, uploadIdentificationMedia, finishIdentification, submitIdentificationDocument, submitIdentificationConsent, t, appContext]);
315
329
  useEffect(() => {
316
- if (appContext.identificationInfo && !appContext.isDemoSession) {
330
+ if (appContext.identificationInfo && !appContext.isDemoSession && !appContext.isTestVideoSession) {
317
331
  submit(appContext.identificationInfo);
318
332
  }
319
- }, [appContext.identificationInfo, appContext.isDemoSession, submit]);
333
+ }, [appContext.identificationInfo, appContext.isDemoSession, appContext.isTestVideoSession, submit]);
320
334
  useEffect(() => {
321
- if (progress === 100 && !appContext.isDemoSession) {
335
+ if (progress === 100 && !appContext.isDemoSession && !appContext.isTestVideoSession) {
322
336
  setTimeout(() => {
323
337
  appContext.onCompleted?.();
324
338
  navigationManagerRef.current?.reset();
@@ -14,27 +14,31 @@ import { analyticsService } from "../../Shared/Services/AnalyticsService.js";
14
14
  import { useTheme } from "../../Shared/Contexts/ThemeContext.js";
15
15
  import LottieView from 'lottie-react-native';
16
16
  import { getSimulatedDemoData, isDemoSession } from "../../Shared/Libs/demo.utils.js";
17
- import { useNavigation, useFocusEffect } from '@react-navigation/native';
17
+ import { useNavigation } from '@react-navigation/native';
18
18
  import { SESSION_CODE_CHARSET_PATTERN, SESSION_CODE_VALIDATION_PATTERN } from "../../Shared/Constants/validation.constants.js";
19
19
  import { trackError, trackFunnelStep, useScreenTracking } from "../../Shared/Libs/analytics.utils.js";
20
+ import { useStatusBarWhiteBackground } from "../../Shared/Libs/status-bar.utils.js";
20
21
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
21
22
  const VerificationSessionCheckScreen = () => {
22
23
  const [sessionCode, setSessionCode] = useState('');
23
24
  const [isCheckingSession, setIsCheckingSession] = useState(false);
24
25
  const isCheckingSessionRef = useRef(false);
26
+ const checkedSessionIdRef = useRef('');
25
27
  const appContext = useContext(AppContext);
26
28
  const {
27
29
  t
28
30
  } = useTranslation();
29
31
  const navigationManagerRef = React.useRef(null);
30
32
  const navigation = useNavigation();
31
- const initialized = useRef(false);
32
33
  const insets = useSafeAreaInsets();
33
34
  const theme = useTheme();
34
35
  const primaryColor = theme.colors.primary;
35
36
 
36
37
  // Track screen view and exit
37
38
  useScreenTracking('verification_session_check');
39
+
40
+ // Configure status bar for white background
41
+ useStatusBarWhiteBackground();
38
42
  const apiUrl = useMemo(() => `${appContext.baseUrl}/api/app/mobile`, [appContext.baseUrl]);
39
43
  const validateSessionCode = useCallback(value => {
40
44
  return SESSION_CODE_VALIDATION_PATTERN.test(value.toUpperCase());
@@ -45,17 +49,15 @@ const VerificationSessionCheckScreen = () => {
45
49
  const response = await httpClient.get(`${apiUrl}/verification-sessions/${id}`, isDemo ? getSimulatedDemoData('GET_SESSION') : undefined);
46
50
  return response;
47
51
  } catch (error) {
48
- if (error instanceof NotFoundError) {
49
- // User entered invalid session ID - expected user behavior, not actionable
50
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.noVerificationSessionFound'));
51
- } else {
52
+ if (!(error instanceof NotFoundError)) {
52
53
  trackError('SESSION_CHECK_ERROR', error instanceof Error ? error.message : 'Unknown error', 'verification_session_check', 'high', {
53
54
  recoverable: false,
54
55
  userAction: 'check_session'
55
56
  });
56
57
  }
58
+ throw error;
57
59
  }
58
- }, [apiUrl, appContext.isDemoSession, t]);
60
+ }, [apiUrl, appContext.isDemoSession]);
59
61
  const getSessionByCode = useCallback(async inputCode => {
60
62
  try {
61
63
  const isDemoMode = isDemoSession(inputCode);
@@ -86,52 +88,50 @@ const VerificationSessionCheckScreen = () => {
86
88
  sessionId
87
89
  });
88
90
  }, [navigation]);
89
-
90
- // Reset initialized flag when screen is focused and sessionId is empty (after reset)
91
- useFocusEffect(useCallback(() => {
92
- if (!appContext.identificationInfo.sessionId) {
93
- initialized.current = false;
94
- isCheckingSessionRef.current = false;
95
- }
96
- }, [appContext.identificationInfo.sessionId]));
91
+ const getSessionRef = useRef(getSession);
92
+ getSessionRef.current = getSession;
93
+ const navigateToOTPScreenRef = useRef(navigateToOTPScreen);
94
+ navigateToOTPScreenRef.current = navigateToOTPScreen;
95
+ const appContextRef = useRef(appContext);
96
+ appContextRef.current = appContext;
97
97
  useEffect(() => {
98
- // Only run this effect if sessionId exists AND we're not currently checking a session
99
- // This prevents race condition when session code is entered
100
- if (!initialized.current && appContext.identificationInfo.sessionId && !isCheckingSessionRef.current) {
101
- initialized.current = true;
102
- isCheckingSessionRef.current = true;
103
- setIsCheckingSession(true);
104
- getSession(appContext.identificationInfo.sessionId).then(session => {
105
- if (!session) {
106
- // Session not found - clear the sessionId and reset flags to allow retry
107
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.noVerificationSessionFound'));
108
- appContext.identificationInfo.sessionId = '';
109
- if (appContext.setSessionId) {
110
- appContext.setSessionId('');
111
- }
112
- initialized.current = false;
113
- return;
114
- }
115
- appContext.workflowSteps = session.workflowSteps;
116
- if (session.branding) {
117
- appContext.branding = appContext.branding || session.branding;
118
- }
119
- if (session.sendOTP) {
120
- navigateToOTPScreen(session.id);
121
- } else {
122
- if (session.identificationId) {
123
- appContext.identificationInfo.identificationId = session.identificationId;
124
- }
125
- navigationManagerRef.current?.navigateToNextStep();
126
- }
127
- }).finally(() => {
128
- setTimeout(() => {
129
- isCheckingSessionRef.current = false;
130
- setIsCheckingSession(false);
131
- }, 1000);
132
- });
98
+ const sid = appContext.identificationInfo.sessionId;
99
+ if (!sid || checkedSessionIdRef.current === sid) {
100
+ return;
133
101
  }
134
- }, [appContext, appContext.identificationInfo.sessionId, getSession, navigateToOTPScreen, t]);
102
+ checkedSessionIdRef.current = sid;
103
+ isCheckingSessionRef.current = true;
104
+ setIsCheckingSession(true);
105
+ getSessionRef.current(sid).then(session => {
106
+ const ctx = appContextRef.current;
107
+ ctx.workflowSteps = session.workflowSteps;
108
+ if (session.branding) {
109
+ ctx.branding = ctx.branding || session.branding;
110
+ }
111
+ if (session.sendOTP) {
112
+ navigateToOTPScreenRef.current(session.id);
113
+ } else {
114
+ if (session.identificationId) {
115
+ ctx.identificationInfo.identificationId = session.identificationId;
116
+ }
117
+ navigationManagerRef.current?.navigateToNextStep();
118
+ }
119
+ }).catch(() => {
120
+ Alert.alert(t('general.error'), t('verificationSessionCheckScreen.noVerificationSessionFound'));
121
+ checkedSessionIdRef.current = '';
122
+ const ctx = appContextRef.current;
123
+ if (ctx.setSessionId) {
124
+ ctx.setSessionId('');
125
+ }
126
+ }).finally(() => {
127
+ isCheckingSessionRef.current = false;
128
+ setIsCheckingSession(false);
129
+ });
130
+ // eslint-disable-next-line react-hooks/exhaustive-deps
131
+ }, [appContext.identificationInfo.sessionId]);
132
+ if (!appContext || !appContext.baseUrl) {
133
+ return null;
134
+ }
135
135
  return /*#__PURE__*/_jsx(SafeAreaView, {
136
136
  style: styles.safeAreaContainer,
137
137
  children: /*#__PURE__*/_jsx(KeyboardAvoidingView, {
@@ -0,0 +1 @@
1
+ {"v":"5.7.3","fr":30,"ip":0,"op":41,"w":600,"h":600,"nm":"Phone Call","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Call Icon","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[293.084,310.786,0],"ix":2},"a":{"a":0,"k":[1371.347,-543.458,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[28,28,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[25,25,100]},{"t":40,"s":[28,28,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-22.59,22.938],[0,0],[23.373,23.448],[0,0],[23.186,-22.195],[0,0],[25.1,60.946],[0,0],[22.137,23.256],[0.601,0.601],[23.496,-22.664],[0,0],[-157.804,5.059]],"o":[[0,0],[23.373,-23.448],[-0.601,-0.601],[-23.249,-22.13],[0,0],[-60.902,-25.206],[0,0],[22.213,-23.184],[0,0],[-23.009,-23.158],[0,0],[-131.678,152.765],[32.193,0.187]],"v":[[1568.371,-346.481],[1586.008,-366.813],[1586.008,-451.645],[1538.775,-488.121],[1455.803,-488.005],[1418.862,-456.878],[1284.51,-591.463],[1315.52,-628.288],[1315.656,-711.279],[1279.141,-758.453],[1195.297,-759.345],[1173.008,-739.964],[1482.685,-310.897]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,10.704],[64.224,0],[0,-10.704],[-10.704,0],[0,-42.816],[-10.704,0]],"o":[[0,-64.224],[-10.704,0],[0,10.704],[42.816,0],[0,10.704],[10.704,0]],"v":[[1526.061,-582.237],[1409.772,-698.526],[1390.391,-679.145],[1409.772,-659.763],[1487.298,-582.237],[1506.679,-562.856]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[10.704,0],[0,10.704],[85.597,0.085],[0,10.704],[-10.704,0],[-0.117,-106.992]],"o":[[-10.704,0],[-0.085,-85.597],[-10.704,0],[0,-10.704],[106.992,0.117],[0,10.704]],"v":[[1584.205,-562.856],[1564.824,-582.237],[1409.772,-737.289],[1390.391,-756.67],[1409.772,-776.052],[1603.587,-582.237]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":45,"st":-8,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Background Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[300,300,0],"ix":2},"a":{"a":0,"k":[1397.949,-584.944,0],"ix":1},"s":{"a":0,"k":[27,27,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-262.123],[262.123,0],[0,262.123],[-262.123,0]],"o":[[0,262.123],[-262.123,0],[0,-262.123],[262.123,0]],"v":[[1872.564,-584.944],[1397.949,-110.329],[923.334,-584.944],[1397.949,-1059.559]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.117700554343,0.127342568192,0.138823505476,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":45,"st":-8,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Small Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":210,"ix":10},"p":{"a":0,"k":[301,301,0],"ix":2},"a":{"a":0,"k":[-7,-71,0],"ix":1},"s":{"a":0,"k":[70,70,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[426,426],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22.03,"s":[0]},{"t":39.5470890812688,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10.769,"s":[0]},{"t":35.7941593937688,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.117647066303,0.125490196078,0.137254901961,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":8,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-7,-71],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":10.7687687687688,"op":45,"st":10.7687687687688,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Medium Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":119,"ix":10},"p":{"a":0,"k":[301,301,0],"ix":2},"a":{"a":0,"k":[-7,-71,0],"ix":1},"s":{"a":0,"k":[85,85,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[426,426],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":12.02,"s":[0]},{"t":29.5370790712588,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0.759,"s":[0]},{"t":25.7841493837588,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.117647066303,0.125490196078,0.137254901961,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-7,-71],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0.75875875875876,"op":45,"st":0.75875875875876,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Large Circle","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[301,301,0],"ix":2},"a":{"a":0,"k":[-7,-71,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[426,426],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15.774,"s":[0]},{"t":33.2908328250125,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4.513,"s":[0]},{"t":29.5379031375125,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.117647066303,0.125490196078,0.137254901961,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":6,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-7,-71],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4.51251251251251,"op":45,"st":4.51251251251251,"bm":0}],"markers":[]}
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { useCallback, useContext, useState } from 'react';
4
- import { View, Text, TouchableOpacity, StyleSheet, Platform, Switch } from 'react-native';
4
+ import { View, Text, TouchableOpacity, StyleSheet, Platform, Switch, ActivityIndicator } from 'react-native';
5
5
  import { useNavigation } from '@react-navigation/native';
6
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
7
  import AppContext from "../Contexts/AppContext.js";
8
8
  import { getSimulatedDemoData } from "../Libs/demo.utils.js";
9
9
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
+ const DEV_BASE_URL = 'https://192.168.0.171:3000';
10
11
  // Icon mapping matching Flutter SDK Material Icons
11
12
  const ICONS = {
12
13
  LOGIN: '�',
@@ -31,6 +32,8 @@ const DebugNavigationPanel = () => {
31
32
  const [voiceGuidanceEnabled, setVoiceGuidanceEnabled] = useState(true);
32
33
  const [allowIdCard, setAllowIdCard] = useState(true);
33
34
  const [allowPassport, setAllowPassport] = useState(true);
35
+ const [isConnectingVideoCall, setIsConnectingVideoCall] = useState(false);
36
+ const [videoCallError, setVideoCallError] = useState(null);
34
37
  const navigation = useNavigation();
35
38
  const appContext = useContext(AppContext);
36
39
  const insets = useSafeAreaInsets();
@@ -151,7 +154,13 @@ const DebugNavigationPanel = () => {
151
154
  }, {
152
155
  screen: 'MRZTestScreen',
153
156
  label: 'MRZ Test',
154
- icon: ICONS.BUG_REPORT
157
+ icon: ICONS.BUG_REPORT,
158
+ isDebug: true
159
+ }, {
160
+ screen: 'BarcodeTestScreen',
161
+ label: 'Barcode Test',
162
+ icon: ICONS.BUG_REPORT,
163
+ isDebug: true
155
164
  }];
156
165
  const selectScreen = useCallback(screen => {
157
166
  if (!screen.hasOptions) {
@@ -167,9 +176,63 @@ const DebugNavigationPanel = () => {
167
176
  setAllowIdCard(true);
168
177
  setAllowPassport(true);
169
178
  }, [navigation]);
170
- const jumpToScreen = useCallback(() => {
171
- if (!selectedScreen) return;
179
+ const handleVideoCallTest = useCallback(async () => {
180
+ setIsConnectingVideoCall(true);
181
+ setVideoCallError(null);
182
+ try {
183
+ const fallbackUrl = (appContext.baseUrl ?? '').replace(/\/$/, '');
184
+ let response;
185
+ let usedBaseUrl = DEV_BASE_URL;
186
+ try {
187
+ response = await fetch(`${DEV_BASE_URL}/api/test/video-sessions/latest`);
188
+ } catch {
189
+ usedBaseUrl = fallbackUrl;
190
+ response = await fetch(`${fallbackUrl}/api/test/video-sessions/latest`);
191
+ }
192
+ const text = await response.text();
193
+ let data;
194
+ try {
195
+ data = JSON.parse(text);
196
+ } catch {
197
+ throw new Error(`Server returned non-JSON (${response.status}): ${text.slice(0, 120)}`);
198
+ }
199
+ if (!response.ok || !data.success) {
200
+ throw new Error(data.message || 'No active test session found');
201
+ }
202
+ // Point SDK at the server where the test session lives.
203
+ // Do NOT call setBaseUrl (state setter) — it triggers a useMemo rebuild in
204
+ // Trustchex.tsx that resets identificationInfo to an empty object before the
205
+ // screen can render. Direct mutation is sufficient for the test flow.
206
+ appContext.baseUrl = usedBaseUrl;
207
+ appContext.isTestVideoSession = true;
208
+ appContext.identificationInfo.identificationId = data.identificationId;
209
+ appContext.identificationInfo.videoSessionId = data.videoSessionId;
210
+ appContext.identificationInfo.sessionId = data.verificationSessionId;
172
211
 
212
+ // Set up a mini workflow: eID scan → video call
213
+ const eidStep = {
214
+ type: 'IDENTITY_DOCUMENT_EID_SCAN',
215
+ required: false,
216
+ data: {
217
+ voiceGuidanceActive: false
218
+ }
219
+ };
220
+ const videoCallStep = {
221
+ type: 'VIDEO_CALL',
222
+ required: true,
223
+ data: {}
224
+ };
225
+ appContext.workflowSteps = [eidStep, videoCallStep];
226
+ appContext.currentWorkflowStep = eidStep;
227
+ navigation.navigate('IdentityDocumentEIDScanningScreen');
228
+ setIsExpanded(false);
229
+ } catch (err) {
230
+ setVideoCallError(err.message || 'Failed to connect');
231
+ } finally {
232
+ setIsConnectingVideoCall(false);
233
+ }
234
+ }, [appContext, navigation]);
235
+ const jumpToScreen = useCallback(() => {
173
236
  // Validate document type selection for document scanning screens
174
237
  if (selectedScreen.hasDocumentTypeOption && !allowIdCard && !allowPassport) {
175
238
  // Don't navigate if no document types are selected
@@ -272,17 +335,56 @@ const DebugNavigationPanel = () => {
272
335
  })
273
336
  })]
274
337
  })]
275
- }) : screens.map(screen => /*#__PURE__*/_jsxs(TouchableOpacity, {
276
- style: styles.screenButton,
277
- onPress: () => selectScreen(screen),
278
- children: [/*#__PURE__*/_jsx(Text, {
279
- style: styles.screenIcon,
280
- children: screen.icon
281
- }), /*#__PURE__*/_jsx(Text, {
282
- style: styles.screenLabel,
283
- children: screen.label
338
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
339
+ children: [screens.filter(s => !s.isDebug).map(screen => /*#__PURE__*/_jsxs(TouchableOpacity, {
340
+ style: styles.screenButton,
341
+ onPress: () => selectScreen(screen),
342
+ children: [/*#__PURE__*/_jsx(Text, {
343
+ style: styles.screenIcon,
344
+ children: screen.icon
345
+ }), /*#__PURE__*/_jsx(Text, {
346
+ style: styles.screenLabel,
347
+ children: screen.label
348
+ })]
349
+ }, screen.screen)), /*#__PURE__*/_jsxs(View, {
350
+ style: styles.sectionDivider,
351
+ children: [/*#__PURE__*/_jsx(View, {
352
+ style: styles.sectionDividerLine
353
+ }), /*#__PURE__*/_jsx(Text, {
354
+ style: styles.sectionDividerLabel,
355
+ children: "DEBUG TOOLS"
356
+ }), /*#__PURE__*/_jsx(View, {
357
+ style: styles.sectionDividerLine
358
+ })]
359
+ }), screens.filter(s => s.isDebug).map(screen => /*#__PURE__*/_jsxs(TouchableOpacity, {
360
+ style: styles.debugScreenButton,
361
+ onPress: () => selectScreen(screen),
362
+ children: [/*#__PURE__*/_jsx(Text, {
363
+ style: styles.screenIcon,
364
+ children: screen.icon
365
+ }), /*#__PURE__*/_jsx(Text, {
366
+ style: styles.debugScreenLabel,
367
+ children: screen.label
368
+ })]
369
+ }, screen.screen)), /*#__PURE__*/_jsxs(TouchableOpacity, {
370
+ style: [styles.videoCallTestButton, isConnectingVideoCall && styles.videoCallTestButtonDisabled],
371
+ onPress: handleVideoCallTest,
372
+ disabled: isConnectingVideoCall,
373
+ children: [isConnectingVideoCall ? /*#__PURE__*/_jsx(ActivityIndicator, {
374
+ size: "small",
375
+ color: "#4CAF50"
376
+ }) : /*#__PURE__*/_jsx(Text, {
377
+ style: styles.screenIcon,
378
+ children: "\uD83D\uDCF9"
379
+ }), /*#__PURE__*/_jsx(Text, {
380
+ style: styles.videoCallTestLabel,
381
+ children: isConnectingVideoCall ? 'Connecting...' : 'Video Call Test'
382
+ })]
383
+ }), videoCallError && /*#__PURE__*/_jsx(Text, {
384
+ style: styles.videoCallTestError,
385
+ children: videoCallError
284
386
  })]
285
- }, screen.screen))]
387
+ })]
286
388
  }), /*#__PURE__*/_jsxs(TouchableOpacity, {
287
389
  style: styles.toggleButton,
288
390
  onPress: () => {
@@ -461,6 +563,70 @@ const styles = StyleSheet.create({
461
563
  },
462
564
  goButtonTextDisabled: {
463
565
  color: '#CCCCCC'
566
+ },
567
+ sectionDivider: {
568
+ flexDirection: 'row',
569
+ alignItems: 'center',
570
+ marginTop: 4,
571
+ marginBottom: 6,
572
+ gap: 6
573
+ },
574
+ sectionDividerLine: {
575
+ flex: 1,
576
+ height: 1,
577
+ backgroundColor: 'rgba(255, 167, 38, 0.4)'
578
+ },
579
+ sectionDividerLabel: {
580
+ color: '#FFA726',
581
+ fontSize: 9,
582
+ fontWeight: 'bold',
583
+ letterSpacing: 1
584
+ },
585
+ debugScreenButton: {
586
+ flexDirection: 'row',
587
+ alignItems: 'center',
588
+ justifyContent: 'flex-start',
589
+ backgroundColor: 'rgba(255, 167, 38, 0.15)',
590
+ borderWidth: 1,
591
+ borderColor: 'rgba(255, 167, 38, 0.4)',
592
+ paddingHorizontal: 12,
593
+ paddingVertical: 8,
594
+ borderRadius: 4,
595
+ marginBottom: 6
596
+ },
597
+ debugScreenLabel: {
598
+ color: '#FFA726',
599
+ fontSize: 12,
600
+ fontWeight: '500',
601
+ flex: 1
602
+ },
603
+ videoCallTestButton: {
604
+ flexDirection: 'row',
605
+ alignItems: 'center',
606
+ justifyContent: 'flex-start',
607
+ backgroundColor: 'rgba(76, 175, 80, 0.15)',
608
+ borderWidth: 1,
609
+ borderColor: 'rgba(76, 175, 80, 0.5)',
610
+ paddingHorizontal: 12,
611
+ paddingVertical: 8,
612
+ borderRadius: 4,
613
+ marginBottom: 6,
614
+ gap: 8
615
+ },
616
+ videoCallTestButtonDisabled: {
617
+ opacity: 0.5
618
+ },
619
+ videoCallTestLabel: {
620
+ color: '#4CAF50',
621
+ fontSize: 12,
622
+ fontWeight: '600',
623
+ flex: 1
624
+ },
625
+ videoCallTestError: {
626
+ color: '#FF5252',
627
+ fontSize: 10,
628
+ marginBottom: 6,
629
+ paddingHorizontal: 4
464
630
  }
465
631
  });
466
632
  export default DebugNavigationPanel;