react-native-inapp-inspector 1.0.4 → 1.0.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.
Files changed (46) hide show
  1. package/README.md +3 -3
  2. package/dist/commonjs/components/AnalyticsEventCard.js +10 -10
  3. package/dist/commonjs/components/CodeSnippet.js +233 -10
  4. package/dist/commonjs/components/ConsoleLogCard.js +55 -9
  5. package/dist/commonjs/components/CopyButton.js +2 -1
  6. package/dist/commonjs/components/ErrorBoundary.d.ts +20 -0
  7. package/dist/commonjs/components/ErrorBoundary.js +332 -0
  8. package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
  9. package/dist/commonjs/components/NetworkIcons.js +45 -1
  10. package/dist/commonjs/customHooks/reduxLogger.d.ts +4 -0
  11. package/dist/commonjs/customHooks/reduxLogger.js +30 -0
  12. package/dist/commonjs/customHooks/webViewLogger.d.ts +2 -0
  13. package/dist/commonjs/customHooks/webViewLogger.js +281 -246
  14. package/dist/commonjs/helpers/index.js +2 -1
  15. package/dist/commonjs/index.d.ts +5 -3
  16. package/dist/commonjs/index.js +685 -911
  17. package/dist/commonjs/styles/AppColors.d.ts +29 -1
  18. package/dist/commonjs/styles/AppColors.js +38 -2
  19. package/dist/commonjs/styles/index.d.ts +438 -229
  20. package/dist/commonjs/styles/index.js +448 -209
  21. package/dist/commonjs/types/index.d.ts +2 -2
  22. package/dist/esm/components/AnalyticsEventCard.js +10 -10
  23. package/dist/esm/components/CodeSnippet.js +232 -12
  24. package/dist/esm/components/ConsoleLogCard.js +55 -9
  25. package/dist/esm/components/CopyButton.js +2 -1
  26. package/dist/esm/components/ErrorBoundary.d.ts +20 -0
  27. package/dist/esm/components/ErrorBoundary.js +295 -0
  28. package/dist/esm/components/NetworkIcons.d.ts +5 -0
  29. package/dist/esm/components/NetworkIcons.js +39 -0
  30. package/dist/esm/customHooks/reduxLogger.d.ts +4 -0
  31. package/dist/esm/customHooks/reduxLogger.js +23 -0
  32. package/dist/esm/customHooks/webViewLogger.d.ts +2 -0
  33. package/dist/esm/customHooks/webViewLogger.js +281 -246
  34. package/dist/esm/helpers/index.js +2 -1
  35. package/dist/esm/index.d.ts +5 -3
  36. package/dist/esm/index.js +683 -914
  37. package/dist/esm/styles/AppColors.d.ts +29 -1
  38. package/dist/esm/styles/AppColors.js +35 -1
  39. package/dist/esm/styles/index.d.ts +438 -229
  40. package/dist/esm/styles/index.js +412 -209
  41. package/dist/esm/types/index.d.ts +2 -2
  42. package/example/App.tsx +351 -127
  43. package/example/ios/Podfile.lock +26 -0
  44. package/example/package-lock.json +20 -4
  45. package/example/package.json +4 -3
  46. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- export type ActiveTab = 'apis' | 'analytics' | 'logs' | 'webview';
2
+ export type ActiveTab = 'insights' | 'apis' | 'analytics' | 'logs' | 'webview' | 'redux';
3
3
  export interface ConsoleLog {
4
4
  id: number;
5
5
  type: 'info' | 'warn' | 'error';
@@ -73,7 +73,7 @@ export type DiffResult = {
73
73
  newVal?: any;
74
74
  };
75
75
  export interface CopyButtonProps {
76
- value: unknown;
76
+ value: unknown | (() => unknown);
77
77
  label: string;
78
78
  iconType?: 'copy' | 'terminal' | 'fetch';
79
79
  }
package/example/App.tsx CHANGED
@@ -8,118 +8,289 @@ import {
8
8
  ScrollView,
9
9
  useColorScheme,
10
10
  } from 'react-native';
11
- import { SafeAreaProvider } from 'react-native-safe-area-context';
11
+ import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
12
12
  import { NavigationContainer } from '@react-navigation/native';
13
13
  import { createNativeStackNavigator } from '@react-navigation/native-stack';
14
- import NetworkInspector from 'react-native-inapp-inspector';
14
+ import NetworkInspector, {
15
+ WebView,
16
+ ErrorBoundary,
17
+ connectReduxStore,
18
+ subscribeNetworkLogs,
19
+ subscribeConsoleLogs,
20
+ } from 'react-native-inapp-inspector';
21
+
22
+ // ─── Mock Redux Store ────────────────────────────────────────────────────────
23
+ const mockStore = {
24
+ state: {
25
+ auth: {
26
+ user: { id: 101, name: 'Venkatesh', role: 'Lead Architect' },
27
+ token: 'bearer-jwt-tok_5548b366d86',
28
+ isAuthenticated: true,
29
+ lastLogin: new Date().toLocaleTimeString(),
30
+ },
31
+ settings: {
32
+ theme: 'dark',
33
+ notifications: true,
34
+ fontSize: 14,
35
+ locales: ['en-US', 'ta-IN'],
36
+ },
37
+ ui: {
38
+ sidebarOpen: false,
39
+ activeModal: null,
40
+ loadingStates: {
41
+ fetchUser: false,
42
+ updateSettings: false,
43
+ },
44
+ },
45
+ },
46
+ listeners: new Set<() => void>(),
47
+ getState() {
48
+ return this.state;
49
+ },
50
+ subscribe(listener: () => void) {
51
+ this.listeners.add(listener);
52
+ return () => {
53
+ this.listeners.delete(listener);
54
+ };
55
+ },
56
+ dispatch(action: any) {
57
+ console.log('[Mock Redux] Dispatching action:', action);
58
+ if (action.type === 'TOGGLE_SIDEBAR') {
59
+ this.state = {
60
+ ...this.state,
61
+ ui: {
62
+ ...this.state.ui,
63
+ sidebarOpen: !this.state.ui.sidebarOpen,
64
+ },
65
+ };
66
+ } else if (action.type === 'SET_THEME') {
67
+ this.state = {
68
+ ...this.state,
69
+ settings: {
70
+ ...this.state.settings,
71
+ theme: action.payload,
72
+ },
73
+ };
74
+ } else if (action.type === 'UPDATE_USER_TIME') {
75
+ this.state = {
76
+ ...this.state,
77
+ auth: {
78
+ ...this.state.auth,
79
+ lastLogin: new Date().toLocaleTimeString(),
80
+ },
81
+ };
82
+ }
83
+ this.listeners.forEach(l => l());
84
+ },
85
+ };
86
+
87
+ // Connect mock store to the inspector
88
+ connectReduxStore(mockStore);
89
+
90
+ function BuggyComponent({ type }: { type: 'js' | 'native' }) {
91
+ if (type === 'js') {
92
+ throw new Error('Simulated JavaScript Crash: ReferenceError: x is not defined in App.tsx at line 67');
93
+ }
94
+ if (type === 'native') {
95
+ throw new Error('Simulated Native Crash: fatal error: Index out of range in Native Swift/Java module at line 70');
96
+ }
97
+ return null;
98
+ }
15
99
 
16
100
  function HomeScreen({ navigation }: any) {
101
+ const [activeCrash, setActiveCrash] = React.useState<'none' | 'js' | 'native'>('none');
102
+ const [apiCount, setApiCount] = React.useState(0);
103
+ const [logCount, setLogCount] = React.useState(0);
104
+ const [reduxState, setReduxState] = React.useState(mockStore.getState());
105
+
106
+ React.useEffect(() => {
107
+ // Subscribe to logs to display live dashboard counters
108
+ const unsubNet = subscribeNetworkLogs(logs => setApiCount(logs.length));
109
+ const unsubConsole = subscribeConsoleLogs(logs => setLogCount(logs.length));
110
+ const unsubRedux = mockStore.subscribe(() => setReduxState(mockStore.getState()));
111
+
112
+ // Initial Logs to populate stats
113
+ console.log('[App] HomeScreen mounted and ready.');
114
+ console.warn('[App] Check the Redux tab to inspect the connected state!');
115
+
116
+ return () => {
117
+ unsubNet();
118
+ unsubConsole();
119
+ unsubRedux();
120
+ };
121
+ }, []);
122
+
17
123
  const triggerNetworkRequest = async () => {
18
124
  try {
19
- console.log('[API] Triggering network request...');
20
- const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
125
+ console.log('[API] Triggering fetch user...');
126
+ const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
21
127
  const data = await response.json();
22
- console.log('[API] Network request succeeded:', data);
128
+ console.log('[API] Fetch completed successfully:', data.name);
23
129
  } catch (error) {
24
- console.error('[API] Network request failed:', error);
130
+ console.error('[API] Fetch failed:', error);
25
131
  }
26
132
  };
27
133
 
28
134
  const triggerFailedNetworkRequest = async () => {
29
135
  try {
30
- console.log('[API] Triggering failing network request...');
31
- await fetch('https://jsonplaceholder.typicode.com/invalid-url-404');
136
+ console.log('[API] Triggering failing fetch request...');
137
+ await fetch('https://jsonplaceholder.typicode.com/invalid-route-error');
32
138
  } catch (error) {
33
- console.error('[API] Network request failed:', error);
139
+ console.error('[API] Fetch failed with error:', error);
34
140
  }
35
141
  };
36
142
 
37
143
  const triggerConsoleLogs = () => {
38
- console.log('[App] Normal log triggered at ' + new Date().toLocaleTimeString());
39
- console.warn('[App] Warning log triggered. Something might be off!');
40
- console.error('[App] Error log triggered! Simulated critical error.');
144
+ console.log('[App] Manual log triggered at ' + new Date().toLocaleTimeString());
145
+ console.warn('[App] Simulated warning. Please check the API config.');
146
+ console.error('[App] Simulated error! Critical DB connection timeout.');
41
147
  };
42
148
 
43
- React.useEffect(() => {
44
- console.log('[Test] HomeScreen mounted, triggering automated tests...');
45
- triggerNetworkRequest();
46
- triggerConsoleLogs();
47
-
48
- const timer = setTimeout(() => {
49
- console.log('[Test] Navigating to Details screen...');
50
- navigation.navigate('Details');
51
- }, 2500);
52
-
53
- return () => clearTimeout(timer);
54
- }, []);
149
+ const handleToggleSidebar = () => {
150
+ mockStore.dispatch({ type: 'TOGGLE_SIDEBAR' });
151
+ mockStore.dispatch({ type: 'UPDATE_USER_TIME' });
152
+ };
55
153
 
56
154
  return (
57
- <View style={styles.container}>
58
- <ScrollView contentContainerStyle={styles.content}>
59
- <Text style={styles.title}>RN In-App Inspector</Text>
60
- <Text style={styles.subtitle}>Reference Implementation</Text>
61
-
62
- <View style={styles.card}>
63
- <Text style={styles.cardTitle}>Inspect Network & Console Logs</Text>
64
- <Text style={styles.cardDesc}>
65
- Tap the buttons below to trigger simulated background events, then click the floating inspector badge to open the inspector overlay.
155
+ <SafeAreaView style={styles.safeContainer}>
156
+ <ScrollView contentContainerStyle={styles.content} showsVerticalScrollIndicator={false}>
157
+ {/* Header Hero Section */}
158
+ <View style={styles.headerHero}>
159
+ <Text style={styles.headerBadge}>INSPECTOR PLAYGROUND</Text>
160
+ <Text style={styles.headerTitle}>Debug Dashboard</Text>
161
+ <Text style={styles.headerSubtitle}>
162
+ A plug-and-play developer kit for real-time inspection.
66
163
  </Text>
164
+ </View>
67
165
 
68
- <TouchableOpacity style={styles.button} onPress={triggerNetworkRequest}>
69
- <Text style={styles.buttonText}>Trigger Fetch (200 OK)</Text>
70
- </TouchableOpacity>
166
+ {/* System Status Metrics Card */}
167
+ <View style={styles.statsCard}>
168
+ <Text style={styles.sectionTitle}>SYSTEM STATUS</Text>
169
+ <View style={styles.statsGrid}>
170
+ <View style={styles.statBox}>
171
+ <Text style={styles.statVal}>{apiCount}</Text>
172
+ <Text style={styles.statLbl}>APIs</Text>
173
+ </View>
174
+ <View style={styles.statBox}>
175
+ <Text style={styles.statVal}>{logCount}</Text>
176
+ <Text style={styles.statLbl}>Logs</Text>
177
+ </View>
178
+ <View style={styles.statBox}>
179
+ <Text style={[styles.statVal, { color: '#A78BFA' }]}>
180
+ {reduxState.ui.sidebarOpen ? 'Open' : 'Closed'}
181
+ </Text>
182
+ <Text style={styles.statLbl}>Sidebar</Text>
183
+ </View>
184
+ </View>
185
+ </View>
71
186
 
72
- <TouchableOpacity style={[styles.button, styles.dangerButton]} onPress={triggerFailedNetworkRequest}>
73
- <Text style={styles.buttonText}>Trigger Fetch (404 Error)</Text>
74
- </TouchableOpacity>
187
+ {/* Action Panel Grid */}
188
+ <View style={styles.panelCard}>
189
+ <Text style={styles.panelHeader}>🌐 API & NETWORK TESTS</Text>
190
+ <View style={styles.btnRow}>
191
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#38BDF8' }]} onPress={triggerNetworkRequest}>
192
+ <Text style={[styles.btnText, { color: '#38BDF8' }]}>Fetch (200 OK)</Text>
193
+ </TouchableOpacity>
194
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#F43F5E' }]} onPress={triggerFailedNetworkRequest}>
195
+ <Text style={[styles.btnText, { color: '#F43F5E' }]}>Fetch (404 Err)</Text>
196
+ </TouchableOpacity>
197
+ </View>
198
+ </View>
75
199
 
76
- <TouchableOpacity style={[styles.button, styles.infoButton]} onPress={triggerConsoleLogs}>
77
- <Text style={styles.buttonText}>Trigger Console Logs</Text>
200
+ <View style={styles.panelCard}>
201
+ <Text style={styles.panelHeader}>📝 CONSOLE EVENT ACTIONS</Text>
202
+ <TouchableOpacity style={[styles.fullWidthBtn, { backgroundColor: '#6366F1' }]} onPress={triggerConsoleLogs}>
203
+ <Text style={styles.fullWidthBtnText}>Trigger Log, Warn & Error Logs</Text>
78
204
  </TouchableOpacity>
79
-
80
- <TouchableOpacity style={[styles.button, styles.successButton]} onPress={() => navigation.navigate('Details')}>
81
- <Text style={styles.buttonText}>Go to Details Screen</Text>
205
+ </View>
206
+
207
+ <View style={styles.panelCard}>
208
+ <Text style={styles.panelHeader}>⚙️ REDUX & STATE ACTIONS</Text>
209
+ <TouchableOpacity style={[styles.fullWidthBtn, { backgroundColor: '#8B5CF6' }]} onPress={handleToggleSidebar}>
210
+ <Text style={styles.fullWidthBtnText}>Dispatch: Toggle Sidebar & Update Time</Text>
82
211
  </TouchableOpacity>
83
212
  </View>
213
+
214
+ <View style={styles.panelCard}>
215
+ <Text style={styles.panelHeader}>➔ ROUTING & WEBVIEW</Text>
216
+ <View style={styles.btnRow}>
217
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#10B981' }]} onPress={() => navigation.navigate('Details')}>
218
+ <Text style={[styles.btnText, { color: '#10B981' }]}>Go to Details</Text>
219
+ </TouchableOpacity>
220
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#F59E0B' }]} onPress={() => navigation.navigate('WebView')}>
221
+ <Text style={[styles.btnText, { color: '#F59E0B' }]}>Go to WebView</Text>
222
+ </TouchableOpacity>
223
+ </View>
224
+ </View>
225
+
226
+ <View style={[styles.panelCard, { borderColor: '#F43F5E' }]}>
227
+ <Text style={[styles.panelHeader, { color: '#F43F5E' }]}>💥 CRASH SIMULATION TESTS</Text>
228
+ <View style={styles.btnRow}>
229
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#F43F5E', backgroundColor: 'rgba(244,63,94,0.05)' }]} onPress={() => setActiveCrash('js')}>
230
+ <Text style={[styles.btnText, { color: '#F43F5E' }]}>JS Crash</Text>
231
+ </TouchableOpacity>
232
+ <TouchableOpacity style={[styles.gridBtn, { borderColor: '#EF4444', backgroundColor: 'rgba(239,68,68,0.1)' }]} onPress={() => setActiveCrash('native')}>
233
+ <Text style={[styles.btnText, { color: '#EF4444' }]}>Native Crash</Text>
234
+ </TouchableOpacity>
235
+ </View>
236
+ </View>
84
237
  </ScrollView>
85
- <NetworkInspector />
86
- </View>
238
+ {activeCrash !== 'none' && <BuggyComponent type={activeCrash} />}
239
+ </SafeAreaView>
87
240
  );
88
241
  }
89
242
 
90
243
  function DetailsScreen({ navigation }: any) {
91
244
  const triggerDetailLogs = () => {
92
- console.log('[Details] User navigated to details screen and triggered a log.');
245
+ console.log('[Details] User triggered log from Details screen.');
93
246
  };
94
247
 
95
248
  React.useEffect(() => {
96
249
  console.log('[Test] DetailsScreen mounted!');
97
- triggerDetailLogs();
98
250
  }, []);
99
251
 
100
252
  return (
101
- <View style={styles.container}>
253
+ <SafeAreaView style={styles.safeContainer}>
102
254
  <ScrollView contentContainerStyle={styles.content}>
103
- <Text style={styles.title}>Details Screen</Text>
104
- <Text style={styles.subtitle}>Navigation State Verification</Text>
105
-
106
- <View style={styles.card}>
107
- <Text style={styles.cardTitle}>Verify Navigation Routing</Text>
108
- <Text style={styles.cardDesc}>
109
- The inspector tracks your current navigation route. Open the inspector overlay and check the 'route' metadata on new network/console logs.
255
+ <View style={styles.headerHero}>
256
+ <Text style={styles.headerBadge}>DETAILS MODULE</Text>
257
+ <Text style={styles.headerTitle}>Navigation Tracking</Text>
258
+ <Text style={styles.headerSubtitle}>
259
+ The breadcrumbs inside the inspector track your stack route in real-time.
110
260
  </Text>
261
+ </View>
111
262
 
112
- <TouchableOpacity style={styles.button} onPress={triggerDetailLogs}>
113
- <Text style={styles.buttonText}>Trigger Log from Details</Text>
263
+ <View style={styles.panelCard}>
264
+ <Text style={styles.panelHeader}>MODULE ACTIONS</Text>
265
+ <TouchableOpacity style={[styles.fullWidthBtn, { backgroundColor: '#10B981', marginBottom: 12 }]} onPress={triggerDetailLogs}>
266
+ <Text style={styles.fullWidthBtnText}>Trigger Log from Details Screen</Text>
114
267
  </TouchableOpacity>
115
268
 
116
- <TouchableOpacity style={[styles.button, styles.secondaryButton]} onPress={() => navigation.goBack()}>
117
- <Text style={styles.buttonText}>Go Back Home</Text>
269
+ <TouchableOpacity style={[styles.fullWidthBtn, { backgroundColor: '#475569' }]} onPress={() => navigation.goBack()}>
270
+ <Text style={styles.fullWidthBtnText}>Go Back Home</Text>
118
271
  </TouchableOpacity>
119
272
  </View>
120
273
  </ScrollView>
121
- <NetworkInspector />
122
- </View>
274
+ </SafeAreaView>
275
+ );
276
+ }
277
+
278
+ function WebViewScreen({ navigation }: any) {
279
+ React.useEffect(() => {
280
+ console.log('[WebView] WebViewScreen mounted, loading apple.com...');
281
+ }, []);
282
+
283
+ return (
284
+ <SafeAreaView style={styles.safeContainer}>
285
+ <View style={{ flex: 1 }}>
286
+ <WebView
287
+ source={{ uri: 'https://apple.com' }}
288
+ style={{ flex: 1 }}
289
+ onLoadStart={() => console.log('[WebView] Navigation started to apple.com')}
290
+ onLoadEnd={() => console.log('[WebView] Navigation finished loading apple.com')}
291
+ />
292
+ </View>
293
+ </SafeAreaView>
123
294
  );
124
295
  }
125
296
 
@@ -131,96 +302,149 @@ function App() {
131
302
  return (
132
303
  <SafeAreaProvider>
133
304
  <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
134
- <NavigationContainer>
135
- <Stack.Navigator
136
- screenOptions={{
137
- headerStyle: {
138
- backgroundColor: '#1E1E24',
139
- },
140
- headerTintColor: '#FFFFFF',
141
- headerTitleStyle: {
142
- fontWeight: 'bold',
143
- },
144
- contentStyle: {
145
- backgroundColor: '#121214',
146
- },
147
- }}
148
- >
149
- <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Dashboard' }} />
150
- <Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Details' }} />
151
- </Stack.Navigator>
152
- </NavigationContainer>
305
+ <ErrorBoundary>
306
+ <NavigationContainer>
307
+ <Stack.Navigator
308
+ screenOptions={{
309
+ headerShown: false,
310
+ contentStyle: {
311
+ backgroundColor: '#0F172A',
312
+ },
313
+ }}
314
+ >
315
+ <Stack.Screen name="Home" component={HomeScreen} />
316
+ <Stack.Screen name="Details" component={DetailsScreen} />
317
+ <Stack.Screen name="WebView" component={WebViewScreen} />
318
+ </Stack.Navigator>
319
+ </NavigationContainer>
320
+ {/* Render inspector globally exactly once at the root level */}
321
+ <NetworkInspector />
322
+ </ErrorBoundary>
153
323
  </SafeAreaProvider>
154
324
  );
155
325
  }
156
326
 
157
327
  const styles = StyleSheet.create({
158
- container: {
328
+ safeContainer: {
159
329
  flex: 1,
160
- backgroundColor: '#121214',
330
+ backgroundColor: '#0F172A',
331
+ paddingTop: 12,
161
332
  },
162
333
  content: {
163
- padding: 24,
334
+ paddingHorizontal: 20,
335
+ paddingBottom: 40,
336
+ },
337
+ headerHero: {
338
+ marginTop: 20,
339
+ marginBottom: 24,
164
340
  alignItems: 'center',
165
341
  },
166
- title: {
167
- fontSize: 28,
342
+ headerBadge: {
343
+ fontSize: 10,
168
344
  fontWeight: 'bold',
169
- color: '#FFFFFF',
170
- marginTop: 20,
345
+ color: '#818CF8',
346
+ letterSpacing: 1.5,
347
+ marginBottom: 6,
171
348
  },
172
- subtitle: {
173
- fontSize: 16,
174
- color: '#8E8E93',
175
- marginBottom: 40,
349
+ headerTitle: {
350
+ fontSize: 28,
351
+ fontWeight: '900',
352
+ color: '#F8FAFC',
353
+ marginBottom: 8,
176
354
  },
177
- card: {
178
- width: '100%',
179
- backgroundColor: '#1E1E24',
355
+ headerSubtitle: {
356
+ fontSize: 14,
357
+ color: '#94A3B8',
358
+ textAlign: 'center',
359
+ lineHeight: 20,
360
+ },
361
+ statsCard: {
362
+ backgroundColor: '#1E293B',
180
363
  borderRadius: 16,
181
- padding: 20,
182
- shadowColor: '#000',
183
- shadowOffset: { width: 0, height: 4 },
184
- shadowOpacity: 0.3,
185
- shadowRadius: 8,
186
- elevation: 5,
364
+ padding: 16,
365
+ borderWidth: 1,
366
+ borderColor: '#334155',
367
+ marginBottom: 20,
187
368
  },
188
- cardTitle: {
369
+ sectionTitle: {
370
+ fontSize: 11,
371
+ fontWeight: '800',
372
+ color: '#94A3B8',
373
+ letterSpacing: 1.2,
374
+ marginBottom: 12,
375
+ },
376
+ statsGrid: {
377
+ flexDirection: 'row',
378
+ justifyContent: 'space-between',
379
+ gap: 12,
380
+ },
381
+ statBox: {
382
+ flex: 1,
383
+ backgroundColor: '#0F172A',
384
+ borderRadius: 12,
385
+ paddingVertical: 12,
386
+ alignItems: 'center',
387
+ borderWidth: 1,
388
+ borderColor: '#1E293B',
389
+ },
390
+ statVal: {
189
391
  fontSize: 18,
392
+ fontWeight: 'bold',
393
+ color: '#38BDF8',
394
+ },
395
+ statLbl: {
396
+ fontSize: 10,
397
+ color: '#64748B',
398
+ marginTop: 2,
190
399
  fontWeight: '600',
191
- color: '#FFFFFF',
192
- marginBottom: 8,
193
400
  },
194
- cardDesc: {
195
- fontSize: 14,
196
- color: '#AEAEB2',
197
- lineHeight: 20,
198
- marginBottom: 24,
401
+ panelCard: {
402
+ backgroundColor: '#1E293B',
403
+ borderRadius: 16,
404
+ padding: 16,
405
+ borderWidth: 1,
406
+ borderColor: '#334155',
407
+ marginBottom: 16,
199
408
  },
200
- button: {
201
- width: '100%',
202
- height: 48,
203
- backgroundColor: '#007AFF',
204
- borderRadius: 10,
205
- justifyContent: 'center',
206
- alignItems: 'center',
409
+ panelHeader: {
410
+ fontSize: 12,
411
+ fontWeight: '800',
412
+ color: '#F8FAFC',
413
+ letterSpacing: 0.8,
207
414
  marginBottom: 12,
208
415
  },
209
- dangerButton: {
210
- backgroundColor: '#FF3B30',
416
+ btnRow: {
417
+ flexDirection: 'row',
418
+ gap: 12,
211
419
  },
212
- infoButton: {
213
- backgroundColor: '#5856D6',
420
+ gridBtn: {
421
+ flex: 1,
422
+ height: 44,
423
+ borderRadius: 10,
424
+ borderWidth: 1.5,
425
+ justifyContent: 'center',
426
+ alignItems: 'center',
427
+ backgroundColor: 'rgba(255,255,255,0.02)',
214
428
  },
215
- successButton: {
216
- backgroundColor: '#34C759',
429
+ btnText: {
430
+ fontSize: 13,
431
+ fontWeight: 'bold',
217
432
  },
218
- secondaryButton: {
219
- backgroundColor: '#8E8E93',
433
+ fullWidthBtn: {
434
+ width: '100%',
435
+ height: 44,
436
+ borderRadius: 10,
437
+ justifyContent: 'center',
438
+ alignItems: 'center',
439
+ shadowColor: '#000',
440
+ shadowOffset: { width: 0, height: 2 },
441
+ shadowOpacity: 0.2,
442
+ shadowRadius: 4,
443
+ elevation: 3,
220
444
  },
221
- buttonText: {
222
- fontSize: 15,
223
- fontWeight: '600',
445
+ fullWidthBtnText: {
446
+ fontSize: 13,
447
+ fontWeight: 'bold',
224
448
  color: '#FFFFFF',
225
449
  },
226
450
  });
@@ -1473,6 +1473,28 @@ PODS:
1473
1473
  - ReactCommon/turbomodule/core
1474
1474
  - ReactNativeDependencies
1475
1475
  - Yoga
1476
+ - react-native-webview (13.16.1):
1477
+ - hermes-engine
1478
+ - RCTRequired
1479
+ - RCTTypeSafety
1480
+ - React-Core
1481
+ - React-Core-prebuilt
1482
+ - React-debug
1483
+ - React-Fabric
1484
+ - React-featureflags
1485
+ - React-graphics
1486
+ - React-ImageManager
1487
+ - React-jsi
1488
+ - React-NativeModulesApple
1489
+ - React-RCTFabric
1490
+ - React-renderercss
1491
+ - React-rendererdebug
1492
+ - React-utils
1493
+ - ReactCodegen
1494
+ - ReactCommon/turbomodule/bridging
1495
+ - ReactCommon/turbomodule/core
1496
+ - ReactNativeDependencies
1497
+ - Yoga
1476
1498
  - React-NativeModulesApple (0.85.3):
1477
1499
  - hermes-engine
1478
1500
  - React-callinvoker
@@ -1995,6 +2017,7 @@ DEPENDENCIES:
1995
2017
  - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
1996
2018
  - React-mutationobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver`)
1997
2019
  - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
2020
+ - react-native-webview (from `../node_modules/react-native-webview`)
1998
2021
  - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
1999
2022
  - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`)
2000
2023
  - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
@@ -2117,6 +2140,8 @@ EXTERNAL SOURCES:
2117
2140
  :path: "../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver"
2118
2141
  react-native-safe-area-context:
2119
2142
  :path: "../node_modules/react-native-safe-area-context"
2143
+ react-native-webview:
2144
+ :path: "../node_modules/react-native-webview"
2120
2145
  React-NativeModulesApple:
2121
2146
  :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
2122
2147
  React-networking:
@@ -2234,6 +2259,7 @@ SPEC CHECKSUMS:
2234
2259
  React-microtasksnativemodule: ab33a818d339f5a1da308893c11b487be66121a8
2235
2260
  React-mutationobservernativemodule: a42d1626651ccd7d0dc02a56e69d4ec77c248893
2236
2261
  react-native-safe-area-context: fb5c8ee9f6dd62ef710611b3d370c501f42a4ac0
2262
+ react-native-webview: 2da09bdea1aeb6c46e27dd94632e21059cade6c1
2237
2263
  React-NativeModulesApple: deba264b03bd79c6bd61014fa30e40321b5e443a
2238
2264
  React-networking: 35e6070b084f435429f85c5db40b4d5b38652fe9
2239
2265
  React-oscompat: 64a0c7ef5441855dc6e2a6afe8ba8f92aa05075e