react-native-inapp-inspector 1.1.29 → 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 (51) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +668 -108
  2. package/dist/commonjs/components/AppHeaderLogo.js +5 -2
  3. package/dist/commonjs/components/ConsoleLogCard.js +81 -59
  4. package/dist/commonjs/components/DomainHeader.js +21 -17
  5. package/dist/commonjs/components/Inspector/AnalyticsTab.js +297 -200
  6. package/dist/commonjs/components/Inspector/ConsoleTab.js +162 -56
  7. package/dist/commonjs/components/Inspector/InspectorHeader.js +56 -119
  8. package/dist/commonjs/components/Inspector/LogDetail.js +45 -12
  9. package/dist/commonjs/components/Inspector/NetworkTab.js +4 -1
  10. package/dist/commonjs/components/Inspector/ReduxDetail.js +237 -42
  11. package/dist/commonjs/components/Inspector/ReduxTab.js +456 -35
  12. package/dist/commonjs/components/JsonViewer.js +1 -1
  13. package/dist/commonjs/components/NetworkIcons.js +19 -10
  14. package/dist/commonjs/components/TreeNode.js +12 -2
  15. package/dist/commonjs/constants/version.d.ts +1 -1
  16. package/dist/commonjs/constants/version.js +1 -1
  17. package/dist/commonjs/customHooks/reduxLogger.js +128 -5
  18. package/dist/commonjs/helpers/index.d.ts +1 -1
  19. package/dist/commonjs/helpers/index.js +32 -16
  20. package/dist/commonjs/i18n/locales/en.json +45 -2
  21. package/dist/commonjs/styles/AppColors.d.ts +6 -0
  22. package/dist/commonjs/styles/AppColors.js +6 -0
  23. package/dist/commonjs/styles/index.d.ts +22 -1
  24. package/dist/commonjs/styles/index.js +25 -4
  25. package/dist/commonjs/types/interfaces.d.ts +7 -0
  26. package/dist/esm/components/AnalyticsDetail.js +670 -110
  27. package/dist/esm/components/AppHeaderLogo.js +5 -2
  28. package/dist/esm/components/ConsoleLogCard.js +81 -59
  29. package/dist/esm/components/DomainHeader.js +21 -17
  30. package/dist/esm/components/Inspector/AnalyticsTab.js +298 -201
  31. package/dist/esm/components/Inspector/ConsoleTab.js +163 -57
  32. package/dist/esm/components/Inspector/InspectorHeader.js +57 -120
  33. package/dist/esm/components/Inspector/LogDetail.js +45 -12
  34. package/dist/esm/components/Inspector/NetworkTab.js +4 -1
  35. package/dist/esm/components/Inspector/ReduxDetail.js +239 -44
  36. package/dist/esm/components/Inspector/ReduxTab.js +458 -37
  37. package/dist/esm/components/JsonViewer.js +1 -1
  38. package/dist/esm/components/NetworkIcons.js +19 -10
  39. package/dist/esm/components/TreeNode.js +12 -2
  40. package/dist/esm/constants/version.d.ts +1 -1
  41. package/dist/esm/constants/version.js +1 -1
  42. package/dist/esm/customHooks/reduxLogger.js +128 -5
  43. package/dist/esm/helpers/index.d.ts +1 -1
  44. package/dist/esm/helpers/index.js +32 -16
  45. package/dist/esm/i18n/locales/en.json +45 -2
  46. package/dist/esm/styles/AppColors.d.ts +6 -0
  47. package/dist/esm/styles/AppColors.js +6 -0
  48. package/dist/esm/styles/index.d.ts +22 -1
  49. package/dist/esm/styles/index.js +25 -4
  50. package/dist/esm/types/interfaces.d.ts +7 -0
  51. package/package.json +11 -11
@@ -41,139 +41,699 @@ const react_native_1 = require("react-native");
41
41
  // Components
42
42
  const CopyButton_1 = __importDefault(require("./CopyButton"));
43
43
  const JsonViewer_1 = __importDefault(require("./JsonViewer"));
44
- const TouchableScale_1 = __importDefault(require("./TouchableScale"));
45
- // Utils
44
+ const SegmentedTabs_1 = __importDefault(require("./SegmentedTabs"));
45
+ const HighlightText_1 = __importDefault(require("./HighlightText"));
46
+ const AnimatedEntrance_1 = __importDefault(require("./AnimatedEntrance"));
47
+ // Helpers & Icons
46
48
  const AppFonts_1 = require("../styles/AppFonts");
47
- const helpers_1 = require("../helpers");
48
- // Stylesheet
49
49
  const AppColors_1 = require("../styles/AppColors");
50
+ const helpers_1 = require("../helpers");
51
+ const gaAnalyticsRegistry_1 = require("../helpers/gaAnalyticsRegistry");
50
52
  const i18n_1 = require("../i18n");
53
+ const NetworkIcons_1 = require("./NetworkIcons");
51
54
  const AnalyticsDetail = ({ event, }) => {
52
55
  const { t } = (0, i18n_1.useTranslation)();
53
- const [expandDepth, setExpandDepth] = (0, react_1.useState)(1);
54
- const [treeKey, setTreeKey] = (0, react_1.useState)(0);
55
- const params = event.params ?? {};
56
- const userProperties = event.userProperties ?? {};
57
- const upCount = Object.keys(userProperties).length;
58
- const jsonData = {
56
+ const [activeViewTab, setActiveViewTab] = (0, react_1.useState)('overview');
57
+ const [paramSearch, setParamSearch] = (0, react_1.useState)('');
58
+ const params = (0, react_1.useMemo)(() => event.params ?? {}, [event.params]);
59
+ const userProperties = (0, react_1.useMemo)(() => event.userProperties ?? {}, [event.userProperties]);
60
+ const paramKeys = (0, react_1.useMemo)(() => Object.keys(params), [params]);
61
+ const userPropKeys = (0, react_1.useMemo)(() => Object.keys(userProperties), [userProperties]);
62
+ const category = (0, react_1.useMemo)(() => (0, gaAnalyticsRegistry_1.getEventCategory)(event.name, params), [event.name, params]);
63
+ // Combined full JSON payload
64
+ const fullJsonData = (0, react_1.useMemo)(() => ({
59
65
  name: event.name,
60
- params: params,
61
- ...(upCount > 0 ? { userProperties } : {}),
62
- };
63
- const isObject = typeof jsonData === 'object' && jsonData !== null;
64
- const isArray = Array.isArray(jsonData);
65
- let typeLabel = typeof jsonData;
66
- let countLabel = '';
67
- if (jsonData === null) {
68
- typeLabel = 'null';
69
- }
70
- else if (isArray) {
71
- typeLabel = 'array';
72
- countLabel = `${jsonData.length} ${t('analytics.items')}`;
73
- }
74
- else if (isObject) {
75
- typeLabel = 'object';
76
- countLabel = `${Object.keys(jsonData).length} keys`;
77
- }
78
- return (<react_native_1.ScrollView style={[detailStyles.scroll, { backgroundColor: AppColors_1.AppColors.grayBackground }]} contentContainerStyle={detailStyles.content} showsVerticalScrollIndicator contentInsetAdjustmentBehavior="never" automaticallyAdjustContentInsets={false}>
66
+ timestamp: event.timestamp,
67
+ source: event.source,
68
+ ...(event.screenName ? { screenName: event.screenName } : {}),
69
+ ...(event.screenClass ? { screenClass: event.screenClass } : {}),
70
+ ...(event.userId ? { userId: event.userId } : {}),
71
+ ...(event.sessionId ? { sessionId: event.sessionId } : {}),
72
+ ...(event.trackingId ? { trackingId: event.trackingId } : {}),
73
+ params,
74
+ ...(userPropKeys.length > 0 ? { userProperties } : {}),
75
+ }), [event, params, userPropKeys.length, userProperties]);
76
+ // E-commerce revenue calculation
77
+ const revenueInfo = (0, react_1.useMemo)(() => {
78
+ const val = params.value ?? params.price;
79
+ const currency = params.currency ?? 'USD';
80
+ if (val !== undefined && val !== null && !isNaN(Number(val))) {
81
+ return {
82
+ amount: Number(val).toFixed(2),
83
+ currency: String(currency).toUpperCase(),
84
+ };
85
+ }
86
+ return null;
87
+ }, [params]);
88
+ // Items count if an items array exists
89
+ const itemsCount = (0, react_1.useMemo)(() => {
90
+ if (Array.isArray(params.items)) {
91
+ return params.items.length;
92
+ }
93
+ return null;
94
+ }, [params.items]);
95
+ // Screen Context
96
+ const screenContext = (0, react_1.useMemo)(() => {
97
+ return (event.screenName ||
98
+ params.firebase_screen ||
99
+ params.screen_name ||
100
+ params.page_title ||
101
+ event.screenClass ||
102
+ params.firebase_screen_class);
103
+ }, [event.screenName, event.screenClass, params]);
104
+ // Filtered parameter entries
105
+ const filteredParamEntries = (0, react_1.useMemo)(() => {
106
+ const entries = Object.entries(params);
107
+ if (!paramSearch.trim())
108
+ return entries;
109
+ const q = paramSearch.toLowerCase();
110
+ return entries.filter(([k, v]) => {
111
+ const valStr = typeof v === 'object' ? JSON.stringify(v) : String(v);
112
+ return k.toLowerCase().includes(q) || valStr.toLowerCase().includes(q);
113
+ });
114
+ }, [params, paramSearch]);
115
+ // Category Theme Meta
116
+ const catMeta = (0, react_1.useMemo)(() => {
117
+ switch (category) {
118
+ case 'ecommerce':
119
+ return {
120
+ label: t('analytics.ecommerceCategory'),
121
+ color: AppColors_1.AppColors.amber700,
122
+ bg: AppColors_1.AppColors.amber100,
123
+ border: AppColors_1.AppColors.amber200,
124
+ icon: (color) => <NetworkIcons_1.CartIcon color={color} size={11}/>,
125
+ };
126
+ case 'page_view':
127
+ return {
128
+ label: t('analytics.screensCategory'),
129
+ color: AppColors_1.AppColors.sky600,
130
+ bg: AppColors_1.AppColors.sky100,
131
+ border: AppColors_1.AppColors.sky400,
132
+ icon: (color) => <NetworkIcons_1.GlobeIcon color={color} size={11}/>,
133
+ };
134
+ case 'system':
135
+ return {
136
+ label: t('analytics.systemCategory'),
137
+ color: AppColors_1.AppColors.purple,
138
+ bg: AppColors_1.AppColors.purple100,
139
+ border: AppColors_1.AppColors.purple200,
140
+ icon: (color) => <NetworkIcons_1.BoltIcon color={color} size={11}/>,
141
+ };
142
+ default:
143
+ return {
144
+ label: t('analytics.customCategory'),
145
+ color: AppColors_1.AppColors.brandPurple,
146
+ bg: AppColors_1.AppColors.purple100,
147
+ border: AppColors_1.AppColors.purple200,
148
+ icon: (color) => <NetworkIcons_1.SparkleIcon color={color} size={11}/>,
149
+ };
150
+ }
151
+ }, [category, t]);
152
+ const viewTabs = [
153
+ {
154
+ key: 'overview',
155
+ label: `${t('analytics.overviewTab')} (${paramKeys.length})`,
156
+ icon: (isActive) => (<NetworkIcons_1.TableIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText} size={12}/>),
157
+ },
158
+ {
159
+ key: 'tree',
160
+ label: t('analytics.jsonTreeTab'),
161
+ icon: (isActive) => (<NetworkIcons_1.PrettyIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText} size={12}/>),
162
+ },
163
+ {
164
+ key: 'raw',
165
+ label: t('analytics.rawPayloadTab'),
166
+ icon: (isActive) => (<NetworkIcons_1.RawIcon color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText} size={12}/>),
167
+ },
168
+ ];
169
+ return (<react_native_1.ScrollView style={detailStyles.scroll} contentContainerStyle={detailStyles.content} showsVerticalScrollIndicator contentInsetAdjustmentBehavior="never" automaticallyAdjustContentInsets={false}>
79
170
 
80
- {/* Clean Toolbar */}
81
- <react_native_1.View style={{
82
- flexDirection: 'row',
83
- justifyContent: 'space-between',
84
- alignItems: 'center',
85
- paddingHorizontal: 16,
86
- paddingVertical: 12,
87
- borderBottomWidth: 1,
88
- borderBottomColor: AppColors_1.AppColors.grayBorderSecondary,
89
- backgroundColor: AppColors_1.AppColors.primaryLight,
90
- }}>
91
- <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
92
- <TouchableScale_1.default style={{
93
- flexDirection: 'row',
94
- alignItems: 'center',
95
- gap: 6,
96
- backgroundColor: AppColors_1.AppColors.grayBackground,
97
- paddingHorizontal: 12,
98
- paddingVertical: 6,
99
- borderRadius: 8,
100
- borderWidth: 1,
101
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
102
- }} onPress={() => {
103
- const nextDepth = expandDepth === 99 ? 1 : 99;
104
- setExpandDepth(nextDepth);
105
- setTreeKey(prev => prev + 1);
106
- }}>
107
- <react_native_1.Text style={{
108
- fontFamily: AppFonts_1.AppFonts.interBold,
109
- fontSize: 12,
110
- color: AppColors_1.AppColors.purple,
111
- }}>
112
- {expandDepth === 99 ? t('common.collapseAll') : t('common.expandAll')}
113
- </react_native_1.Text>
114
- </TouchableScale_1.default>
115
- <react_native_1.View style={{
116
- flexDirection: 'row',
117
- alignItems: 'center',
118
- backgroundColor: AppColors_1.AppColors.grayBackground,
119
- borderRadius: 6,
120
- overflow: 'hidden',
121
- borderWidth: 1,
122
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
123
- }}>
124
- <react_native_1.View style={{ paddingHorizontal: 6, paddingVertical: 4, backgroundColor: AppColors_1.AppColors.purple + '18' }}>
125
- <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interBold, fontSize: 9, color: AppColors_1.AppColors.purple, letterSpacing: 0.3 }}>
126
- {typeLabel.toUpperCase()}
171
+ {/* ── 1. Hero Event Header Card ────────────────────────────────────── */}
172
+ <react_native_1.View style={detailStyles.heroCard}>
173
+ {/* Top Badges Row */}
174
+ <react_native_1.View style={detailStyles.heroTopRow}>
175
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexWrap: 'wrap', flex: 1 }}>
176
+ {/* Source Badge */}
177
+ <react_native_1.View style={[
178
+ detailStyles.sourceBadge,
179
+ event.source === 'firebase'
180
+ ? { backgroundColor: AppColors_1.AppColors.amberBg, borderColor: AppColors_1.AppColors.amberBorder }
181
+ : { backgroundColor: AppColors_1.AppColors.purpleBg, borderColor: AppColors_1.AppColors.purpleBorder },
182
+ ]}>
183
+ <react_native_1.View style={[
184
+ detailStyles.sourceDot,
185
+ {
186
+ backgroundColor: event.source === 'firebase'
187
+ ? AppColors_1.AppColors.firebaseOrange
188
+ : AppColors_1.AppColors.purple,
189
+ },
190
+ ]}/>
191
+ <react_native_1.Text style={[
192
+ detailStyles.sourceBadgeText,
193
+ {
194
+ color: event.source === 'firebase'
195
+ ? AppColors_1.AppColors.amber800Warm
196
+ : AppColors_1.AppColors.purple,
197
+ },
198
+ ]}>
199
+ {event.source === 'firebase' ? t('analytics.sourceFirebase') : t('analytics.sourceCustom')}
200
+ </react_native_1.Text>
201
+ </react_native_1.View>
202
+
203
+ {/* Category Badge */}
204
+ <react_native_1.View style={[
205
+ detailStyles.catBadge,
206
+ { backgroundColor: catMeta.bg, borderColor: catMeta.border },
207
+ ]}>
208
+ {catMeta.icon(catMeta.color)}
209
+ <react_native_1.Text style={[detailStyles.catBadgeText, { color: catMeta.color }]}>
210
+ {catMeta.label}
127
211
  </react_native_1.Text>
128
212
  </react_native_1.View>
129
- {countLabel ? (<react_native_1.View style={{ paddingHorizontal: 6, paddingVertical: 4 }}>
130
- <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interMedium, fontSize: 9, color: AppColors_1.AppColors.grayText }}>
131
- {countLabel}
132
- </react_native_1.Text>
133
- </react_native_1.View>) : null}
134
213
  </react_native_1.View>
135
- <react_native_1.View style={{
136
- backgroundColor: AppColors_1.AppColors.grayBackground,
137
- borderRadius: 6,
138
- paddingHorizontal: 6,
139
- paddingVertical: 4,
140
- borderWidth: 1,
141
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
142
- }}>
143
- <react_native_1.Text style={{ fontFamily: AppFonts_1.AppFonts.interMedium, fontSize: 9, color: AppColors_1.AppColors.grayText }}>
144
- {(0, helpers_1.getSize)(jsonData)}
214
+
215
+ {/* Copy Full Event JSON Button */}
216
+ <CopyButton_1.default value={JSON.stringify(fullJsonData, null, 2)} label={t('analytics.eventDetails')}/>
217
+ </react_native_1.View>
218
+
219
+ {/* Event Name Heading */}
220
+ <react_native_1.View style={detailStyles.titleRow}>
221
+ <react_native_1.Text style={detailStyles.eventTitle} selectable numberOfLines={2}>
222
+ {event.name}
223
+ </react_native_1.Text>
224
+ </react_native_1.View>
225
+
226
+ {/* Sub Details Row: Timestamp & Screen Location */}
227
+ <react_native_1.View style={detailStyles.metaRow}>
228
+ <react_native_1.View style={detailStyles.timePill}>
229
+ <NetworkIcons_1.ClockIcon color={AppColors_1.AppColors.purple} size={11}/>
230
+ <react_native_1.Text style={detailStyles.timeText}>
231
+ {(0, helpers_1.formatDateTime)(event.timestamp)}
145
232
  </react_native_1.Text>
146
233
  </react_native_1.View>
234
+
235
+ {screenContext && (<react_native_1.View style={detailStyles.screenPill}>
236
+ <NetworkIcons_1.PinIcon color={AppColors_1.AppColors.sky600} size={11}/>
237
+ <react_native_1.Text style={detailStyles.screenText} numberOfLines={1}>
238
+ {String(screenContext)}
239
+ </react_native_1.Text>
240
+ </react_native_1.View>)}
147
241
  </react_native_1.View>
148
242
 
149
- <CopyButton_1.default value={JSON.stringify(jsonData, null, 2)} label={t('common.copyJson')}/>
243
+ {/* ── 2. Metric Pills Summary ──────────────────────────────────────── */}
244
+ <react_native_1.View style={detailStyles.metricsBar}>
245
+ <react_native_1.View style={detailStyles.metricPill}>
246
+ <react_native_1.Text style={detailStyles.metricLabel}>Params:</react_native_1.Text>
247
+ <react_native_1.Text style={detailStyles.metricValue}>{paramKeys.length}</react_native_1.Text>
248
+ </react_native_1.View>
249
+
250
+ {userPropKeys.length > 0 && (<react_native_1.View style={detailStyles.metricPill}>
251
+ <react_native_1.Text style={detailStyles.metricLabel}>User Props:</react_native_1.Text>
252
+ <react_native_1.Text style={detailStyles.metricValue}>{userPropKeys.length}</react_native_1.Text>
253
+ </react_native_1.View>)}
254
+
255
+ <react_native_1.View style={detailStyles.metricPill}>
256
+ <react_native_1.Text style={detailStyles.metricLabel}>Size:</react_native_1.Text>
257
+ <react_native_1.Text style={detailStyles.metricValue}>{(0, helpers_1.getSize)(fullJsonData)}</react_native_1.Text>
258
+ </react_native_1.View>
259
+
260
+ {revenueInfo && (<react_native_1.View style={detailStyles.revenuePill}>
261
+ <NetworkIcons_1.MoneyIcon color={AppColors_1.AppColors.emerald600} size={11}/>
262
+ <react_native_1.Text style={detailStyles.revenueValue}>
263
+ ${revenueInfo.amount} {revenueInfo.currency}
264
+ </react_native_1.Text>
265
+ </react_native_1.View>)}
266
+
267
+ {itemsCount !== null && (<react_native_1.View style={detailStyles.itemsPill}>
268
+ <react_native_1.Text style={detailStyles.itemsValue}>
269
+ 📦 {itemsCount} items
270
+ </react_native_1.Text>
271
+ </react_native_1.View>)}
272
+ </react_native_1.View>
150
273
  </react_native_1.View>
151
274
 
152
- {/* Direct JSON Viewer View */}
153
- <react_native_1.View style={[
154
- detailStyles.jsonBlockContainer,
155
- {
156
- backgroundColor: AppColors_1.AppColors.primaryLight,
157
- borderColor: AppColors_1.AppColors.grayBorderSecondary,
158
- marginTop: 16,
159
- },
160
- ]}>
161
- <JsonViewer_1.default key={treeKey} data={jsonData} defaultExpandDepth={expandDepth} fullHeight/>
275
+ {/* ── 3. View Switcher Tabs (Overview, Tree, Raw) ───────────────────── */}
276
+ <react_native_1.View style={detailStyles.tabsWrap}>
277
+ <SegmentedTabs_1.default tabs={viewTabs} activeKey={activeViewTab} onChange={key => setActiveViewTab(key)}/>
162
278
  </react_native_1.View>
279
+
280
+ {/* ── 4. Main Tab Body Content ───────────────────────────────────────── */}
281
+ {activeViewTab === 'overview' && (<react_native_1.View style={detailStyles.tabContent}>
282
+ {/* Metadata Card (Session, User ID, Client ID) */}
283
+ {(event.userId || event.sessionId || event.trackingId) && (<react_native_1.View style={detailStyles.sectionCard}>
284
+ <react_native_1.View style={detailStyles.sectionHeader}>
285
+ <NetworkIcons_1.LayersIcon color={AppColors_1.AppColors.purple} size={12}/>
286
+ <react_native_1.Text style={detailStyles.sectionTitle}>SESSION & IDENTITY</react_native_1.Text>
287
+ </react_native_1.View>
288
+ <react_native_1.View style={detailStyles.sectionBody}>
289
+ {event.userId && (<react_native_1.View style={detailStyles.kvRow}>
290
+ <react_native_1.Text style={detailStyles.kvKey}>User ID:</react_native_1.Text>
291
+ <react_native_1.Text style={detailStyles.kvVal} selectable>{event.userId}</react_native_1.Text>
292
+ </react_native_1.View>)}
293
+ {event.sessionId && (<react_native_1.View style={detailStyles.kvRow}>
294
+ <react_native_1.Text style={detailStyles.kvKey}>Session ID:</react_native_1.Text>
295
+ <react_native_1.Text style={detailStyles.kvVal} selectable>{event.sessionId}</react_native_1.Text>
296
+ </react_native_1.View>)}
297
+ {event.trackingId && (<react_native_1.View style={detailStyles.kvRow}>
298
+ <react_native_1.Text style={detailStyles.kvKey}>Tracking ID:</react_native_1.Text>
299
+ <react_native_1.Text style={detailStyles.kvVal} selectable>{event.trackingId}</react_native_1.Text>
300
+ </react_native_1.View>)}
301
+ </react_native_1.View>
302
+ </react_native_1.View>)}
303
+
304
+ {/* Parameters Table Section */}
305
+ <react_native_1.View style={detailStyles.sectionCard}>
306
+ <react_native_1.View style={detailStyles.sectionHeaderBetween}>
307
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
308
+ <NetworkIcons_1.TableIcon color={AppColors_1.AppColors.brandPurple} size={12}/>
309
+ <react_native_1.Text style={detailStyles.sectionTitle}>
310
+ EVENT PARAMETERS ({paramKeys.length})
311
+ </react_native_1.Text>
312
+ </react_native_1.View>
313
+ <react_native_1.Text style={detailStyles.sectionSubtitle}>
314
+ Key-Value Attributes
315
+ </react_native_1.Text>
316
+ </react_native_1.View>
317
+
318
+ {/* Search filter within parameters (if > 4 params) */}
319
+ {paramKeys.length > 4 && (<react_native_1.View style={detailStyles.searchBar}>
320
+ <NetworkIcons_1.SearchIcon color={AppColors_1.AppColors.grayTextWeak} size={13}/>
321
+ <react_native_1.TextInput placeholder="Filter parameters by key or value..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} value={paramSearch} onChangeText={setParamSearch} style={detailStyles.searchInput} autoCorrect={false} autoCapitalize="none"/>
322
+ {paramSearch.length > 0 && (<react_native_1.Pressable onPress={() => setParamSearch('')} hitSlop={8}>
323
+ <NetworkIcons_1.ClearIcon color={AppColors_1.AppColors.grayTextWeak} size={13}/>
324
+ </react_native_1.Pressable>)}
325
+ </react_native_1.View>)}
326
+
327
+ {paramKeys.length === 0 ? (<react_native_1.View style={detailStyles.emptyParamsBox}>
328
+ <NetworkIcons_1.DocIcon color={AppColors_1.AppColors.grayTextWeak} size={16}/>
329
+ <react_native_1.Text style={detailStyles.emptyParamsText}>
330
+ No custom parameters recorded for this event.
331
+ </react_native_1.Text>
332
+ </react_native_1.View>) : filteredParamEntries.length === 0 ? (<react_native_1.View style={detailStyles.emptyParamsBox}>
333
+ <react_native_1.Text style={detailStyles.emptyParamsText}>
334
+ No parameters matching "{paramSearch}"
335
+ </react_native_1.Text>
336
+ </react_native_1.View>) : (<react_native_1.View style={detailStyles.paramList}>
337
+ {filteredParamEntries.map(([key, val], pIdx) => {
338
+ const isObject = typeof val === 'object' && val !== null;
339
+ const isArray = Array.isArray(val);
340
+ let typeStr = typeof val;
341
+ if (val === null)
342
+ typeStr = 'null';
343
+ else if (isArray)
344
+ typeStr = `array [${val.length}]`;
345
+ else if (isObject)
346
+ typeStr = 'object';
347
+ const valString = isObject ? JSON.stringify(val, null, 2) : String(val);
348
+ // Highlight standard GA4 ecom/screen keys
349
+ const isKeyHighlighted = key === 'value' ||
350
+ key === 'price' ||
351
+ key === 'currency' ||
352
+ key === 'screen_name' ||
353
+ key === 'item_id' ||
354
+ key === 'item_name';
355
+ return (<AnimatedEntrance_1.default key={key} index={pIdx} distance={4}>
356
+ <react_native_1.View style={detailStyles.paramCard}>
357
+ {/* Param Top Row: Key + Type + Copy */}
358
+ <react_native_1.View style={detailStyles.paramCardHeader}>
359
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flex: 1, minWidth: 0 }}>
360
+ <HighlightText_1.default text={key} search={paramSearch} style={[
361
+ detailStyles.paramKeyText,
362
+ isKeyHighlighted && detailStyles.paramKeyHighlighted,
363
+ ]} highlightStyle={detailStyles.highlight}/>
364
+ <react_native_1.View style={detailStyles.typeBadge}>
365
+ <react_native_1.Text style={detailStyles.typeBadgeText}>
366
+ {typeStr.toUpperCase()}
367
+ </react_native_1.Text>
368
+ </react_native_1.View>
369
+ </react_native_1.View>
370
+
371
+ <CopyButton_1.default value={valString} label={key}/>
372
+ </react_native_1.View>
373
+
374
+ {/* Param Value Display */}
375
+ <react_native_1.View style={detailStyles.paramValBox}>
376
+ {isObject ? (<JsonViewer_1.default data={val} search={paramSearch} hideTabs wrap/>) : (<HighlightText_1.default text={valString} search={paramSearch} style={detailStyles.paramValText} highlightStyle={detailStyles.highlight} selectable/>)}
377
+ </react_native_1.View>
378
+ </react_native_1.View>
379
+ </AnimatedEntrance_1.default>);
380
+ })}
381
+ </react_native_1.View>)}
382
+ </react_native_1.View>
383
+
384
+ {/* User Properties Section (if any) */}
385
+ {userPropKeys.length > 0 && (<react_native_1.View style={detailStyles.sectionCard}>
386
+ <react_native_1.View style={detailStyles.sectionHeader}>
387
+ <NetworkIcons_1.SparkleIcon color={AppColors_1.AppColors.purple} size={12}/>
388
+ <react_native_1.Text style={detailStyles.sectionTitle}>
389
+ USER PROPERTIES SNAPSHOT ({userPropKeys.length})
390
+ </react_native_1.Text>
391
+ </react_native_1.View>
392
+ <react_native_1.View style={detailStyles.sectionBody}>
393
+ {userPropKeys.map(k => (<react_native_1.View key={k} style={detailStyles.kvRow}>
394
+ <react_native_1.Text style={detailStyles.kvKey}>{k}:</react_native_1.Text>
395
+ <react_native_1.Text style={detailStyles.kvVal} selectable>
396
+ {String(userProperties[k])}
397
+ </react_native_1.Text>
398
+ </react_native_1.View>))}
399
+ </react_native_1.View>
400
+ </react_native_1.View>)}
401
+ </react_native_1.View>)}
402
+
403
+ {/* ── JSON Tree View ────────────────────────────────────────────────── */}
404
+ {activeViewTab === 'tree' && (<react_native_1.View style={detailStyles.jsonContainer}>
405
+ <JsonViewer_1.default data={fullJsonData} defaultExpandDepth={1} mode="pretty" fullHeight/>
406
+ </react_native_1.View>)}
407
+
408
+ {/* ── Raw Payload View ──────────────────────────────────────────────── */}
409
+ {activeViewTab === 'raw' && (<react_native_1.View style={detailStyles.jsonContainer}>
410
+ <JsonViewer_1.default data={fullJsonData} mode="raw" fullHeight/>
411
+ </react_native_1.View>)}
163
412
  </react_native_1.ScrollView>);
164
413
  };
165
414
  const detailStyles = react_native_1.StyleSheet.create({
166
- scroll: { flex: 1, backgroundColor: AppColors_1.AppColors.grayBackground },
415
+ scroll: {
416
+ flex: 1,
417
+ backgroundColor: AppColors_1.AppColors.grayBackground,
418
+ },
167
419
  content: {
168
- paddingTop: 0,
420
+ paddingTop: 12,
169
421
  paddingBottom: 40,
422
+ paddingHorizontal: 12,
423
+ },
424
+ heroCard: {
425
+ backgroundColor: AppColors_1.AppColors.white,
426
+ borderRadius: 12,
427
+ padding: 14,
428
+ borderWidth: 1,
429
+ borderColor: AppColors_1.AppColors.dividerColor,
430
+ shadowColor: AppColors_1.AppColors.primaryBlack,
431
+ shadowOffset: { width: 0, height: 1 },
432
+ shadowOpacity: 0.04,
433
+ shadowRadius: 4,
434
+ elevation: 2,
435
+ marginBottom: 12,
170
436
  },
171
- jsonBlockContainer: {
172
- marginHorizontal: 16,
173
- marginTop: 16,
174
- marginBottom: 16,
437
+ heroTopRow: {
438
+ flexDirection: 'row',
439
+ alignItems: 'center',
440
+ justifyContent: 'space-between',
441
+ marginBottom: 10,
442
+ },
443
+ sourceBadge: {
444
+ flexDirection: 'row',
445
+ alignItems: 'center',
446
+ gap: 4.5,
447
+ paddingHorizontal: 7,
448
+ paddingVertical: 3,
449
+ borderRadius: 5,
450
+ borderWidth: 1,
451
+ },
452
+ sourceDot: {
453
+ width: 6,
454
+ height: 6,
455
+ borderRadius: 3,
456
+ },
457
+ sourceBadgeText: {
458
+ fontFamily: AppFonts_1.AppFonts.interBold,
459
+ fontSize: 9.5,
460
+ letterSpacing: 0.4,
461
+ },
462
+ catBadge: {
463
+ flexDirection: 'row',
464
+ alignItems: 'center',
465
+ gap: 4,
466
+ paddingHorizontal: 7,
467
+ paddingVertical: 3,
468
+ borderRadius: 5,
175
469
  borderWidth: 1,
470
+ },
471
+ catBadgeText: {
472
+ fontFamily: AppFonts_1.AppFonts.interBold,
473
+ fontSize: 9.5,
474
+ letterSpacing: 0.3,
475
+ },
476
+ titleRow: {
477
+ marginBottom: 8,
478
+ },
479
+ eventTitle: {
480
+ fontFamily: AppFonts_1.AppFonts.interBold,
481
+ fontSize: 16,
482
+ color: AppColors_1.AppColors.primaryBlack,
483
+ lineHeight: 22,
484
+ },
485
+ metaRow: {
486
+ flexDirection: 'row',
487
+ alignItems: 'center',
488
+ gap: 6,
489
+ flexWrap: 'wrap',
490
+ marginBottom: 10,
491
+ },
492
+ timePill: {
493
+ flexDirection: 'row',
494
+ alignItems: 'center',
495
+ gap: 4,
496
+ backgroundColor: `${AppColors_1.AppColors.purple}14`,
497
+ paddingHorizontal: 7,
498
+ paddingVertical: 3,
499
+ borderRadius: 5,
500
+ borderWidth: 1,
501
+ borderColor: `${AppColors_1.AppColors.purple}2E`,
502
+ },
503
+ timeText: {
504
+ fontFamily: AppFonts_1.AppFonts.interMedium,
505
+ fontSize: 10.5,
506
+ color: AppColors_1.AppColors.purple,
507
+ },
508
+ screenPill: {
509
+ flexDirection: 'row',
510
+ alignItems: 'center',
511
+ gap: 4,
512
+ backgroundColor: `${AppColors_1.AppColors.sky500}14`,
513
+ paddingHorizontal: 7,
514
+ paddingVertical: 3,
515
+ borderRadius: 5,
516
+ borderWidth: 1,
517
+ borderColor: `${AppColors_1.AppColors.sky500}2E`,
518
+ maxWidth: 220,
519
+ },
520
+ screenText: {
521
+ fontFamily: AppFonts_1.AppFonts.interMedium,
522
+ fontSize: 10.5,
523
+ color: AppColors_1.AppColors.sky600,
524
+ },
525
+ metricsBar: {
526
+ flexDirection: 'row',
527
+ alignItems: 'center',
528
+ gap: 6,
529
+ flexWrap: 'wrap',
530
+ paddingTop: 8,
531
+ borderTopWidth: 1,
532
+ borderTopColor: AppColors_1.AppColors.dividerColor,
533
+ },
534
+ metricPill: {
535
+ flexDirection: 'row',
536
+ alignItems: 'center',
537
+ gap: 4,
538
+ backgroundColor: AppColors_1.AppColors.grayBackground,
539
+ paddingHorizontal: 7,
540
+ paddingVertical: 3,
541
+ borderRadius: 5,
542
+ borderWidth: 1,
543
+ borderColor: AppColors_1.AppColors.dividerColor,
544
+ },
545
+ metricLabel: {
546
+ fontFamily: AppFonts_1.AppFonts.interMedium,
547
+ fontSize: 10.5,
548
+ color: AppColors_1.AppColors.grayTextWeak,
549
+ },
550
+ metricValue: {
551
+ fontFamily: AppFonts_1.AppFonts.interBold,
552
+ fontSize: 10.5,
553
+ color: AppColors_1.AppColors.primaryBlack,
554
+ },
555
+ revenuePill: {
556
+ flexDirection: 'row',
557
+ alignItems: 'center',
558
+ gap: 4,
559
+ backgroundColor: AppColors_1.AppColors.emeraldBg,
560
+ paddingHorizontal: 7,
561
+ paddingVertical: 3,
562
+ borderRadius: 5,
563
+ borderWidth: 1,
564
+ borderColor: AppColors_1.AppColors.emeraldBorder,
565
+ },
566
+ revenueValue: {
567
+ fontFamily: AppFonts_1.AppFonts.interBold,
568
+ fontSize: 10.5,
569
+ color: '#047857',
570
+ },
571
+ itemsPill: {
572
+ backgroundColor: '#EFF6FF',
573
+ paddingHorizontal: 7,
574
+ paddingVertical: 3,
575
+ borderRadius: 5,
576
+ borderWidth: 1,
577
+ borderColor: '#BFDBFE',
578
+ },
579
+ itemsValue: {
580
+ fontFamily: AppFonts_1.AppFonts.interBold,
581
+ fontSize: 10.5,
582
+ color: '#1D4ED8',
583
+ },
584
+ tabsWrap: {
585
+ marginBottom: 12,
586
+ },
587
+ tabContent: {
588
+ gap: 12,
589
+ },
590
+ sectionCard: {
591
+ backgroundColor: AppColors_1.AppColors.white,
176
592
  borderRadius: 12,
593
+ padding: 12,
594
+ borderWidth: 1,
595
+ borderColor: AppColors_1.AppColors.dividerColor,
596
+ shadowColor: AppColors_1.AppColors.primaryBlack,
597
+ shadowOffset: { width: 0, height: 1 },
598
+ shadowOpacity: 0.04,
599
+ shadowRadius: 4,
600
+ elevation: 2,
601
+ },
602
+ sectionHeader: {
603
+ flexDirection: 'row',
604
+ alignItems: 'center',
605
+ gap: 6,
606
+ marginBottom: 10,
607
+ paddingBottom: 6,
608
+ borderBottomWidth: 1,
609
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
610
+ },
611
+ sectionHeaderBetween: {
612
+ flexDirection: 'row',
613
+ alignItems: 'center',
614
+ justifyContent: 'space-between',
615
+ marginBottom: 10,
616
+ paddingBottom: 6,
617
+ borderBottomWidth: 1,
618
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
619
+ },
620
+ sectionTitle: {
621
+ fontFamily: AppFonts_1.AppFonts.interBold,
622
+ fontSize: 11,
623
+ color: AppColors_1.AppColors.slate700,
624
+ letterSpacing: 0.4,
625
+ },
626
+ sectionSubtitle: {
627
+ fontFamily: AppFonts_1.AppFonts.interMedium,
628
+ fontSize: 10,
629
+ color: AppColors_1.AppColors.grayTextWeak,
630
+ },
631
+ sectionBody: {
632
+ gap: 6,
633
+ },
634
+ kvRow: {
635
+ flexDirection: 'row',
636
+ alignItems: 'center',
637
+ justifyContent: 'space-between',
638
+ paddingVertical: 3,
639
+ },
640
+ kvKey: {
641
+ fontFamily: AppFonts_1.AppFonts.interMedium,
642
+ fontSize: 11,
643
+ color: AppColors_1.AppColors.grayTextWeak,
644
+ },
645
+ kvVal: {
646
+ fontFamily: AppFonts_1.AppFonts.interBold,
647
+ fontSize: 11,
648
+ color: AppColors_1.AppColors.primaryBlack,
649
+ },
650
+ searchBar: {
651
+ flexDirection: 'row',
652
+ alignItems: 'center',
653
+ backgroundColor: AppColors_1.AppColors.grayBackground,
654
+ borderRadius: 8,
655
+ paddingHorizontal: 8,
656
+ paddingVertical: 5,
657
+ borderWidth: 1,
658
+ borderColor: AppColors_1.AppColors.dividerColor,
659
+ marginBottom: 10,
660
+ gap: 6,
661
+ },
662
+ searchInput: {
663
+ flex: 1,
664
+ fontFamily: AppFonts_1.AppFonts.interRegular,
665
+ fontSize: 11,
666
+ color: AppColors_1.AppColors.primaryBlack,
667
+ paddingVertical: 0,
668
+ },
669
+ emptyParamsBox: {
670
+ alignItems: 'center',
671
+ justifyContent: 'center',
672
+ paddingVertical: 20,
673
+ gap: 6,
674
+ },
675
+ emptyParamsText: {
676
+ fontFamily: AppFonts_1.AppFonts.interMedium,
677
+ fontSize: 11,
678
+ color: AppColors_1.AppColors.grayTextWeak,
679
+ },
680
+ paramList: {
681
+ gap: 8,
682
+ },
683
+ paramCard: {
684
+ backgroundColor: AppColors_1.AppColors.grayBackground,
685
+ borderRadius: 8,
686
+ padding: 9,
687
+ borderWidth: 1,
688
+ borderColor: AppColors_1.AppColors.dividerColor,
689
+ },
690
+ paramCardHeader: {
691
+ flexDirection: 'row',
692
+ alignItems: 'center',
693
+ justifyContent: 'space-between',
694
+ marginBottom: 4,
695
+ },
696
+ paramKeyText: {
697
+ fontFamily: AppFonts_1.AppFonts.interBold,
698
+ fontSize: 11.5,
699
+ color: AppColors_1.AppColors.primaryBlack,
700
+ },
701
+ paramKeyHighlighted: {
702
+ color: AppColors_1.AppColors.brandPurple,
703
+ },
704
+ typeBadge: {
705
+ backgroundColor: '#E2E8F0',
706
+ paddingHorizontal: 5,
707
+ paddingVertical: 1.5,
708
+ borderRadius: 3,
709
+ },
710
+ typeBadgeText: {
711
+ fontFamily: AppFonts_1.AppFonts.interBold,
712
+ fontSize: 8.5,
713
+ color: AppColors_1.AppColors.slate700,
714
+ letterSpacing: 0.3,
715
+ },
716
+ paramValBox: {
717
+ marginTop: 2,
718
+ },
719
+ paramValText: {
720
+ fontFamily: AppFonts_1.AppFonts.interRegular,
721
+ fontSize: 11,
722
+ color: AppColors_1.AppColors.slate700,
723
+ lineHeight: 16,
724
+ },
725
+ jsonContainer: {
726
+ borderRadius: 12,
727
+ borderWidth: 1,
728
+ borderColor: AppColors_1.AppColors.dividerColor,
729
+ overflow: 'hidden',
730
+ backgroundColor: AppColors_1.AppColors.white,
731
+ minHeight: 300,
732
+ },
733
+ highlight: {
734
+ backgroundColor: '#FEF08A',
735
+ color: '#854D0E',
736
+ fontFamily: AppFonts_1.AppFonts.interBold,
177
737
  },
178
738
  });
179
739
  exports.default = AnalyticsDetail;