react-native-inapp-inspector 1.1.25 → 1.1.26

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 (70) hide show
  1. package/android/build.gradle +36 -0
  2. package/android/src/main/AndroidManifest.xml +3 -0
  3. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +114 -0
  4. package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +28 -0
  5. package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
  6. package/dist/commonjs/components/ErrorBoundary.js +9 -145
  7. package/dist/commonjs/components/Inspector/CrashDetail.d.ts +3 -0
  8. package/dist/commonjs/components/Inspector/CrashDetail.js +796 -0
  9. package/dist/commonjs/components/Inspector/CrashFilterModal.d.ts +20 -0
  10. package/dist/commonjs/components/Inspector/CrashFilterModal.js +597 -0
  11. package/dist/commonjs/components/Inspector/CrashTab.d.ts +3 -0
  12. package/dist/commonjs/components/Inspector/CrashTab.js +727 -0
  13. package/dist/commonjs/components/Inspector/InspectorHeader.js +52 -23
  14. package/dist/commonjs/components/Inspector/LogDetail.js +4 -3
  15. package/dist/commonjs/components/Inspector/MainScreen.js +12 -3
  16. package/dist/commonjs/components/Inspector/SettingsPanel.js +90 -1
  17. package/dist/commonjs/components/Inspector/TabBar.js +15 -3
  18. package/dist/commonjs/components/NetworkIcons.d.ts +11 -0
  19. package/dist/commonjs/components/NetworkIcons.js +96 -1
  20. package/dist/commonjs/components/SegmentedTabs.js +2 -1
  21. package/dist/commonjs/constants/version.d.ts +1 -1
  22. package/dist/commonjs/constants/version.js +1 -1
  23. package/dist/commonjs/customHooks/analyticsLogger.js +70 -44
  24. package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
  25. package/dist/commonjs/customHooks/consoleLogger.js +70 -6
  26. package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
  27. package/dist/commonjs/customHooks/crashHandler.js +681 -0
  28. package/dist/commonjs/customHooks/networkLogger.js +64 -48
  29. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -1
  30. package/dist/commonjs/i18n/locales/en.json +131 -0
  31. package/dist/commonjs/index.d.ts +3 -1
  32. package/dist/commonjs/index.js +95 -1
  33. package/dist/commonjs/types/enums.d.ts +41 -0
  34. package/dist/commonjs/types/enums.js +37 -1
  35. package/dist/commonjs/types/interfaces.d.ts +51 -1
  36. package/dist/esm/components/ErrorBoundary.d.ts +1 -1
  37. package/dist/esm/components/ErrorBoundary.js +10 -113
  38. package/dist/esm/components/Inspector/CrashDetail.d.ts +3 -0
  39. package/dist/esm/components/Inspector/CrashDetail.js +758 -0
  40. package/dist/esm/components/Inspector/CrashFilterModal.d.ts +20 -0
  41. package/dist/esm/components/Inspector/CrashFilterModal.js +557 -0
  42. package/dist/esm/components/Inspector/CrashTab.d.ts +3 -0
  43. package/dist/esm/components/Inspector/CrashTab.js +689 -0
  44. package/dist/esm/components/Inspector/InspectorHeader.js +52 -23
  45. package/dist/esm/components/Inspector/LogDetail.js +4 -3
  46. package/dist/esm/components/Inspector/MainScreen.js +12 -3
  47. package/dist/esm/components/Inspector/SettingsPanel.js +91 -2
  48. package/dist/esm/components/Inspector/TabBar.js +16 -4
  49. package/dist/esm/components/NetworkIcons.d.ts +11 -0
  50. package/dist/esm/components/NetworkIcons.js +83 -0
  51. package/dist/esm/components/SegmentedTabs.js +2 -1
  52. package/dist/esm/constants/version.d.ts +1 -1
  53. package/dist/esm/constants/version.js +1 -1
  54. package/dist/esm/customHooks/analyticsLogger.js +70 -44
  55. package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
  56. package/dist/esm/customHooks/consoleLogger.js +68 -5
  57. package/dist/esm/customHooks/crashHandler.d.ts +64 -0
  58. package/dist/esm/customHooks/crashHandler.js +659 -0
  59. package/dist/esm/customHooks/networkLogger.js +64 -48
  60. package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -1
  61. package/dist/esm/i18n/locales/en.json +131 -0
  62. package/dist/esm/index.d.ts +3 -1
  63. package/dist/esm/index.js +73 -1
  64. package/dist/esm/types/enums.d.ts +41 -0
  65. package/dist/esm/types/enums.js +36 -0
  66. package/dist/esm/types/interfaces.d.ts +51 -1
  67. package/ios/NetworkInspectorModule.h +6 -0
  68. package/ios/NetworkInspectorModule.m +125 -0
  69. package/package.json +5 -2
  70. package/react-native-inapp-inspector.podspec +18 -0
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { CrashFilterType } from '../../types/enums';
3
+ export interface CrashFilters {
4
+ types: Set<CrashFilterType>;
5
+ timeWindow: 'all' | '15m' | '1h' | '24h' | '7d';
6
+ platform: 'all' | 'ios' | 'android';
7
+ engine: 'all' | 'hermes' | 'jsc';
8
+ sortBy: 'time_desc' | 'time_asc';
9
+ }
10
+ export declare const DEFAULT_CRASH_FILTERS: CrashFilters;
11
+ export declare const isCrashFiltersDefault: (f: CrashFilters) => boolean;
12
+ interface CrashFilterModalProps {
13
+ visible: boolean;
14
+ onClose: () => void;
15
+ filters: CrashFilters;
16
+ onApply: (filters: CrashFilters) => void;
17
+ searchQuery?: string;
18
+ }
19
+ declare const CrashFilterModal: React.FC<CrashFilterModalProps>;
20
+ export default CrashFilterModal;
@@ -0,0 +1,557 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { Modal, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from 'react-native';
3
+ import { useInspector } from './InspectorContext';
4
+ import { AppColors } from '../../styles/AppColors';
5
+ import { AppFonts } from '../../styles/AppFonts';
6
+ import { useTranslation } from '../../i18n';
7
+ import { FilterIcon, CloseWhite, CheckIcon, ClockIcon, HourglassIcon, SkullIcon, JsIcon, LayoutIcon, ChipIcon, AppleIcon, AndroidIcon, BoltIcon, } from '../NetworkIcons';
8
+ import TouchableScale from '../TouchableScale';
9
+ export const DEFAULT_CRASH_FILTERS = {
10
+ types: new Set(['all']),
11
+ timeWindow: 'all',
12
+ platform: 'all',
13
+ engine: 'all',
14
+ sortBy: 'time_desc',
15
+ };
16
+ export const isCrashFiltersDefault = (f) => (f.types.has('all') || f.types.size === 0) &&
17
+ f.timeWindow === 'all' &&
18
+ f.platform === 'all' &&
19
+ f.engine === 'all' &&
20
+ f.sortBy === 'time_desc';
21
+ const CrashFilterModal = ({ visible, onClose, filters, onApply, searchQuery = '', }) => {
22
+ const { t } = useTranslation();
23
+ const { crashRecords } = useInspector();
24
+ const [draft, setDraft] = useState(() => ({
25
+ ...filters,
26
+ types: new Set(filters.types),
27
+ }));
28
+ useEffect(() => {
29
+ if (visible) {
30
+ setDraft({
31
+ ...filters,
32
+ types: new Set(filters.types),
33
+ });
34
+ }
35
+ // eslint-disable-next-line react-hooks/exhaustive-deps
36
+ }, [visible]);
37
+ const toggleType = (key) => {
38
+ setDraft(prev => {
39
+ const next = new Set(prev.types);
40
+ if (key === 'all') {
41
+ return { ...prev, types: new Set(['all']) };
42
+ }
43
+ next.delete('all');
44
+ if (next.has(key)) {
45
+ next.delete(key);
46
+ if (next.size === 0)
47
+ next.add('all');
48
+ }
49
+ else {
50
+ next.add(key);
51
+ }
52
+ return { ...prev, types: next };
53
+ });
54
+ };
55
+ const setTimeWindow = (tw) => {
56
+ setDraft(prev => ({ ...prev, timeWindow: tw }));
57
+ };
58
+ const setPlatform = (p) => {
59
+ setDraft(prev => ({ ...prev, platform: p }));
60
+ };
61
+ const setEngine = (e) => {
62
+ setDraft(prev => ({ ...prev, engine: e }));
63
+ };
64
+ const setSort = (sortBy) => {
65
+ setDraft(prev => ({ ...prev, sortBy }));
66
+ };
67
+ const handleResetDraft = () => {
68
+ setDraft({
69
+ ...DEFAULT_CRASH_FILTERS,
70
+ types: new Set(DEFAULT_CRASH_FILTERS.types),
71
+ });
72
+ };
73
+ const handleApply = () => {
74
+ onApply({
75
+ ...draft,
76
+ types: new Set(draft.types),
77
+ });
78
+ onClose();
79
+ };
80
+ const handleDiscard = () => {
81
+ setDraft({
82
+ ...filters,
83
+ types: new Set(filters.types),
84
+ });
85
+ onClose();
86
+ };
87
+ const draftMatchCount = useMemo(() => {
88
+ let crashes = crashRecords;
89
+ if (searchQuery.trim().length > 0) {
90
+ const q = searchQuery.toLowerCase();
91
+ crashes = crashes.filter(c => (c.message || '').toLowerCase().includes(q) ||
92
+ (c.name || '').toLowerCase().includes(q) ||
93
+ (c.stack || '').toLowerCase().includes(q));
94
+ }
95
+ if (draft.types.size > 0 && !draft.types.has('all')) {
96
+ crashes = crashes.filter(c => {
97
+ if (draft.types.has('fatal') && c.isFatal)
98
+ return true;
99
+ if (draft.types.has('js') && c.type === 'js')
100
+ return true;
101
+ if (draft.types.has('promise') && c.type === 'promise')
102
+ return true;
103
+ if (draft.types.has('render') && c.type === 'render')
104
+ return true;
105
+ if (draft.types.has('native') && c.type === 'native')
106
+ return true;
107
+ return false;
108
+ });
109
+ }
110
+ if (draft.timeWindow !== 'all') {
111
+ const now = Date.now();
112
+ const cutoff = draft.timeWindow === '15m'
113
+ ? now - 15 * 60 * 1000
114
+ : draft.timeWindow === '1h'
115
+ ? now - 60 * 60 * 1000
116
+ : draft.timeWindow === '24h'
117
+ ? now - 24 * 60 * 60 * 1000
118
+ : now - 7 * 24 * 60 * 60 * 1000;
119
+ crashes = crashes.filter(c => c.timestamp >= cutoff);
120
+ }
121
+ if (draft.platform !== 'all') {
122
+ crashes = crashes.filter(c => (c.deviceInfo?.platform || '').toLowerCase() === draft.platform);
123
+ }
124
+ if (draft.engine !== 'all') {
125
+ crashes = crashes.filter(c => {
126
+ const isHermes = c.deviceInfo?.isHermes;
127
+ if (draft.engine === 'hermes')
128
+ return isHermes === true;
129
+ return isHermes === false || isHermes === undefined;
130
+ });
131
+ }
132
+ return crashes.length;
133
+ }, [crashRecords, searchQuery, draft]);
134
+ const isAllTypes = draft.types.has('all') || draft.types.size === 0;
135
+ const typeChips = [
136
+ { key: 'all', label: t('crash.filterTypeAll'), Icon: FilterIcon, color: AppColors.grayTextStrong },
137
+ { key: 'fatal', label: t('crash.filterFatal'), Icon: SkullIcon, color: AppColors.errorColor },
138
+ { key: 'js', label: t('crash.filterJsError'), Icon: JsIcon, color: AppColors.sky600 },
139
+ { key: 'promise', label: t('crash.filterPromise'), Icon: HourglassIcon, color: AppColors.darkOrange },
140
+ { key: 'render', label: t('crash.filterRender'), Icon: LayoutIcon, color: AppColors.purple },
141
+ { key: 'native', label: t('crash.filterNative'), Icon: ChipIcon, color: AppColors.amber700 },
142
+ ];
143
+ return (<Modal visible={visible} transparent animationType="fade" onRequestClose={handleDiscard}>
144
+ <View style={styles.backdrop}>
145
+ <Pressable style={StyleSheet.absoluteFill} onPress={handleDiscard}/>
146
+
147
+ <View style={styles.modalCard}>
148
+ <View style={styles.header}>
149
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
150
+ <View style={styles.headerIconBox}>
151
+ <FilterIcon color={AppColors.brandPurple} size={15}/>
152
+ </View>
153
+ <View>
154
+ <Text style={styles.headerTitle}>{t('crash.filterTitle')}</Text>
155
+ <Text style={styles.headerSubtitle}>
156
+ {t('crash.filterSubtitle')}
157
+ </Text>
158
+ </View>
159
+ </View>
160
+
161
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
162
+ <TouchableOpacity onPress={handleResetDraft} hitSlop={8} style={styles.resetBtn}>
163
+ <Text style={styles.resetBtnText}>{t('crash.filterReset')}</Text>
164
+ </TouchableOpacity>
165
+
166
+ <TouchableOpacity onPress={handleDiscard} hitSlop={10} style={styles.closeBtn}>
167
+ <CloseWhite />
168
+ </TouchableOpacity>
169
+ </View>
170
+ </View>
171
+
172
+ <ScrollView style={{ maxHeight: 460 }} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={true}>
173
+ <View style={styles.section}>
174
+ <View style={styles.sectionHeaderRow}>
175
+ <SkullIcon color={AppColors.grayTextWeak} size={12}/>
176
+ <Text style={styles.sectionTitle}>
177
+ {t('crash.filterTypeSection')}
178
+ </Text>
179
+ </View>
180
+ <View style={styles.chipsWrap}>
181
+ {typeChips.map(chip => {
182
+ const isSelected = chip.key === 'all' ? isAllTypes : draft.types.has(chip.key);
183
+ return (<TouchableScale key={chip.key} onPress={() => toggleType(chip.key)} style={[
184
+ styles.filterPill,
185
+ isSelected && styles.filterPillActive,
186
+ ]}>
187
+ {chip.key === 'all' && isSelected && (<CheckIcon color={AppColors.white} size={12}/>)}
188
+ <chip.Icon size={12} color={isSelected ? AppColors.white : chip.color}/>
189
+ <Text style={[
190
+ styles.filterPillText,
191
+ isSelected && styles.filterPillTextActive,
192
+ ]}>
193
+ {chip.label}
194
+ </Text>
195
+ </TouchableScale>);
196
+ })}
197
+ </View>
198
+ </View>
199
+
200
+ <View style={styles.section}>
201
+ <View style={styles.sectionHeaderRow}>
202
+ <ClockIcon color={AppColors.grayTextWeak} size={12}/>
203
+ <Text style={styles.sectionTitle}>
204
+ {t('crash.filterTimeSection')}
205
+ </Text>
206
+ </View>
207
+ <View style={styles.chipsWrap}>
208
+ {[
209
+ { key: 'all', label: t('crash.filterTimeAll') },
210
+ { key: '15m', label: t('crash.filterTime15m') },
211
+ { key: '1h', label: t('crash.filterTime1h') },
212
+ { key: '24h', label: t('crash.filterTime24h') },
213
+ { key: '7d', label: t('crash.filterTime7d') },
214
+ ].map(item => (<TouchableScale key={item.key} onPress={() => setTimeWindow(item.key)} style={[
215
+ styles.filterPill,
216
+ draft.timeWindow === item.key && styles.filterPillActive,
217
+ ]}>
218
+ <Text style={[
219
+ styles.filterPillText,
220
+ draft.timeWindow === item.key &&
221
+ styles.filterPillTextActive,
222
+ ]}>
223
+ {item.label}
224
+ </Text>
225
+ </TouchableScale>))}
226
+ </View>
227
+ </View>
228
+
229
+ <View style={styles.section}>
230
+ <View style={styles.sectionHeaderRow}>
231
+ <AppleIcon color={AppColors.grayTextWeak} size={12}/>
232
+ <Text style={styles.sectionTitle}>
233
+ {t('crash.filterPlatformSection')}
234
+ </Text>
235
+ </View>
236
+ <View style={styles.chipsWrap}>
237
+ <TouchableScale onPress={() => setPlatform('all')} style={[
238
+ styles.filterPill,
239
+ draft.platform === 'all' && styles.filterPillActive,
240
+ ]}>
241
+ <Text style={[
242
+ styles.filterPillText,
243
+ draft.platform === 'all' && styles.filterPillTextActive,
244
+ ]}>
245
+ {t('crash.filterPlatformAll')}
246
+ </Text>
247
+ </TouchableScale>
248
+
249
+ <TouchableScale onPress={() => setPlatform('ios')} style={[
250
+ styles.filterPill,
251
+ draft.platform === 'ios' && styles.filterPillActive,
252
+ ]}>
253
+ <AppleIcon size={12} color={draft.platform === 'ios'
254
+ ? AppColors.white
255
+ : AppColors.grayTextStrong}/>
256
+ <Text style={[
257
+ styles.filterPillText,
258
+ draft.platform === 'ios' && styles.filterPillTextActive,
259
+ ]}>
260
+ {t('crash.filterPlatformIos')}
261
+ </Text>
262
+ </TouchableScale>
263
+
264
+ <TouchableScale onPress={() => setPlatform('android')} style={[
265
+ styles.filterPill,
266
+ draft.platform === 'android' && styles.filterPillActive,
267
+ ]}>
268
+ <AndroidIcon size={12} color={draft.platform === 'android'
269
+ ? AppColors.white
270
+ : AppColors.greenColor}/>
271
+ <Text style={[
272
+ styles.filterPillText,
273
+ draft.platform === 'android' && styles.filterPillTextActive,
274
+ ]}>
275
+ {t('crash.filterPlatformAndroid')}
276
+ </Text>
277
+ </TouchableScale>
278
+ </View>
279
+ </View>
280
+
281
+ <View style={styles.section}>
282
+ <View style={styles.sectionHeaderRow}>
283
+ <BoltIcon color={AppColors.grayTextWeak} size={12}/>
284
+ <Text style={styles.sectionTitle}>
285
+ {t('crash.filterEngineSection')}
286
+ </Text>
287
+ </View>
288
+ <View style={styles.chipsWrap}>
289
+ <TouchableScale onPress={() => setEngine('all')} style={[
290
+ styles.filterPill,
291
+ draft.engine === 'all' && styles.filterPillActive,
292
+ ]}>
293
+ <Text style={[
294
+ styles.filterPillText,
295
+ draft.engine === 'all' && styles.filterPillTextActive,
296
+ ]}>
297
+ {t('crash.filterEngineAll')}
298
+ </Text>
299
+ </TouchableScale>
300
+
301
+ <TouchableScale onPress={() => setEngine('hermes')} style={[
302
+ styles.filterPill,
303
+ draft.engine === 'hermes' && styles.filterPillActive,
304
+ ]}>
305
+ <BoltIcon size={12} color={draft.engine === 'hermes'
306
+ ? AppColors.white
307
+ : AppColors.brandPurple}/>
308
+ <Text style={[
309
+ styles.filterPillText,
310
+ draft.engine === 'hermes' && styles.filterPillTextActive,
311
+ ]}>
312
+ {t('crash.filterEngineHermes')}
313
+ </Text>
314
+ </TouchableScale>
315
+
316
+ <TouchableScale onPress={() => setEngine('jsc')} style={[
317
+ styles.filterPill,
318
+ draft.engine === 'jsc' && styles.filterPillActive,
319
+ ]}>
320
+ <Text style={[
321
+ styles.filterPillText,
322
+ draft.engine === 'jsc' && styles.filterPillTextActive,
323
+ ]}>
324
+ {t('crash.jsc')}
325
+ </Text>
326
+ </TouchableScale>
327
+ </View>
328
+ </View>
329
+
330
+ <View style={styles.section}>
331
+ <View style={styles.sectionHeaderRow}>
332
+ <ClockIcon color={AppColors.grayTextWeak} size={12}/>
333
+ <Text style={styles.sectionTitle}>
334
+ {t('crash.filterSortSection')}
335
+ </Text>
336
+ </View>
337
+ <View style={styles.chipsWrap}>
338
+ <TouchableScale onPress={() => setSort('time_desc')} style={[
339
+ styles.filterPill,
340
+ draft.sortBy === 'time_desc' && styles.filterPillActive,
341
+ ]}>
342
+ <ClockIcon size={12} color={draft.sortBy === 'time_desc'
343
+ ? AppColors.white
344
+ : AppColors.grayText}/>
345
+ <Text style={[
346
+ styles.filterPillText,
347
+ draft.sortBy === 'time_desc' &&
348
+ styles.filterPillTextActive,
349
+ ]}>
350
+ {t('crash.filterSortNewest')}
351
+ </Text>
352
+ </TouchableScale>
353
+
354
+ <TouchableScale onPress={() => setSort('time_asc')} style={[
355
+ styles.filterPill,
356
+ draft.sortBy === 'time_asc' && styles.filterPillActive,
357
+ ]}>
358
+ <HourglassIcon size={12} color={draft.sortBy === 'time_asc'
359
+ ? AppColors.white
360
+ : AppColors.grayText}/>
361
+ <Text style={[
362
+ styles.filterPillText,
363
+ draft.sortBy === 'time_asc' &&
364
+ styles.filterPillTextActive,
365
+ ]}>
366
+ {t('crash.filterSortOldest')}
367
+ </Text>
368
+ </TouchableScale>
369
+ </View>
370
+ </View>
371
+ </ScrollView>
372
+
373
+ <View style={styles.footer}>
374
+ <TouchableOpacity onPress={handleDiscard} style={styles.discardBtn} activeOpacity={0.8}>
375
+ <Text style={styles.discardBtnText}>
376
+ {t('crash.filterDiscard')}
377
+ </Text>
378
+ </TouchableOpacity>
379
+
380
+ <TouchableOpacity onPress={handleApply} style={styles.applyBtn} activeOpacity={0.85}>
381
+ <Text style={styles.applyBtnText}>
382
+ {t('crash.filterApply', { count: draftMatchCount })}
383
+ </Text>
384
+ </TouchableOpacity>
385
+ </View>
386
+ </View>
387
+ </View>
388
+ </Modal>);
389
+ };
390
+ const styles = StyleSheet.create({
391
+ backdrop: {
392
+ flex: 1,
393
+ backgroundColor: `${AppColors.primaryBlack}85`,
394
+ justifyContent: 'center',
395
+ alignItems: 'center',
396
+ padding: 16,
397
+ },
398
+ modalCard: {
399
+ width: '100%',
400
+ maxWidth: 440,
401
+ backgroundColor: AppColors.white,
402
+ borderRadius: 14,
403
+ borderWidth: 1,
404
+ borderColor: AppColors.dividerColor,
405
+ shadowColor: AppColors.black,
406
+ shadowOpacity: 0.18,
407
+ shadowRadius: 12,
408
+ shadowOffset: { width: 0, height: 4 },
409
+ elevation: 8,
410
+ overflow: 'hidden',
411
+ },
412
+ header: {
413
+ flexDirection: 'row',
414
+ alignItems: 'center',
415
+ justifyContent: 'space-between',
416
+ paddingHorizontal: 14,
417
+ paddingVertical: 12,
418
+ borderBottomWidth: 1,
419
+ borderBottomColor: AppColors.dividerColor,
420
+ backgroundColor: `${AppColors.brandPurple}08`,
421
+ },
422
+ headerIconBox: {
423
+ width: 28,
424
+ height: 28,
425
+ borderRadius: 7,
426
+ backgroundColor: `${AppColors.brandPurple}18`,
427
+ alignItems: 'center',
428
+ justifyContent: 'center',
429
+ },
430
+ headerTitle: {
431
+ fontFamily: AppFonts.interBold,
432
+ fontSize: 13.5,
433
+ color: AppColors.primaryBlack,
434
+ },
435
+ headerSubtitle: {
436
+ fontFamily: AppFonts.interMedium,
437
+ fontSize: 10,
438
+ color: AppColors.grayTextWeak,
439
+ },
440
+ resetBtn: {
441
+ paddingHorizontal: 8,
442
+ paddingVertical: 4,
443
+ borderRadius: 5,
444
+ backgroundColor: `${AppColors.darkOrange}14`,
445
+ borderWidth: 1,
446
+ borderColor: `${AppColors.darkOrange}30`,
447
+ },
448
+ resetBtnText: {
449
+ fontFamily: AppFonts.interBold,
450
+ fontSize: 10,
451
+ color: AppColors.darkOrange,
452
+ },
453
+ closeBtn: {
454
+ width: 24,
455
+ height: 24,
456
+ borderRadius: 12,
457
+ backgroundColor: `${AppColors.primaryBlack}18`,
458
+ alignItems: 'center',
459
+ justifyContent: 'center',
460
+ },
461
+ scrollContent: {
462
+ padding: 14,
463
+ gap: 14,
464
+ },
465
+ section: {
466
+ gap: 7,
467
+ },
468
+ sectionHeaderRow: {
469
+ flexDirection: 'row',
470
+ alignItems: 'center',
471
+ gap: 5,
472
+ },
473
+ sectionTitle: {
474
+ fontFamily: AppFonts.interBold,
475
+ fontSize: 9.5,
476
+ color: AppColors.grayTextWeak,
477
+ letterSpacing: 0.5,
478
+ },
479
+ chipsWrap: {
480
+ flexDirection: 'row',
481
+ flexWrap: 'wrap',
482
+ gap: 6.5,
483
+ },
484
+ filterPill: {
485
+ flexDirection: 'row',
486
+ alignItems: 'center',
487
+ gap: 5,
488
+ paddingHorizontal: 9,
489
+ paddingVertical: 5.5,
490
+ borderRadius: 7,
491
+ backgroundColor: AppColors.grayBackground,
492
+ borderWidth: 1,
493
+ borderColor: AppColors.dividerColor,
494
+ },
495
+ filterPillActive: {
496
+ backgroundColor: AppColors.brandPurple,
497
+ borderColor: AppColors.brandPurple,
498
+ shadowColor: AppColors.brandPurple,
499
+ shadowOffset: { width: 0, height: 1 },
500
+ shadowOpacity: 0.25,
501
+ shadowRadius: 3,
502
+ elevation: 2,
503
+ },
504
+ filterPillText: {
505
+ fontFamily: AppFonts.interMedium,
506
+ fontSize: 11,
507
+ color: AppColors.primaryBlack,
508
+ },
509
+ filterPillTextActive: {
510
+ color: AppColors.white,
511
+ fontFamily: AppFonts.interBold,
512
+ },
513
+ footer: {
514
+ flexDirection: 'row',
515
+ alignItems: 'center',
516
+ gap: 10,
517
+ paddingHorizontal: 14,
518
+ paddingVertical: 12,
519
+ borderTopWidth: 1,
520
+ borderTopColor: AppColors.dividerColor,
521
+ backgroundColor: AppColors.grayBackground,
522
+ },
523
+ discardBtn: {
524
+ flex: 1,
525
+ paddingVertical: 9.5,
526
+ borderRadius: 8,
527
+ borderWidth: 1,
528
+ borderColor: AppColors.dividerColor,
529
+ backgroundColor: AppColors.white,
530
+ alignItems: 'center',
531
+ justifyContent: 'center',
532
+ },
533
+ discardBtnText: {
534
+ fontFamily: AppFonts.interBold,
535
+ fontSize: 12.5,
536
+ color: AppColors.grayTextStrong,
537
+ },
538
+ applyBtn: {
539
+ flex: 2,
540
+ backgroundColor: AppColors.brandPurple,
541
+ paddingVertical: 9.5,
542
+ borderRadius: 8,
543
+ alignItems: 'center',
544
+ justifyContent: 'center',
545
+ shadowColor: AppColors.brandPurple,
546
+ shadowOffset: { width: 0, height: 1 },
547
+ shadowOpacity: 0.25,
548
+ shadowRadius: 3,
549
+ elevation: 2,
550
+ },
551
+ applyBtnText: {
552
+ fontFamily: AppFonts.interBold,
553
+ fontSize: 12.5,
554
+ color: AppColors.white,
555
+ },
556
+ });
557
+ export default CrashFilterModal;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const CrashTab: React.MemoExoticComponent<() => React.JSX.Element>;
3
+ export default CrashTab;