react-native-inapp-inspector 2.2.2 → 2.2.4

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 (159) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +5 -1
  2. package/dist/commonjs/components/AnalyticsEventCard.js +2 -1
  3. package/dist/commonjs/components/DiffViewer.js +1 -1
  4. package/dist/commonjs/components/Inspector/BundleTab.js +22 -0
  5. package/dist/commonjs/components/Inspector/DeviceInfoTab.d.ts +3 -0
  6. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +835 -0
  7. package/dist/commonjs/components/Inspector/InspectorHeader.js +12 -14
  8. package/dist/commonjs/components/Inspector/LogDetail.js +6 -3
  9. package/dist/commonjs/components/Inspector/MainScreen.js +7 -3
  10. package/dist/commonjs/components/Inspector/NetworkTab.js +92 -15
  11. package/dist/commonjs/components/Inspector/PerformanceTab.js +38 -12
  12. package/dist/commonjs/components/Inspector/SettingsPanel.js +440 -229
  13. package/dist/commonjs/components/Inspector/StorageTab.d.ts +3 -0
  14. package/dist/commonjs/components/Inspector/StorageTab.js +892 -0
  15. package/dist/commonjs/components/Inspector/TabBar.js +14 -0
  16. package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +11 -2
  17. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +4 -1
  18. package/dist/commonjs/components/NetworkIcons.d.ts +6 -0
  19. package/dist/commonjs/components/NetworkIcons.js +30 -1
  20. package/dist/commonjs/constants/version.d.ts +1 -1
  21. package/dist/commonjs/constants/version.js +1 -1
  22. package/dist/commonjs/customHooks/bundleAnalyzer.js +44 -22
  23. package/dist/commonjs/customHooks/storageInspector.d.ts +67 -0
  24. package/dist/commonjs/customHooks/storageInspector.js +486 -0
  25. package/dist/commonjs/i18n/locales/en.json +8 -2
  26. package/dist/commonjs/index.d.ts +1 -0
  27. package/dist/commonjs/index.js +16 -1
  28. package/dist/commonjs/storage.d.ts +5 -0
  29. package/dist/commonjs/storage.js +18 -0
  30. package/dist/commonjs/types/enums.d.ts +5 -0
  31. package/dist/commonjs/types/enums.js +5 -0
  32. package/dist/esm/components/AnalyticsDetail.js +6 -2
  33. package/dist/esm/components/AnalyticsEventCard.js +2 -1
  34. package/dist/esm/components/DiffViewer.js +1 -1
  35. package/dist/esm/components/Inspector/BundleTab.js +22 -0
  36. package/dist/esm/components/Inspector/DeviceInfoTab.d.ts +3 -0
  37. package/dist/esm/components/Inspector/DeviceInfoTab.js +796 -0
  38. package/dist/esm/components/Inspector/InspectorHeader.js +13 -15
  39. package/dist/esm/components/Inspector/LogDetail.js +7 -4
  40. package/dist/esm/components/Inspector/MainScreen.js +7 -3
  41. package/dist/esm/components/Inspector/NetworkTab.js +93 -16
  42. package/dist/esm/components/Inspector/PerformanceTab.js +39 -13
  43. package/dist/esm/components/Inspector/SettingsPanel.js +441 -230
  44. package/dist/esm/components/Inspector/StorageTab.d.ts +3 -0
  45. package/dist/esm/components/Inspector/StorageTab.js +853 -0
  46. package/dist/esm/components/Inspector/TabBar.js +15 -1
  47. package/dist/esm/components/Inspector/TelemetryConsentModal.js +11 -2
  48. package/dist/esm/components/Inspector/UpdateAvailableModal.js +4 -1
  49. package/dist/esm/components/NetworkIcons.d.ts +6 -0
  50. package/dist/esm/components/NetworkIcons.js +23 -0
  51. package/dist/esm/constants/version.d.ts +1 -1
  52. package/dist/esm/constants/version.js +1 -1
  53. package/dist/esm/customHooks/bundleAnalyzer.js +44 -22
  54. package/dist/esm/customHooks/storageInspector.d.ts +67 -0
  55. package/dist/esm/customHooks/storageInspector.js +469 -0
  56. package/dist/esm/i18n/locales/en.json +8 -2
  57. package/dist/esm/index.d.ts +1 -0
  58. package/dist/esm/index.js +5 -0
  59. package/dist/esm/storage.d.ts +5 -0
  60. package/dist/esm/storage.js +5 -0
  61. package/dist/esm/types/enums.d.ts +5 -0
  62. package/dist/esm/types/enums.js +5 -0
  63. package/package.json +9 -1
  64. package/src/analytics.ts +35 -0
  65. package/src/bundle.ts +25 -0
  66. package/src/components/AnalyticsDetail.tsx +870 -0
  67. package/src/components/AnalyticsEventCard.tsx +442 -0
  68. package/src/components/AnalyticsGraph.tsx +583 -0
  69. package/src/components/AnimatedEntrance.tsx +64 -0
  70. package/src/components/AppHeaderLogo.tsx +109 -0
  71. package/src/components/BrandCircleIcon.tsx +144 -0
  72. package/src/components/BrandSquareIcon.tsx +144 -0
  73. package/src/components/CodeSnippet.tsx +725 -0
  74. package/src/components/ConsoleLogCard.tsx +628 -0
  75. package/src/components/CopyButton.tsx +87 -0
  76. package/src/components/DiffViewer.tsx +82 -0
  77. package/src/components/DomainHeader.tsx +237 -0
  78. package/src/components/EmptyState.tsx +73 -0
  79. package/src/components/EndOfListFooter.tsx +100 -0
  80. package/src/components/ErrorBoundary.tsx +688 -0
  81. package/src/components/HeadersSection.tsx +192 -0
  82. package/src/components/HighlightText.tsx +100 -0
  83. package/src/components/Inspector/AnalyticsFilterModal.tsx +1250 -0
  84. package/src/components/Inspector/AnalyticsTab.tsx +1336 -0
  85. package/src/components/Inspector/BundleTab.tsx +4760 -0
  86. package/src/components/Inspector/ConsoleTab.tsx +702 -0
  87. package/src/components/Inspector/CrashDetail.tsx +941 -0
  88. package/src/components/Inspector/CrashFilterModal.tsx +721 -0
  89. package/src/components/Inspector/CrashTab.tsx +871 -0
  90. package/src/components/Inspector/DeviceInfoTab.tsx +1204 -0
  91. package/src/components/Inspector/FabLauncher.tsx +80 -0
  92. package/src/components/Inspector/InspectorContext.tsx +28 -0
  93. package/src/components/Inspector/InspectorHeader.tsx +972 -0
  94. package/src/components/Inspector/LogDetail.tsx +1431 -0
  95. package/src/components/Inspector/MainScreen.tsx +262 -0
  96. package/src/components/Inspector/NavigationTracker.tsx +13 -0
  97. package/src/components/Inspector/NetworkDetail.tsx +794 -0
  98. package/src/components/Inspector/NetworkTab.tsx +1183 -0
  99. package/src/components/Inspector/NpmUpdateToast.tsx +392 -0
  100. package/src/components/Inspector/PerformanceTab.tsx +1928 -0
  101. package/src/components/Inspector/ReduxDetail.tsx +1651 -0
  102. package/src/components/Inspector/ReduxTab.tsx +954 -0
  103. package/src/components/Inspector/SettingsPanel.tsx +3447 -0
  104. package/src/components/Inspector/StorageTab.tsx +1048 -0
  105. package/src/components/Inspector/TabBar.tsx +207 -0
  106. package/src/components/Inspector/TelemetryConsentModal.tsx +416 -0
  107. package/src/components/Inspector/UpdateAvailableModal.tsx +557 -0
  108. package/src/components/JsonViewer.tsx +486 -0
  109. package/src/components/LogCard.tsx +491 -0
  110. package/src/components/LogSyntaxHighlighter.tsx +178 -0
  111. package/src/components/MetaAccordion.tsx +340 -0
  112. package/src/components/MiniBarChart.tsx +42 -0
  113. package/src/components/MiniLineChart.tsx +33 -0
  114. package/src/components/NetworkIcons.tsx +2221 -0
  115. package/src/components/SectionHeader.tsx +113 -0
  116. package/src/components/SegmentedTabs.tsx +83 -0
  117. package/src/components/Slider.tsx +300 -0
  118. package/src/components/SourcePageCard.tsx +148 -0
  119. package/src/components/Toast.tsx +131 -0
  120. package/src/components/TouchableScale.tsx +91 -0
  121. package/src/components/TreeNode.tsx +186 -0
  122. package/src/console.ts +24 -0
  123. package/src/constants/index.ts +38 -0
  124. package/src/constants/version.ts +3 -0
  125. package/src/crash.ts +32 -0
  126. package/src/customHooks/analyticsLogger.ts +336 -0
  127. package/src/customHooks/bundleAnalyzer.ts +1256 -0
  128. package/src/customHooks/consoleLogger.ts +497 -0
  129. package/src/customHooks/crashHandler.ts +944 -0
  130. package/src/customHooks/logFilters.ts +32 -0
  131. package/src/customHooks/networkLogger.ts +419 -0
  132. package/src/customHooks/performanceTracker.ts +1014 -0
  133. package/src/customHooks/reduxLogger.ts +406 -0
  134. package/src/customHooks/storageInspector.ts +509 -0
  135. package/src/customHooks/useAccordion.tsx +60 -0
  136. package/src/decorators/index.ts +184 -0
  137. package/src/helpers/gaAnalyticsRegistry.ts +204 -0
  138. package/src/helpers/index.ts +860 -0
  139. package/src/helpers/memoryManager.ts +138 -0
  140. package/src/helpers/searchQueryParser.ts +283 -0
  141. package/src/helpers/settingsStore.ts +171 -0
  142. package/src/helpers/telemetry.ts +505 -0
  143. package/src/helpers/toast.ts +17 -0
  144. package/src/i18n/index.ts +69 -0
  145. package/src/i18n/locales/en.json +1058 -0
  146. package/src/index.tsx +2356 -0
  147. package/src/native/NativeInspector.ts +397 -0
  148. package/src/native/NativeNetworkInspector.ts +24 -0
  149. package/src/network.ts +22 -0
  150. package/src/performance.ts +38 -0
  151. package/src/redux.ts +23 -0
  152. package/src/storage.ts +18 -0
  153. package/src/styles/AppColors.ts +408 -0
  154. package/src/styles/AppFonts.ts +8 -0
  155. package/src/styles/common.ts +209 -0
  156. package/src/styles/index.ts +1570 -0
  157. package/src/types/enums.ts +199 -0
  158. package/src/types/index.ts +34 -0
  159. package/src/types/interfaces.ts +515 -0
@@ -0,0 +1,702 @@
1
+ import React, {useCallback, useMemo} from 'react';
2
+ import {
3
+ FlatList,
4
+ Pressable,
5
+ ScrollView,
6
+ Text,
7
+ TextInput,
8
+ View,
9
+ } from 'react-native';
10
+ import {useInspector} from './InspectorContext';
11
+ import {useTranslation} from '../../i18n';
12
+ import TouchableScale from '../TouchableScale';
13
+ import AnimatedEntrance from '../AnimatedEntrance';
14
+ import {ConsoleLogCard} from '../ConsoleLogCard';
15
+ import EmptyState from '../EmptyState';
16
+ import EndOfListFooter from '../EndOfListFooter';
17
+ import styles from '../../styles';
18
+ import {AppColors} from '../../styles/AppColors';
19
+ import {AppFonts} from '../../styles/AppFonts';
20
+ import {
21
+ SearchIcon,
22
+ ClearIcon,
23
+ SortArrowIcon,
24
+ TrashIcon,
25
+ LayersIcon,
26
+ CheckIcon,
27
+ UserIcon,
28
+ InfoCircleIcon,
29
+ WarningTriangleIcon,
30
+ ErrorCircleIcon,
31
+ AnalyticsIcon,
32
+ HeaderPauseIcon,
33
+ } from '../NetworkIcons';
34
+
35
+ const ConsoleTab = React.memo(() => {
36
+ const {t} = useTranslation();
37
+ const {
38
+ logSearch,
39
+ setLogSearch,
40
+ logSortOrder,
41
+ setLogSortOrder,
42
+ handleDelete,
43
+ logFilters,
44
+ setLogFilters,
45
+ logCounts,
46
+ filteredConsoleLogs,
47
+ visibleConsoleLogs,
48
+ isConsolePaused,
49
+ setIsConsolePaused,
50
+ } = useInspector();
51
+
52
+ const renderItem = useCallback(
53
+ ({item, index}: {item: any; index: number}) => (
54
+ <AnimatedEntrance index={index} distance={8}>
55
+ <ConsoleLogCard item={item} searchStr={logSearch} />
56
+ </AnimatedEntrance>
57
+ ),
58
+ [logSearch],
59
+ );
60
+
61
+ const keyExtractor = useCallback(
62
+ (item: any, index: number) => item?.id?.toString() ?? index.toString(),
63
+ [],
64
+ );
65
+
66
+ const listHeader = useMemo(() => {
67
+ const total = visibleConsoleLogs.length;
68
+ const filtered = filteredConsoleLogs.length;
69
+ const isAllSelected =
70
+ logFilters.has('all') ||
71
+ !Array.from(logFilters).some(f => f !== 'all');
72
+ if (isAllSelected) {
73
+ return (
74
+ <Text
75
+ style={[
76
+ styles.resultCount,
77
+ {marginBottom: 4, marginTop: 12},
78
+ ]}>
79
+ Showing ({filtered}/{total}) logs showing
80
+ </Text>
81
+ );
82
+ } else {
83
+ const activeFilterNames = Array.from(logFilters)
84
+ .filter(f => f !== 'all')
85
+ .map(f => {
86
+ if (f === 'user-log') return 'User Log';
87
+ if (f === 'analytics') return 'Analytics';
88
+ return (
89
+ (f as string).charAt(0).toUpperCase() +
90
+ (f as string).slice(1)
91
+ );
92
+ });
93
+ return (
94
+ <Text
95
+ style={[
96
+ styles.resultCount,
97
+ {marginBottom: 4, marginTop: 12},
98
+ ]}>
99
+ Filtering with {activeFilterNames.join(', ')} (
100
+ {filtered}/{total}) logs is showing
101
+ </Text>
102
+ );
103
+ }
104
+ }, [visibleConsoleLogs.length, filteredConsoleLogs.length, logFilters]);
105
+
106
+ const [isSearchFocused, setIsSearchFocused] = React.useState(false);
107
+
108
+ const QUICK_TAG_SUGGESTIONS = useMemo(
109
+ () => ['[AXIOS]', '[API]', '[REDUX]', '[ANALYTICS]', '[AUTH]', '[WARN]', '[ERROR]'],
110
+ [],
111
+ );
112
+
113
+ return (
114
+ <View style={{flex: 1}}>
115
+ <View
116
+ style={{
117
+ backgroundColor: AppColors.white,
118
+ borderBottomWidth: 1,
119
+ borderBottomColor: AppColors.dividerColor,
120
+ paddingBottom: 6,
121
+ }}>
122
+ <View
123
+ style={[
124
+ styles.toolbarRow,
125
+ {marginTop: 12, marginBottom: 8},
126
+ ]}>
127
+ <View
128
+ style={[
129
+ styles.searchContainer,
130
+ isSearchFocused && {
131
+ borderColor: AppColors.purple,
132
+ borderWidth: 1.5,
133
+ },
134
+ ]}>
135
+ <SearchIcon
136
+ color={isSearchFocused ? AppColors.purple : AppColors.grayTextWeak}
137
+ size={16}
138
+ />
139
+ <TextInput
140
+ placeholder={t('console.searchPlaceholder')}
141
+ placeholderTextColor={AppColors.grayTextWeak}
142
+ value={logSearch}
143
+ onChangeText={setLogSearch}
144
+ onFocus={() => setIsSearchFocused(true)}
145
+ onBlur={() => setIsSearchFocused(false)}
146
+ style={styles.searchInput}
147
+ autoCorrect={false}
148
+ autoCapitalize="none"
149
+ />
150
+ {logSearch.length > 0 && (
151
+ <View
152
+ style={{
153
+ flexDirection: 'row',
154
+ alignItems: 'center',
155
+ gap: 4,
156
+ }}>
157
+ <View
158
+ style={{
159
+ backgroundColor: `${AppColors.purple}20`,
160
+ borderRadius: 10,
161
+ paddingHorizontal: 6,
162
+ paddingVertical: 2,
163
+ }}>
164
+ <Text
165
+ style={{
166
+ color: AppColors.purple,
167
+ fontSize: 10,
168
+ fontFamily: AppFonts.interBold,
169
+ }}>
170
+ {filteredConsoleLogs.length}
171
+ </Text>
172
+ </View>
173
+ <Pressable
174
+ onPress={() => setLogSearch('')}
175
+ hitSlop={10}
176
+ style={styles.clearBtn}>
177
+ <ClearIcon
178
+ color={AppColors.grayTextWeak}
179
+ size={14}
180
+ />
181
+ </Pressable>
182
+ </View>
183
+ )}
184
+ </View>
185
+
186
+ <View style={styles.toolbarRight}>
187
+ <TouchableScale
188
+ style={[
189
+ styles.toolbarBtn,
190
+ isConsolePaused && {
191
+ borderColor: `${AppColors.darkOrange}50`,
192
+ backgroundColor: `${AppColors.darkOrange}18`,
193
+ },
194
+ ]}
195
+ onPress={() => setIsConsolePaused(p => !p)}
196
+ hitSlop={6}>
197
+ <HeaderPauseIcon
198
+ isPaused={isConsolePaused}
199
+ color={
200
+ isConsolePaused
201
+ ? AppColors.darkOrange
202
+ : AppColors.grayTextStrong
203
+ }
204
+ size={16}
205
+ />
206
+ </TouchableScale>
207
+ <TouchableScale
208
+ style={styles.toolbarBtn}
209
+ onPress={() =>
210
+ setLogSortOrder(o =>
211
+ o === 'newest' ? 'oldest' : 'newest',
212
+ )
213
+ }
214
+ hitSlop={10}>
215
+ <SortArrowIcon
216
+ color={AppColors.grayTextStrong}
217
+ size={18}
218
+ direction={
219
+ logSortOrder === 'newest' ? 'down' : 'up'
220
+ }
221
+ />
222
+ </TouchableScale>
223
+ <TouchableScale
224
+ style={[
225
+ styles.toolbarBtn,
226
+ {
227
+ borderColor: `${AppColors.errorColor}38`,
228
+ backgroundColor: `${AppColors.errorColor}0F`,
229
+ },
230
+ ]}
231
+ onPress={handleDelete}
232
+ hitSlop={6}>
233
+ <TrashIcon
234
+ color={AppColors.errorColor}
235
+ size={15}
236
+ />
237
+ </TouchableScale>
238
+ </View>
239
+ </View>
240
+
241
+ {/* Quick Tag Search Suggestions Bar */}
242
+ {(isSearchFocused || logSearch.length > 0) && (
243
+ <ScrollView
244
+ horizontal
245
+ showsHorizontalScrollIndicator={false}
246
+ style={{marginBottom: 6, maxHeight: 30}}
247
+ contentContainerStyle={{
248
+ paddingHorizontal: 16,
249
+ flexDirection: 'row',
250
+ alignItems: 'center',
251
+ gap: 6,
252
+ }}>
253
+ {QUICK_TAG_SUGGESTIONS.map(tag => {
254
+ const isSelected = logSearch.includes(tag);
255
+ return (
256
+ <TouchableScale
257
+ key={tag}
258
+ onPress={() => {
259
+ if (isSelected) {
260
+ setLogSearch(prev =>
261
+ prev.replace(tag, '').trim(),
262
+ );
263
+ } else {
264
+ setLogSearch(prev =>
265
+ prev ? `${prev} ${tag}`.trim() : tag,
266
+ );
267
+ }
268
+ }}>
269
+ <View
270
+ style={{
271
+ paddingHorizontal: 8,
272
+ paddingVertical: 3,
273
+ borderRadius: 6,
274
+ backgroundColor: isSelected
275
+ ? AppColors.purple
276
+ : `${AppColors.purple}14`,
277
+ borderWidth: 1,
278
+ borderColor: isSelected
279
+ ? AppColors.purple
280
+ : `${AppColors.purple}30`,
281
+ }}>
282
+ <Text
283
+ style={{
284
+ fontFamily: AppFonts.interBold,
285
+ fontSize: 10,
286
+ color: isSelected
287
+ ? AppColors.white
288
+ : AppColors.purple,
289
+ }}>
290
+ {tag}
291
+ </Text>
292
+ </View>
293
+ </TouchableScale>
294
+ );
295
+ })}
296
+ </ScrollView>
297
+ )}
298
+
299
+ <ScrollView
300
+ horizontal
301
+ showsHorizontalScrollIndicator={false}
302
+ style={{marginVertical: 4, maxHeight: 46}}
303
+ contentContainerStyle={{
304
+ paddingHorizontal: 16,
305
+ paddingBottom: 4,
306
+ flexDirection: 'row',
307
+ alignItems: 'center',
308
+ gap: 8,
309
+ }}>
310
+ {/* All Filter */}
311
+ {(() => {
312
+ const active = logFilters.has('all');
313
+ return (
314
+ <TouchableScale
315
+ onPress={() => {
316
+ setLogFilters(new Set(['all']));
317
+ }}>
318
+ <View
319
+ style={[
320
+ styles.statusFilterChip,
321
+ {
322
+ backgroundColor: active ? AppColors.indigo600Alt : AppColors.indigo50,
323
+ borderColor: active ? AppColors.indigo600 : AppColors.indigo400,
324
+ borderRadius: 8,
325
+ paddingHorizontal: 10,
326
+ paddingVertical: 6,
327
+ },
328
+ active && {
329
+ shadowColor: AppColors.indigo600Alt,
330
+ shadowOffset: {width: 0, height: 1},
331
+ shadowOpacity: 0.28,
332
+ shadowRadius: 2.5,
333
+ elevation: 2,
334
+ },
335
+ ]}>
336
+ <View
337
+ style={{
338
+ flexDirection: 'row',
339
+ alignItems: 'center',
340
+ gap: 6,
341
+ }}>
342
+ <LayersIcon
343
+ size={13}
344
+ color={active ? AppColors.white : AppColors.indigo600Alt}
345
+ />
346
+ <Text
347
+ numberOfLines={1}
348
+ style={[
349
+ styles.statusFilterText,
350
+ {
351
+ color: active ? AppColors.white : AppColors.indigo600Alt,
352
+ fontFamily: AppFonts.interBold,
353
+ },
354
+ ]}>
355
+ {t('common.all', 'All')} ({logCounts.all})
356
+ </Text>
357
+ </View>
358
+ </View>
359
+ </TouchableScale>
360
+ );
361
+ })()}
362
+
363
+ {/* User Log / Standard Log Filter */}
364
+ {(() => {
365
+ const active = logFilters.has('user-log');
366
+ return (
367
+ <TouchableScale
368
+ onPress={() => {
369
+ setLogFilters(prev => {
370
+ const next = new Set(prev);
371
+ next.delete('all');
372
+ next.has('user-log')
373
+ ? next.delete('user-log')
374
+ : next.add('user-log');
375
+ if (next.size === 0) next.add('all');
376
+ return next;
377
+ });
378
+ }}>
379
+ <View
380
+ style={[
381
+ styles.statusFilterChip,
382
+ {
383
+ backgroundColor: active ? AppColors.teal600 : AppColors.teal100,
384
+ borderColor: active ? AppColors.teal600 : AppColors.teal400,
385
+ borderRadius: 8,
386
+ paddingHorizontal: 10,
387
+ paddingVertical: 6,
388
+ },
389
+ active && {
390
+ shadowColor: AppColors.teal600,
391
+ shadowOffset: {width: 0, height: 1},
392
+ shadowOpacity: 0.28,
393
+ shadowRadius: 2.5,
394
+ elevation: 2,
395
+ },
396
+ ]}>
397
+ <View
398
+ style={{
399
+ flexDirection: 'row',
400
+ alignItems: 'center',
401
+ gap: 6,
402
+ }}>
403
+ <UserIcon
404
+ size={13}
405
+ color={active ? AppColors.white : AppColors.teal600}
406
+ />
407
+ <Text
408
+ numberOfLines={1}
409
+ style={[
410
+ styles.statusFilterText,
411
+ {
412
+ color: active ? AppColors.white : AppColors.teal600,
413
+ fontFamily: AppFonts.interBold,
414
+ },
415
+ ]}>
416
+ {t('console.log', 'Log')} ({logCounts['user-log']})
417
+ </Text>
418
+ </View>
419
+ </View>
420
+ </TouchableScale>
421
+ );
422
+ })()}
423
+
424
+ {/* Info Filter */}
425
+ {(() => {
426
+ const active = logFilters.has('info');
427
+ return (
428
+ <TouchableScale
429
+ onPress={() => {
430
+ setLogFilters(prev => {
431
+ const next = new Set(prev);
432
+ next.delete('all');
433
+ next.has('info')
434
+ ? next.delete('info')
435
+ : next.add('info');
436
+ if (next.size === 0) next.add('all');
437
+ return next;
438
+ });
439
+ }}>
440
+ <View
441
+ style={[
442
+ styles.statusFilterChip,
443
+ {
444
+ backgroundColor: active ? AppColors.sky600 : AppColors.sky100,
445
+ borderColor: active ? AppColors.blue700 : AppColors.sky400,
446
+ borderRadius: 8,
447
+ paddingHorizontal: 10,
448
+ paddingVertical: 6,
449
+ },
450
+ active && {
451
+ shadowColor: AppColors.sky600,
452
+ shadowOffset: {width: 0, height: 1},
453
+ shadowOpacity: 0.28,
454
+ shadowRadius: 2.5,
455
+ elevation: 2,
456
+ },
457
+ ]}>
458
+ <View
459
+ style={{
460
+ flexDirection: 'row',
461
+ alignItems: 'center',
462
+ gap: 6,
463
+ }}>
464
+ <InfoCircleIcon
465
+ size={13}
466
+ color={active ? AppColors.white : AppColors.sky600}
467
+ />
468
+ <Text
469
+ numberOfLines={1}
470
+ style={[
471
+ styles.statusFilterText,
472
+ {
473
+ color: active ? AppColors.white : AppColors.sky600,
474
+ fontFamily: AppFonts.interBold,
475
+ },
476
+ ]}>
477
+ {t('console.info', 'Info')} ({logCounts.info})
478
+ </Text>
479
+ </View>
480
+ </View>
481
+ </TouchableScale>
482
+ );
483
+ })()}
484
+
485
+ {/* Warning Filter */}
486
+ {(() => {
487
+ const active = logFilters.has('warn');
488
+ return (
489
+ <TouchableScale
490
+ onPress={() => {
491
+ setLogFilters(prev => {
492
+ const next = new Set(prev);
493
+ next.delete('all');
494
+ next.has('warn')
495
+ ? next.delete('warn')
496
+ : next.add('warn');
497
+ if (next.size === 0) next.add('all');
498
+ return next;
499
+ });
500
+ }}>
501
+ <View
502
+ style={[
503
+ styles.statusFilterChip,
504
+ {
505
+ backgroundColor: active ? AppColors.amber600 : AppColors.amber100,
506
+ borderColor: active ? AppColors.amber700 : AppColors.amber200,
507
+ borderRadius: 8,
508
+ paddingHorizontal: 10,
509
+ paddingVertical: 6,
510
+ },
511
+ active && {
512
+ shadowColor: AppColors.amber600,
513
+ shadowOffset: {width: 0, height: 1},
514
+ shadowOpacity: 0.28,
515
+ shadowRadius: 2.5,
516
+ elevation: 2,
517
+ },
518
+ ]}>
519
+ <View
520
+ style={{
521
+ flexDirection: 'row',
522
+ alignItems: 'center',
523
+ gap: 6,
524
+ }}>
525
+ <WarningTriangleIcon
526
+ size={13}
527
+ color={active ? AppColors.white : AppColors.amber700}
528
+ />
529
+ <Text
530
+ numberOfLines={1}
531
+ style={[
532
+ styles.statusFilterText,
533
+ {
534
+ color: active ? AppColors.white : AppColors.amber800Warm,
535
+ fontFamily: AppFonts.interBold,
536
+ },
537
+ ]}>
538
+ {t('console.warning', 'Warn')} ({logCounts.warn})
539
+ </Text>
540
+ </View>
541
+ </View>
542
+ </TouchableScale>
543
+ );
544
+ })()}
545
+
546
+ {/* Error Filter */}
547
+ {(() => {
548
+ const active = logFilters.has('error');
549
+ return (
550
+ <TouchableScale
551
+ onPress={() => {
552
+ setLogFilters(prev => {
553
+ const next = new Set(prev);
554
+ next.delete('all');
555
+ next.has('error')
556
+ ? next.delete('error')
557
+ : next.add('error');
558
+ if (next.size === 0) next.add('all');
559
+ return next;
560
+ });
561
+ }}>
562
+ <View
563
+ style={[
564
+ styles.statusFilterChip,
565
+ {
566
+ backgroundColor: active ? AppColors.red500 : AppColors.red100,
567
+ borderColor: active ? AppColors.red600 : AppColors.errorBorder,
568
+ borderRadius: 8,
569
+ paddingHorizontal: 10,
570
+ paddingVertical: 6,
571
+ },
572
+ active && {
573
+ shadowColor: AppColors.red500,
574
+ shadowOffset: {width: 0, height: 1},
575
+ shadowOpacity: 0.28,
576
+ shadowRadius: 2.5,
577
+ elevation: 2,
578
+ },
579
+ ]}>
580
+ <View
581
+ style={{
582
+ flexDirection: 'row',
583
+ alignItems: 'center',
584
+ gap: 6,
585
+ }}>
586
+ <ErrorCircleIcon
587
+ size={13}
588
+ color={active ? AppColors.white : AppColors.red500}
589
+ />
590
+ <Text
591
+ numberOfLines={1}
592
+ style={[
593
+ styles.statusFilterText,
594
+ {
595
+ color: active ? AppColors.white : AppColors.redErrorText,
596
+ fontFamily: AppFonts.interBold,
597
+ },
598
+ ]}>
599
+ {t('console.error', 'Error')} ({logCounts.error})
600
+ </Text>
601
+ </View>
602
+ </View>
603
+ </TouchableScale>
604
+ );
605
+ })()}
606
+
607
+ {/* Analytics Filter */}
608
+ {(() => {
609
+ const active = logFilters.has('analytics');
610
+ return (
611
+ <TouchableScale
612
+ onPress={() => {
613
+ setLogFilters(prev => {
614
+ const next = new Set(prev);
615
+ next.delete('all');
616
+ next.has('analytics')
617
+ ? next.delete('analytics')
618
+ : next.add('analytics');
619
+ if (next.size === 0) next.add('all');
620
+ return next;
621
+ });
622
+ }}>
623
+ <View
624
+ style={[
625
+ styles.statusFilterChip,
626
+ {
627
+ backgroundColor: active ? AppColors.violet600 : AppColors.purple100,
628
+ borderColor: active ? AppColors.purple700 : AppColors.purple200,
629
+ borderRadius: 8,
630
+ paddingHorizontal: 10,
631
+ paddingVertical: 6,
632
+ },
633
+ active && {
634
+ shadowColor: AppColors.violet600,
635
+ shadowOffset: {width: 0, height: 1},
636
+ shadowOpacity: 0.28,
637
+ shadowRadius: 2.5,
638
+ elevation: 2,
639
+ },
640
+ ]}>
641
+ <View
642
+ style={{
643
+ flexDirection: 'row',
644
+ alignItems: 'center',
645
+ gap: 6,
646
+ }}>
647
+ <AnalyticsIcon
648
+ size={13}
649
+ color={active ? AppColors.white : AppColors.violet600}
650
+ />
651
+ <Text
652
+ numberOfLines={1}
653
+ style={[
654
+ styles.statusFilterText,
655
+ {
656
+ color: active ? AppColors.white : AppColors.purpleText,
657
+ fontFamily: AppFonts.interBold,
658
+ },
659
+ ]}>
660
+ {t('console.analytics', 'Analytics')} ({logCounts.analytics})
661
+ </Text>
662
+ </View>
663
+ </View>
664
+ </TouchableScale>
665
+ );
666
+ })()}
667
+ </ScrollView>
668
+ </View>
669
+
670
+ <FlatList
671
+ data={filteredConsoleLogs}
672
+ keyExtractor={keyExtractor}
673
+ ListHeaderComponent={listHeader}
674
+ renderItem={renderItem}
675
+ initialNumToRender={12}
676
+ maxToRenderPerBatch={8}
677
+ windowSize={5}
678
+ removeClippedSubviews={true}
679
+ renderToHardwareTextureAndroid={true}
680
+ ListEmptyComponent={
681
+ <EmptyState
682
+ isSearch={
683
+ logSearch.length > 0 || logFilters.size > 0
684
+ }
685
+ />
686
+ }
687
+ ListFooterComponent={
688
+ filteredConsoleLogs.length > 0 ? (
689
+ <EndOfListFooter count={filteredConsoleLogs.length} label="logs" />
690
+ ) : null
691
+ }
692
+ contentContainerStyle={[
693
+ styles.listContent,
694
+ filteredConsoleLogs.length === 0 && {flexGrow: 1},
695
+ ]}
696
+ keyboardShouldPersistTaps="handled"
697
+ />
698
+ </View>
699
+ );
700
+ });
701
+
702
+ export default ConsoleTab;