react-native-inapp-inspector 1.1.11 → 1.1.12

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.
@@ -1,297 +1,82 @@
1
1
  import React, { useState } from 'react';
2
- import { Pressable, ScrollView, StyleSheet, Text, TextInput, View, } from 'react-native';
3
- import LinearGradient from 'react-native-linear-gradient';
2
+ import { ScrollView, StyleSheet, Text, View, } from 'react-native';
4
3
  // Components
5
4
  import CopyButton from './CopyButton';
6
5
  import JsonViewer from './JsonViewer';
7
- // Icons
8
- import { ClearIcon } from './NetworkIcons';
6
+ import TouchableScale from './TouchableScale';
9
7
  // Utils
10
8
  import { AppFonts } from '../styles/AppFonts';
11
9
  // Stylesheet
12
10
  import { AppColors } from '../styles/AppColors';
13
- import styles from '../styles';
14
- import { getEventColor } from './AnalyticsEventCard';
15
- // Helpers
16
- import { formatDateTimeToAnalytics } from '../helpers';
17
- // Sub Components
18
- const ParamRowItem = ({ paramKey, value, }) => {
19
- const isObject = typeof value === 'object' && value !== null;
20
- const valStr = isObject ? JSON.stringify(value, null, 2) : String(value);
21
- const [expanded, setExpanded] = useState(false);
22
- const isLong = valStr.length > 80 || valStr.includes('\n') || isObject;
23
- return (<View style={[detailStyles.dataBox, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
24
- <View style={detailStyles.dataBoxHeader}>
25
- <Text style={[detailStyles.dataBoxKey, { color: AppColors.primaryBlack }]} numberOfLines={1}>
26
- {paramKey}
27
- </Text>
28
- <CopyButton value={valStr} label={paramKey}/>
29
- </View>
30
- {expanded && isObject ? (<View style={[detailStyles.jsonBlock, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
31
- <JsonViewer data={value}/>
32
- </View>) : (<Text style={[detailStyles.dataBoxVal, { color: AppColors.primaryBlack }]} selectable numberOfLines={expanded ? undefined : 2}>
33
- {valStr}
34
- </Text>)}
35
- {isLong && (<Pressable onPress={() => setExpanded(!expanded)} style={[detailStyles.showMoreBtn, { backgroundColor: AppColors.grayBackground }]}>
36
- <Text style={[detailStyles.showMoreText, { color: AppColors.grayTextStrong }]}>
37
- {expanded ? 'Show Less' : 'Show More'}
38
- </Text>
39
- </Pressable>)}
40
- </View>);
41
- };
42
- const ParamTable = ({ data, emptyLabel, }) => {
43
- const entries = Object.keys(data).map(key => ({
44
- key,
45
- value: data[key],
46
- }));
47
- if (entries.length === 0) {
48
- return (<View style={[detailStyles.emptyParams, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
49
- <Text style={[detailStyles.emptyParamsText, { color: AppColors.grayTextWeak }]}>
50
- {emptyLabel ?? 'No parameters'}
51
- </Text>
52
- </View>);
53
- }
54
- return (<View style={detailStyles.paramList}>
55
- {entries.map(({ key, value }) => (<ParamRowItem key={key} paramKey={key} value={value}/>))}
56
- </View>);
57
- };
58
- const SectionCard = ({ title, children, count, accentColor = AppColors.purple, }) => {
59
- if (!title) {
60
- return (<View style={{ paddingHorizontal: 16, paddingTop: 12, paddingBottom: 20 }}>
61
- {children}
62
- </View>);
63
- }
64
- return (<View style={[detailStyles.sectionCard, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
65
- <View style={detailStyles.sectionHeader}>
66
- <View style={detailStyles.sectionTitleRow}>
67
- <View style={[
68
- detailStyles.sectionAccentDot,
69
- { backgroundColor: accentColor },
70
- ]}/>
71
- <Text style={[detailStyles.sectionTitle, { color: AppColors.primaryBlack }]}>{title.toUpperCase()}</Text>
72
- </View>
73
- {typeof count === 'number' && (<View style={[
74
- detailStyles.countBadge,
75
- {
76
- borderColor: `${accentColor}55`,
77
- backgroundColor: `${accentColor}12`,
78
- },
79
- ]}>
80
- <Text style={[detailStyles.countBadgeText, { color: accentColor }]}>
81
- {count}
82
- </Text>
83
- </View>)}
84
- </View>
85
- <View style={{ paddingHorizontal: 14, paddingBottom: 14 }}>{children}</View>
86
- </View>);
87
- };
88
11
  const AnalyticsDetail = ({ event, }) => {
89
- const [search, setSearch] = useState('');
90
- const [activeTab, setActiveTab] = useState('unformatted');
91
- const SOURCE_COLORS = {
92
- firebase: '#E07B1A',
93
- manual: AppColors.purple,
94
- };
12
+ const [expandDepth, setExpandDepth] = useState(1);
13
+ const [treeKey, setTreeKey] = useState(0);
95
14
  const params = event.params ?? {};
96
15
  const userProperties = event.userProperties ?? {};
97
- const eventColor = getEventColor(event.name);
98
- const sourceColor = SOURCE_COLORS[event.source] ?? AppColors.purple;
99
- const paramCount = Object.keys(params).length;
100
16
  const upCount = Object.keys(userProperties).length;
101
- const topMetrics = [];
102
- if (event.screenName) {
103
- topMetrics.push({
104
- key: 'Screen',
105
- value: event.screenName,
106
- color: AppColors.skyBlue,
107
- });
108
- }
109
- if (event.userId) {
110
- topMetrics.push({
111
- key: 'User ID',
112
- value: event.userId,
113
- color: AppColors.greenColor,
114
- });
115
- }
116
- if (event.pageTitle) {
117
- topMetrics.push({
118
- key: 'Page',
119
- value: event.pageTitle,
120
- color: AppColors.purple,
121
- });
122
- }
123
- if (params?.primary_category) {
124
- topMetrics.push({
125
- key: 'Category',
126
- value: String(params.primary_category),
127
- color: AppColors.purple,
128
- });
129
- }
130
- if (params?.flow) {
131
- topMetrics.push({
132
- key: 'Flow',
133
- value: String(params.flow),
134
- color: AppColors.greenColor,
135
- });
136
- }
137
- if (params?.market_language) {
138
- topMetrics.push({
139
- key: 'Language',
140
- value: String(params.market_language),
141
- color: '#F59E0B',
142
- }); // Amber
143
- }
144
- if (params?.tripType) {
145
- topMetrics.push({
146
- key: 'Trip Type',
147
- value: String(params.tripType),
148
- color: '#3B82F6',
149
- }); // Blue
150
- }
151
- if (userProperties?.platform_type) {
152
- topMetrics.push({
153
- key: 'Platform',
154
- value: String(userProperties.platform_type),
155
- color: AppColors.skyBlue,
156
- });
157
- }
158
- if (userProperties?.login_status) {
159
- topMetrics.push({
160
- key: 'Login Status',
161
- value: String(userProperties.login_status),
162
- color: '#64748B',
163
- });
164
- }
165
- topMetrics.unshift({
166
- key: 'Source',
167
- value: event.source,
168
- color: sourceColor,
169
- });
170
17
  return (<ScrollView style={[detailStyles.scroll, { backgroundColor: AppColors.grayBackground }]} contentContainerStyle={detailStyles.content} showsVerticalScrollIndicator contentInsetAdjustmentBehavior="never" automaticallyAdjustContentInsets={false}>
171
- <LinearGradient colors={[
172
- `${eventColor}18`,
173
- `${eventColor}06`,
174
- AppColors.grayBackground,
175
- ]} style={detailStyles.hero}>
176
- <View style={{
18
+
19
+ {/* Clean Toolbar */}
20
+ <View style={{
177
21
  flexDirection: 'row',
178
- width: '100%',
179
22
  justifyContent: 'space-between',
180
- alignItems: 'flex-start',
23
+ alignItems: 'center',
181
24
  paddingHorizontal: 16,
182
- paddingTop: 14,
183
- marginBottom: 8,
25
+ paddingVertical: 12,
26
+ borderBottomWidth: 1,
27
+ borderBottomColor: AppColors.grayBorderSecondary,
28
+ backgroundColor: AppColors.primaryLight,
184
29
  }}>
185
- <View style={{ flex: 1, paddingRight: 10 }}>
186
- <Text style={{
30
+ <TouchableScale style={{
31
+ flexDirection: 'row',
32
+ alignItems: 'center',
33
+ gap: 6,
34
+ backgroundColor: AppColors.grayBackground,
35
+ paddingHorizontal: 12,
36
+ paddingVertical: 6,
37
+ borderRadius: 8,
38
+ borderWidth: 1,
39
+ borderColor: AppColors.grayBorderSecondary,
40
+ }} onPress={() => {
41
+ const nextDepth = expandDepth === 99 ? 1 : 99;
42
+ setExpandDepth(nextDepth);
43
+ setTreeKey(prev => prev + 1);
44
+ }}>
45
+ <Text style={{
187
46
  fontFamily: AppFonts.interBold,
188
- fontSize: 18,
189
- color: AppColors.primaryBlack,
190
- marginBottom: 4,
191
- }} numberOfLines={2}>
192
- {event.name}
193
- </Text>
194
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
195
- <View style={{
196
- width: 8,
197
- height: 8,
198
- borderRadius: 4,
199
- backgroundColor: sourceColor,
200
- }}/>
201
- <Text style={{
202
- fontFamily: AppFonts.interMedium,
203
47
  fontSize: 12,
204
- color: AppColors.grayTextStrong,
48
+ color: AppColors.purple,
205
49
  }}>
206
- {formatDateTimeToAnalytics(event.timestamp)}
207
- </Text>
208
- </View>
209
- </View>
210
- <CopyButton value={JSON.stringify({ name: event.name, params: params }, null, 2)} label="Copy JSON"/>
211
- </View>
50
+ {expandDepth === 99 ? 'Collapse All' : 'Expand All'}
51
+ </Text>
52
+ </TouchableScale>
212
53
 
213
- {topMetrics.length > 0 && (<ScrollView horizontal showsHorizontalScrollIndicator={false} style={detailStyles.metricsScroll} contentContainerStyle={detailStyles.metricsGrid}>
214
- {topMetrics.map((item, idx) => (<View key={idx} style={[
215
- detailStyles.metricCard,
216
- {
217
- borderLeftColor: item.color,
218
- backgroundColor: AppColors.primaryLight,
219
- },
220
- ]}>
221
- <Text style={[detailStyles.metricLabel, { color: AppColors.grayTextWeak }]}>{item.key}</Text>
222
- <Text style={[detailStyles.metricValue, { color: item.color }]} numberOfLines={1}>
223
- {item.value}
224
- </Text>
225
- </View>))}
226
- </ScrollView>)}
227
- </LinearGradient>
54
+ <CopyButton value={JSON.stringify({
55
+ name: event.name,
56
+ params: params,
57
+ ...(upCount > 0 ? { userProperties } : {}),
58
+ }, null, 2)} label="Copy JSON"/>
59
+ </View>
228
60
 
229
- <View style={[detailStyles.tabRow, { backgroundColor: AppColors.grayBackground }]}>
230
- <Pressable style={[
231
- detailStyles.tabButton,
232
- activeTab === 'unformatted' && [detailStyles.tabActive, { backgroundColor: AppColors.primaryLight }],
233
- ]} onPress={() => setActiveTab('unformatted')}>
234
- <Text style={[
235
- detailStyles.tabText,
236
- { color: AppColors.grayTextWeak },
237
- activeTab === 'unformatted' && [detailStyles.tabTextActive, { color: AppColors.primaryBlack }],
61
+ {/* Direct JSON Viewer View */}
62
+ <View style={[
63
+ detailStyles.jsonBlockContainer,
64
+ {
65
+ backgroundColor: AppColors.primaryLight,
66
+ borderColor: AppColors.grayBorderSecondary,
67
+ marginTop: 16,
68
+ },
238
69
  ]}>
239
- JSON Viewer
240
- </Text>
241
- </Pressable>
242
- <Pressable style={[
243
- detailStyles.tabButton,
244
- activeTab === 'formatted' && [detailStyles.tabActive, { backgroundColor: AppColors.primaryLight }],
245
- ]} onPress={() => setActiveTab('formatted')}>
246
- <Text style={[
247
- detailStyles.tabText,
248
- { color: AppColors.grayTextWeak },
249
- activeTab === 'formatted' && [detailStyles.tabTextActive, { color: AppColors.primaryBlack }],
250
- ]}>
251
- Tabular View
252
- </Text>
253
- </Pressable>
70
+ <JsonViewer key={treeKey} data={{
71
+ name: event.name,
72
+ params: params,
73
+ ...(upCount > 0
74
+ ? {
75
+ userProperties: userProperties,
76
+ }
77
+ : {}),
78
+ }} defaultExpandDepth={expandDepth}/>
254
79
  </View>
255
-
256
- {activeTab === 'unformatted' && (<View style={detailStyles.searchRow}>
257
- <View style={[styles.detailSearchBox, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
258
- <TextInput placeholder="Search JSON data..." placeholderTextColor={AppColors.grayTextWeak} value={search} onChangeText={setSearch} style={[styles.detailSearchInput, { color: AppColors.primaryBlack }]} autoCorrect={false} autoCapitalize="none"/>
259
- {search.length > 0 && (<Pressable onPress={() => setSearch('')} hitSlop={10} style={{ padding: 8 }}>
260
- <ClearIcon color={AppColors.grayTextWeak} size={14}/>
261
- </Pressable>)}
262
- </View>
263
- </View>)}
264
-
265
- {activeTab === 'formatted' && (<View style={{ gap: 10 }}>
266
- {paramCount > 0 && (<SectionCard title="Event Parameters" count={paramCount} accentColor={eventColor}>
267
- <ParamTable data={params} emptyLabel="No parameters"/>
268
- </SectionCard>)}
269
-
270
- {upCount > 0 && (<SectionCard title="User Properties" count={upCount} accentColor={AppColors.greenColor}>
271
- <ParamTable data={userProperties} emptyLabel="No user properties"/>
272
- </SectionCard>)}
273
- </View>)}
274
-
275
- {activeTab === 'unformatted' && (<SectionCard accentColor={AppColors.purple}>
276
- <View style={[detailStyles.jsonBlock, { marginLeft: 0, marginTop: 0, backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
277
- <JsonViewer data={{
278
- name: event.name,
279
- params: params,
280
- ...(upCount > 0
281
- ? {
282
- userProperties: userProperties,
283
- }
284
- : {}),
285
- }} search={search}/>
286
- </View>
287
- </SectionCard>)}
288
-
289
- {/* Empty state */}
290
- {paramCount === 0 && upCount === 0 && activeTab !== 'unformatted' && (<View style={[detailStyles.emptyParams, { backgroundColor: AppColors.primaryLight, borderColor: AppColors.grayBorderSecondary }]}>
291
- <Text style={[detailStyles.emptyParamsText, { color: AppColors.grayTextWeak }]}>
292
- No parameters recorded for this event
293
- </Text>
294
- </View>)}
295
80
  </ScrollView>);
296
81
  };
297
82
  const detailStyles = StyleSheet.create({
@@ -300,226 +85,12 @@ const detailStyles = StyleSheet.create({
300
85
  paddingTop: 0,
301
86
  paddingBottom: 40,
302
87
  },
303
- hero: {
304
- paddingTop: 0,
305
- paddingBottom: 16,
306
- paddingHorizontal: 0,
307
- gap: 8,
308
- marginTop: 0,
309
- marginBottom: 0,
310
- width: '100%',
311
- alignSelf: 'stretch',
312
- },
313
- searchRow: {
314
- paddingHorizontal: 16,
315
- marginVertical: 6,
316
- },
317
- sectionCard: {
318
- marginHorizontal: 0,
319
- borderRadius: 12,
320
- overflow: 'hidden',
321
- borderWidth: 1,
322
- borderColor: AppColors.grayBorderSecondary,
323
- backgroundColor: AppColors.primaryLight,
324
- shadowColor: '#000',
325
- shadowOpacity: 0.04,
326
- shadowRadius: 4,
327
- shadowOffset: { width: 0, height: 1 },
328
- elevation: 1,
329
- },
330
- sectionHeader: {
331
- flexDirection: 'row',
332
- alignItems: 'center',
333
- justifyContent: 'space-between',
334
- paddingHorizontal: 14,
335
- paddingVertical: 12,
336
- },
337
- sectionTitleRow: {
338
- flexDirection: 'row',
339
- alignItems: 'center',
340
- gap: 8,
341
- flex: 1,
342
- },
343
- sectionAccentDot: {
344
- width: 8,
345
- height: 8,
346
- borderRadius: 4,
347
- },
348
- sectionTitle: {
349
- fontFamily: AppFonts.interBold,
350
- fontSize: 13,
351
- color: AppColors.primaryBlack,
352
- },
353
- sectionActions: {
354
- flexDirection: 'row',
355
- alignItems: 'center',
356
- gap: 6,
357
- },
358
- countBadge: {
359
- paddingHorizontal: 7,
360
- paddingVertical: 2,
361
- borderRadius: 8,
362
- borderWidth: 1,
363
- },
364
- countBadgeText: {
365
- fontFamily: AppFonts.interBold,
366
- fontSize: 10,
367
- },
368
- paramList: {
369
- gap: 8,
370
- },
371
- emptyParams: {
372
- marginVertical: 12,
373
- paddingVertical: 18,
374
- paddingHorizontal: 14,
375
- borderRadius: 10,
376
- borderWidth: 1,
377
- borderColor: AppColors.grayBorderSecondary,
378
- backgroundColor: AppColors.primaryLight,
379
- alignItems: 'center',
380
- justifyContent: 'center',
381
- },
382
- emptyParamsText: {
383
- fontFamily: AppFonts.interMedium,
384
- fontSize: 13,
385
- color: AppColors.grayTextWeak,
386
- textAlign: 'center',
387
- lineHeight: 18,
388
- },
389
- dataBox: {
390
- backgroundColor: '#FFFFFF',
391
- borderRadius: 8,
392
- borderWidth: 1,
393
- borderColor: '#E5E7EB',
394
- padding: 12,
395
- },
396
- dataBoxHeader: {
397
- flexDirection: 'row',
398
- justifyContent: 'space-between',
399
- alignItems: 'center',
400
- marginBottom: 8,
401
- },
402
- dataBoxKey: {
403
- fontFamily: AppFonts.interBold,
404
- fontWeight: 'bold',
405
- fontSize: 13,
406
- color: AppColors.primaryBlack,
407
- flex: 1,
408
- paddingRight: 8,
409
- },
410
- dataBoxVal: {
411
- fontFamily: AppFonts.interRegular,
412
- fontSize: 13,
413
- color: AppColors.primaryBlack,
414
- lineHeight: 18,
415
- },
416
- showMoreBtn: {
88
+ jsonBlockContainer: {
89
+ marginHorizontal: 16,
417
90
  marginTop: 8,
418
- alignSelf: 'flex-start',
419
- backgroundColor: '#F3F4F6',
420
- paddingHorizontal: 10,
421
- paddingVertical: 4,
422
- borderRadius: 4,
423
- },
424
- showMoreText: {
425
- fontFamily: AppFonts.interMedium,
426
- fontSize: 11,
427
- color: '#4B5563', // matching previous UI color
428
- },
429
- jsonBlock: {
430
91
  padding: 12,
431
92
  borderWidth: 1,
432
- borderColor: '#E0E7FF',
433
- borderRadius: 8,
434
- backgroundColor: '#EEF2FF',
435
- },
436
- metricsScroll: {
437
- height: 92,
438
- overflow: 'visible',
439
- },
440
- metricsGrid: {
441
- gap: 8,
442
- marginTop: 4,
443
- paddingHorizontal: 16,
444
- paddingBottom: 14,
445
- },
446
- metricCard: {
447
- backgroundColor: '#FFFFFF',
448
- paddingVertical: 8,
449
- paddingHorizontal: 10,
450
- borderRadius: 6,
451
- borderLeftWidth: 3,
452
- width: 130, // fixed width for horizontal scrolling
453
- shadowColor: '#000',
454
- shadowOpacity: 0.04,
455
- shadowRadius: 4,
456
- shadowOffset: { width: 0, height: 2 },
457
- elevation: 2,
458
- alignItems: 'flex-start',
459
- },
460
- metricLabel: {
461
- fontFamily: AppFonts.interMedium,
462
- fontSize: 10,
463
- color: AppColors.grayTextWeak,
464
- textTransform: 'uppercase',
465
- marginBottom: 4,
466
- },
467
- metricValue: {
468
- fontFamily: AppFonts.interBold,
469
- fontSize: 13,
470
- },
471
- tabRow: {
472
- flexDirection: 'row',
473
- marginHorizontal: 16,
474
- marginTop: 6,
475
- backgroundColor: '#E5E7EB',
476
- borderRadius: 8,
477
- padding: 4,
478
- },
479
- tabButton: {
480
- flex: 1,
481
- flexDirection: 'row',
482
- alignItems: 'center',
483
- justifyContent: 'center',
484
- paddingVertical: 8,
485
- borderRadius: 6,
486
- gap: 6,
487
- },
488
- tabActive: {
489
- backgroundColor: '#FFFFFF',
490
- shadowColor: '#000',
491
- shadowOpacity: 0.1,
492
- shadowRadius: 2,
493
- shadowOffset: { width: 0, height: 1 },
494
- elevation: 2,
495
- },
496
- tabText: {
497
- fontFamily: AppFonts.interMedium,
498
- fontSize: 13,
499
- color: AppColors.grayTextWeak,
500
- },
501
- tabTextActive: {
502
- fontFamily: AppFonts.interBold,
503
- color: AppColors.primaryBlack,
504
- },
505
- tabBadge: {
506
- backgroundColor: '#D1D5DB',
507
- paddingHorizontal: 6,
508
- paddingVertical: 2,
509
- borderRadius: 10,
510
- },
511
- tabBadgeActive: {
512
- backgroundColor: AppColors.primaryLight,
513
- borderWidth: 1,
514
- borderColor: '#E5E7EB',
515
- },
516
- tabBadgeText: {
517
- fontFamily: AppFonts.interBold,
518
- fontSize: 10,
519
- color: '#6B7280',
520
- },
521
- tabBadgeTextActive: {
522
- color: AppColors.primaryBlack,
93
+ borderRadius: 12,
523
94
  },
524
95
  });
525
96
  export default AnalyticsDetail;
@@ -136,34 +136,34 @@ const AnalyticsEventCard = React.memo(function AnalyticsEventCard({ event, onPre
136
136
  {userPropCount > 0 && (<View style={[cardStyles.chip, { backgroundColor: AppColors.grayBackground, borderColor: AppColors.grayBorderSecondary }]}>
137
137
  <Text style={[cardStyles.chipText, { color: AppColors.grayText }]}>★ {userPropCount} props</Text>
138
138
  </View>)}
139
- </View>
140
139
 
141
- {/* Inline Mini Graph for E-commerce Items */}
142
- {(() => {
140
+ {(() => {
143
141
  const items = event.params?.items;
144
- if (!Array.isArray(items) || items.length === 0)
145
- return null;
146
- const prices = items
147
- .map((item) => parseFloat(item.price || item.value))
148
- .filter(p => !isNaN(p));
149
- if (prices.length === 0)
150
- return null;
151
- const max = Math.max(...prices);
152
- if (max === 0)
153
- return null;
154
- return (<View style={cardStyles.miniGraphWrapper}>
155
- {prices.map((val, idx) => {
156
- const hPct = (val / max) * 100;
157
- return (<View key={idx} style={[
158
- cardStyles.miniGraphBar,
159
- {
160
- height: `${Math.max(15, hPct)}%`,
161
- backgroundColor: color,
162
- },
163
- ]}/>);
164
- })}
165
- </View>);
142
+ if (Array.isArray(items) && items.length > 0) {
143
+ return (<View style={[cardStyles.chip, { backgroundColor: '#FEF3C7', borderColor: '#FDE68A' }]}>
144
+ <Text style={[cardStyles.chipText, { color: '#D97706', fontFamily: AppFonts.interBold }]}>
145
+ 🛒 {items.length} {items.length === 1 ? 'item' : 'items'}
146
+ </Text>
147
+ </View>);
148
+ }
149
+ return null;
150
+ })()}
151
+
152
+ {(() => {
153
+ const val = event.params?.value ?? event.params?.price;
154
+ const currency = event.params?.currency ?? '';
155
+ const isPrimitive = typeof val === 'string' || typeof val === 'number';
156
+ if (isPrimitive) {
157
+ const currencyStr = typeof currency === 'string' || typeof currency === 'number' ? String(currency) : '';
158
+ return (<View style={[cardStyles.chip, { backgroundColor: '#ECFDF5', borderColor: '#A7F3D0' }]}>
159
+ <Text style={[cardStyles.chipText, { color: '#059669', fontFamily: AppFonts.interBold }]}>
160
+ 💰 {String(val)} {currencyStr}
161
+ </Text>
162
+ </View>);
163
+ }
164
+ return null;
166
165
  })()}
166
+ </View>
167
167
  </View>
168
168
  </TouchableScale>
169
169
  </View>);
@@ -215,7 +215,9 @@ export const ConsoleLogCard = React.memo(function ConsoleLogCard({ item, searchS
215
215
  }).start();
216
216
  }, [chevronAnim, expanded]);
217
217
  const toggleExpanded = () => {
218
- LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
218
+ if (Platform.OS === 'ios') {
219
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
220
+ }
219
221
  setExpanded(prev => !prev);
220
222
  };
221
223
  const chevronRotate = chevronAnim.interpolate({
@@ -1,21 +1,7 @@
1
1
  import React from 'react';
2
2
  export declare const ReduxStoreIcon: ({ color, size, }: any) => React.JSX.Element;
3
- export declare const ReduxBoltIcon: ({ color, size, }: any) => React.JSX.Element;
4
- export declare const ReduxTimelineIcon: ({ color, size, }: any) => React.JSX.Element;
5
- export declare const ReduxTreeIcon: ({ color, size, }: any) => React.JSX.Element;
6
3
  export declare const ReduxTreeView: ({ state, lastActionMap, search, }: {
7
4
  state: any;
8
5
  lastActionMap: Record<string, any>;
9
6
  search?: string;
10
7
  }) => React.JSX.Element;
11
- export declare const ReduxActionTimeline: ({ history, onClear, search, }: {
12
- history: Array<{
13
- id: number;
14
- type: string;
15
- payload: any;
16
- timestamp: string;
17
- affectedSlices: string[];
18
- }>;
19
- onClear: () => void;
20
- search?: string;
21
- }) => React.JSX.Element;