@trustchex/react-native-sdk 1.267.0 → 1.354.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 (72) hide show
  1. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +8 -2
  2. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +5 -1
  3. package/lib/module/Screens/Dynamic/IdentityDocumentScanningScreen.js +5 -1
  4. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +29 -15
  5. package/lib/module/Screens/Static/OTPVerificationScreen.js +285 -0
  6. package/lib/module/Screens/Static/ResultScreen.js +90 -26
  7. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +48 -134
  8. package/lib/module/Shared/Components/DebugNavigationPanel.js +252 -0
  9. package/lib/module/Shared/Components/EIDScanner.js +142 -17
  10. package/lib/module/Shared/Components/FaceCamera.js +23 -11
  11. package/lib/module/Shared/Components/IdentityDocumentCamera.js +295 -44
  12. package/lib/module/Shared/Components/NavigationManager.js +19 -3
  13. package/lib/module/Shared/Config/camera-enhancement.config.js +58 -0
  14. package/lib/module/Shared/Contexts/AppContext.js +1 -0
  15. package/lib/module/Shared/Libs/camera.utils.js +221 -1
  16. package/lib/module/Shared/Libs/frame-enhancement.utils.js +133 -0
  17. package/lib/module/Shared/Libs/mrz.utils.js +98 -1
  18. package/lib/module/Translation/Resources/en.js +30 -0
  19. package/lib/module/Translation/Resources/tr.js +30 -0
  20. package/lib/module/Trustchex.js +49 -39
  21. package/lib/module/version.js +1 -1
  22. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  23. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  24. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentScanningScreen.d.ts.map +1 -1
  25. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  26. package/lib/typescript/src/Screens/Static/OTPVerificationScreen.d.ts +3 -0
  27. package/lib/typescript/src/Screens/Static/OTPVerificationScreen.d.ts.map +1 -0
  28. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  29. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  30. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts +3 -0
  31. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -0
  32. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  33. package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
  34. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  35. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  36. package/lib/typescript/src/Shared/Config/camera-enhancement.config.d.ts +54 -0
  37. package/lib/typescript/src/Shared/Config/camera-enhancement.config.d.ts.map +1 -0
  38. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts +2 -0
  39. package/lib/typescript/src/Shared/Contexts/AppContext.d.ts.map +1 -1
  40. package/lib/typescript/src/Shared/Libs/camera.utils.d.ts +65 -1
  41. package/lib/typescript/src/Shared/Libs/camera.utils.d.ts.map +1 -1
  42. package/lib/typescript/src/Shared/Libs/frame-enhancement.utils.d.ts +25 -0
  43. package/lib/typescript/src/Shared/Libs/frame-enhancement.utils.d.ts.map +1 -0
  44. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  45. package/lib/typescript/src/Translation/Resources/en.d.ts +30 -0
  46. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  47. package/lib/typescript/src/Translation/Resources/tr.d.ts +30 -0
  48. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  49. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  50. package/lib/typescript/src/version.d.ts +1 -1
  51. package/package.json +3 -3
  52. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +6 -2
  53. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +3 -1
  54. package/src/Screens/Dynamic/IdentityDocumentScanningScreen.tsx +3 -1
  55. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +27 -17
  56. package/src/Screens/Static/OTPVerificationScreen.tsx +379 -0
  57. package/src/Screens/Static/ResultScreen.tsx +160 -101
  58. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +51 -196
  59. package/src/Shared/Components/DebugNavigationPanel.tsx +262 -0
  60. package/src/Shared/Components/EIDScanner.tsx +144 -19
  61. package/src/Shared/Components/FaceCamera.tsx +38 -21
  62. package/src/Shared/Components/IdentityDocumentCamera.tsx +399 -101
  63. package/src/Shared/Components/NavigationManager.tsx +19 -3
  64. package/src/Shared/Config/camera-enhancement.config.ts +46 -0
  65. package/src/Shared/Contexts/AppContext.ts +3 -0
  66. package/src/Shared/Libs/camera.utils.ts +240 -1
  67. package/src/Shared/Libs/frame-enhancement.utils.ts +217 -0
  68. package/src/Shared/Libs/mrz.utils.ts +78 -1
  69. package/src/Translation/Resources/en.ts +30 -0
  70. package/src/Translation/Resources/tr.ts +30 -0
  71. package/src/Trustchex.tsx +58 -46
  72. package/src/version.ts +1 -1
@@ -4,7 +4,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useRef, useState }
4
4
  import { SafeAreaView, Text, StyleSheet, Alert, View, Image, Dimensions, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
5
5
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
6
6
  import AppContext from "../../Shared/Contexts/AppContext.js";
7
- import httpClient, { BadRequestError, NotFoundError, TooManyRequestsError } from "../../Shared/Libs/http-client.js";
7
+ import httpClient, { NotFoundError } from "../../Shared/Libs/http-client.js";
8
8
  import { useTranslation } from 'react-i18next';
9
9
  import LanguageSelector from "../../Shared/Components/LanguageSelector.js";
10
10
  import NavigationManager from "../../Shared/Components/NavigationManager.js";
@@ -20,11 +20,8 @@ import { trackError, trackFunnelStep, useScreenTracking } from "../../Shared/Lib
20
20
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
21
21
  const VerificationSessionCheckScreen = () => {
22
22
  const [sessionCode, setSessionCode] = useState('');
23
- const [code, setCode] = useState('');
24
23
  const [isCheckingSession, setIsCheckingSession] = useState(false);
25
- const [isSendAgainEnabled, setIsSendAgainEnabled] = useState(false);
26
- const [isCodeSent, setIsCodeSent] = useState(false);
27
- const [isCodeGettingVerified, setIsCodeGettingVerified] = useState(false);
24
+ const isCheckingSessionRef = useRef(false);
28
25
  const appContext = useContext(AppContext);
29
26
  const {
30
27
  t
@@ -42,9 +39,10 @@ const VerificationSessionCheckScreen = () => {
42
39
  const validateSessionCode = useCallback(value => {
43
40
  return SESSION_CODE_VALIDATION_PATTERN.test(value.toUpperCase());
44
41
  }, []);
45
- const getSession = useCallback(async id => {
42
+ const getSession = useCallback(async (id, isDemoMode) => {
43
+ const isDemo = isDemoMode ?? appContext.isDemoSession;
46
44
  try {
47
- const response = await httpClient.get(`${apiUrl}/verification-sessions/${id}`, appContext.isDemoSession ? getSimulatedDemoData('GET_SESSION') : undefined);
45
+ const response = await httpClient.get(`${apiUrl}/verification-sessions/${id}`, isDemo ? getSimulatedDemoData('GET_SESSION') : undefined);
48
46
  return response;
49
47
  } catch (error) {
50
48
  if (error instanceof NotFoundError) {
@@ -60,9 +58,10 @@ const VerificationSessionCheckScreen = () => {
60
58
  }, [apiUrl, appContext.isDemoSession, t]);
61
59
  const getSessionByCode = useCallback(async inputCode => {
62
60
  try {
63
- appContext.isDemoSession = isDemoSession(inputCode);
64
- analyticsService.setDemoSession(appContext.isDemoSession);
65
- const response = await httpClient.get(`${apiUrl}/verification-sessions?sessionCode=${inputCode.toUpperCase()}`, appContext.isDemoSession ? getSimulatedDemoData('GET_SESSION_BY_CODE') : undefined);
61
+ const isDemoMode = isDemoSession(inputCode);
62
+ appContext.setIsDemoSession?.(isDemoMode);
63
+ analyticsService.setDemoSession(isDemoMode);
64
+ const response = await httpClient.get(`${apiUrl}/verification-sessions?sessionCode=${inputCode.toUpperCase()}`, isDemoMode ? getSimulatedDemoData('GET_SESSION_BY_CODE') : undefined);
66
65
  if (!response || !response.id) {
67
66
  throw new NotFoundError();
68
67
  }
@@ -82,68 +81,17 @@ const VerificationSessionCheckScreen = () => {
82
81
  }
83
82
  }
84
83
  }, [apiUrl, appContext, t]);
85
- const sendVerificationCode = useCallback(async sessionId => {
86
- try {
87
- await httpClient.post(`${apiUrl}/verification-sessions/${sessionId}`, {}, appContext.isDemoSession ? getSimulatedDemoData('SEND_VERIFICATION_CODE') : undefined);
88
- return true;
89
- } catch (error) {
90
- if (error instanceof NotFoundError) {
91
- // Session expired or invalid - expected behavior, not actionable
92
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.noVerificationSessionFound'));
93
- } else if (error instanceof TooManyRequestsError) {
94
- // Code was already sent recently - this is expected behavior
95
- // Return true since the code was already sent
96
- return true;
97
- } else {
98
- trackError('VERIFICATION_CODE_SEND_FAILED', 'Failed to send verification code', 'verification_session_check', 'high', {
99
- recoverable: true,
100
- userAction: 'send_verification_code'
101
- });
102
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.cannotSendVerificationCode'));
103
- }
104
- }
105
- return false;
106
- }, [apiUrl, appContext.isDemoSession, t]);
107
- const getVerifiedSession = useCallback(async (sessionId, verificationCode) => {
108
- try {
109
- const response = await httpClient.post(`${apiUrl}/verification-sessions/${sessionId}`, {
110
- code: verificationCode
111
- }, appContext.isDemoSession ? getSimulatedDemoData('GET_VERIFIED_SESSION', {
112
- code: verificationCode
113
- }) : undefined);
114
- return response;
115
- } catch (error) {
116
- if (error instanceof NotFoundError) {
117
- // Session expired or invalid - expected behavior, not actionable
118
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.noVerificationSessionFound'));
119
- } else if (error instanceof BadRequestError) {
120
- // Wrong OTP code - expected user behavior, not actionable
121
- } else {
122
- trackError('VERIFIED_SESSION_CHECK_ERROR', error instanceof Error ? error.message : 'Unknown error', 'verification_session_check', 'high', {
123
- recoverable: false,
124
- userAction: 'check_verified_session'
125
- });
126
- }
127
- }
128
- }, [apiUrl, appContext.isDemoSession, t]);
129
- const sendOTPCode = useCallback(async sessionId => {
130
- if (!sessionId) {
131
- return false;
132
- }
133
- const isSent = await sendVerificationCode(sessionId);
134
- if (!isSent) {
135
- return false;
136
- }
137
- setIsSendAgainEnabled(false);
138
- setTimeout(() => {
139
- setIsSendAgainEnabled(true);
140
- }, 3 * 60 * 1000);
141
- setIsCodeSent(true);
142
- return true;
143
- }, [sendVerificationCode]);
84
+ const navigateToOTPScreen = useCallback(sessionId => {
85
+ navigation.navigate('OTPVerificationScreen', {
86
+ sessionId
87
+ });
88
+ }, [navigation]);
144
89
  useEffect(() => {
145
- if (!initialized.current && appContext.identificationInfo.sessionId) {
90
+ // Only run this effect if sessionId exists AND we're not currently checking a session
91
+ // This prevents race condition when session code is entered
92
+ if (!initialized.current && appContext.identificationInfo.sessionId && !isCheckingSessionRef.current) {
146
93
  initialized.current = true;
94
+ isCheckingSessionRef.current = true;
147
95
  setIsCheckingSession(true);
148
96
  getSession(appContext.identificationInfo.sessionId).then(session => {
149
97
  appContext.workflowSteps = session?.workflowSteps;
@@ -151,18 +99,21 @@ const VerificationSessionCheckScreen = () => {
151
99
  appContext.branding = appContext.branding || session.branding;
152
100
  }
153
101
  if (session?.sendOTP) {
154
- return sendOTPCode(session.id);
155
- } else if (session?.identificationId) {
156
- appContext.identificationInfo.identificationId = session?.identificationId;
102
+ navigateToOTPScreen(session.id);
103
+ } else {
104
+ if (session?.identificationId) {
105
+ appContext.identificationInfo.identificationId = session?.identificationId;
106
+ }
157
107
  navigationManagerRef.current?.navigateToNextStep();
158
108
  }
159
109
  }).finally(() => {
160
110
  setTimeout(() => {
111
+ isCheckingSessionRef.current = false;
161
112
  setIsCheckingSession(false);
162
113
  }, 1000);
163
114
  });
164
115
  }
165
- }, [appContext, appContext.identificationInfo.sessionId, getSession, sendOTPCode]);
116
+ }, [appContext, appContext.identificationInfo.sessionId, getSession, navigateToOTPScreen]);
166
117
  return /*#__PURE__*/_jsx(SafeAreaView, {
167
118
  style: styles.safeAreaContainer,
168
119
  children: /*#__PURE__*/_jsx(KeyboardAvoidingView, {
@@ -187,13 +138,13 @@ const VerificationSessionCheckScreen = () => {
187
138
  source: require('../../Shared/Assets/trustchex-logo-black.png'),
188
139
  style: styles.trustchexLogo
189
140
  })
190
- }), isCheckingSession || isCodeGettingVerified ? /*#__PURE__*/_jsx(LottieView, {
141
+ }), isCheckingSession ? /*#__PURE__*/_jsx(LottieView, {
191
142
  source: require('../../Shared/Animations/loading.json'),
192
143
  style: styles.loadingAnimation,
193
144
  autoPlay: true,
194
145
  loop: true,
195
146
  resizeMode: "cover"
196
- }) : !isCodeSent ? /*#__PURE__*/_jsxs(_Fragment, {
147
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
197
148
  children: [/*#__PURE__*/_jsx(Text, {
198
149
  style: styles.mainText,
199
150
  children: t('verificationSessionCheckScreen.mainText')
@@ -211,21 +162,37 @@ const VerificationSessionCheckScreen = () => {
211
162
  setSessionCode(alphanumericText);
212
163
  if (validateSessionCode(alphanumericText) && alphanumericText.length === 8) {
213
164
  try {
165
+ isCheckingSessionRef.current = true;
214
166
  setIsCheckingSession(true);
215
- const session = await getSessionByCode(alphanumericText);
216
- if (session?.id) {
167
+ const isDemoMode = isDemoSession(alphanumericText);
168
+ const sessionResponse = await getSessionByCode(alphanumericText);
169
+ if (sessionResponse?.id) {
217
170
  if (appContext.setSessionId) {
218
- appContext.setSessionId(session.id);
171
+ appContext.setSessionId(sessionResponse.id);
219
172
  } else {
220
- appContext.identificationInfo.sessionId = session.id;
173
+ appContext.identificationInfo.sessionId = sessionResponse.id;
174
+ }
175
+ const session = await getSession(sessionResponse.id, isDemoMode);
176
+ appContext.workflowSteps = session?.workflowSteps;
177
+ if (session?.branding) {
178
+ appContext.branding = appContext.branding || session.branding;
179
+ }
180
+ if (session?.sendOTP) {
181
+ navigateToOTPScreen(sessionResponse.id);
182
+ } else {
183
+ if (session?.identificationId) {
184
+ appContext.identificationInfo.identificationId = session?.identificationId;
185
+ }
186
+ navigationManagerRef.current?.navigateToNextStep();
221
187
  }
222
188
  } else {
223
189
  setSessionCode('');
224
190
  }
225
- } catch {
191
+ } catch (error) {
226
192
  setSessionCode('');
227
193
  } finally {
228
194
  setTimeout(() => {
195
+ isCheckingSessionRef.current = false;
229
196
  setIsCheckingSession(false);
230
197
  }, 1000);
231
198
  }
@@ -254,53 +221,6 @@ const VerificationSessionCheckScreen = () => {
254
221
  },
255
222
  children: t('verificationSessionCheckScreen.scanQRCode')
256
223
  })]
257
- }) : /*#__PURE__*/_jsxs(_Fragment, {
258
- children: [/*#__PURE__*/_jsx(Text, {
259
- style: styles.mainText,
260
- children: t('verificationSessionCheckScreen.codeText')
261
- }), /*#__PURE__*/_jsx(StyledTextInput, {
262
- autoFocus: true,
263
- placeholder: "",
264
- borderColor: primaryColor,
265
- focusedBorderColor: primaryColor,
266
- inputStyle: styles.otpCodeTextInput,
267
- keyboardType: "number-pad",
268
- textContentType: "oneTimeCode",
269
- autoComplete: "sms-otp",
270
- maxLength: 6,
271
- onChangeText: text => {
272
- const numericText = text.replace(/[^0-9]/g, '');
273
- if (numericText.length <= 6) {
274
- setCode(numericText);
275
- if (numericText.length === 6) {
276
- (async () => {
277
- setIsCodeGettingVerified(true);
278
- const verifiedSession = await getVerifiedSession(appContext.identificationInfo.sessionId, numericText);
279
- if (verifiedSession?.identificationId) {
280
- appContext.identificationInfo.identificationId = verifiedSession?.identificationId;
281
- setCode('');
282
- setIsCodeSent(false);
283
- navigationManagerRef.current?.navigateToNextStep();
284
- } else {
285
- // User entered wrong OTP code - expected behavior, not actionable
286
- appContext.onError?.('Invalid OTP code');
287
- Alert.alert(t('general.error'), t('verificationSessionCheckScreen.codeError'));
288
- setCode('');
289
- setIsCodeGettingVerified(false);
290
- }
291
- })();
292
- }
293
- }
294
- },
295
- value: code
296
- }), /*#__PURE__*/_jsx(StyledButton, {
297
- mode: "contained",
298
- disabled: !isSendAgainEnabled,
299
- onPress: () => {
300
- sendOTPCode(appContext.identificationInfo.sessionId);
301
- },
302
- children: t('verificationSessionCheckScreen.sendCodeAgain')
303
- })]
304
224
  })]
305
225
  }), appContext.branding.logoUrl && /*#__PURE__*/_jsxs(View, {
306
226
  style: [styles.footer, {
@@ -428,12 +348,6 @@ const styles = StyleSheet.create({
428
348
  letterSpacing: 0,
429
349
  textAlign: 'center',
430
350
  textTransform: 'none'
431
- },
432
- otpCodeTextInput: {
433
- fontWeight: '800',
434
- fontSize: 28,
435
- textAlign: 'center',
436
- letterSpacing: 8
437
351
  }
438
352
  });
439
353
  export default VerificationSessionCheckScreen;
@@ -0,0 +1,252 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useContext, useState } from 'react';
4
+ import { View, Text, TouchableOpacity, StyleSheet, Platform } from 'react-native';
5
+ import { useNavigation } from '@react-navigation/native';
6
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
+ import AppContext from "../Contexts/AppContext.js";
8
+ import { getSimulatedDemoData } from "../Libs/demo.utils.js";
9
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
+ // Icon mapping matching Flutter SDK Material Icons
11
+ const ICONS = {
12
+ LOGIN: '🔑',
13
+ // Icons.login
14
+ HANDSHAKE: '🤝',
15
+ // Icons.handshake
16
+ CREDIT_CARD: '💳',
17
+ // Icons.credit_card
18
+ NFC: '📡',
19
+ // Icons.nfc
20
+ FACE: '👤',
21
+ // Icons.face
22
+ CHECK_CIRCLE: '✅',
23
+ // Icons.check_circle
24
+ BUG_REPORT: '🔧',
25
+ // Icons.bug_report (using wrench for debug)
26
+ PHONE: '📱' // Icons.phone
27
+ };
28
+ const DebugNavigationPanel = () => {
29
+ const [isExpanded, setIsExpanded] = useState(false);
30
+ const navigation = useNavigation();
31
+ const appContext = useContext(AppContext);
32
+ const insets = useSafeAreaInsets();
33
+ const setupDemoSession = useCallback((setDebugFlag = false) => {
34
+ appContext.setIsDemoSession?.(true);
35
+ appContext.identificationInfo.sessionId = 'demo-verification-id';
36
+ appContext.identificationInfo.identificationId = 'demo-identification-id';
37
+ appContext.isDebugNavigated = setDebugFlag;
38
+
39
+ // Populate workflow steps with demo data (including contract URLs)
40
+ const demoSession = getSimulatedDemoData('GET_SESSION');
41
+ appContext.workflowSteps = demoSession.workflowSteps;
42
+ }, [appContext]);
43
+ const screens = [{
44
+ screen: 'VerificationSessionCheckScreen',
45
+ label: 'Session Check',
46
+ icon: ICONS.LOGIN
47
+ }, {
48
+ screen: 'OTPVerificationScreen',
49
+ label: 'OTP',
50
+ icon: ICONS.PHONE,
51
+ setupDemo: () => {
52
+ setupDemoSession(true);
53
+ },
54
+ params: {
55
+ sessionId: 'demo-verification-id'
56
+ }
57
+ }, {
58
+ screen: 'ContractAcceptanceScreen',
59
+ label: 'Consent',
60
+ icon: ICONS.HANDSHAKE,
61
+ setupDemo: () => {
62
+ setupDemoSession(true);
63
+ // Set current workflow step to contract acceptance so demo contract URLs are loaded
64
+ const contractStep = appContext.workflowSteps?.find(step => step.type === 'CONTRACT_ACCEPTANCE');
65
+ if (contractStep) {
66
+ appContext.currentWorkflowStep = contractStep;
67
+ }
68
+ }
69
+ }, {
70
+ screen: 'IdentityDocumentScanningScreen',
71
+ label: 'ID Scan',
72
+ icon: ICONS.CREDIT_CARD,
73
+ setupDemo: () => {
74
+ setupDemoSession(true);
75
+ }
76
+ }, {
77
+ screen: 'IdentityDocumentEIDScanningScreen',
78
+ label: 'eID Scan',
79
+ icon: ICONS.NFC,
80
+ setupDemo: () => {
81
+ setupDemoSession(true);
82
+ }
83
+ }, {
84
+ screen: 'LivenessDetectionScreen',
85
+ label: 'Liveness',
86
+ icon: ICONS.FACE,
87
+ setupDemo: () => {
88
+ setupDemoSession(true);
89
+ }
90
+ }, {
91
+ screen: 'ResultScreen',
92
+ label: 'Result',
93
+ icon: ICONS.CHECK_CIRCLE,
94
+ setupDemo: () => {
95
+ setupDemoSession();
96
+ }
97
+ }];
98
+ const jumpToScreen = useCallback(screen => {
99
+ if (screen.setupDemo) {
100
+ screen.setupDemo();
101
+ }
102
+ navigation.navigate(screen.screen, screen.params);
103
+ setIsExpanded(false);
104
+ }, [navigation]);
105
+
106
+ // Only show in development mode
107
+ if (!__DEV__) {
108
+ return null;
109
+ }
110
+ return /*#__PURE__*/_jsxs(View, {
111
+ style: [styles.container, {
112
+ bottom: 20 + insets.bottom
113
+ }],
114
+ children: [isExpanded && /*#__PURE__*/_jsxs(View, {
115
+ style: styles.panel,
116
+ children: [/*#__PURE__*/_jsx(Text, {
117
+ style: styles.title,
118
+ children: "SDK JUMP TO SCREEN:"
119
+ }), screens.map(screen => /*#__PURE__*/_jsxs(TouchableOpacity, {
120
+ style: styles.screenButton,
121
+ onPress: () => jumpToScreen(screen),
122
+ children: [/*#__PURE__*/_jsx(Text, {
123
+ style: styles.screenIcon,
124
+ children: screen.icon
125
+ }), /*#__PURE__*/_jsx(Text, {
126
+ style: styles.screenLabel,
127
+ children: screen.label
128
+ })]
129
+ }, screen.screen))]
130
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
131
+ style: styles.toggleButton,
132
+ onPress: () => setIsExpanded(!isExpanded),
133
+ children: [/*#__PURE__*/_jsx(Text, {
134
+ style: styles.bugIcon,
135
+ children: ICONS.BUG_REPORT
136
+ }), isExpanded && /*#__PURE__*/_jsxs(_Fragment, {
137
+ children: [/*#__PURE__*/_jsx(View, {
138
+ style: styles.spacing
139
+ }), /*#__PURE__*/_jsx(Text, {
140
+ style: styles.toggleText,
141
+ children: "DEBUG NAV"
142
+ })]
143
+ }), /*#__PURE__*/_jsx(View, {
144
+ style: styles.spacing
145
+ }), /*#__PURE__*/_jsx(Text, {
146
+ style: styles.arrow,
147
+ children: isExpanded ? '▼' : '▲'
148
+ })]
149
+ })]
150
+ });
151
+ };
152
+ const styles = StyleSheet.create({
153
+ container: {
154
+ position: 'absolute',
155
+ right: 20,
156
+ alignItems: 'flex-end',
157
+ zIndex: 9999
158
+ },
159
+ toggleButton: {
160
+ flexDirection: 'row',
161
+ alignItems: 'center',
162
+ backgroundColor: '#FF5252',
163
+ paddingHorizontal: 12,
164
+ paddingVertical: 10,
165
+ borderRadius: 10,
166
+ borderWidth: 2,
167
+ borderColor: 'white',
168
+ ...Platform.select({
169
+ ios: {
170
+ shadowColor: '#000',
171
+ shadowOffset: {
172
+ width: 0,
173
+ height: 4
174
+ },
175
+ shadowOpacity: 0.3,
176
+ shadowRadius: 8
177
+ },
178
+ android: {
179
+ elevation: 8
180
+ }
181
+ })
182
+ },
183
+ bugIcon: {
184
+ fontSize: 24
185
+ },
186
+ spacing: {
187
+ width: 8
188
+ },
189
+ toggleText: {
190
+ color: 'white',
191
+ fontSize: 14,
192
+ fontWeight: 'bold'
193
+ },
194
+ arrow: {
195
+ color: 'white',
196
+ fontSize: 20
197
+ },
198
+ panel: {
199
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
200
+ borderRadius: 12,
201
+ padding: 12,
202
+ marginBottom: 10,
203
+ borderWidth: 1,
204
+ borderColor: 'rgba(255, 82, 82, 0.5)',
205
+ minWidth: 180,
206
+ ...Platform.select({
207
+ ios: {
208
+ shadowColor: '#000',
209
+ shadowOffset: {
210
+ width: 0,
211
+ height: 4
212
+ },
213
+ shadowOpacity: 0.5,
214
+ shadowRadius: 15
215
+ },
216
+ android: {
217
+ elevation: 15
218
+ }
219
+ })
220
+ },
221
+ title: {
222
+ color: 'rgba(255, 255, 255, 0.7)',
223
+ fontSize: 11,
224
+ fontWeight: 'bold',
225
+ letterSpacing: 1.2,
226
+ marginBottom: 12,
227
+ textAlign: 'right'
228
+ },
229
+ screenButton: {
230
+ flexDirection: 'row',
231
+ alignItems: 'center',
232
+ justifyContent: 'flex-start',
233
+ backgroundColor: '#616161',
234
+ paddingHorizontal: 12,
235
+ paddingVertical: 8,
236
+ borderRadius: 4,
237
+ marginBottom: 6
238
+ },
239
+ screenIcon: {
240
+ fontSize: 16,
241
+ marginRight: 8,
242
+ width: 20,
243
+ textAlign: 'center'
244
+ },
245
+ screenLabel: {
246
+ color: 'white',
247
+ fontSize: 12,
248
+ fontWeight: '500',
249
+ flex: 1
250
+ }
251
+ });
252
+ export default DebugNavigationPanel;