react-native-inapp-inspector 2.3.14 → 2.3.16

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 (125) hide show
  1. package/README.md +1 -0
  2. package/dist/commonjs/components/AnimatedEntrance.js +3 -3
  3. package/dist/commonjs/components/ConsoleLogCard.js +174 -100
  4. package/dist/commonjs/components/Inspector/AnalyticsTab.js +0 -22
  5. package/dist/commonjs/components/Inspector/ConsoleTab.js +25 -38
  6. package/dist/commonjs/components/Inspector/CrashTab.js +19 -28
  7. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +198 -98
  8. package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +7 -0
  9. package/dist/commonjs/components/Inspector/FeedbackModal.js +552 -0
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +58 -6
  11. package/dist/commonjs/components/Inspector/MainScreen.js +100 -58
  12. package/dist/commonjs/components/Inspector/NetworkTab.js +26 -371
  13. package/dist/commonjs/components/Inspector/NpmStarPrompt.d.ts +3 -0
  14. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +494 -0
  15. package/dist/commonjs/components/Inspector/PerformanceTab.js +40 -7
  16. package/dist/commonjs/components/Inspector/ReduxTab.js +3 -23
  17. package/dist/commonjs/components/Inspector/SettingsPanel.js +1035 -173
  18. package/dist/commonjs/components/Inspector/StorageTab.js +23 -28
  19. package/dist/commonjs/components/Inspector/TabBar.js +50 -15
  20. package/dist/commonjs/components/JsonViewer.js +14 -2
  21. package/dist/commonjs/components/LogCard.js +428 -227
  22. package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
  23. package/dist/commonjs/components/NetworkIcons.js +33 -2
  24. package/dist/commonjs/constants/version.d.ts +1 -1
  25. package/dist/commonjs/constants/version.js +1 -1
  26. package/dist/commonjs/customHooks/analyticsLogger.js +1 -1
  27. package/dist/commonjs/customHooks/consoleLogger.js +34 -2
  28. package/dist/commonjs/customHooks/crashHandler.js +1 -1
  29. package/dist/commonjs/customHooks/networkLogger.js +184 -26
  30. package/dist/commonjs/helpers/index.d.ts +1 -0
  31. package/dist/commonjs/helpers/index.js +1 -0
  32. package/dist/commonjs/helpers/remoteConfig.d.ts +4 -0
  33. package/dist/commonjs/helpers/remoteConfig.js +165 -0
  34. package/dist/commonjs/helpers/searchQueryParser.d.ts +1 -1
  35. package/dist/commonjs/helpers/searchQueryParser.js +39 -291
  36. package/dist/commonjs/helpers/telemetry.d.ts +5 -0
  37. package/dist/commonjs/helpers/telemetry.js +339 -8
  38. package/dist/commonjs/index.d.ts +1 -0
  39. package/dist/commonjs/index.js +173 -29
  40. package/dist/commonjs/styles/AppFonts.d.ts +2 -0
  41. package/dist/commonjs/styles/AppFonts.js +1 -0
  42. package/dist/commonjs/styles/index.d.ts +22 -0
  43. package/dist/commonjs/styles/index.js +19 -0
  44. package/dist/commonjs/types/enums.d.ts +1 -0
  45. package/dist/commonjs/types/enums.js +1 -0
  46. package/dist/commonjs/types/interfaces.d.ts +12 -0
  47. package/dist/esm/components/AnimatedEntrance.js +3 -3
  48. package/dist/esm/components/ConsoleLogCard.js +141 -100
  49. package/dist/esm/components/Inspector/AnalyticsTab.js +1 -23
  50. package/dist/esm/components/Inspector/ConsoleTab.js +26 -39
  51. package/dist/esm/components/Inspector/CrashTab.js +20 -29
  52. package/dist/esm/components/Inspector/DeviceInfoTab.js +198 -98
  53. package/dist/esm/components/Inspector/FeedbackModal.d.ts +7 -0
  54. package/dist/esm/components/Inspector/FeedbackModal.js +515 -0
  55. package/dist/esm/components/Inspector/InspectorHeader.js +60 -8
  56. package/dist/esm/components/Inspector/MainScreen.js +101 -59
  57. package/dist/esm/components/Inspector/NetworkTab.js +27 -372
  58. package/dist/esm/components/Inspector/NpmStarPrompt.d.ts +3 -0
  59. package/dist/esm/components/Inspector/NpmStarPrompt.js +454 -0
  60. package/dist/esm/components/Inspector/PerformanceTab.js +40 -7
  61. package/dist/esm/components/Inspector/ReduxTab.js +4 -24
  62. package/dist/esm/components/Inspector/SettingsPanel.js +1038 -176
  63. package/dist/esm/components/Inspector/StorageTab.js +23 -28
  64. package/dist/esm/components/Inspector/TabBar.js +50 -15
  65. package/dist/esm/components/JsonViewer.js +14 -2
  66. package/dist/esm/components/LogCard.js +422 -221
  67. package/dist/esm/components/NetworkIcons.d.ts +5 -0
  68. package/dist/esm/components/NetworkIcons.js +26 -0
  69. package/dist/esm/constants/version.d.ts +1 -1
  70. package/dist/esm/constants/version.js +1 -1
  71. package/dist/esm/customHooks/analyticsLogger.js +1 -1
  72. package/dist/esm/customHooks/consoleLogger.js +34 -2
  73. package/dist/esm/customHooks/crashHandler.js +1 -1
  74. package/dist/esm/customHooks/networkLogger.js +184 -26
  75. package/dist/esm/helpers/index.d.ts +1 -0
  76. package/dist/esm/helpers/index.js +1 -0
  77. package/dist/esm/helpers/remoteConfig.d.ts +4 -0
  78. package/dist/esm/helpers/remoteConfig.js +160 -0
  79. package/dist/esm/helpers/searchQueryParser.d.ts +1 -1
  80. package/dist/esm/helpers/searchQueryParser.js +39 -291
  81. package/dist/esm/helpers/telemetry.d.ts +5 -0
  82. package/dist/esm/helpers/telemetry.js +332 -9
  83. package/dist/esm/index.d.ts +1 -0
  84. package/dist/esm/index.js +171 -29
  85. package/dist/esm/styles/AppFonts.d.ts +2 -0
  86. package/dist/esm/styles/AppFonts.js +1 -0
  87. package/dist/esm/styles/index.d.ts +22 -0
  88. package/dist/esm/styles/index.js +19 -0
  89. package/dist/esm/types/enums.d.ts +1 -0
  90. package/dist/esm/types/enums.js +1 -0
  91. package/dist/esm/types/interfaces.d.ts +12 -0
  92. package/package.json +1 -1
  93. package/src/components/AnimatedEntrance.tsx +3 -3
  94. package/src/components/ConsoleLogCard.tsx +154 -103
  95. package/src/components/Inspector/AnalyticsTab.tsx +0 -23
  96. package/src/components/Inspector/ConsoleTab.tsx +27 -41
  97. package/src/components/Inspector/CrashTab.tsx +19 -28
  98. package/src/components/Inspector/DeviceInfoTab.tsx +224 -102
  99. package/src/components/Inspector/FeedbackModal.tsx +626 -0
  100. package/src/components/Inspector/InspectorHeader.tsx +83 -5
  101. package/src/components/Inspector/MainScreen.tsx +61 -6
  102. package/src/components/Inspector/NetworkTab.tsx +70 -480
  103. package/src/components/Inspector/NpmStarPrompt.tsx +532 -0
  104. package/src/components/Inspector/PerformanceTab.tsx +44 -8
  105. package/src/components/Inspector/ReduxTab.tsx +9 -24
  106. package/src/components/Inspector/SettingsPanel.tsx +1162 -197
  107. package/src/components/Inspector/StorageTab.tsx +27 -30
  108. package/src/components/Inspector/TabBar.tsx +57 -20
  109. package/src/components/JsonViewer.tsx +15 -2
  110. package/src/components/LogCard.tsx +528 -339
  111. package/src/components/NetworkIcons.tsx +92 -0
  112. package/src/constants/version.ts +1 -1
  113. package/src/customHooks/analyticsLogger.ts +1 -1
  114. package/src/customHooks/consoleLogger.ts +36 -3
  115. package/src/customHooks/crashHandler.ts +1 -1
  116. package/src/customHooks/networkLogger.ts +214 -26
  117. package/src/helpers/index.ts +1 -0
  118. package/src/helpers/remoteConfig.ts +212 -0
  119. package/src/helpers/searchQueryParser.ts +42 -284
  120. package/src/helpers/telemetry.ts +381 -10
  121. package/src/index.tsx +374 -211
  122. package/src/styles/AppFonts.ts +2 -0
  123. package/src/styles/index.ts +20 -1
  124. package/src/types/enums.ts +1 -0
  125. package/src/types/interfaces.ts +12 -0
@@ -0,0 +1,515 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Alert, Dimensions, PixelRatio, Platform, Linking, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native';
3
+ import { AppColors } from '../../styles/AppColors';
4
+ import { AppFonts } from '../../styles/AppFonts';
5
+ import { LIB_VERSION } from '../../constants/version';
6
+ import { getAppName, getBundleIdentifier, getAppVersionAndBuild, copyToClipboard, showToast, } from '../../helpers';
7
+ import { trackTelemetryEvent } from '../../helpers/telemetry';
8
+ import { HeadphonesIcon, SendIcon, StarIcon, CopyIcon, InfoCircleIcon, CheckIcon, } from '../NetworkIcons';
9
+ const DEVELOPER_EMAIL = 'vengatmacuser@gmail.com';
10
+ const CATEGORIES = [
11
+ { key: 'feedback', label: 'Feedback', icon: '💬' },
12
+ { key: 'bug', label: 'Bug Report', icon: '🐛' },
13
+ { key: 'feature', label: 'Feature Request', icon: '✨' },
14
+ { key: 'performance', label: 'Performance', icon: '⚡' },
15
+ { key: 'help', label: 'Support / Help', icon: '❓' },
16
+ ];
17
+ const RATING_LABELS = ['', 'Poor', 'Fair', 'Good', 'Very Good', 'Excellent!'];
18
+ export const FeedbackModal = ({ onClose }) => {
19
+ const [category, setCategory] = useState('feedback');
20
+ const [rating, setRating] = useState(5);
21
+ const [subject, setSubject] = useState('');
22
+ const [message, setMessage] = useState('');
23
+ const [showDiagnostics, setShowDiagnostics] = useState(false);
24
+ const [isSending, setIsSending] = useState(false);
25
+ const [copiedDraft, setCopiedDraft] = useState(false);
26
+ useEffect(() => {
27
+ trackTelemetryEvent('feedback_modal_opened', { category });
28
+ }, []);
29
+ const appName = getAppName() || 'React Native App';
30
+ const bundleId = getBundleIdentifier() || 'unknown';
31
+ const appVersion = getAppVersionAndBuild() || '1.0.0';
32
+ const { width, height } = Dimensions.get('window');
33
+ const getDiagnosticsText = () => {
34
+ return [
35
+ `• Package: react-native-inapp-inspector@${LIB_VERSION}`,
36
+ `• Platform: ${Platform.OS.toUpperCase()} (${Platform.Version})`,
37
+ `• App: ${appName} (${bundleId}) v${appVersion}`,
38
+ `• Screen: ${Math.round(width)} x ${Math.round(height)} (Scale ${PixelRatio.get()})`,
39
+ `• Timestamp: ${new Date().toISOString()}`,
40
+ ].join('\n');
41
+ };
42
+ const buildEmailDraft = () => {
43
+ const activeCat = CATEGORIES.find(c => c.key === category)?.label || category;
44
+ const emailSubject = `[In-App Inspector] [${activeCat}] ${subject.trim() || 'User Feedback'}`;
45
+ const bodyLines = [
46
+ `Category: ${activeCat}`,
47
+ `Rating: ${rating} / 5 (${RATING_LABELS[rating] || ''})`,
48
+ ...(subject.trim() ? [`Subject: ${subject.trim()}`] : []),
49
+ '',
50
+ 'Feedback / Message:',
51
+ message.trim() || '(No message provided)',
52
+ '',
53
+ '----------------------------------------',
54
+ 'System & Diagnostic Info:',
55
+ getDiagnosticsText(),
56
+ '----------------------------------------',
57
+ ];
58
+ return {
59
+ activeCat,
60
+ subject: emailSubject,
61
+ body: bodyLines.join('\n'),
62
+ };
63
+ };
64
+ const handleCopyDraft = () => {
65
+ const draft = buildEmailDraft();
66
+ const fullText = `To: ${DEVELOPER_EMAIL}\nSubject: ${draft.subject}\n\n${draft.body}`;
67
+ copyToClipboard(fullText, 'Email Draft & Diagnostics');
68
+ setCopiedDraft(true);
69
+ setTimeout(() => setCopiedDraft(false), 2000);
70
+ showToast('Feedback draft copied to clipboard');
71
+ };
72
+ const handleSendEmail = async () => {
73
+ if (isSending)
74
+ return;
75
+ setIsSending(true);
76
+ try {
77
+ const draft = buildEmailDraft();
78
+ const mailtoUrl = `mailto:${DEVELOPER_EMAIL}?subject=${encodeURIComponent(draft.subject)}&body=${encodeURIComponent(draft.body)}`;
79
+ trackTelemetryEvent('feedback_submitted', {
80
+ category,
81
+ rating,
82
+ has_subject: Boolean(subject.trim()),
83
+ has_message: Boolean(message.trim()),
84
+ });
85
+ let opened = false;
86
+ try {
87
+ const canOpen = await Linking.canOpenURL(mailtoUrl);
88
+ if (canOpen) {
89
+ await Linking.openURL(mailtoUrl);
90
+ opened = true;
91
+ }
92
+ else {
93
+ await Linking.openURL(mailtoUrl);
94
+ opened = true;
95
+ }
96
+ }
97
+ catch (err) {
98
+ opened = false;
99
+ }
100
+ if (opened) {
101
+ showToast('Opening mail client...');
102
+ onClose();
103
+ }
104
+ else {
105
+ const fullDraft = `To: ${DEVELOPER_EMAIL}\nSubject: ${draft.subject}\n\n${draft.body}`;
106
+ copyToClipboard(fullDraft, 'Feedback Draft');
107
+ Alert.alert('Email Client Not Available', `Your feedback and diagnostics have been copied to the clipboard!\n\nYou can paste and send directly to:\n${DEVELOPER_EMAIL}`, [
108
+ {
109
+ text: 'Copy Email Address',
110
+ onPress: () => {
111
+ copyToClipboard(DEVELOPER_EMAIL, 'Email Address');
112
+ showToast('Email address copied!');
113
+ },
114
+ },
115
+ {
116
+ text: 'Done',
117
+ style: 'default',
118
+ onPress: onClose,
119
+ },
120
+ ]);
121
+ }
122
+ }
123
+ catch (err) {
124
+ console.warn('[FeedbackModal] Error sending email:', err);
125
+ }
126
+ finally {
127
+ setIsSending(false);
128
+ }
129
+ };
130
+ return (<View style={styles.container}>
131
+
132
+ <View style={styles.bannerBar}>
133
+ <View style={styles.bannerIconBox}>
134
+ <HeadphonesIcon size={18} color={AppColors.purple}/>
135
+ </View>
136
+ <View style={{ flex: 1 }}>
137
+ <Text style={styles.bannerTitle}>Share your feedback or report an issue</Text>
138
+ <Text style={styles.bannerSub}>
139
+ Direct communication with the maintainers. Diagnostic info is auto-attached.
140
+ </Text>
141
+ </View>
142
+ </View>
143
+
144
+ <ScrollView style={styles.scrollContent} contentContainerStyle={styles.scrollInner} showsVerticalScrollIndicator={false} keyboardShouldPersistTaps="handled">
145
+
146
+ <Text style={styles.sectionLabel}>WHAT CAN WE HELP WITH?</Text>
147
+ <View style={styles.categoryGrid}>
148
+ {CATEGORIES.map(cat => {
149
+ const isSelected = category === cat.key;
150
+ return (<TouchableOpacity key={cat.key} activeOpacity={0.7} onPress={() => setCategory(cat.key)} style={[
151
+ styles.categoryChip,
152
+ isSelected && styles.categoryChipSelected,
153
+ ]}>
154
+ <Text style={styles.categoryIcon}>{cat.icon}</Text>
155
+ <Text style={[
156
+ styles.categoryText,
157
+ isSelected && styles.categoryTextSelected,
158
+ ]}>
159
+ {cat.label}
160
+ </Text>
161
+ </TouchableOpacity>);
162
+ })}
163
+ </View>
164
+
165
+
166
+ <View style={styles.ratingCard}>
167
+ <View style={styles.ratingHeader}>
168
+ <Text style={styles.ratingTitle}>Rate your experience</Text>
169
+ {rating > 0 && (<Text style={styles.ratingBadge}>
170
+ {RATING_LABELS[rating]}
171
+ </Text>)}
172
+ </View>
173
+ <View style={styles.starsRow}>
174
+ {[1, 2, 3, 4, 5].map(star => {
175
+ const filled = star <= rating;
176
+ return (<TouchableOpacity key={star} activeOpacity={0.7} onPress={() => setRating(star)} style={styles.starTouch}>
177
+ <StarIcon size={26} color={filled ? '#FFB800' : AppColors.grayTextWeak}/>
178
+ </TouchableOpacity>);
179
+ })}
180
+ </View>
181
+ </View>
182
+
183
+
184
+ <Text style={styles.sectionLabel}>SUBJECT (OPTIONAL)</Text>
185
+ <View style={styles.inputWrapper}>
186
+ <TextInput style={styles.textInput} placeholder="Brief summary..." placeholderTextColor={AppColors.grayTextWeak} value={subject} onChangeText={setSubject} maxLength={80}/>
187
+ </View>
188
+
189
+
190
+ <Text style={styles.sectionLabel}>YOUR MESSAGE / DETAILS</Text>
191
+ <View style={[styles.inputWrapper, styles.textareaWrapper]}>
192
+ <TextInput style={[styles.textInput, styles.textarea]} placeholder="Describe your issue, feature request, or suggestion in detail..." placeholderTextColor={AppColors.grayTextWeak} value={message} onChangeText={setMessage} multiline numberOfLines={4} textAlignVertical="top"/>
193
+ </View>
194
+
195
+
196
+ <TouchableOpacity activeOpacity={0.8} onPress={() => setShowDiagnostics(!showDiagnostics)} style={styles.diagnosticsToggle}>
197
+ <View style={styles.diagnosticsHeader}>
198
+ <InfoCircleIcon size={14} color={AppColors.purple}/>
199
+ <Text style={styles.diagnosticsTitle}>
200
+ Diagnostics & System Details (Auto-attached)
201
+ </Text>
202
+ </View>
203
+ <Text style={styles.diagnosticsArrow}>
204
+ {showDiagnostics ? '▲' : '▼'}
205
+ </Text>
206
+ </TouchableOpacity>
207
+
208
+ {showDiagnostics && (<View style={styles.diagnosticsBox}>
209
+ <Text style={styles.diagnosticsText}>
210
+ {getDiagnosticsText()}
211
+ </Text>
212
+ </View>)}
213
+
214
+
215
+ <View style={styles.recipientBadge}>
216
+ <Text style={styles.recipientText}>
217
+ 📧 Emails to: <Text style={styles.recipientHighlight}>{DEVELOPER_EMAIL}</Text>
218
+ </Text>
219
+ </View>
220
+ </ScrollView>
221
+
222
+
223
+ <View style={styles.footer}>
224
+ <TouchableOpacity activeOpacity={0.7} onPress={handleCopyDraft} style={styles.copyDraftBtn}>
225
+ {copiedDraft ? (<CheckIcon size={14} color={AppColors.emerald500}/>) : (<CopyIcon size={14} color={AppColors.grayText}/>)}
226
+ <Text style={[
227
+ styles.copyDraftBtnText,
228
+ copiedDraft && { color: AppColors.emerald500 },
229
+ ]}>
230
+ {copiedDraft ? 'Copied!' : 'Copy Draft'}
231
+ </Text>
232
+ </TouchableOpacity>
233
+
234
+ <View style={styles.footerRight}>
235
+ <TouchableOpacity activeOpacity={0.7} onPress={onClose} style={styles.cancelBtn}>
236
+ <Text style={styles.cancelBtnText}>Cancel</Text>
237
+ </TouchableOpacity>
238
+
239
+ <TouchableOpacity activeOpacity={0.8} onPress={handleSendEmail} style={styles.submitBtn}>
240
+ <SendIcon size={16} color={AppColors.white}/>
241
+ <Text style={styles.submitBtnText}>
242
+ {isSending ? 'Sending...' : 'Send via Email'}
243
+ </Text>
244
+ </TouchableOpacity>
245
+ </View>
246
+ </View>
247
+ </View>);
248
+ };
249
+ const styles = StyleSheet.create({
250
+ container: {
251
+ flex: 1,
252
+ backgroundColor: AppColors.primaryLight,
253
+ },
254
+ bannerBar: {
255
+ flexDirection: 'row',
256
+ alignItems: 'center',
257
+ gap: 10,
258
+ backgroundColor: `${AppColors.purple}12`,
259
+ paddingHorizontal: 14,
260
+ paddingVertical: 10,
261
+ borderBottomWidth: 1,
262
+ borderBottomColor: `${AppColors.purple}20`,
263
+ },
264
+ bannerIconBox: {
265
+ width: 32,
266
+ height: 32,
267
+ borderRadius: 8,
268
+ backgroundColor: `${AppColors.purple}20`,
269
+ alignItems: 'center',
270
+ justifyContent: 'center',
271
+ },
272
+ bannerTitle: {
273
+ fontFamily: AppFonts.interSemiBold,
274
+ fontSize: 12.5,
275
+ color: AppColors.purple,
276
+ },
277
+ bannerSub: {
278
+ fontFamily: AppFonts.interRegular,
279
+ fontSize: 10.5,
280
+ color: AppColors.grayText,
281
+ marginTop: 1,
282
+ },
283
+ scrollContent: {
284
+ flex: 1,
285
+ },
286
+ scrollInner: {
287
+ paddingHorizontal: 16,
288
+ paddingTop: 12,
289
+ paddingBottom: 20,
290
+ },
291
+ sectionLabel: {
292
+ fontFamily: AppFonts.interSemiBold,
293
+ fontSize: 10.5,
294
+ color: AppColors.grayText,
295
+ letterSpacing: 0.8,
296
+ marginBottom: 8,
297
+ marginTop: 10,
298
+ },
299
+ categoryGrid: {
300
+ flexDirection: 'row',
301
+ flexWrap: 'wrap',
302
+ gap: 8,
303
+ paddingBottom: 4,
304
+ },
305
+ categoryChip: {
306
+ flexDirection: 'row',
307
+ alignItems: 'center',
308
+ gap: 6,
309
+ paddingVertical: 7,
310
+ paddingHorizontal: 12,
311
+ borderRadius: 8,
312
+ backgroundColor: AppColors.grayBackground,
313
+ borderWidth: 1,
314
+ borderColor: AppColors.dividerColor,
315
+ },
316
+ categoryChipSelected: {
317
+ backgroundColor: `${AppColors.purple}15`,
318
+ borderColor: AppColors.purple,
319
+ },
320
+ categoryIcon: {
321
+ fontSize: 13,
322
+ },
323
+ categoryText: {
324
+ fontFamily: AppFonts.interMedium,
325
+ fontSize: 12,
326
+ color: AppColors.grayText,
327
+ },
328
+ categoryTextSelected: {
329
+ color: AppColors.purple,
330
+ fontFamily: AppFonts.interSemiBold,
331
+ },
332
+ ratingCard: {
333
+ backgroundColor: AppColors.grayBackground,
334
+ borderRadius: 12,
335
+ padding: 12,
336
+ marginTop: 12,
337
+ borderWidth: 1,
338
+ borderColor: AppColors.dividerColor,
339
+ },
340
+ ratingHeader: {
341
+ flexDirection: 'row',
342
+ justifyContent: 'space-between',
343
+ alignItems: 'center',
344
+ marginBottom: 8,
345
+ },
346
+ ratingTitle: {
347
+ fontFamily: AppFonts.interSemiBold,
348
+ fontSize: 12.5,
349
+ color: AppColors.primaryBlack,
350
+ },
351
+ ratingBadge: {
352
+ fontFamily: AppFonts.interSemiBold,
353
+ fontSize: 11,
354
+ color: '#D97706',
355
+ backgroundColor: '#FEF3C7',
356
+ paddingHorizontal: 8,
357
+ paddingVertical: 2,
358
+ borderRadius: 6,
359
+ },
360
+ starsRow: {
361
+ flexDirection: 'row',
362
+ alignItems: 'center',
363
+ gap: 12,
364
+ paddingVertical: 4,
365
+ },
366
+ starTouch: {
367
+ padding: 2,
368
+ },
369
+ inputWrapper: {
370
+ backgroundColor: AppColors.grayBackground,
371
+ borderRadius: 10,
372
+ borderWidth: 1,
373
+ borderColor: AppColors.dividerColor,
374
+ paddingHorizontal: 12,
375
+ paddingVertical: 8,
376
+ },
377
+ textareaWrapper: {
378
+ minHeight: 88,
379
+ paddingVertical: 10,
380
+ },
381
+ textInput: {
382
+ fontFamily: AppFonts.interRegular,
383
+ fontSize: 13,
384
+ color: AppColors.primaryBlack,
385
+ padding: 0,
386
+ },
387
+ textarea: {
388
+ height: 72,
389
+ },
390
+ diagnosticsToggle: {
391
+ flexDirection: 'row',
392
+ alignItems: 'center',
393
+ justifyContent: 'space-between',
394
+ backgroundColor: `${AppColors.purple}10`,
395
+ borderRadius: 8,
396
+ paddingHorizontal: 12,
397
+ paddingVertical: 9,
398
+ marginTop: 14,
399
+ borderWidth: 1,
400
+ borderColor: `${AppColors.purple}25`,
401
+ },
402
+ diagnosticsHeader: {
403
+ flexDirection: 'row',
404
+ alignItems: 'center',
405
+ gap: 8,
406
+ flex: 1,
407
+ },
408
+ diagnosticsTitle: {
409
+ fontFamily: AppFonts.interMedium,
410
+ fontSize: 11.5,
411
+ color: AppColors.purple,
412
+ },
413
+ diagnosticsArrow: {
414
+ fontSize: 10,
415
+ color: AppColors.purple,
416
+ },
417
+ diagnosticsBox: {
418
+ backgroundColor: '#1E1B2E',
419
+ borderRadius: 8,
420
+ padding: 10,
421
+ marginTop: 6,
422
+ borderWidth: 1,
423
+ borderColor: AppColors.dividerColor,
424
+ },
425
+ diagnosticsText: {
426
+ fontFamily: AppFonts.interRegular,
427
+ fontSize: 11,
428
+ color: '#E2DFEB',
429
+ lineHeight: 17,
430
+ },
431
+ recipientBadge: {
432
+ marginTop: 12,
433
+ paddingVertical: 6,
434
+ paddingHorizontal: 10,
435
+ borderRadius: 6,
436
+ backgroundColor: AppColors.grayBackground,
437
+ borderWidth: 1,
438
+ borderColor: AppColors.dividerColor,
439
+ alignSelf: 'flex-start',
440
+ },
441
+ recipientText: {
442
+ fontFamily: AppFonts.interRegular,
443
+ fontSize: 11,
444
+ color: AppColors.grayText,
445
+ },
446
+ recipientHighlight: {
447
+ fontFamily: AppFonts.interSemiBold,
448
+ color: AppColors.purple,
449
+ },
450
+ footer: {
451
+ flexDirection: 'row',
452
+ alignItems: 'center',
453
+ justifyContent: 'space-between',
454
+ paddingHorizontal: 14,
455
+ paddingTop: 10,
456
+ paddingBottom: 14,
457
+ borderTopWidth: 1,
458
+ borderTopColor: AppColors.dividerColor,
459
+ backgroundColor: AppColors.primaryLight,
460
+ },
461
+ copyDraftBtn: {
462
+ flexDirection: 'row',
463
+ alignItems: 'center',
464
+ gap: 5,
465
+ paddingVertical: 8,
466
+ paddingHorizontal: 10,
467
+ borderRadius: 8,
468
+ backgroundColor: AppColors.grayBackground,
469
+ borderWidth: 1,
470
+ borderColor: AppColors.dividerColor,
471
+ },
472
+ copyDraftBtnText: {
473
+ fontFamily: AppFonts.interMedium,
474
+ fontSize: 11.5,
475
+ color: AppColors.grayText,
476
+ },
477
+ footerRight: {
478
+ flexDirection: 'row',
479
+ alignItems: 'center',
480
+ gap: 8,
481
+ },
482
+ cancelBtn: {
483
+ paddingVertical: 8,
484
+ paddingHorizontal: 14,
485
+ borderRadius: 8,
486
+ backgroundColor: AppColors.grayBackground,
487
+ borderWidth: 1,
488
+ borderColor: AppColors.dividerColor,
489
+ },
490
+ cancelBtnText: {
491
+ fontFamily: AppFonts.interMedium,
492
+ fontSize: 12.5,
493
+ color: AppColors.grayText,
494
+ },
495
+ submitBtn: {
496
+ flexDirection: 'row',
497
+ alignItems: 'center',
498
+ gap: 6,
499
+ backgroundColor: AppColors.purple,
500
+ paddingVertical: 8,
501
+ paddingHorizontal: 15,
502
+ borderRadius: 8,
503
+ shadowColor: AppColors.purple,
504
+ shadowOffset: { width: 0, height: 2 },
505
+ shadowOpacity: 0.35,
506
+ shadowRadius: 6,
507
+ elevation: 4,
508
+ },
509
+ submitBtnText: {
510
+ fontFamily: AppFonts.interSemiBold,
511
+ fontSize: 12.5,
512
+ color: AppColors.white,
513
+ },
514
+ });
515
+ export default FeedbackModal;
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo } from 'react';
2
- import { Alert, Animated, Linking, Platform, Pressable, ScrollView, Text, useWindowDimensions, View, } from 'react-native';
2
+ import { Alert, Animated, Linking, Platform, Pressable, ScrollView, Text, TouchableOpacity, useWindowDimensions, View, } from 'react-native';
3
3
  import LinearGradient from 'react-native-linear-gradient';
4
4
  import { useInspector } from './InspectorContext';
5
5
  import TouchableScale from '../TouchableScale';
@@ -12,9 +12,9 @@ import { LIB_VERSION } from '../../constants';
12
12
  import { getStatusColor, getAppName, formatTime, getSize, getAppVersionAndBuild, } from '../../helpers';
13
13
  import { getNativeDeviceMetrics } from '../../native/NativeInspector';
14
14
  import { UpdateAvailableModal } from './UpdateAvailableModal';
15
- import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ClockIcon, SizeIcon, AppleIcon, AndroidIcon, NpmIcon, ResetIcon, BoltIcon, } from '../NetworkIcons';
15
+ import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ClockIcon, SizeIcon, AppleIcon, AndroidIcon, NpmIcon, ResetIcon, BoltIcon, InfoCircleIcon, } from '../NetworkIcons';
16
16
  const InspectorHeader = React.memo(() => {
17
- const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, settingsPage, setSettingsPage, resetToDefaults, closeModal, detailTitle, activeTab, environment, visible, selectedCrash, setSelectedCrash, } = useInspector();
17
+ const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, settingsPage, setSettingsPage, setSettingsActiveSubTab, isFeedbackOpen, setIsFeedbackOpen, resetToDefaults, closeModal, detailTitle, activeTab, environment, visible, selectedCrash, setSelectedCrash, } = useInspector();
18
18
  const { width: windowWidth } = useWindowDimensions();
19
19
  const isNarrow = windowWidth < 360;
20
20
  const isCompact = windowWidth < 400;
@@ -75,7 +75,7 @@ const InspectorHeader = React.memo(() => {
75
75
  (selectedReduxSlice != null || selectedReduxAction != null)) ||
76
76
  (activeTab === 'crash' && selectedCrash != null);
77
77
  const isSettingsView = settingsPage !== null;
78
- const isAnySelected = isDetailView || isSettingsView;
78
+ const isAnySelected = isDetailView || isSettingsView || isFeedbackOpen;
79
79
  const settingsModuleTitle = useMemo(() => {
80
80
  switch (settingsPage) {
81
81
  case 'apis':
@@ -121,6 +121,10 @@ const InspectorHeader = React.memo(() => {
121
121
  },
122
122
  ]}>
123
123
  <TouchableScale onPress={() => {
124
+ if (isFeedbackOpen) {
125
+ setIsFeedbackOpen(false);
126
+ return;
127
+ }
124
128
  if (isSettingsView) {
125
129
  if (settingsPage === 'main') {
126
130
  setSettingsPage(null);
@@ -161,7 +165,41 @@ const InspectorHeader = React.memo(() => {
161
165
  <WhiteBackNavigation />
162
166
  </TouchableScale>
163
167
 
164
- {isSettingsView ? (<View style={{ gap: 2, flex: 1, minWidth: 0 }}>
168
+ {isFeedbackOpen ? (<View style={{ gap: 2, flex: 1, minWidth: 0 }}>
169
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
170
+ <Text style={{
171
+ fontFamily: AppFonts.interBold,
172
+ fontSize: isNarrow ? 14 : 16,
173
+ color: AppColors.white,
174
+ letterSpacing: -0.2,
175
+ }} numberOfLines={1}>
176
+ Support & Feedback
177
+ </Text>
178
+ <View style={{
179
+ backgroundColor: `${AppColors.white}26`,
180
+ paddingHorizontal: isNarrow ? 4 : 6,
181
+ paddingVertical: 1.5,
182
+ borderRadius: 10,
183
+ borderWidth: 1,
184
+ borderColor: `${AppColors.white}20`,
185
+ }}>
186
+ <Text style={{
187
+ fontFamily: AppFonts.interBold,
188
+ fontSize: isNarrow ? 8 : 9,
189
+ color: AppColors.white,
190
+ }}>
191
+ v{LIB_VERSION}
192
+ </Text>
193
+ </View>
194
+ </View>
195
+ <Text style={{
196
+ fontFamily: AppFonts.interRegular,
197
+ fontSize: isNarrow ? 9.5 : 10.5,
198
+ color: `${AppColors.white}CC`,
199
+ }} numberOfLines={1}>
200
+ Direct line to maintainers & developers
201
+ </Text>
202
+ </View>) : isSettingsView ? (<View style={{ gap: 2, flex: 1, minWidth: 0 }}>
165
203
  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
166
204
  <Text style={{
167
205
  fontFamily: AppFonts.interBold,
@@ -753,7 +791,7 @@ const InspectorHeader = React.memo(() => {
753
791
  </Animated.View>
754
792
  </TouchableScale>)}
755
793
 
756
- {!isAnySelected && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
794
+ {!isAnySelected && (<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Settings" onPress={() => setSettingsPage('main')} hitSlop={15} style={[
757
795
  styles.closeButtonSquare,
758
796
  {
759
797
  width: buttonSize,
@@ -764,7 +802,21 @@ const InspectorHeader = React.memo(() => {
764
802
  <SettingsIcon color={AppColors.white} size={isNarrow ? 12 : 14}/>
765
803
  </TouchableScale>)}
766
804
 
767
- <TouchableScale onPress={closeModal} hitSlop={15} style={[
805
+ {!isAnySelected && (<TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="About and System Specifications" onPress={() => {
806
+ setSettingsActiveSubTab('about');
807
+ setSettingsPage('main');
808
+ }} hitSlop={15} style={[
809
+ styles.closeButtonSquare,
810
+ {
811
+ width: buttonSize,
812
+ height: buttonSize,
813
+ borderRadius: isNarrow ? 6 : 7,
814
+ },
815
+ ]}>
816
+ <InfoCircleIcon color={AppColors.white} size={isNarrow ? 12 : 14}/>
817
+ </TouchableScale>)}
818
+
819
+ <TouchableOpacity onPress={closeModal} hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }} activeOpacity={0.6} style={[
768
820
  styles.closeButtonSquare,
769
821
  {
770
822
  width: buttonSize,
@@ -773,7 +825,7 @@ const InspectorHeader = React.memo(() => {
773
825
  },
774
826
  ]}>
775
827
  <CloseWhite size={isNarrow ? 12 : 14}/>
776
- </TouchableScale>
828
+ </TouchableOpacity>
777
829
  </View>
778
830
  </View>
779
831
  </View>