react-native-inapp-inspector 1.1.28 → 1.1.31

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 (77) hide show
  1. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +29 -80
  2. package/dist/commonjs/components/AnalyticsDetail.js +668 -108
  3. package/dist/commonjs/components/AppHeaderLogo.js +15 -15
  4. package/dist/commonjs/components/ConsoleLogCard.js +112 -66
  5. package/dist/commonjs/components/CopyButton.js +15 -1
  6. package/dist/commonjs/components/DomainHeader.js +64 -32
  7. package/dist/commonjs/components/HighlightText.js +7 -1
  8. package/dist/commonjs/components/Inspector/AnalyticsTab.js +332 -221
  9. package/dist/commonjs/components/Inspector/ConsoleTab.js +162 -56
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +70 -119
  11. package/dist/commonjs/components/Inspector/LogDetail.js +53 -17
  12. package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
  13. package/dist/commonjs/components/Inspector/NetworkDetail.js +24 -24
  14. package/dist/commonjs/components/Inspector/NetworkTab.js +4 -1
  15. package/dist/commonjs/components/Inspector/ReduxDetail.js +237 -42
  16. package/dist/commonjs/components/Inspector/ReduxTab.js +456 -35
  17. package/dist/commonjs/components/JsonViewer.js +26 -4
  18. package/dist/commonjs/components/LogCard.js +103 -11
  19. package/dist/commonjs/components/NetworkIcons.js +19 -10
  20. package/dist/commonjs/components/Toast.d.ts +3 -0
  21. package/dist/commonjs/components/Toast.js +152 -0
  22. package/dist/commonjs/components/TouchableScale.d.ts +1 -0
  23. package/dist/commonjs/components/TouchableScale.js +3 -3
  24. package/dist/commonjs/components/TreeNode.js +12 -2
  25. package/dist/commonjs/constants/index.js +6 -6
  26. package/dist/commonjs/constants/version.d.ts +1 -1
  27. package/dist/commonjs/constants/version.js +1 -1
  28. package/dist/commonjs/customHooks/reduxLogger.js +128 -5
  29. package/dist/commonjs/helpers/index.d.ts +4 -0
  30. package/dist/commonjs/helpers/index.js +107 -92
  31. package/dist/commonjs/helpers/toast.d.ts +4 -0
  32. package/dist/commonjs/helpers/toast.js +20 -0
  33. package/dist/commonjs/i18n/locales/en.json +49 -3
  34. package/dist/commonjs/styles/AppColors.d.ts +6 -0
  35. package/dist/commonjs/styles/AppColors.js +6 -0
  36. package/dist/commonjs/styles/index.d.ts +82 -15
  37. package/dist/commonjs/styles/index.js +92 -26
  38. package/dist/commonjs/types/interfaces.d.ts +7 -0
  39. package/dist/esm/components/AnalyticsDetail.js +670 -110
  40. package/dist/esm/components/AppHeaderLogo.js +15 -15
  41. package/dist/esm/components/ConsoleLogCard.js +114 -68
  42. package/dist/esm/components/CopyButton.js +15 -1
  43. package/dist/esm/components/DomainHeader.js +64 -32
  44. package/dist/esm/components/HighlightText.js +7 -1
  45. package/dist/esm/components/Inspector/AnalyticsTab.js +334 -223
  46. package/dist/esm/components/Inspector/ConsoleTab.js +163 -57
  47. package/dist/esm/components/Inspector/InspectorHeader.js +71 -120
  48. package/dist/esm/components/Inspector/LogDetail.js +55 -19
  49. package/dist/esm/components/Inspector/MainScreen.js +4 -0
  50. package/dist/esm/components/Inspector/NetworkDetail.js +25 -25
  51. package/dist/esm/components/Inspector/NetworkTab.js +4 -1
  52. package/dist/esm/components/Inspector/ReduxDetail.js +239 -44
  53. package/dist/esm/components/Inspector/ReduxTab.js +458 -37
  54. package/dist/esm/components/JsonViewer.js +26 -4
  55. package/dist/esm/components/LogCard.js +105 -13
  56. package/dist/esm/components/NetworkIcons.js +19 -10
  57. package/dist/esm/components/Toast.d.ts +3 -0
  58. package/dist/esm/components/Toast.js +117 -0
  59. package/dist/esm/components/TouchableScale.d.ts +1 -0
  60. package/dist/esm/components/TouchableScale.js +3 -3
  61. package/dist/esm/components/TreeNode.js +12 -2
  62. package/dist/esm/constants/index.js +6 -6
  63. package/dist/esm/constants/version.d.ts +1 -1
  64. package/dist/esm/constants/version.js +1 -1
  65. package/dist/esm/customHooks/reduxLogger.js +128 -5
  66. package/dist/esm/helpers/index.d.ts +4 -0
  67. package/dist/esm/helpers/index.js +102 -92
  68. package/dist/esm/helpers/toast.d.ts +4 -0
  69. package/dist/esm/helpers/toast.js +15 -0
  70. package/dist/esm/i18n/locales/en.json +49 -3
  71. package/dist/esm/styles/AppColors.d.ts +6 -0
  72. package/dist/esm/styles/AppColors.js +6 -0
  73. package/dist/esm/styles/index.d.ts +82 -15
  74. package/dist/esm/styles/index.js +92 -26
  75. package/dist/esm/types/interfaces.d.ts +7 -0
  76. package/ios/NetworkInspectorModule.m +0 -10
  77. package/package.json +13 -10
@@ -125,17 +125,36 @@ const AnalyticsHeader = react_1.default.memo(() => {
125
125
  barWidthPct: Math.round((count / maxVal) * 100),
126
126
  }));
127
127
  }, [filteredAnalyticsEvents]);
128
- // Toggle category filter from top button group
128
+ // Multi-select category toggle from top button group
129
129
  const toggleCategoryFilter = (cat) => {
130
130
  (0, InspectorContext_1.animateNextLayout)();
131
131
  setAnalyticsFilters(prev => {
132
- const isSelected = !prev.categories.has('all') && prev.categories.has(cat);
133
- if (isSelected) {
132
+ if (cat === 'all') {
134
133
  return { ...prev, categories: new Set(['all']) };
135
134
  }
135
+ const nextCategories = new Set(prev.categories);
136
+ if (nextCategories.has('all')) {
137
+ nextCategories.delete('all');
138
+ nextCategories.add(cat);
139
+ }
136
140
  else {
137
- return { ...prev, categories: new Set([cat]) };
141
+ if (nextCategories.has(cat)) {
142
+ nextCategories.delete(cat);
143
+ if (nextCategories.size === 0) {
144
+ nextCategories.add('all');
145
+ }
146
+ }
147
+ else {
148
+ nextCategories.add(cat);
149
+ if (nextCategories.has('ecommerce') &&
150
+ nextCategories.has('page_view') &&
151
+ nextCategories.has('system') &&
152
+ nextCategories.has('custom')) {
153
+ return { ...prev, categories: new Set(['all']) };
154
+ }
155
+ }
138
156
  }
157
+ return { ...prev, categories: nextCategories };
139
158
  });
140
159
  };
141
160
  // 12-Bucket GA4 Realtime Stacked Histogram & Spline Wave Graph (-30m / 30s to NOW)
@@ -215,7 +234,7 @@ const AnalyticsHeader = react_1.default.memo(() => {
215
234
  }, [filteredAnalyticsEvents, chartHeight, svgWidth, t]);
216
235
  const selectedBucket = selectedBucketIdx != null ? histogramData.buckets[selectedBucketIdx] : null;
217
236
  return (<react_native_1.View style={styles_1.default.analyticsHeaderCard}>
218
- {/* ── Top Header Row (GA4 Style) ─────────────────────────────────────── */}
237
+ {/* ── 1. Top Header Row (GA4 Style) ─────────────────────────────────── */}
219
238
  <react_native_1.View style={styles_1.default.analyticsHeaderTop}>
220
239
  <react_native_1.View style={{ flex: 1 }}>
221
240
  <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
@@ -255,9 +274,280 @@ const AnalyticsHeader = react_1.default.memo(() => {
255
274
  </react_native_1.TouchableOpacity>
256
275
  </react_native_1.View>
257
276
 
258
- {/* ── GA4 Realtime Metric Hero & Activity Chart ─────────────────────── */}
277
+ {/* ── 2. Multi-Select Category Filter Buttons (AT THE TOP) ──────────── */}
278
+ <react_native_1.View style={{ marginTop: 10, marginBottom: 8 }}>
279
+ {/* Multi-color Proportional Segmented Bar */}
280
+ <react_native_1.View style={{
281
+ height: 4.5,
282
+ borderRadius: 2.5,
283
+ backgroundColor: `${AppColors_1.AppColors.grayBorderSecondary}40`,
284
+ flexDirection: 'row',
285
+ overflow: 'hidden',
286
+ marginBottom: 8,
287
+ }}>
288
+ {categoryStats.ecommerce > 0 && (<react_native_1.View style={{
289
+ flex: categoryStats.ecommerce,
290
+ backgroundColor: AppColors_1.AppColors.amber500,
291
+ }}/>)}
292
+ {categoryStats.page_view > 0 && (<react_native_1.View style={{
293
+ flex: categoryStats.page_view,
294
+ backgroundColor: AppColors_1.AppColors.sky500,
295
+ }}/>)}
296
+ {categoryStats.system > 0 && (<react_native_1.View style={{
297
+ flex: categoryStats.system,
298
+ backgroundColor: AppColors_1.AppColors.purple,
299
+ }}/>)}
300
+ {categoryStats.custom > 0 && (<react_native_1.View style={{
301
+ flex: categoryStats.custom,
302
+ backgroundColor: AppColors_1.AppColors.brandPurple,
303
+ }}/>)}
304
+ </react_native_1.View>
305
+
306
+ {/* Multi-Select Category Buttons with Checkboxes */}
307
+ <react_native_1.View style={{
308
+ flexDirection: 'row',
309
+ flexWrap: 'wrap',
310
+ gap: 6,
311
+ }}>
312
+ {/* All Button */}
313
+ {(() => {
314
+ const isAllSelected = analyticsFilters.categories.has('all');
315
+ return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('all')} style={[
316
+ {
317
+ flexDirection: 'row',
318
+ alignItems: 'center',
319
+ gap: 5,
320
+ backgroundColor: isAllSelected ? AppColors_1.AppColors.indigo600Alt : AppColors_1.AppColors.indigo50,
321
+ paddingHorizontal: 8,
322
+ paddingVertical: 5,
323
+ borderRadius: 7,
324
+ borderWidth: 1,
325
+ borderColor: isAllSelected ? AppColors_1.AppColors.indigo600 : AppColors_1.AppColors.indigo400,
326
+ },
327
+ isAllSelected && {
328
+ shadowColor: AppColors_1.AppColors.indigo600Alt,
329
+ shadowOffset: { width: 0, height: 1 },
330
+ shadowOpacity: 0.28,
331
+ shadowRadius: 2.5,
332
+ elevation: 2,
333
+ },
334
+ ]}>
335
+ <react_native_1.View style={{
336
+ width: 12,
337
+ height: 12,
338
+ borderRadius: 3,
339
+ borderWidth: 1.2,
340
+ borderColor: isAllSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.indigo400,
341
+ backgroundColor: isAllSelected ? AppColors_1.AppColors.white : 'transparent',
342
+ alignItems: 'center',
343
+ justifyContent: 'center',
344
+ }}>
345
+ {isAllSelected && <NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.indigo600Alt} size={8}/>}
346
+ </react_native_1.View>
347
+ <NetworkIcons_1.LayersIcon color={isAllSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.indigo600Alt} size={11}/>
348
+ <react_native_1.Text style={{
349
+ fontFamily: AppFonts_1.AppFonts.interBold,
350
+ fontSize: 10,
351
+ color: isAllSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.indigo600Alt,
352
+ }}>
353
+ {t('analytics.allCategory')}: {categoryStats.totalCount}
354
+ </react_native_1.Text>
355
+ </TouchableScale_1.default>);
356
+ })()}
357
+
358
+ {/* Ecommerce Button */}
359
+ {(() => {
360
+ const isSelected = !analyticsFilters.categories.has('all') &&
361
+ analyticsFilters.categories.has('ecommerce');
362
+ return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('ecommerce')} style={[
363
+ {
364
+ flexDirection: 'row',
365
+ alignItems: 'center',
366
+ gap: 5,
367
+ backgroundColor: isSelected ? AppColors_1.AppColors.amber600 : AppColors_1.AppColors.amber100,
368
+ paddingHorizontal: 8,
369
+ paddingVertical: 5,
370
+ borderRadius: 7,
371
+ borderWidth: 1,
372
+ borderColor: isSelected ? AppColors_1.AppColors.amber700 : AppColors_1.AppColors.amber200,
373
+ },
374
+ isSelected && {
375
+ shadowColor: AppColors_1.AppColors.amber600,
376
+ shadowOffset: { width: 0, height: 1 },
377
+ shadowOpacity: 0.28,
378
+ shadowRadius: 2.5,
379
+ elevation: 2,
380
+ },
381
+ ]}>
382
+ <react_native_1.View style={{
383
+ width: 12,
384
+ height: 12,
385
+ borderRadius: 3,
386
+ borderWidth: 1.2,
387
+ borderColor: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.amber500,
388
+ backgroundColor: isSelected ? AppColors_1.AppColors.white : 'transparent',
389
+ alignItems: 'center',
390
+ justifyContent: 'center',
391
+ }}>
392
+ {isSelected && <NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.amber600} size={8}/>}
393
+ </react_native_1.View>
394
+ <NetworkIcons_1.CartIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.amber700} size={11}/>
395
+ <react_native_1.Text style={{
396
+ fontFamily: AppFonts_1.AppFonts.interBold,
397
+ fontSize: 10,
398
+ color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.amber800Warm,
399
+ }}>
400
+ {t('analytics.ecommerceCategory')}: {categoryStats.ecommerce} ({categoryStats.ecommercePct}%)
401
+ </react_native_1.Text>
402
+ </TouchableScale_1.default>);
403
+ })()}
404
+
405
+ {/* Screens Button */}
406
+ {(() => {
407
+ const isSelected = !analyticsFilters.categories.has('all') &&
408
+ analyticsFilters.categories.has('page_view');
409
+ return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('page_view')} style={[
410
+ {
411
+ flexDirection: 'row',
412
+ alignItems: 'center',
413
+ gap: 5,
414
+ backgroundColor: isSelected ? AppColors_1.AppColors.sky600 : AppColors_1.AppColors.sky100,
415
+ paddingHorizontal: 8,
416
+ paddingVertical: 5,
417
+ borderRadius: 7,
418
+ borderWidth: 1,
419
+ borderColor: isSelected ? AppColors_1.AppColors.blue700 : AppColors_1.AppColors.sky400,
420
+ },
421
+ isSelected && {
422
+ shadowColor: AppColors_1.AppColors.sky600,
423
+ shadowOffset: { width: 0, height: 1 },
424
+ shadowOpacity: 0.28,
425
+ shadowRadius: 2.5,
426
+ elevation: 2,
427
+ },
428
+ ]}>
429
+ <react_native_1.View style={{
430
+ width: 12,
431
+ height: 12,
432
+ borderRadius: 3,
433
+ borderWidth: 1.2,
434
+ borderColor: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.sky400,
435
+ backgroundColor: isSelected ? AppColors_1.AppColors.white : 'transparent',
436
+ alignItems: 'center',
437
+ justifyContent: 'center',
438
+ }}>
439
+ {isSelected && <NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.sky600} size={8}/>}
440
+ </react_native_1.View>
441
+ <NetworkIcons_1.GlobeIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.sky600} size={11}/>
442
+ <react_native_1.Text style={{
443
+ fontFamily: AppFonts_1.AppFonts.interBold,
444
+ fontSize: 10,
445
+ color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.sky600,
446
+ }}>
447
+ {t('analytics.screensCategory')}: {categoryStats.page_view} ({categoryStats.page_viewPct}%)
448
+ </react_native_1.Text>
449
+ </TouchableScale_1.default>);
450
+ })()}
451
+
452
+ {/* System Button */}
453
+ {(() => {
454
+ const isSelected = !analyticsFilters.categories.has('all') &&
455
+ analyticsFilters.categories.has('system');
456
+ return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('system')} style={[
457
+ {
458
+ flexDirection: 'row',
459
+ alignItems: 'center',
460
+ gap: 5,
461
+ backgroundColor: isSelected ? AppColors_1.AppColors.violet600 : AppColors_1.AppColors.purple100,
462
+ paddingHorizontal: 8,
463
+ paddingVertical: 5,
464
+ borderRadius: 7,
465
+ borderWidth: 1,
466
+ borderColor: isSelected ? AppColors_1.AppColors.purpleShade700 : AppColors_1.AppColors.purple200,
467
+ },
468
+ isSelected && {
469
+ shadowColor: AppColors_1.AppColors.violet600,
470
+ shadowOffset: { width: 0, height: 1 },
471
+ shadowOpacity: 0.28,
472
+ shadowRadius: 2.5,
473
+ elevation: 2,
474
+ },
475
+ ]}>
476
+ <react_native_1.View style={{
477
+ width: 12,
478
+ height: 12,
479
+ borderRadius: 3,
480
+ borderWidth: 1.2,
481
+ borderColor: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple400,
482
+ backgroundColor: isSelected ? AppColors_1.AppColors.white : 'transparent',
483
+ alignItems: 'center',
484
+ justifyContent: 'center',
485
+ }}>
486
+ {isSelected && <NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.violet600} size={8}/>}
487
+ </react_native_1.View>
488
+ <NetworkIcons_1.BoltIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={11}/>
489
+ <react_native_1.Text style={{
490
+ fontFamily: AppFonts_1.AppFonts.interBold,
491
+ fontSize: 10,
492
+ color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.brandPurple,
493
+ }}>
494
+ {t('analytics.systemCategory')}: {categoryStats.system} ({categoryStats.systemPct}%)
495
+ </react_native_1.Text>
496
+ </TouchableScale_1.default>);
497
+ })()}
498
+
499
+ {/* Custom Button */}
500
+ {(() => {
501
+ const isSelected = !analyticsFilters.categories.has('all') &&
502
+ analyticsFilters.categories.has('custom');
503
+ return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('custom')} style={[
504
+ {
505
+ flexDirection: 'row',
506
+ alignItems: 'center',
507
+ gap: 5,
508
+ backgroundColor: isSelected ? AppColors_1.AppColors.pink600 : AppColors_1.AppColors.pink100,
509
+ paddingHorizontal: 8,
510
+ paddingVertical: 5,
511
+ borderRadius: 7,
512
+ borderWidth: 1,
513
+ borderColor: isSelected ? AppColors_1.AppColors.rose700 : AppColors_1.AppColors.roseBorder,
514
+ },
515
+ isSelected && {
516
+ shadowColor: AppColors_1.AppColors.pink600,
517
+ shadowOffset: { width: 0, height: 1 },
518
+ shadowOpacity: 0.28,
519
+ shadowRadius: 2.5,
520
+ elevation: 2,
521
+ },
522
+ ]}>
523
+ <react_native_1.View style={{
524
+ width: 12,
525
+ height: 12,
526
+ borderRadius: 3,
527
+ borderWidth: 1.2,
528
+ borderColor: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.pink400,
529
+ backgroundColor: isSelected ? AppColors_1.AppColors.white : 'transparent',
530
+ alignItems: 'center',
531
+ justifyContent: 'center',
532
+ }}>
533
+ {isSelected && <NetworkIcons_1.CheckIcon color={AppColors_1.AppColors.pink600} size={8}/>}
534
+ </react_native_1.View>
535
+ <NetworkIcons_1.SparkleIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.brandPurple} size={11}/>
536
+ <react_native_1.Text style={{
537
+ fontFamily: AppFonts_1.AppFonts.interBold,
538
+ fontSize: 10,
539
+ color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.pink600,
540
+ }}>
541
+ {t('analytics.customCategory')}: {categoryStats.custom} ({categoryStats.customPct}%)
542
+ </react_native_1.Text>
543
+ </TouchableScale_1.default>);
544
+ })()}
545
+ </react_native_1.View>
546
+ </react_native_1.View>
547
+
548
+ {/* ── 3. GA4 Realtime Metric Hero & Activity Chart (UNDER CATEGORIES) ─ */}
259
549
  <react_native_1.View style={{
260
- marginTop: 10,
550
+ marginTop: 2,
261
551
  marginBottom: 8,
262
552
  backgroundColor: AppColors_1.AppColors.grayBackground,
263
553
  borderRadius: 10,
@@ -337,41 +627,55 @@ const AnalyticsHeader = react_1.default.memo(() => {
337
627
  </react_native_1.View>
338
628
  </react_native_1.View>
339
629
 
340
- {/* ── High Precision SVG Spline Area Graph ── */}
630
+ {/* ── Crashlytics-Style Multi-Bar Histogram with Trendline Overlay ── */}
341
631
  <react_native_1.View style={{ height: chartHeight, position: 'relative' }}>
342
632
  <react_native_svg_1.default width="100%" height={chartHeight} viewBox={`0 0 ${svgWidth} ${chartHeight}`}>
343
633
  <react_native_svg_1.Defs>
344
- <react_native_svg_1.LinearGradient id="telemetryAreaGrad" x1="0" y1="0" x2="0" y2="1">
345
- <react_native_svg_1.Stop offset="0%" stopColor={AppColors_1.AppColors.brandPurple} stopOpacity="0.4"/>
346
- <react_native_svg_1.Stop offset="80%" stopColor={AppColors_1.AppColors.brandPurple} stopOpacity="0.05"/>
347
- <react_native_svg_1.Stop offset="100%" stopColor={AppColors_1.AppColors.brandPurple} stopOpacity="0.0"/>
634
+ <react_native_svg_1.LinearGradient id="crashlyticsBarGrad" x1="0" y1="0" x2="0" y2="1">
635
+ <react_native_svg_1.Stop offset="0%" stopColor="#8B5CF6" stopOpacity="0.9"/>
636
+ <react_native_svg_1.Stop offset="100%" stopColor="#6366F1" stopOpacity="0.6"/>
637
+ </react_native_svg_1.LinearGradient>
638
+ <react_native_svg_1.LinearGradient id="crashlyticsAreaGrad" x1="0" y1="0" x2="0" y2="1">
639
+ <react_native_svg_1.Stop offset="0%" stopColor="#8B5CF6" stopOpacity="0.25"/>
640
+ <react_native_svg_1.Stop offset="80%" stopColor="#8B5CF6" stopOpacity="0.04"/>
641
+ <react_native_svg_1.Stop offset="100%" stopColor="#8B5CF6" stopOpacity="0.0"/>
348
642
  </react_native_svg_1.LinearGradient>
349
643
  </react_native_svg_1.Defs>
350
644
 
351
- {/* Baseline & Grid lines */}
352
- <react_native_svg_1.Line x1="8" y1={chartHeight - 6} x2={svgWidth - 8} y2={chartHeight - 6} stroke={AppColors_1.AppColors.dividerColor} strokeWidth="1"/>
353
- <react_native_svg_1.Line x1="8" y1={chartHeight / 2} x2={svgWidth - 8} y2={chartHeight / 2} stroke={AppColors_1.AppColors.dividerColor} strokeWidth="0.8" strokeDasharray="3,3"/>
645
+ {/* Subtle Grid Guidelines */}
646
+ <react_native_svg_1.Line x1="6" y1={chartHeight - 6} x2={svgWidth - 6} y2={chartHeight - 6} stroke="#E2E8F0" strokeWidth="1"/>
647
+ <react_native_svg_1.Line x1="6" y1={chartHeight / 2} x2={svgWidth - 6} y2={chartHeight / 2} stroke="#F1F5F9" strokeWidth="1" strokeDasharray="4,4"/>
354
648
 
355
- {/* Glowing Area Fill */}
356
- <react_native_svg_1.Path d={histogramData.areaPath} fill="url(#telemetryAreaGrad)"/>
649
+ {/* Glowing Area Underlay */}
650
+ <react_native_svg_1.Path d={histogramData.areaPath} fill="url(#crashlyticsAreaGrad)"/>
357
651
 
358
- {/* Smooth Spline Wave Stroke */}
359
- <react_native_svg_1.Path d={histogramData.linePath} fill="none" stroke={AppColors_1.AppColors.brandPurple} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/>
360
-
361
- {/* Data Points & Active Bucket Indicators */}
652
+ {/* Vertical Crashlytics Histogram Bars */}
362
653
  {histogramData.buckets.map((b, idx) => {
363
654
  const isSelected = selectedBucketIdx === idx;
364
- return (<react_native_svg_1.G key={b.index}>
365
- {isSelected && (<react_native_svg_1.Line x1={b.x} y1={4} x2={b.x} y2={chartHeight - 6} stroke={AppColors_1.AppColors.brandPurple} strokeWidth="1.2" strokeDasharray="2,2"/>)}
655
+ const barWidth = 10;
656
+ const barX = b.x - barWidth / 2;
657
+ const barHeight = Math.max(3, chartHeight - 8 - b.y);
658
+ const barY = chartHeight - 8 - barHeight;
659
+ return (<react_native_svg_1.G key={`bar-${b.index}`}>
660
+ {/* Background slot */}
661
+ <react_native_svg_1.Rect x={barX} y={6} width={barWidth} height={chartHeight - 14} rx={3} fill={isSelected ? '#EDE9FE' : '#F8FAFC'}/>
366
662
 
367
- {b.total > 0 && (<react_native_svg_1.Circle cx={b.x} cy={b.y} r={isSelected ? 4.5 : 2.8} fill={isSelected ? AppColors_1.AppColors.brandPurple : AppColors_1.AppColors.white} stroke={AppColors_1.AppColors.brandPurple} strokeWidth={isSelected ? 2 : 1.5}/>)}
663
+ {/* Active Event Bar */}
664
+ {b.total > 0 && (<react_native_svg_1.Rect x={barX} y={barY} width={barWidth} height={barHeight} rx={3} fill="url(#crashlyticsBarGrad)"/>)}
368
665
 
369
- {b.isLatest && (<react_native_svg_1.G>
370
- <react_native_svg_1.Circle cx={b.x} cy={b.y} r="6.5" fill={AppColors_1.AppColors.brandPurple} opacity="0.22"/>
371
- <react_native_svg_1.Circle cx={b.x} cy={b.y} r="3" fill={AppColors_1.AppColors.brandPurple}/>
372
- </react_native_svg_1.G>)}
666
+ {/* Selected Cursor Line */}
667
+ {isSelected && (<react_native_svg_1.Line x1={b.x} y1={4} x2={b.x} y2={chartHeight - 6} stroke="#8B5CF6" strokeWidth="1.5" strokeDasharray="2,2"/>)}
373
668
  </react_native_svg_1.G>);
374
669
  })}
670
+
671
+ {/* Crashlytics Apex Trendline */}
672
+ <react_native_svg_1.Path d={histogramData.linePath} fill="none" stroke="#8B5CF6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
673
+
674
+ {/* Pulsing Dot on Current Active Time Bucket */}
675
+ {histogramData.buckets.length > 0 && (<react_native_svg_1.G>
676
+ <react_native_svg_1.Circle cx={histogramData.buckets[histogramData.buckets.length - 1].x} cy={histogramData.buckets[histogramData.buckets.length - 1].y} r="5.5" fill="#8B5CF6" opacity="0.25"/>
677
+ <react_native_svg_1.Circle cx={histogramData.buckets[histogramData.buckets.length - 1].x} cy={histogramData.buckets[histogramData.buckets.length - 1].y} r="3" fill="#7C3AED"/>
678
+ </react_native_svg_1.G>)}
375
679
  </react_native_svg_1.default>
376
680
 
377
681
  {/* Invisible Touch Columns for Interactive Bucket Selection */}
@@ -461,199 +765,6 @@ const AnalyticsHeader = react_1.default.memo(() => {
461
765
  </react_native_1.View>
462
766
  </react_native_1.View>
463
767
 
464
- {/* ── Category Breakdown Distribution Bar & Interactive Filter Buttons ─ */}
465
- <react_native_1.View style={{ marginTop: 2, marginBottom: 4 }}>
466
- {/* Multi-color Proportional Segmented Bar */}
467
- <react_native_1.View style={{
468
- height: 5,
469
- borderRadius: 2.5,
470
- backgroundColor: `${AppColors_1.AppColors.grayBorderSecondary}40`,
471
- flexDirection: 'row',
472
- overflow: 'hidden',
473
- marginBottom: 8,
474
- }}>
475
- {categoryStats.ecommerce > 0 && (<react_native_1.View style={{
476
- flex: categoryStats.ecommerce,
477
- backgroundColor: AppColors_1.AppColors.amber500,
478
- }}/>)}
479
- {categoryStats.page_view > 0 && (<react_native_1.View style={{
480
- flex: categoryStats.page_view,
481
- backgroundColor: AppColors_1.AppColors.sky500,
482
- }}/>)}
483
- {categoryStats.system > 0 && (<react_native_1.View style={{
484
- flex: categoryStats.system,
485
- backgroundColor: AppColors_1.AppColors.purple,
486
- }}/>)}
487
- {categoryStats.custom > 0 && (<react_native_1.View style={{
488
- flex: categoryStats.custom,
489
- backgroundColor: AppColors_1.AppColors.brandPurple,
490
- }}/>)}
491
- </react_native_1.View>
492
-
493
- {/* 4 Interactive Category Filter Buttons */}
494
- <react_native_1.View style={{
495
- flexDirection: 'row',
496
- flexWrap: 'wrap',
497
- gap: 6,
498
- }}>
499
- {/* Ecommerce Button */}
500
- {(() => {
501
- const isSelected = !analyticsFilters.categories.has('all') &&
502
- analyticsFilters.categories.has('ecommerce');
503
- return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('ecommerce')} style={[
504
- {
505
- flexDirection: 'row',
506
- alignItems: 'center',
507
- gap: 4.5,
508
- backgroundColor: isSelected
509
- ? AppColors_1.AppColors.amber500
510
- : `${AppColors_1.AppColors.amber500}14`,
511
- paddingHorizontal: 7,
512
- paddingVertical: 4.5,
513
- borderRadius: 6,
514
- borderWidth: 1,
515
- borderColor: isSelected
516
- ? AppColors_1.AppColors.amber500
517
- : `${AppColors_1.AppColors.amber500}35`,
518
- },
519
- isSelected && {
520
- shadowColor: AppColors_1.AppColors.amber500,
521
- shadowOffset: { width: 0, height: 1 },
522
- shadowOpacity: 0.25,
523
- shadowRadius: 2,
524
- elevation: 2,
525
- },
526
- ]}>
527
- <NetworkIcons_1.CartIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.amber700} size={11}/>
528
- <react_native_1.Text style={{
529
- fontFamily: AppFonts_1.AppFonts.interBold,
530
- fontSize: 10,
531
- color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.amber700,
532
- }}>
533
- Ecommerce: {categoryStats.ecommerce} ({categoryStats.ecommercePct}%)
534
- </react_native_1.Text>
535
- </TouchableScale_1.default>);
536
- })()}
537
-
538
- {/* Screens Button */}
539
- {(() => {
540
- const isSelected = !analyticsFilters.categories.has('all') &&
541
- analyticsFilters.categories.has('page_view');
542
- return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('page_view')} style={[
543
- {
544
- flexDirection: 'row',
545
- alignItems: 'center',
546
- gap: 4.5,
547
- backgroundColor: isSelected
548
- ? AppColors_1.AppColors.sky600
549
- : `${AppColors_1.AppColors.sky500}14`,
550
- paddingHorizontal: 7,
551
- paddingVertical: 4.5,
552
- borderRadius: 6,
553
- borderWidth: 1,
554
- borderColor: isSelected
555
- ? AppColors_1.AppColors.sky600
556
- : `${AppColors_1.AppColors.sky500}35`,
557
- },
558
- isSelected && {
559
- shadowColor: AppColors_1.AppColors.sky600,
560
- shadowOffset: { width: 0, height: 1 },
561
- shadowOpacity: 0.25,
562
- shadowRadius: 2,
563
- elevation: 2,
564
- },
565
- ]}>
566
- <NetworkIcons_1.GlobeIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.sky600} size={11}/>
567
- <react_native_1.Text style={{
568
- fontFamily: AppFonts_1.AppFonts.interBold,
569
- fontSize: 10,
570
- color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.sky600,
571
- }}>
572
- Screens: {categoryStats.page_view} ({categoryStats.page_viewPct}%)
573
- </react_native_1.Text>
574
- </TouchableScale_1.default>);
575
- })()}
576
-
577
- {/* System Button */}
578
- {(() => {
579
- const isSelected = !analyticsFilters.categories.has('all') &&
580
- analyticsFilters.categories.has('system');
581
- return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('system')} style={[
582
- {
583
- flexDirection: 'row',
584
- alignItems: 'center',
585
- gap: 4.5,
586
- backgroundColor: isSelected
587
- ? AppColors_1.AppColors.purple
588
- : `${AppColors_1.AppColors.purple}14`,
589
- paddingHorizontal: 7,
590
- paddingVertical: 4.5,
591
- borderRadius: 6,
592
- borderWidth: 1,
593
- borderColor: isSelected
594
- ? AppColors_1.AppColors.purple
595
- : `${AppColors_1.AppColors.purple}35`,
596
- },
597
- isSelected && {
598
- shadowColor: AppColors_1.AppColors.purple,
599
- shadowOffset: { width: 0, height: 1 },
600
- shadowOpacity: 0.25,
601
- shadowRadius: 2,
602
- elevation: 2,
603
- },
604
- ]}>
605
- <NetworkIcons_1.BoltIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple} size={11}/>
606
- <react_native_1.Text style={{
607
- fontFamily: AppFonts_1.AppFonts.interBold,
608
- fontSize: 10,
609
- color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.purple,
610
- }}>
611
- System: {categoryStats.system} ({categoryStats.systemPct}%)
612
- </react_native_1.Text>
613
- </TouchableScale_1.default>);
614
- })()}
615
-
616
- {/* Custom Button */}
617
- {(() => {
618
- const isSelected = !analyticsFilters.categories.has('all') &&
619
- analyticsFilters.categories.has('custom');
620
- return (<TouchableScale_1.default onPress={() => toggleCategoryFilter('custom')} style={[
621
- {
622
- flexDirection: 'row',
623
- alignItems: 'center',
624
- gap: 4.5,
625
- backgroundColor: isSelected
626
- ? AppColors_1.AppColors.brandPurple
627
- : `${AppColors_1.AppColors.brandPurple}14`,
628
- paddingHorizontal: 7,
629
- paddingVertical: 4.5,
630
- borderRadius: 6,
631
- borderWidth: 1,
632
- borderColor: isSelected
633
- ? AppColors_1.AppColors.brandPurple
634
- : `${AppColors_1.AppColors.brandPurple}35`,
635
- },
636
- isSelected && {
637
- shadowColor: AppColors_1.AppColors.brandPurple,
638
- shadowOffset: { width: 0, height: 1 },
639
- shadowOpacity: 0.25,
640
- shadowRadius: 2,
641
- elevation: 2,
642
- },
643
- ]}>
644
- <NetworkIcons_1.SparkleIcon color={isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.brandPurple} size={11}/>
645
- <react_native_1.Text style={{
646
- fontFamily: AppFonts_1.AppFonts.interBold,
647
- fontSize: 10,
648
- color: isSelected ? AppColors_1.AppColors.white : AppColors_1.AppColors.brandPurple,
649
- }}>
650
- Custom: {categoryStats.custom} ({categoryStats.customPct}%)
651
- </react_native_1.Text>
652
- </TouchableScale_1.default>);
653
- })()}
654
- </react_native_1.View>
655
- </react_native_1.View>
656
-
657
768
  {/* ── Top Screens / Views Mini Leaderboard (GA4 Realtime Overview) ──── */}
658
769
  {topScreens.length > 0 && (<react_native_1.View style={{
659
770
  marginTop: 8,