react-native-inapp-inspector 1.1.12 → 1.1.14

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 (64) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +64 -21
  2. package/dist/commonjs/components/AnalyticsEventCard.js +100 -13
  3. package/dist/commonjs/components/HighlightText.js +1 -1
  4. package/dist/commonjs/components/JsonViewer.d.ts +3 -1
  5. package/dist/commonjs/components/JsonViewer.js +327 -9
  6. package/dist/commonjs/components/MetaAccordion.d.ts +10 -1
  7. package/dist/commonjs/components/MetaAccordion.js +121 -24
  8. package/dist/commonjs/components/NetworkIcons.d.ts +1 -0
  9. package/dist/commonjs/components/NetworkIcons.js +8 -1
  10. package/dist/commonjs/components/ReduxTreeView.d.ts +12 -3
  11. package/dist/commonjs/components/ReduxTreeView.js +1096 -278
  12. package/dist/commonjs/components/SectionHeader.d.ts +1 -1
  13. package/dist/commonjs/components/SectionHeader.js +7 -1
  14. package/dist/commonjs/constants/version.d.ts +1 -1
  15. package/dist/commonjs/constants/version.js +1 -1
  16. package/dist/commonjs/customHooks/analyticsLogger.d.ts +8 -0
  17. package/dist/commonjs/customHooks/analyticsLogger.js +42 -1
  18. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  19. package/dist/commonjs/customHooks/reduxLogger.js +2 -0
  20. package/dist/commonjs/helpers/index.d.ts +1 -0
  21. package/dist/commonjs/helpers/index.js +15 -1
  22. package/dist/commonjs/helpers/settingsStore.d.ts +1 -0
  23. package/dist/commonjs/helpers/settingsStore.js +4 -0
  24. package/dist/commonjs/index.d.ts +1 -1
  25. package/dist/commonjs/index.js +347 -444
  26. package/dist/commonjs/styles/index.d.ts +92 -33
  27. package/dist/commonjs/styles/index.js +101 -45
  28. package/dist/commonjs/types/index.d.ts +3 -0
  29. package/dist/esm/components/AnalyticsDetail.js +64 -21
  30. package/dist/esm/components/AnalyticsEventCard.js +100 -13
  31. package/dist/esm/components/HighlightText.js +3 -3
  32. package/dist/esm/components/JsonViewer.d.ts +3 -1
  33. package/dist/esm/components/JsonViewer.js +295 -10
  34. package/dist/esm/components/MetaAccordion.d.ts +10 -1
  35. package/dist/esm/components/MetaAccordion.js +90 -26
  36. package/dist/esm/components/NetworkIcons.d.ts +1 -0
  37. package/dist/esm/components/NetworkIcons.js +6 -0
  38. package/dist/esm/components/ReduxTreeView.d.ts +12 -3
  39. package/dist/esm/components/ReduxTreeView.js +1095 -279
  40. package/dist/esm/components/SectionHeader.d.ts +1 -1
  41. package/dist/esm/components/SectionHeader.js +8 -2
  42. package/dist/esm/constants/version.d.ts +1 -1
  43. package/dist/esm/constants/version.js +1 -1
  44. package/dist/esm/customHooks/analyticsLogger.d.ts +8 -0
  45. package/dist/esm/customHooks/analyticsLogger.js +37 -0
  46. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  47. package/dist/esm/customHooks/reduxLogger.js +2 -0
  48. package/dist/esm/helpers/index.d.ts +1 -0
  49. package/dist/esm/helpers/index.js +14 -1
  50. package/dist/esm/helpers/settingsStore.d.ts +1 -0
  51. package/dist/esm/helpers/settingsStore.js +3 -0
  52. package/dist/esm/index.d.ts +1 -1
  53. package/dist/esm/index.js +345 -446
  54. package/dist/esm/styles/index.d.ts +92 -33
  55. package/dist/esm/styles/index.js +101 -45
  56. package/dist/esm/types/index.d.ts +3 -0
  57. package/example/android/app/build.gradle +29 -1
  58. package/example/android/app/src/main/java/com/example/MainApplication.kt +25 -0
  59. package/example/android/build.gradle +31 -4
  60. package/example/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  61. package/example/android/gradle.properties +1 -0
  62. package/example/android/settings.gradle +20 -1
  63. package/example/package-lock.json +1 -1
  64. package/package.json +1 -1
@@ -305,6 +305,25 @@ export declare const getRawStyles: (colors: typeof AppColors) => {
305
305
  color: string;
306
306
  fontSize: number;
307
307
  };
308
+ fabGreenDot: {
309
+ position: string;
310
+ top: number;
311
+ right: number;
312
+ width: number;
313
+ height: number;
314
+ borderRadius: number;
315
+ backgroundColor: string;
316
+ borderWidth: number;
317
+ borderColor: string;
318
+ shadowColor: string;
319
+ shadowOffset: {
320
+ width: number;
321
+ height: number;
322
+ };
323
+ shadowOpacity: number;
324
+ shadowRadius: number;
325
+ elevation: number;
326
+ };
308
327
  statBox: {
309
328
  flex: number;
310
329
  alignItems: string;
@@ -1670,15 +1689,22 @@ export declare const getRawStyles: (colors: typeof AppColors) => {
1670
1689
  marginTop: number;
1671
1690
  };
1672
1691
  analyticsCardRow: {};
1673
- analyticsTopEventsCard: {
1674
- marginHorizontal: number;
1675
- marginBottom: number;
1692
+ analyticsIconCircle: {
1693
+ width: number;
1694
+ height: number;
1695
+ borderRadius: number;
1696
+ alignItems: string;
1697
+ justifyContent: string;
1698
+ };
1699
+ analyticsHeaderCard: {
1676
1700
  backgroundColor: string;
1677
1701
  borderRadius: number;
1678
1702
  borderWidth: number;
1679
1703
  borderColor: string;
1680
- paddingHorizontal: number;
1681
- paddingVertical: number;
1704
+ padding: number;
1705
+ marginHorizontal: number;
1706
+ marginTop: number;
1707
+ marginBottom: number;
1682
1708
  shadowColor: string;
1683
1709
  shadowOpacity: number;
1684
1710
  shadowRadius: number;
@@ -1688,61 +1714,94 @@ export declare const getRawStyles: (colors: typeof AppColors) => {
1688
1714
  };
1689
1715
  elevation: number;
1690
1716
  };
1691
- analyticsTopEventsHeaderRow: {
1717
+ analyticsHeaderTop: {
1692
1718
  flexDirection: string;
1693
- alignItems: string;
1694
1719
  justifyContent: string;
1720
+ alignItems: string;
1695
1721
  marginBottom: number;
1696
1722
  };
1697
- analyticsTopEventsTitle: {
1723
+ analyticsHeaderTitle: {
1698
1724
  fontFamily: string;
1699
1725
  fontSize: number;
1700
1726
  color: string;
1701
- letterSpacing: number;
1702
- textTransform: string;
1703
1727
  };
1704
- analyticsTopEventsSubtitle: {
1728
+ statusDot: {
1729
+ width: number;
1730
+ height: number;
1731
+ borderRadius: number;
1732
+ };
1733
+ analyticsHeaderSubtitle: {
1705
1734
  fontFamily: string;
1706
1735
  fontSize: number;
1707
1736
  color: string;
1708
- letterSpacing: number;
1737
+ marginTop: number;
1709
1738
  };
1710
- analyticsTopEventRow: {
1711
- flexDirection: string;
1712
- alignItems: string;
1713
- marginBottom: number;
1714
- gap: number;
1739
+ analyticsHeaderToggle: {
1740
+ paddingVertical: number;
1741
+ paddingHorizontal: number;
1742
+ borderRadius: number;
1743
+ backgroundColor: string;
1744
+ borderWidth: number;
1745
+ borderColor: string;
1715
1746
  };
1716
- analyticsTopEventName: {
1747
+ analyticsHeaderToggleText: {
1717
1748
  fontFamily: string;
1718
1749
  fontSize: number;
1719
1750
  color: string;
1720
- flex: number;
1721
1751
  };
1722
- analyticsTopEventBarWrap: {
1752
+ analyticsStatsRow: {
1753
+ flexDirection: string;
1754
+ gap: number;
1755
+ borderTopWidth: number;
1756
+ borderTopColor: string;
1757
+ paddingTop: number;
1758
+ };
1759
+ analyticsStatBox: {
1723
1760
  flex: number;
1724
- height: number;
1725
1761
  backgroundColor: string;
1726
1762
  borderRadius: number;
1727
- overflow: string;
1763
+ paddingVertical: number;
1764
+ alignItems: string;
1728
1765
  };
1729
- analyticsTopEventBar: {
1730
- height: string;
1731
- borderRadius: number;
1766
+ analyticsStatValue: {
1767
+ fontFamily: string;
1768
+ fontSize: number;
1769
+ color: string;
1732
1770
  };
1733
- analyticsTopEventCount: {
1771
+ analyticsStatLabel: {
1734
1772
  fontFamily: string;
1735
1773
  fontSize: number;
1736
1774
  color: string;
1737
- width: number;
1738
- textAlign: string;
1775
+ marginTop: number;
1739
1776
  };
1740
- analyticsIconCircle: {
1741
- width: number;
1742
- height: number;
1743
- borderRadius: number;
1744
- alignItems: string;
1777
+ analyticsHeaderDetails: {
1778
+ borderTopWidth: number;
1779
+ borderTopColor: string;
1780
+ paddingTop: number;
1781
+ marginTop: number;
1782
+ };
1783
+ detailsGroupTitle: {
1784
+ fontFamily: string;
1785
+ fontSize: number;
1786
+ color: string;
1787
+ marginBottom: number;
1788
+ };
1789
+ detailsRow: {
1790
+ flexDirection: string;
1745
1791
  justifyContent: string;
1792
+ paddingVertical: number;
1793
+ borderBottomWidth: number;
1794
+ borderBottomColor: string;
1795
+ };
1796
+ detailsKey: {
1797
+ fontFamily: string;
1798
+ fontSize: number;
1799
+ color: string;
1800
+ };
1801
+ detailsValue: {
1802
+ fontFamily: string;
1803
+ fontSize: number;
1804
+ color: string;
1746
1805
  };
1747
1806
  };
1748
1807
  declare const styles: any;
@@ -297,6 +297,22 @@ const getRawStyles = (colors) => ({
297
297
  color: colors.primaryLight,
298
298
  fontSize: 11,
299
299
  },
300
+ fabGreenDot: {
301
+ position: 'absolute',
302
+ top: 2,
303
+ right: 2,
304
+ width: 12,
305
+ height: 12,
306
+ borderRadius: 6,
307
+ backgroundColor: '#00E676',
308
+ borderWidth: 2,
309
+ borderColor: colors.primaryLight,
310
+ shadowColor: '#000000',
311
+ shadowOffset: { width: 0, height: 1 },
312
+ shadowOpacity: 0.2,
313
+ shadowRadius: 1.5,
314
+ elevation: 2,
315
+ },
300
316
  statBox: {
301
317
  flex: 1,
302
318
  alignItems: 'center',
@@ -1561,76 +1577,116 @@ const getRawStyles = (colors) => ({
1561
1577
  marginTop: 2,
1562
1578
  },
1563
1579
  analyticsCardRow: {},
1564
- analyticsTopEventsCard: {
1565
- marginHorizontal: 16,
1566
- marginBottom: 12,
1580
+ analyticsIconCircle: {
1581
+ width: 24,
1582
+ height: 24,
1583
+ borderRadius: 12,
1584
+ alignItems: 'center',
1585
+ justifyContent: 'center',
1586
+ },
1587
+ analyticsHeaderCard: {
1567
1588
  backgroundColor: colors.primaryLight,
1568
1589
  borderRadius: 12,
1569
1590
  borderWidth: 1,
1570
1591
  borderColor: colors.grayBorderSecondary,
1571
- paddingHorizontal: 16,
1572
- paddingVertical: 12,
1573
- shadowColor: '#000',
1574
- shadowOpacity: 0.04,
1592
+ padding: 14,
1593
+ marginHorizontal: 12,
1594
+ marginTop: 8,
1595
+ marginBottom: 8,
1596
+ shadowColor: '#000000',
1597
+ shadowOpacity: 0.03,
1575
1598
  shadowRadius: 4,
1576
1599
  shadowOffset: { width: 0, height: 1 },
1577
1600
  elevation: 1,
1578
1601
  },
1579
- analyticsTopEventsHeaderRow: {
1602
+ analyticsHeaderTop: {
1580
1603
  flexDirection: 'row',
1581
- alignItems: 'center',
1582
1604
  justifyContent: 'space-between',
1583
- marginBottom: 12,
1605
+ alignItems: 'center',
1606
+ marginBottom: 10,
1584
1607
  },
1585
- analyticsTopEventsTitle: {
1608
+ analyticsHeaderTitle: {
1586
1609
  fontFamily: AppFonts_1.AppFonts.interBold,
1587
- fontSize: 10,
1588
- color: colors.grayTextWeak,
1589
- letterSpacing: 0.8,
1590
- textTransform: 'uppercase',
1610
+ fontSize: 14,
1611
+ color: colors.primaryBlack,
1612
+ },
1613
+ statusDot: {
1614
+ width: 6,
1615
+ height: 6,
1616
+ borderRadius: 3,
1591
1617
  },
1592
- analyticsTopEventsSubtitle: {
1618
+ analyticsHeaderSubtitle: {
1593
1619
  fontFamily: AppFonts_1.AppFonts.interMedium,
1594
- fontSize: 9,
1595
- color: colors.grayTextWeak,
1596
- letterSpacing: 0.4,
1620
+ fontSize: 11,
1621
+ color: colors.grayText,
1622
+ marginTop: 2,
1623
+ },
1624
+ analyticsHeaderToggle: {
1625
+ paddingVertical: 4,
1626
+ paddingHorizontal: 8,
1627
+ borderRadius: 4,
1628
+ backgroundColor: colors.grayBackground,
1629
+ borderWidth: 1,
1630
+ borderColor: colors.grayBorderSecondary,
1631
+ },
1632
+ analyticsHeaderToggleText: {
1633
+ fontFamily: AppFonts_1.AppFonts.interBold,
1634
+ fontSize: 10,
1635
+ color: colors.purple,
1597
1636
  },
1598
- analyticsTopEventRow: {
1637
+ analyticsStatsRow: {
1599
1638
  flexDirection: 'row',
1600
- alignItems: 'center',
1601
- marginBottom: 8,
1602
1639
  gap: 8,
1640
+ borderTopWidth: 1,
1641
+ borderTopColor: colors.dividerColor,
1642
+ paddingTop: 10,
1603
1643
  },
1604
- analyticsTopEventName: {
1605
- fontFamily: AppFonts_1.AppFonts.interMedium,
1606
- fontSize: 12,
1607
- color: colors.primaryBlack,
1644
+ analyticsStatBox: {
1608
1645
  flex: 1,
1609
- },
1610
- analyticsTopEventBarWrap: {
1611
- flex: 0.8,
1612
- height: 3,
1613
1646
  backgroundColor: colors.grayBackground,
1614
- borderRadius: 2,
1615
- overflow: 'hidden',
1647
+ borderRadius: 6,
1648
+ paddingVertical: 6,
1649
+ alignItems: 'center',
1616
1650
  },
1617
- analyticsTopEventBar: {
1618
- height: '100%',
1619
- borderRadius: 2,
1651
+ analyticsStatValue: {
1652
+ fontFamily: AppFonts_1.AppFonts.interBold,
1653
+ fontSize: 14,
1654
+ color: colors.primaryBlack,
1620
1655
  },
1621
- analyticsTopEventCount: {
1656
+ analyticsStatLabel: {
1657
+ fontFamily: AppFonts_1.AppFonts.interRegular,
1658
+ fontSize: 9,
1659
+ color: colors.grayText,
1660
+ marginTop: 1,
1661
+ },
1662
+ analyticsHeaderDetails: {
1663
+ borderTopWidth: 1,
1664
+ borderTopColor: colors.dividerColor,
1665
+ paddingTop: 10,
1666
+ marginTop: 10,
1667
+ },
1668
+ detailsGroupTitle: {
1622
1669
  fontFamily: AppFonts_1.AppFonts.interBold,
1623
1670
  fontSize: 11,
1624
- color: colors.grayText,
1625
- width: 24,
1626
- textAlign: 'right',
1671
+ color: colors.purple,
1672
+ marginBottom: 6,
1627
1673
  },
1628
- analyticsIconCircle: {
1629
- width: 24,
1630
- height: 24,
1631
- borderRadius: 12,
1632
- alignItems: 'center',
1633
- justifyContent: 'center',
1674
+ detailsRow: {
1675
+ flexDirection: 'row',
1676
+ justifyContent: 'space-between',
1677
+ paddingVertical: 4,
1678
+ borderBottomWidth: 0.5,
1679
+ borderBottomColor: colors.dividerColor,
1680
+ },
1681
+ detailsKey: {
1682
+ fontFamily: AppFonts_1.AppFonts.interMedium,
1683
+ fontSize: 11,
1684
+ color: colors.primaryBlack,
1685
+ },
1686
+ detailsValue: {
1687
+ fontFamily: AppFonts_1.AppFonts.interRegular,
1688
+ fontSize: 11,
1689
+ color: colors.grayText,
1634
1690
  },
1635
1691
  });
1636
1692
  exports.getRawStyles = getRawStyles;
@@ -89,6 +89,9 @@ export interface SectionHeaderProps {
89
89
  showDiff?: boolean;
90
90
  isDiffing?: boolean;
91
91
  onToggleDiff?: () => void;
92
+ showSearch?: boolean;
93
+ isSearching?: boolean;
94
+ onToggleSearch?: () => void;
92
95
  }
93
96
  export interface TreeNodeProps {
94
97
  data: unknown;
@@ -6,6 +6,7 @@ import JsonViewer from './JsonViewer';
6
6
  import TouchableScale from './TouchableScale';
7
7
  // Utils
8
8
  import { AppFonts } from '../styles/AppFonts';
9
+ import { getSize } from '../helpers';
9
10
  // Stylesheet
10
11
  import { AppColors } from '../styles/AppColors';
11
12
  const AnalyticsDetail = ({ event, }) => {
@@ -14,6 +15,26 @@ const AnalyticsDetail = ({ event, }) => {
14
15
  const params = event.params ?? {};
15
16
  const userProperties = event.userProperties ?? {};
16
17
  const upCount = Object.keys(userProperties).length;
18
+ const jsonData = {
19
+ name: event.name,
20
+ params: params,
21
+ ...(upCount > 0 ? { userProperties } : {}),
22
+ };
23
+ const isObject = typeof jsonData === 'object' && jsonData !== null;
24
+ const isArray = Array.isArray(jsonData);
25
+ let typeLabel = typeof jsonData;
26
+ let countLabel = '';
27
+ if (jsonData === null) {
28
+ typeLabel = 'null';
29
+ }
30
+ else if (isArray) {
31
+ typeLabel = 'array';
32
+ countLabel = `${jsonData.length} items`;
33
+ }
34
+ else if (isObject) {
35
+ typeLabel = 'object';
36
+ countLabel = `${Object.keys(jsonData).length} keys`;
37
+ }
17
38
  return (<ScrollView style={[detailStyles.scroll, { backgroundColor: AppColors.grayBackground }]} contentContainerStyle={detailStyles.content} showsVerticalScrollIndicator contentInsetAdjustmentBehavior="never" automaticallyAdjustContentInsets={false}>
18
39
 
19
40
  {/* Clean Toolbar */}
@@ -27,7 +48,8 @@ const AnalyticsDetail = ({ event, }) => {
27
48
  borderBottomColor: AppColors.grayBorderSecondary,
28
49
  backgroundColor: AppColors.primaryLight,
29
50
  }}>
30
- <TouchableScale style={{
51
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
52
+ <TouchableScale style={{
31
53
  flexDirection: 'row',
32
54
  alignItems: 'center',
33
55
  gap: 6,
@@ -42,20 +64,49 @@ const AnalyticsDetail = ({ event, }) => {
42
64
  setExpandDepth(nextDepth);
43
65
  setTreeKey(prev => prev + 1);
44
66
  }}>
45
- <Text style={{
67
+ <Text style={{
46
68
  fontFamily: AppFonts.interBold,
47
69
  fontSize: 12,
48
70
  color: AppColors.purple,
49
71
  }}>
50
- {expandDepth === 99 ? 'Collapse All' : 'Expand All'}
51
- </Text>
52
- </TouchableScale>
72
+ {expandDepth === 99 ? 'Collapse All' : 'Expand All'}
73
+ </Text>
74
+ </TouchableScale>
75
+ <View style={{
76
+ flexDirection: 'row',
77
+ alignItems: 'center',
78
+ backgroundColor: AppColors.grayBackground,
79
+ borderRadius: 6,
80
+ overflow: 'hidden',
81
+ borderWidth: 1,
82
+ borderColor: AppColors.grayBorderSecondary,
83
+ }}>
84
+ <View style={{ paddingHorizontal: 6, paddingVertical: 4, backgroundColor: AppColors.purple + '18' }}>
85
+ <Text style={{ fontFamily: AppFonts.interBold, fontSize: 9, color: AppColors.purple, letterSpacing: 0.3 }}>
86
+ {typeLabel.toUpperCase()}
87
+ </Text>
88
+ </View>
89
+ {countLabel ? (<View style={{ paddingHorizontal: 6, paddingVertical: 4 }}>
90
+ <Text style={{ fontFamily: AppFonts.interMedium, fontSize: 9, color: AppColors.grayText }}>
91
+ {countLabel}
92
+ </Text>
93
+ </View>) : null}
94
+ </View>
95
+ <View style={{
96
+ backgroundColor: AppColors.grayBackground,
97
+ borderRadius: 6,
98
+ paddingHorizontal: 6,
99
+ paddingVertical: 4,
100
+ borderWidth: 1,
101
+ borderColor: AppColors.grayBorderSecondary,
102
+ }}>
103
+ <Text style={{ fontFamily: AppFonts.interMedium, fontSize: 9, color: AppColors.grayText }}>
104
+ {getSize(jsonData)}
105
+ </Text>
106
+ </View>
107
+ </View>
53
108
 
54
- <CopyButton value={JSON.stringify({
55
- name: event.name,
56
- params: params,
57
- ...(upCount > 0 ? { userProperties } : {}),
58
- }, null, 2)} label="Copy JSON"/>
109
+ <CopyButton value={JSON.stringify(jsonData, null, 2)} label="Copy JSON"/>
59
110
  </View>
60
111
 
61
112
  {/* Direct JSON Viewer View */}
@@ -67,15 +118,7 @@ const AnalyticsDetail = ({ event, }) => {
67
118
  marginTop: 16,
68
119
  },
69
120
  ]}>
70
- <JsonViewer key={treeKey} data={{
71
- name: event.name,
72
- params: params,
73
- ...(upCount > 0
74
- ? {
75
- userProperties: userProperties,
76
- }
77
- : {}),
78
- }} defaultExpandDepth={expandDepth}/>
121
+ <JsonViewer key={treeKey} data={jsonData} defaultExpandDepth={expandDepth} fullHeight/>
79
122
  </View>
80
123
  </ScrollView>);
81
124
  };
@@ -87,8 +130,8 @@ const detailStyles = StyleSheet.create({
87
130
  },
88
131
  jsonBlockContainer: {
89
132
  marginHorizontal: 16,
90
- marginTop: 8,
91
- padding: 12,
133
+ marginTop: 16,
134
+ marginBottom: 16,
92
135
  borderWidth: 1,
93
136
  borderRadius: 12,
94
137
  },
@@ -16,9 +16,10 @@ const EVENT_PALETTE = [
16
16
  '#2E7D32', // dark green
17
17
  ];
18
18
  export function getEventColor(name) {
19
+ const safeName = typeof name === 'string' ? name : String(name || '');
19
20
  let hash = 0;
20
- for (let i = 0; i < name.length; i++) {
21
- hash = (hash * 31 + name.charCodeAt(i)) | 0;
21
+ for (let i = 0; i < safeName.length; i++) {
22
+ hash = (hash * 31 + safeName.charCodeAt(i)) | 0;
22
23
  }
23
24
  return EVENT_PALETTE[Math.abs(hash) % EVENT_PALETTE.length];
24
25
  }
@@ -41,6 +42,63 @@ function formatGap(ms) {
41
42
  const rem = s % 60;
42
43
  return rem > 0 ? `+${m}m ${rem}s` : `+${m}m`;
43
44
  }
45
+ function getEventCategory(name) {
46
+ if (!name)
47
+ return 'Custom';
48
+ const lowercaseName = name.toLowerCase();
49
+ if (lowercaseName === 'screen_view' || lowercaseName === 'page_view') {
50
+ return 'Page View';
51
+ }
52
+ // Ecommerce events
53
+ const ecommerceEvents = [
54
+ 'purchase', 'add_to_cart', 'begin_checkout', 'view_item',
55
+ 'select_item', 'remove_from_cart', 'view_cart',
56
+ 'add_shipping_info', 'add_payment_info', 'refund',
57
+ 'view_item_list', 'select_promotion', 'view_promotion'
58
+ ];
59
+ if (ecommerceEvents.includes(lowercaseName)) {
60
+ return 'Ecommerce';
61
+ }
62
+ // Firebase System Auto-events
63
+ const systemEvents = [
64
+ 'first_open', 'session_start', 'user_engagement',
65
+ 'app_clear_data', 'app_exception', 'app_update', 'os_update',
66
+ 'notification_receive', 'notification_open', 'notification_dismiss',
67
+ 'screen_active', 'screen_inactive'
68
+ ];
69
+ if (systemEvents.includes(lowercaseName) || lowercaseName.startsWith('firebase_') || lowercaseName.startsWith('_')) {
70
+ return 'System';
71
+ }
72
+ return 'Custom';
73
+ }
74
+ function getCategoryColors(category) {
75
+ switch (category) {
76
+ case 'Page View':
77
+ return {
78
+ bg: '#E3F2FD',
79
+ border: '#BBDEFB',
80
+ text: '#1976D2',
81
+ };
82
+ case 'Ecommerce':
83
+ return {
84
+ bg: '#E8F5E9',
85
+ border: '#C8E6C9',
86
+ text: '#2E7D32',
87
+ };
88
+ case 'System':
89
+ return {
90
+ bg: '#F5F5F5',
91
+ border: '#E0E0E0',
92
+ text: '#616161',
93
+ };
94
+ default:
95
+ return {
96
+ bg: '#F3E5F5',
97
+ border: '#E1BEE7',
98
+ text: '#7B1FA2',
99
+ };
100
+ }
101
+ }
44
102
  // ─── Component ────────────────────────────────────────────────────────────────
45
103
  const AnalyticsEventCard = React.memo(function AnalyticsEventCard({ event, onPress, isNew = false, searchStr = '', msSincePrev, computedScreenName, }) {
46
104
  const color = getEventColor(event.name);
@@ -89,6 +147,19 @@ const AnalyticsEventCard = React.memo(function AnalyticsEventCard({ event, onPre
89
147
  <HighlightText text={event.name} search={searchStr} style={[cardStyles.eventName, { color: color }]} highlightStyle={cardStyles.highlight}/>
90
148
  </View>
91
149
 
150
+ {(() => {
151
+ const category = getEventCategory(event.name);
152
+ const tagColors = getCategoryColors(category);
153
+ return (<View style={[
154
+ cardStyles.categoryBadge,
155
+ { backgroundColor: tagColors.bg, borderColor: tagColors.border },
156
+ ]}>
157
+ <Text style={[cardStyles.categoryText, { color: tagColors.text }]}>
158
+ {category}
159
+ </Text>
160
+ </View>);
161
+ })()}
162
+
92
163
  {event.count !== undefined ? (<View style={[
93
164
  cardStyles.duplicateBadge,
94
165
  event.count === 1 && {
@@ -112,20 +183,24 @@ const AnalyticsEventCard = React.memo(function AnalyticsEventCard({ event, onPre
112
183
  {/* Bottom Row: Metadata Chips & Sparkline */}
113
184
  <View style={cardStyles.cardBody}>
114
185
  <View style={cardStyles.chipsRow}>
115
- {computedScreenName ||
116
- event.screenName ||
117
- event.params?.firebase_screen ||
118
- event.params?.screen_name ||
119
- event.params?.firebase_screen_class ? (<View style={[cardStyles.chip, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
120
- <View style={[cardStyles.screenDot, { backgroundColor: color }]}/>
121
- <Text style={[cardStyles.chipText, { color: AppColors.grayText }]} numberOfLines={1}>
122
- {computedScreenName ||
186
+ {(() => {
187
+ const rawScreenName = computedScreenName ||
123
188
  event.screenName ||
124
189
  event.params?.firebase_screen ||
125
190
  event.params?.screen_name ||
126
- event.params?.firebase_screen_class}
127
- </Text>
128
- </View>) : null}
191
+ event.params?.firebase_screen_class;
192
+ if (!rawScreenName)
193
+ return null;
194
+ const screenNameStr = typeof rawScreenName === 'object'
195
+ ? JSON.stringify(rawScreenName)
196
+ : String(rawScreenName);
197
+ return (<View style={[cardStyles.chip, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
198
+ <View style={[cardStyles.screenDot, { backgroundColor: color }]}/>
199
+ <Text style={[cardStyles.chipText, { color: AppColors.grayText }]} numberOfLines={1}>
200
+ {screenNameStr}
201
+ </Text>
202
+ </View>);
203
+ })()}
129
204
 
130
205
  <View style={[cardStyles.chip, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
131
206
  <Text style={[cardStyles.chipText, { color: AppColors.grayText }]}>
@@ -272,6 +347,18 @@ const cardStyles = StyleSheet.create({
272
347
  textTransform: 'uppercase',
273
348
  letterSpacing: 0.5,
274
349
  },
350
+ categoryBadge: {
351
+ borderWidth: 1,
352
+ paddingHorizontal: 5,
353
+ paddingVertical: 2,
354
+ borderRadius: 4,
355
+ },
356
+ categoryText: {
357
+ fontFamily: AppFonts.interBold,
358
+ fontSize: 9,
359
+ textTransform: 'uppercase',
360
+ letterSpacing: 0.5,
361
+ },
275
362
  miniGraphWrapper: {
276
363
  flexDirection: 'row',
277
364
  alignItems: 'flex-end',
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
- import { Text, Linking } from 'react-native';
2
+ import { Text } from 'react-native';
3
3
  // Helpers
4
- import { escapeRegex } from '../helpers';
4
+ import { escapeRegex, handleOpenExternalLink } from '../helpers';
5
5
  const HighlightText = ({ text, search, style, highlightStyle, detectLinks, ...rest }) => {
6
6
  const hasNumberOfLines = 'numberOfLines' in rest;
7
7
  const numLines = hasNumberOfLines ? rest.numberOfLines : 1;
@@ -28,7 +28,7 @@ const HighlightText = ({ text, search, style, highlightStyle, detectLinks, ...re
28
28
  color: '#007AFF', // skyBlue link color
29
29
  textDecorationLine: 'underline',
30
30
  }} onPress={() => {
31
- Linking.openURL(part).catch(() => { });
31
+ handleOpenExternalLink(part);
32
32
  }}>
33
33
  {part}
34
34
  </Text>);
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
- declare const JsonViewer: ({ data, search, forceOpen, defaultExpandDepth, wrap, }: {
2
+ declare const JsonViewer: ({ data, search, forceOpen, defaultExpandDepth, wrap, fullHeight, onModeChange, }: {
3
3
  data: unknown;
4
4
  search?: string;
5
5
  forceOpen?: boolean;
6
6
  defaultExpandDepth?: number;
7
7
  wrap?: boolean;
8
+ fullHeight?: boolean;
9
+ onModeChange?: (mode: "pretty" | "raw" | "table") => void;
8
10
  }) => React.JSX.Element;
9
11
  export default JsonViewer;