@mushi-mushi/react-native 0.23.0 → 0.24.1
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.
- package/README.md +4 -4
- package/dist/index.cjs +904 -503
- package/dist/index.d.cts +115 -7
- package/dist/index.d.ts +115 -7
- package/dist/index.js +726 -317
- package/package.json +4 -10
package/dist/index.cjs
CHANGED
|
@@ -48,12 +48,184 @@ __export(index_exports, {
|
|
|
48
48
|
module.exports = __toCommonJS(index_exports);
|
|
49
49
|
|
|
50
50
|
// src/provider.tsx
|
|
51
|
-
var
|
|
52
|
-
var
|
|
53
|
-
var
|
|
51
|
+
var import_react5 = require("react");
|
|
52
|
+
var import_react_native6 = require("react-native");
|
|
53
|
+
var import_core10 = require("@mushi-mushi/core");
|
|
54
|
+
var import_reporter_channels2 = require("@mushi-mushi/core/reporter-channels");
|
|
55
|
+
var import_reporter_ui3 = require("@mushi-mushi/core/reporter-ui");
|
|
54
56
|
|
|
55
|
-
// src/
|
|
57
|
+
// src/storage/reporter-flags.ts
|
|
58
|
+
async function readReporterFlag(projectId, flag) {
|
|
59
|
+
try {
|
|
60
|
+
const store = (await import("@react-native-async-storage/async-storage")).default;
|
|
61
|
+
return await store.getItem(`@mushi:${flag}:${projectId}`);
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function writeReporterFlag(projectId, flag, value) {
|
|
67
|
+
try {
|
|
68
|
+
const store = (await import("@react-native-async-storage/async-storage")).default;
|
|
69
|
+
await store.setItem(`@mushi:${flag}:${projectId}`, value);
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/components/MushiUpdateToast.tsx
|
|
75
|
+
var import_react = require("react");
|
|
76
|
+
var import_react_native = require("react-native");
|
|
77
|
+
var import_core2 = require("@mushi-mushi/core");
|
|
78
|
+
var import_reporter_ui = require("@mushi-mushi/core/reporter-ui");
|
|
79
|
+
|
|
80
|
+
// src/theme.ts
|
|
56
81
|
var import_core = require("@mushi-mushi/core");
|
|
82
|
+
function hexToRgb(hex) {
|
|
83
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})([0-9a-f]{2})?$/i.exec(hex.trim());
|
|
84
|
+
if (!m) return null;
|
|
85
|
+
const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
|
|
86
|
+
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
87
|
+
}
|
|
88
|
+
function luminance([r, g, b]) {
|
|
89
|
+
const lin = (c) => {
|
|
90
|
+
const s5 = c / 255;
|
|
91
|
+
return s5 <= 0.03928 ? s5 / 12.92 : ((s5 + 0.055) / 1.055) ** 2.4;
|
|
92
|
+
};
|
|
93
|
+
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
94
|
+
}
|
|
95
|
+
function contrastingText(bg, fallback) {
|
|
96
|
+
const rgb = hexToRgb(bg);
|
|
97
|
+
if (!rgb) return fallback;
|
|
98
|
+
const l = luminance(rgb);
|
|
99
|
+
return 1.05 / (l + 0.05) >= (l + 0.05) / 0.05 ? "#FFFFFF" : "#000000";
|
|
100
|
+
}
|
|
101
|
+
function resolveRNTheme(dark, override = {}) {
|
|
102
|
+
const pal = (0, import_core.mushiPalette)(dark ? "dark" : "light");
|
|
103
|
+
const base = {
|
|
104
|
+
bg: dark ? pal.paper : pal.paperRaised,
|
|
105
|
+
fg: pal.ink,
|
|
106
|
+
muted: pal.inkMuted,
|
|
107
|
+
surface: dark ? pal.paperRaised : pal.paper,
|
|
108
|
+
border: pal.ruleStrong,
|
|
109
|
+
accent: pal.ink,
|
|
110
|
+
accentFg: dark ? pal.paper : pal.paperRaised,
|
|
111
|
+
success: pal.ok,
|
|
112
|
+
error: pal.danger,
|
|
113
|
+
fontFamily: void 0,
|
|
114
|
+
radius: import_core.MUSHI_RADIUS.card
|
|
115
|
+
};
|
|
116
|
+
const defined = Object.fromEntries(
|
|
117
|
+
Object.entries(override).filter(([, v]) => v !== void 0 && v !== null && v !== "")
|
|
118
|
+
);
|
|
119
|
+
const merged = { ...base, ...defined };
|
|
120
|
+
if (defined.accent && !defined.accentFg) merged.accentFg = contrastingText(defined.accent, base.accentFg);
|
|
121
|
+
return {
|
|
122
|
+
...merged,
|
|
123
|
+
backdrop: dark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.35)",
|
|
124
|
+
disabled: dark ? import_core.MUSHI_CONTROL_DISABLED.dark : import_core.MUSHI_CONTROL_DISABLED.light,
|
|
125
|
+
disabledFg: pal.inkFaint
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/components/MushiUpdateToast.tsx
|
|
130
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
131
|
+
var AUTO_HIDE_MS = 8e3;
|
|
132
|
+
var MushiUpdateToast = ({ message, onView, onDismiss, theme }) => {
|
|
133
|
+
const colors = resolveRNTheme((0, import_react_native.useColorScheme)() === "dark", theme);
|
|
134
|
+
const copy = (0, import_reporter_ui.reporterCopy)(
|
|
135
|
+
(0, import_reporter_ui.resolveReporterLocale)(typeof navigator !== "undefined" ? navigator.language : void 0)
|
|
136
|
+
).ui;
|
|
137
|
+
const font = colors.fontFamily ? { fontFamily: colors.fontFamily } : null;
|
|
138
|
+
(0, import_react.useEffect)(() => {
|
|
139
|
+
const timer = setTimeout(onDismiss, AUTO_HIDE_MS);
|
|
140
|
+
return () => clearTimeout(timer);
|
|
141
|
+
}, [onDismiss]);
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
143
|
+
import_react_native.View,
|
|
144
|
+
{
|
|
145
|
+
style: [s.toast, { backgroundColor: colors.bg, borderColor: colors.border, borderRadius: colors.radius }],
|
|
146
|
+
accessibilityLiveRegion: "polite",
|
|
147
|
+
accessibilityRole: "alert",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: [s.text, { color: colors.fg }, font], numberOfLines: 2, children: message }),
|
|
150
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
151
|
+
import_react_native.TouchableOpacity,
|
|
152
|
+
{
|
|
153
|
+
onPress: onView,
|
|
154
|
+
accessibilityRole: "button",
|
|
155
|
+
style: [s.btn, { backgroundColor: colors.accent, borderRadius: colors.radius }],
|
|
156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: [{ color: colors.accentFg, fontWeight: "600" }, font], children: copy.view })
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
160
|
+
import_react_native.TouchableOpacity,
|
|
161
|
+
{
|
|
162
|
+
onPress: onDismiss,
|
|
163
|
+
accessibilityRole: "button",
|
|
164
|
+
accessibilityLabel: copy.done,
|
|
165
|
+
hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
|
|
166
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: [{ color: colors.muted, fontSize: 18 }, font], children: "\xD7" })
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
var s = import_react_native.StyleSheet.create({
|
|
174
|
+
toast: {
|
|
175
|
+
position: "absolute",
|
|
176
|
+
left: 16,
|
|
177
|
+
right: 16,
|
|
178
|
+
bottom: 32,
|
|
179
|
+
flexDirection: "row",
|
|
180
|
+
alignItems: "center",
|
|
181
|
+
gap: 10,
|
|
182
|
+
paddingVertical: 10,
|
|
183
|
+
paddingHorizontal: 14,
|
|
184
|
+
borderWidth: import_react_native.StyleSheet.hairlineWidth,
|
|
185
|
+
shadowColor: import_core2.MUSHI_SHADOW_INK,
|
|
186
|
+
shadowOpacity: 0.18,
|
|
187
|
+
shadowRadius: 12,
|
|
188
|
+
shadowOffset: { width: 0, height: 6 },
|
|
189
|
+
elevation: 6
|
|
190
|
+
},
|
|
191
|
+
text: { flex: 1, fontSize: 14 },
|
|
192
|
+
btn: { paddingHorizontal: 12, paddingVertical: 6 }
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/optional-modules.ts
|
|
196
|
+
function unwrap(mod, key) {
|
|
197
|
+
if (!mod || typeof mod !== "object" && typeof mod !== "function") return null;
|
|
198
|
+
if (key in mod) return mod;
|
|
199
|
+
const def = mod.default;
|
|
200
|
+
return def && (typeof def === "object" || typeof def === "function") && key in def ? def : null;
|
|
201
|
+
}
|
|
202
|
+
function resolveNetInfo(injected) {
|
|
203
|
+
if (injected) return unwrap(injected, "addEventListener");
|
|
204
|
+
try {
|
|
205
|
+
return unwrap(require("@react-native-community/netinfo"), "addEventListener");
|
|
206
|
+
} catch {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function resolveViewShot(injected) {
|
|
211
|
+
if (injected) return unwrap(injected, "captureScreen");
|
|
212
|
+
try {
|
|
213
|
+
return unwrap(require("react-native-view-shot"), "captureScreen");
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function resolveExpoSensors(injected) {
|
|
219
|
+
if (injected) return unwrap(injected, "Accelerometer");
|
|
220
|
+
try {
|
|
221
|
+
return unwrap(require("expo-sensors"), "Accelerometer");
|
|
222
|
+
} catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/capture/console-capture.ts
|
|
228
|
+
var import_core3 = require("@mushi-mushi/core");
|
|
57
229
|
function setupConsoleCapture(maxEntries = 100) {
|
|
58
230
|
const entries = [];
|
|
59
231
|
const methods = ["log", "warn", "error"];
|
|
@@ -64,7 +236,7 @@ function setupConsoleCapture(maxEntries = 100) {
|
|
|
64
236
|
console[method] = (...args) => {
|
|
65
237
|
entries.push({
|
|
66
238
|
level: method,
|
|
67
|
-
message: (0,
|
|
239
|
+
message: (0, import_core3.scrubPii)(args.map(String).join(" ").slice(0, 500)),
|
|
68
240
|
timestamp: Date.now()
|
|
69
241
|
});
|
|
70
242
|
if (entries.length > maxEntries) entries.shift();
|
|
@@ -140,28 +312,28 @@ function stripQueryParams(url) {
|
|
|
140
312
|
}
|
|
141
313
|
|
|
142
314
|
// src/capture/device-info.ts
|
|
143
|
-
var
|
|
315
|
+
var import_react_native2 = require("react-native");
|
|
144
316
|
function getDeviceInfo() {
|
|
145
|
-
const { width, height } =
|
|
317
|
+
const { width, height } = import_react_native2.Dimensions.get("window");
|
|
146
318
|
const locale = (
|
|
147
319
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
148
|
-
|
|
149
|
-
|
|
320
|
+
import_react_native2.NativeModules.SettingsManager?.settings?.AppleLocale ?? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
321
|
+
import_react_native2.NativeModules.I18nManager?.localeIdentifier ?? "en"
|
|
150
322
|
);
|
|
151
323
|
let timezone = "UTC";
|
|
152
324
|
try {
|
|
153
325
|
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
154
326
|
} catch {
|
|
155
327
|
}
|
|
156
|
-
const appVersion =
|
|
328
|
+
const appVersion = import_react_native2.NativeModules.RNDeviceInfo?.appVersion ?? import_react_native2.NativeModules.RNBuildConfig?.VERSION_NAME ?? String(import_react_native2.Platform.Version);
|
|
157
329
|
return {
|
|
158
|
-
platform:
|
|
159
|
-
osVersion:
|
|
330
|
+
platform: import_react_native2.Platform.OS,
|
|
331
|
+
osVersion: import_react_native2.Platform.Version,
|
|
160
332
|
screenWidth: width,
|
|
161
333
|
screenHeight: height,
|
|
162
|
-
pixelRatio:
|
|
163
|
-
fontScale:
|
|
164
|
-
systemName:
|
|
334
|
+
pixelRatio: import_react_native2.PixelRatio.get(),
|
|
335
|
+
fontScale: import_react_native2.PixelRatio.getFontScale(),
|
|
336
|
+
systemName: import_react_native2.Platform.OS,
|
|
165
337
|
locale,
|
|
166
338
|
timezone,
|
|
167
339
|
appVersion
|
|
@@ -193,7 +365,7 @@ function getDeviceFingerprintHash(device) {
|
|
|
193
365
|
}
|
|
194
366
|
|
|
195
367
|
// src/storage/async-storage-queue.ts
|
|
196
|
-
var
|
|
368
|
+
var import_core4 = require("@mushi-mushi/core");
|
|
197
369
|
|
|
198
370
|
// src/storage/secure-storage.ts
|
|
199
371
|
var REPORTER_TOKEN_KEY = "@mushi:reporter_token";
|
|
@@ -393,19 +565,19 @@ var AsyncStorageQueue = class {
|
|
|
393
565
|
scrubReportPii(report) {
|
|
394
566
|
const next = { ...report };
|
|
395
567
|
if (typeof next.description === "string") {
|
|
396
|
-
next.description = (0,
|
|
568
|
+
next.description = (0, import_core4.scrubPii)(next.description);
|
|
397
569
|
}
|
|
398
570
|
if (typeof next.summary === "string") {
|
|
399
|
-
next.summary = (0,
|
|
571
|
+
next.summary = (0, import_core4.scrubPii)(next.summary);
|
|
400
572
|
}
|
|
401
573
|
if (Array.isArray(next.breadcrumbs)) {
|
|
402
574
|
next.breadcrumbs = next.breadcrumbs.map(
|
|
403
|
-
(b) => typeof b?.message === "string" ? { ...b, message: (0,
|
|
575
|
+
(b) => typeof b?.message === "string" ? { ...b, message: (0, import_core4.scrubPii)(b.message) } : b
|
|
404
576
|
);
|
|
405
577
|
}
|
|
406
578
|
if (Array.isArray(next.consoleLogs)) {
|
|
407
579
|
next.consoleLogs = next.consoleLogs.map(
|
|
408
|
-
(entry) => typeof entry?.message === "string" ? { ...entry, message: (0,
|
|
580
|
+
(entry) => typeof entry?.message === "string" ? { ...entry, message: (0, import_core4.scrubPii)(entry.message) } : entry
|
|
409
581
|
);
|
|
410
582
|
}
|
|
411
583
|
return next;
|
|
@@ -447,7 +619,7 @@ async function sendWithRetry(item, ctx, attempt = 0) {
|
|
|
447
619
|
try {
|
|
448
620
|
const res = await fetch(`${ctx.apiEndpoint}/v1/reports`, {
|
|
449
621
|
method: "POST",
|
|
450
|
-
headers: (0,
|
|
622
|
+
headers: (0, import_core4.buildSdkIngestHeaders)({
|
|
451
623
|
apiKey: ctx.apiKey,
|
|
452
624
|
projectId: ctx.projectId,
|
|
453
625
|
sdkPackage: ctx.sdkPackage,
|
|
@@ -456,7 +628,7 @@ async function sendWithRetry(item, ctx, attempt = 0) {
|
|
|
456
628
|
internalKind
|
|
457
629
|
}),
|
|
458
630
|
body: JSON.stringify(item.report),
|
|
459
|
-
[
|
|
631
|
+
[import_core4.MUSHI_INTERNAL_INIT_MARKER]: internalKind
|
|
460
632
|
});
|
|
461
633
|
if ((res.status === 429 || res.status >= 500) && attempt < 3) {
|
|
462
634
|
await sleep(delay);
|
|
@@ -476,62 +648,14 @@ function sleep(ms) {
|
|
|
476
648
|
}
|
|
477
649
|
|
|
478
650
|
// src/components/MushiBottomSheet.tsx
|
|
479
|
-
var
|
|
480
|
-
var
|
|
481
|
-
var
|
|
482
|
-
var
|
|
651
|
+
var import_react2 = require("react");
|
|
652
|
+
var import_react_native3 = require("react-native");
|
|
653
|
+
var import_core5 = require("@mushi-mushi/core");
|
|
654
|
+
var import_reporter_ui2 = require("@mushi-mushi/core/reporter-ui");
|
|
483
655
|
var import_i18n = require("@mushi-mushi/web/i18n");
|
|
484
656
|
|
|
485
|
-
// src/theme.ts
|
|
486
|
-
var import_core3 = require("@mushi-mushi/core");
|
|
487
|
-
function hexToRgb(hex) {
|
|
488
|
-
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})([0-9a-f]{2})?$/i.exec(hex.trim());
|
|
489
|
-
if (!m) return null;
|
|
490
|
-
const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
|
|
491
|
-
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
492
|
-
}
|
|
493
|
-
function luminance([r, g, b]) {
|
|
494
|
-
const lin = (c) => {
|
|
495
|
-
const s4 = c / 255;
|
|
496
|
-
return s4 <= 0.03928 ? s4 / 12.92 : ((s4 + 0.055) / 1.055) ** 2.4;
|
|
497
|
-
};
|
|
498
|
-
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
499
|
-
}
|
|
500
|
-
function contrastingText(bg, fallback) {
|
|
501
|
-
const rgb = hexToRgb(bg);
|
|
502
|
-
if (!rgb) return fallback;
|
|
503
|
-
const l = luminance(rgb);
|
|
504
|
-
return 1.05 / (l + 0.05) >= (l + 0.05) / 0.05 ? "#FFFFFF" : "#000000";
|
|
505
|
-
}
|
|
506
|
-
function resolveRNTheme(dark, override = {}) {
|
|
507
|
-
const pal = (0, import_core3.mushiPalette)(dark ? "dark" : "light");
|
|
508
|
-
const base = {
|
|
509
|
-
bg: dark ? pal.paper : pal.paperRaised,
|
|
510
|
-
fg: pal.ink,
|
|
511
|
-
muted: pal.inkMuted,
|
|
512
|
-
surface: dark ? pal.paperRaised : pal.paper,
|
|
513
|
-
border: pal.ruleStrong,
|
|
514
|
-
accent: pal.ink,
|
|
515
|
-
accentFg: dark ? pal.paper : pal.paperRaised,
|
|
516
|
-
success: pal.ok,
|
|
517
|
-
error: pal.danger,
|
|
518
|
-
fontFamily: void 0,
|
|
519
|
-
radius: import_core3.MUSHI_RADIUS.card
|
|
520
|
-
};
|
|
521
|
-
const defined = Object.fromEntries(
|
|
522
|
-
Object.entries(override).filter(([, v]) => v !== void 0 && v !== null && v !== "")
|
|
523
|
-
);
|
|
524
|
-
const merged = { ...base, ...defined };
|
|
525
|
-
if (defined.accent && !defined.accentFg) merged.accentFg = contrastingText(defined.accent, base.accentFg);
|
|
526
|
-
return {
|
|
527
|
-
...merged,
|
|
528
|
-
backdrop: dark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.35)",
|
|
529
|
-
disabled: dark ? import_core3.MUSHI_CONTROL_DISABLED.dark : import_core3.MUSHI_CONTROL_DISABLED.light,
|
|
530
|
-
disabledFg: pal.inkFaint
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
|
|
534
657
|
// src/reporter-thread.ts
|
|
658
|
+
var import_reporter_channels = require("@mushi-mushi/core/reporter-channels");
|
|
535
659
|
var THREAD_LOAD_TIMEOUT_MS = 12e3;
|
|
536
660
|
function settleWithin(p, ms) {
|
|
537
661
|
return new Promise((resolve) => {
|
|
@@ -559,6 +683,9 @@ function loadReporterThread(load, reportId, timeoutMs = THREAD_LOAD_TIMEOUT_MS)
|
|
|
559
683
|
}
|
|
560
684
|
async function markReporterReportRead(client, reporterToken, reportId) {
|
|
561
685
|
try {
|
|
686
|
+
const v2 = await (0, import_reporter_channels.reporterChannels)(client).markReportRead(reportId, reporterToken);
|
|
687
|
+
if (v2.ok) return v2.data?.marked_read ?? 0;
|
|
688
|
+
if (v2.error?.status !== 404) return 0;
|
|
562
689
|
const res = await client.listNotifications(reporterToken, { limit: 100 });
|
|
563
690
|
if (!res.ok) return 0;
|
|
564
691
|
const rows = res.data?.notifications ?? [];
|
|
@@ -573,21 +700,59 @@ async function markReporterReportRead(client, reporterToken, reportId) {
|
|
|
573
700
|
return 0;
|
|
574
701
|
}
|
|
575
702
|
}
|
|
703
|
+
function createReporterUpdateHub(fetchUpdates) {
|
|
704
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
705
|
+
async function emit() {
|
|
706
|
+
let updates = null;
|
|
707
|
+
try {
|
|
708
|
+
updates = await fetchUpdates();
|
|
709
|
+
} catch {
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
if (updates) {
|
|
713
|
+
for (const cb of listeners) {
|
|
714
|
+
try {
|
|
715
|
+
cb(updates);
|
|
716
|
+
} catch {
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return updates;
|
|
721
|
+
}
|
|
722
|
+
return {
|
|
723
|
+
subscribe(cb) {
|
|
724
|
+
listeners.add(cb);
|
|
725
|
+
void emit();
|
|
726
|
+
return () => {
|
|
727
|
+
listeners.delete(cb);
|
|
728
|
+
};
|
|
729
|
+
},
|
|
730
|
+
emit,
|
|
731
|
+
listenerCount: () => listeners.size
|
|
732
|
+
};
|
|
733
|
+
}
|
|
576
734
|
|
|
577
735
|
// src/components/MushiBottomSheet.tsx
|
|
578
|
-
var
|
|
579
|
-
var { height: SCREEN_HEIGHT } =
|
|
736
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
737
|
+
var { height: SCREEN_HEIGHT } = import_react_native3.Dimensions.get("window");
|
|
580
738
|
var SHEET_HEIGHT = SCREEN_HEIGHT * 0.55;
|
|
581
739
|
var DISMISS_THRESHOLD = 80;
|
|
582
|
-
var MIN_DESCRIPTION = 20;
|
|
583
|
-
var CATEGORY_KEYS = ["bug", "slow", "visual", "confusing", "other"];
|
|
584
740
|
var CATEGORY_EMOJI = {
|
|
585
741
|
bug: "\u{1F41B}",
|
|
586
742
|
slow: "\u{1F422}",
|
|
587
743
|
visual: "\u{1F3A8}",
|
|
588
744
|
confusing: "\u{1F615}",
|
|
589
|
-
|
|
745
|
+
idea: "\u{1F4A1}"
|
|
590
746
|
};
|
|
747
|
+
function commentsToTimeline(comments) {
|
|
748
|
+
return comments.map((c) => ({
|
|
749
|
+
kind: c.author_kind === "reporter" ? "reporter_comment" : "comment",
|
|
750
|
+
at: c.created_at,
|
|
751
|
+
text: c.body,
|
|
752
|
+
body: c.body,
|
|
753
|
+
comment_id: c.id
|
|
754
|
+
}));
|
|
755
|
+
}
|
|
591
756
|
var MushiBottomSheet = ({
|
|
592
757
|
visible,
|
|
593
758
|
onClose,
|
|
@@ -596,52 +761,66 @@ var MushiBottomSheet = ({
|
|
|
596
761
|
onClearScreenshot,
|
|
597
762
|
screenshotSensitiveHint,
|
|
598
763
|
assistantEnabled = false,
|
|
599
|
-
assistantLabel =
|
|
764
|
+
assistantLabel = import_core5.MUSHI_COPY.assistantTab,
|
|
600
765
|
assistantGreeting,
|
|
601
766
|
assistantSuggestions = [],
|
|
602
767
|
inboxPollIntervalMs = 0,
|
|
603
|
-
theme
|
|
768
|
+
theme,
|
|
769
|
+
minDescriptionLength,
|
|
770
|
+
emailOptIn = true
|
|
604
771
|
}) => {
|
|
605
772
|
const mushi = useMushiContext();
|
|
606
773
|
const t = (0, import_i18n.getLocale)();
|
|
607
|
-
const locale = (0,
|
|
774
|
+
const locale = (0, import_reporter_ui2.resolveReporterLocale)(
|
|
608
775
|
typeof navigator !== "undefined" ? navigator.language : void 0
|
|
609
776
|
);
|
|
610
|
-
const rc = (0,
|
|
777
|
+
const rc = (0, import_reporter_ui2.reporterCopy)(locale);
|
|
611
778
|
const greeting = assistantGreeting ?? t.assistant.defaultGreeting;
|
|
612
|
-
const scheme = (0,
|
|
779
|
+
const scheme = (0, import_react_native3.useColorScheme)();
|
|
613
780
|
const dark = scheme === "dark";
|
|
614
|
-
const translateY = (0,
|
|
615
|
-
const backdropOpacity = (0,
|
|
616
|
-
const [category, setCategory] = (0,
|
|
617
|
-
const [description, setDescription] = (0,
|
|
618
|
-
const [phase, setPhase] = (0,
|
|
619
|
-
const [submitError, setSubmitError] = (0,
|
|
620
|
-
const [sheetTab, setSheetTab] = (0,
|
|
621
|
-
const [inboxReports, setInboxReports] = (0,
|
|
622
|
-
const [inboxLoaded, setInboxLoaded] = (0,
|
|
623
|
-
const [inboxLoading, setInboxLoading] = (0,
|
|
624
|
-
const [selectedReportId, setSelectedReportId] = (0,
|
|
625
|
-
const selectedRef = (0,
|
|
626
|
-
const [
|
|
627
|
-
const [threadStatus, setThreadStatus] = (0,
|
|
628
|
-
const [replyText, setReplyText] = (0,
|
|
629
|
-
const [replyState, setReplyState] = (0,
|
|
630
|
-
const [feedbackSending, setFeedbackSending] = (0,
|
|
631
|
-
const [feedbackError, setFeedbackError] = (0,
|
|
632
|
-
const [assistantInput, setAssistantInput] = (0,
|
|
633
|
-
const [assistantThreadId, setAssistantThreadId] = (0,
|
|
634
|
-
const [assistantSending, setAssistantSending] = (0,
|
|
635
|
-
const [assistantError, setAssistantError] = (0,
|
|
636
|
-
const [assistantTurns, setAssistantTurns] = (0,
|
|
637
|
-
const [screenshotAttached, setScreenshotAttached] = (0,
|
|
638
|
-
const
|
|
781
|
+
const translateY = (0, import_react2.useRef)(new import_react_native3.Animated.Value(SHEET_HEIGHT)).current;
|
|
782
|
+
const backdropOpacity = (0, import_react2.useRef)(new import_react_native3.Animated.Value(0)).current;
|
|
783
|
+
const [category, setCategory] = (0, import_react2.useState)(null);
|
|
784
|
+
const [description, setDescription] = (0, import_react2.useState)("");
|
|
785
|
+
const [phase, setPhase] = (0, import_react2.useState)("form");
|
|
786
|
+
const [submitError, setSubmitError] = (0, import_react2.useState)(null);
|
|
787
|
+
const [sheetTab, setSheetTab] = (0, import_react2.useState)("report");
|
|
788
|
+
const [inboxReports, setInboxReports] = (0, import_react2.useState)([]);
|
|
789
|
+
const [inboxLoaded, setInboxLoaded] = (0, import_react2.useState)(false);
|
|
790
|
+
const [inboxLoading, setInboxLoading] = (0, import_react2.useState)(false);
|
|
791
|
+
const [selectedReportId, setSelectedReportId] = (0, import_react2.useState)(null);
|
|
792
|
+
const selectedRef = (0, import_react2.useRef)(null);
|
|
793
|
+
const [threadItems, setThreadItems] = (0, import_react2.useState)([]);
|
|
794
|
+
const [threadStatus, setThreadStatus] = (0, import_react2.useState)("idle");
|
|
795
|
+
const [replyText, setReplyText] = (0, import_react2.useState)("");
|
|
796
|
+
const [replyState, setReplyState] = (0, import_react2.useState)("idle");
|
|
797
|
+
const [feedbackSending, setFeedbackSending] = (0, import_react2.useState)(false);
|
|
798
|
+
const [feedbackError, setFeedbackError] = (0, import_react2.useState)(false);
|
|
799
|
+
const [assistantInput, setAssistantInput] = (0, import_react2.useState)("");
|
|
800
|
+
const [assistantThreadId, setAssistantThreadId] = (0, import_react2.useState)(null);
|
|
801
|
+
const [assistantSending, setAssistantSending] = (0, import_react2.useState)(false);
|
|
802
|
+
const [assistantError, setAssistantError] = (0, import_react2.useState)(null);
|
|
803
|
+
const [assistantTurns, setAssistantTurns] = (0, import_react2.useState)([]);
|
|
804
|
+
const [screenshotAttached, setScreenshotAttached] = (0, import_react2.useState)(true);
|
|
805
|
+
const [emailState, setEmailState] = (0, import_react2.useState)("hidden");
|
|
806
|
+
const [emailInput, setEmailInput] = (0, import_react2.useState)("");
|
|
807
|
+
const [reduceMotion, setReduceMotion] = (0, import_react2.useState)(false);
|
|
808
|
+
(0, import_react2.useEffect)(() => {
|
|
809
|
+
let alive = true;
|
|
810
|
+
import_react_native3.AccessibilityInfo?.isReduceMotionEnabled?.().then((on) => alive && setReduceMotion(Boolean(on))).catch(() => void 0);
|
|
811
|
+
const sub = import_react_native3.AccessibilityInfo?.addEventListener?.("reduceMotionChanged", (on) => setReduceMotion(Boolean(on)));
|
|
812
|
+
return () => {
|
|
813
|
+
alive = false;
|
|
814
|
+
sub?.remove?.();
|
|
815
|
+
};
|
|
816
|
+
}, []);
|
|
817
|
+
const loadInbox = (0, import_react2.useCallback)(
|
|
639
818
|
async (opts = {}) => {
|
|
640
819
|
if (!mushi?.listMyReports) return;
|
|
641
820
|
if (!opts.silent) setInboxLoading(true);
|
|
642
821
|
try {
|
|
643
822
|
const rows = await mushi.listMyReports();
|
|
644
|
-
setInboxReports(rows.filter((r) => !(0,
|
|
823
|
+
setInboxReports(rows.filter((r) => !(0, import_reporter_ui2.reporterStatus)(r, locale).hidden));
|
|
645
824
|
setInboxLoaded(true);
|
|
646
825
|
} catch {
|
|
647
826
|
} finally {
|
|
@@ -650,38 +829,45 @@ var MushiBottomSheet = ({
|
|
|
650
829
|
},
|
|
651
830
|
[mushi, locale]
|
|
652
831
|
);
|
|
653
|
-
(0,
|
|
832
|
+
(0, import_react2.useEffect)(() => {
|
|
654
833
|
if (visible) {
|
|
655
834
|
setScreenshotAttached(true);
|
|
656
835
|
setSheetTab(preferredTab);
|
|
657
836
|
if (preferredTab === "inbox") void loadInbox();
|
|
658
837
|
}
|
|
659
838
|
}, [visible, preferredTab, loadInbox]);
|
|
660
|
-
(0,
|
|
839
|
+
(0, import_react2.useEffect)(() => {
|
|
661
840
|
if (!visible || sheetTab !== "inbox" || inboxPollIntervalMs <= 0) return;
|
|
662
841
|
const timer = setInterval(() => {
|
|
663
842
|
void loadInbox({ silent: true });
|
|
664
843
|
}, inboxPollIntervalMs);
|
|
665
844
|
return () => clearInterval(timer);
|
|
666
845
|
}, [visible, sheetTab, inboxPollIntervalMs, loadInbox]);
|
|
667
|
-
const openThread = (0,
|
|
846
|
+
const openThread = (0, import_react2.useCallback)(
|
|
668
847
|
async (reportId, opts = {}) => {
|
|
669
848
|
selectedRef.current = reportId;
|
|
670
849
|
setSelectedReportId(reportId);
|
|
671
850
|
if (!opts.silent) {
|
|
672
|
-
|
|
851
|
+
setThreadItems([]);
|
|
673
852
|
setThreadStatus("loading");
|
|
674
853
|
setReplyState("idle");
|
|
675
854
|
setFeedbackError(false);
|
|
676
855
|
}
|
|
677
|
-
|
|
678
|
-
const
|
|
856
|
+
let items = null;
|
|
857
|
+
const detail = mushi?.loadMyReportDetail ? await settleWithin(mushi.loadMyReportDetail(reportId), THREAD_LOAD_TIMEOUT_MS) : "unsupported";
|
|
858
|
+
if (detail && detail !== "unsupported") {
|
|
859
|
+
items = detail.timeline;
|
|
860
|
+
} else if (detail === "unsupported") {
|
|
861
|
+
const load = mushi?.loadMyThread ?? mushi?.listMyComments;
|
|
862
|
+
const comments = load ? await loadReporterThread(load, reportId) : null;
|
|
863
|
+
items = comments ? commentsToTimeline(comments) : null;
|
|
864
|
+
}
|
|
679
865
|
if (selectedRef.current !== reportId) return;
|
|
680
|
-
if (
|
|
866
|
+
if (items === null) {
|
|
681
867
|
setThreadStatus((prev) => opts.silent && prev === "ready" ? "ready" : "error");
|
|
682
868
|
return;
|
|
683
869
|
}
|
|
684
|
-
|
|
870
|
+
setThreadItems(items);
|
|
685
871
|
setThreadStatus("ready");
|
|
686
872
|
if (!opts.silent && mushi?.markReportRead) {
|
|
687
873
|
mushi.markReportRead(reportId).then((marked) => {
|
|
@@ -693,12 +879,12 @@ var MushiBottomSheet = ({
|
|
|
693
879
|
},
|
|
694
880
|
[mushi]
|
|
695
881
|
);
|
|
696
|
-
const closeThread = (0,
|
|
882
|
+
const closeThread = (0, import_react2.useCallback)(() => {
|
|
697
883
|
selectedRef.current = null;
|
|
698
884
|
setSelectedReportId(null);
|
|
699
885
|
setThreadStatus("idle");
|
|
700
886
|
}, []);
|
|
701
|
-
const sendReply = (0,
|
|
887
|
+
const sendReply = (0, import_react2.useCallback)(async () => {
|
|
702
888
|
const body = replyText.trim();
|
|
703
889
|
const reportId = selectedReportId;
|
|
704
890
|
if (!mushi?.replyToReport || !reportId || !body || replyState === "sending") return;
|
|
@@ -712,14 +898,17 @@ var MushiBottomSheet = ({
|
|
|
712
898
|
setReplyText("");
|
|
713
899
|
setReplyState("idle");
|
|
714
900
|
if (selectedRef.current === reportId) {
|
|
715
|
-
|
|
901
|
+
setThreadItems((prev) => [
|
|
902
|
+
...prev,
|
|
903
|
+
{ kind: "reporter_comment", at: comment.created_at, text: comment.body, body: comment.body, comment_id: comment.id }
|
|
904
|
+
]);
|
|
716
905
|
void openThread(reportId, { silent: true });
|
|
717
906
|
}
|
|
718
907
|
} catch {
|
|
719
908
|
setReplyState("failed");
|
|
720
909
|
}
|
|
721
910
|
}, [mushi, selectedReportId, replyText, replyState, openThread]);
|
|
722
|
-
const submitFeedback = (0,
|
|
911
|
+
const submitFeedback = (0, import_react2.useCallback)(
|
|
723
912
|
async (signal) => {
|
|
724
913
|
const reportId = selectedReportId;
|
|
725
914
|
if (!mushi?.submitFeedbackSignal || !reportId || feedbackSending) return;
|
|
@@ -741,7 +930,7 @@ var MushiBottomSheet = ({
|
|
|
741
930
|
},
|
|
742
931
|
[mushi, selectedReportId, feedbackSending, loadInbox, openThread]
|
|
743
932
|
);
|
|
744
|
-
const sendAssistant = (0,
|
|
933
|
+
const sendAssistant = (0, import_react2.useCallback)(async (message) => {
|
|
745
934
|
if (!mushi?.askAssistant || !message.trim() || assistantSending) return;
|
|
746
935
|
const trimmed = message.trim();
|
|
747
936
|
setAssistantInput("");
|
|
@@ -766,37 +955,44 @@ var MushiBottomSheet = ({
|
|
|
766
955
|
setAssistantSending(false);
|
|
767
956
|
}
|
|
768
957
|
}, [mushi, assistantSending, assistantThreadId]);
|
|
769
|
-
const resetForm = (0,
|
|
958
|
+
const resetForm = (0, import_react2.useCallback)(() => {
|
|
770
959
|
setCategory(null);
|
|
771
960
|
setDescription("");
|
|
772
961
|
setPhase("form");
|
|
962
|
+
setEmailState("hidden");
|
|
963
|
+
setEmailInput("");
|
|
773
964
|
}, []);
|
|
774
|
-
const animateIn = (0,
|
|
775
|
-
|
|
776
|
-
|
|
965
|
+
const animateIn = (0, import_react2.useCallback)(() => {
|
|
966
|
+
if (reduceMotion) {
|
|
967
|
+
translateY.setValue(0);
|
|
968
|
+
backdropOpacity.setValue(1);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
import_react_native3.Animated.parallel([
|
|
972
|
+
import_react_native3.Animated.spring(translateY, {
|
|
777
973
|
toValue: 0,
|
|
778
974
|
useNativeDriver: true,
|
|
779
975
|
damping: 20,
|
|
780
976
|
stiffness: 200
|
|
781
977
|
}),
|
|
782
|
-
|
|
978
|
+
import_react_native3.Animated.timing(backdropOpacity, {
|
|
783
979
|
toValue: 1,
|
|
784
980
|
duration: 250,
|
|
785
981
|
useNativeDriver: true
|
|
786
982
|
})
|
|
787
983
|
]).start();
|
|
788
|
-
}, [translateY, backdropOpacity]);
|
|
789
|
-
const animateOut = (0,
|
|
984
|
+
}, [translateY, backdropOpacity, reduceMotion]);
|
|
985
|
+
const animateOut = (0, import_react2.useCallback)(
|
|
790
986
|
(cb) => {
|
|
791
|
-
|
|
792
|
-
|
|
987
|
+
import_react_native3.Animated.parallel([
|
|
988
|
+
import_react_native3.Animated.timing(translateY, {
|
|
793
989
|
toValue: SHEET_HEIGHT,
|
|
794
|
-
duration: 220,
|
|
990
|
+
duration: reduceMotion ? 0 : 220,
|
|
795
991
|
useNativeDriver: true
|
|
796
992
|
}),
|
|
797
|
-
|
|
993
|
+
import_react_native3.Animated.timing(backdropOpacity, {
|
|
798
994
|
toValue: 0,
|
|
799
|
-
duration: 200,
|
|
995
|
+
duration: reduceMotion ? 0 : 200,
|
|
800
996
|
useNativeDriver: true
|
|
801
997
|
})
|
|
802
998
|
]).start(() => {
|
|
@@ -804,16 +1000,16 @@ var MushiBottomSheet = ({
|
|
|
804
1000
|
cb?.();
|
|
805
1001
|
});
|
|
806
1002
|
},
|
|
807
|
-
[translateY, backdropOpacity, resetForm]
|
|
1003
|
+
[translateY, backdropOpacity, resetForm, reduceMotion]
|
|
808
1004
|
);
|
|
809
|
-
(0,
|
|
1005
|
+
(0, import_react2.useEffect)(() => {
|
|
810
1006
|
if (visible) animateIn();
|
|
811
1007
|
}, [visible, animateIn]);
|
|
812
|
-
const handleClose = (0,
|
|
1008
|
+
const handleClose = (0, import_react2.useCallback)(() => {
|
|
813
1009
|
animateOut(onClose);
|
|
814
1010
|
}, [animateOut, onClose]);
|
|
815
|
-
const panResponder = (0,
|
|
816
|
-
|
|
1011
|
+
const panResponder = (0, import_react2.useRef)(
|
|
1012
|
+
import_react_native3.PanResponder.create({
|
|
817
1013
|
onStartShouldSetPanResponder: () => true,
|
|
818
1014
|
onMoveShouldSetPanResponder: (_, g) => g.dy > 4,
|
|
819
1015
|
onPanResponderMove: (_, g) => {
|
|
@@ -823,7 +1019,7 @@ var MushiBottomSheet = ({
|
|
|
823
1019
|
if (g.dy > DISMISS_THRESHOLD) {
|
|
824
1020
|
handleClose();
|
|
825
1021
|
} else {
|
|
826
|
-
|
|
1022
|
+
import_react_native3.Animated.spring(translateY, {
|
|
827
1023
|
toValue: 0,
|
|
828
1024
|
useNativeDriver: true,
|
|
829
1025
|
damping: 20,
|
|
@@ -833,20 +1029,43 @@ var MushiBottomSheet = ({
|
|
|
833
1029
|
}
|
|
834
1030
|
})
|
|
835
1031
|
).current;
|
|
836
|
-
const
|
|
837
|
-
if (!
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1032
|
+
const offerEmail = (0, import_react2.useCallback)(async () => {
|
|
1033
|
+
if (!emailOptIn || !mushi?.getNotificationPrefs) return;
|
|
1034
|
+
try {
|
|
1035
|
+
const prefs = await mushi.getNotificationPrefs();
|
|
1036
|
+
if (prefs?.available.email && !prefs.email_verified && !prefs.email_pending) {
|
|
1037
|
+
setEmailInput(mushi.emailPrefill?.() ?? "");
|
|
1038
|
+
setEmailState("offer");
|
|
1039
|
+
}
|
|
1040
|
+
} catch {
|
|
1041
|
+
}
|
|
1042
|
+
}, [emailOptIn, mushi]);
|
|
1043
|
+
const submitEmail = (0, import_react2.useCallback)(async () => {
|
|
1044
|
+
const email = emailInput.trim();
|
|
1045
|
+
if (!(0, import_reporter_ui2.isPlausibleReporterEmail)(email)) {
|
|
1046
|
+
setEmailState("invalid");
|
|
841
1047
|
return;
|
|
842
1048
|
}
|
|
1049
|
+
if (!mushi?.setNotificationPrefs) return;
|
|
1050
|
+
setEmailState("sending");
|
|
1051
|
+
try {
|
|
1052
|
+
const res = await mushi.setNotificationPrefs({ email });
|
|
1053
|
+
setEmailState(res.ok ? "sent" : res.error?.status === 422 ? "invalid" : "failed");
|
|
1054
|
+
} catch {
|
|
1055
|
+
setEmailState("failed");
|
|
1056
|
+
}
|
|
1057
|
+
}, [emailInput, mushi]);
|
|
1058
|
+
const handleSubmit = async () => {
|
|
1059
|
+
const hasAttachment = Boolean(screenshotDataUrl && screenshotAttached);
|
|
1060
|
+
if (!mushi || !(0, import_reporter_ui2.reporterCanSend)(description, hasAttachment, minDescriptionLength)) return;
|
|
1061
|
+
const trimmed = description.trim();
|
|
843
1062
|
setSubmitError(null);
|
|
844
1063
|
setPhase("sending");
|
|
845
1064
|
try {
|
|
846
1065
|
const outcome = await mushi.submitReport({
|
|
847
|
-
category,
|
|
1066
|
+
...(0, import_reporter_ui2.reporterChipToReport)(category),
|
|
848
1067
|
description: trimmed,
|
|
849
|
-
screenshotDataUrl:
|
|
1068
|
+
screenshotDataUrl: hasAttachment ? screenshotDataUrl : void 0
|
|
850
1069
|
});
|
|
851
1070
|
if (!outcome.ok) {
|
|
852
1071
|
if (outcome.failureKind === "credentials" || outcome.failureKind === "quota") {
|
|
@@ -864,7 +1083,7 @@ var MushiBottomSheet = ({
|
|
|
864
1083
|
return;
|
|
865
1084
|
}
|
|
866
1085
|
setPhase("sent");
|
|
867
|
-
|
|
1086
|
+
void offerEmail();
|
|
868
1087
|
} catch {
|
|
869
1088
|
setSubmitError("Something went wrong. Please try again.");
|
|
870
1089
|
setPhase("error");
|
|
@@ -875,94 +1094,106 @@ var MushiBottomSheet = ({
|
|
|
875
1094
|
const font = colors.fontFamily ? { fontFamily: colors.fontFamily } : null;
|
|
876
1095
|
const radius = colors.radius;
|
|
877
1096
|
const sheetTabs = ["report", "inbox", ...assistantEnabled ? ["assistant"] : []];
|
|
878
|
-
const canSubmit =
|
|
879
|
-
const submitHint = canSubmit || phase === "sending" ? void 0 :
|
|
1097
|
+
const canSubmit = (0, import_reporter_ui2.reporterCanSend)(description, Boolean(activeScreenshot), minDescriptionLength) && (phase === "form" || phase === "error");
|
|
1098
|
+
const submitHint = canSubmit || phase === "sending" ? void 0 : rc.ui.addWords;
|
|
880
1099
|
const selectedReport = selectedReportId ? inboxReports.find((r) => r.id === selectedReportId) ?? null : null;
|
|
881
|
-
const selectedView = selectedReport ? (0,
|
|
1100
|
+
const selectedView = selectedReport ? (0, import_reporter_ui2.reporterStatus)(selectedReport, locale) : null;
|
|
882
1101
|
const headerTitle = sheetTab === "assistant" ? assistantLabel : sheetTab === "inbox" ? t.flows.reports.title : t.widget.title;
|
|
883
|
-
const renderThread = () => /* @__PURE__ */ (0,
|
|
884
|
-
/* @__PURE__ */ (0,
|
|
885
|
-
|
|
1102
|
+
const renderThread = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1103
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1104
|
+
import_react_native3.TouchableOpacity,
|
|
886
1105
|
{
|
|
887
1106
|
onPress: closeThread,
|
|
888
1107
|
accessibilityRole: "button",
|
|
889
1108
|
accessibilityLabel: t.widget.back,
|
|
890
1109
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
891
|
-
children: /* @__PURE__ */ (0,
|
|
1110
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.Text, { style: [{ color: colors.accent, marginBottom: 8 }, font], children: [
|
|
892
1111
|
"\u2190 ",
|
|
893
1112
|
t.widget.back
|
|
894
1113
|
] })
|
|
895
1114
|
}
|
|
896
1115
|
),
|
|
897
|
-
selectedReport && selectedView ? /* @__PURE__ */ (0,
|
|
898
|
-
/* @__PURE__ */ (0,
|
|
899
|
-
/* @__PURE__ */ (0,
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
1116
|
+
selectedReport && selectedView ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: [s2.headerCard, { backgroundColor: colors.surface, borderRadius: radius, borderColor: colors.border }], children: [
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.pill, { color: colors.fg, borderColor: colors.border }, font], children: selectedView.label }),
|
|
1118
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, fontSize: 12, marginTop: 4 }, font], children: selectedView.detail }),
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, marginTop: 8 }, font], numberOfLines: 4, children: selectedReport.title ?? selectedReport.summary ?? selectedReport.description ?? "" })
|
|
901
1120
|
] }) : null,
|
|
902
|
-
threadStatus === "loading" ? /* @__PURE__ */ (0,
|
|
903
|
-
/* @__PURE__ */ (0,
|
|
904
|
-
/* @__PURE__ */ (0,
|
|
905
|
-
|
|
1121
|
+
threadStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { accessibilityLabel: t.flows.reports.loading, accessibilityLiveRegion: "polite", children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [s2.skeleton, { backgroundColor: colors.surface, width: `${90 - i * 18}%` }] }, i)) }) : threadStatus === "error" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.errorRow, accessibilityLiveRegion: "polite", children: [
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.error, flex: 1 }, font], accessibilityRole: "alert", children: rc.ui.loadError }),
|
|
1123
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1124
|
+
import_react_native3.TouchableOpacity,
|
|
906
1125
|
{
|
|
907
1126
|
onPress: () => selectedReportId && void openThread(selectedReportId),
|
|
908
1127
|
accessibilityRole: "button",
|
|
909
|
-
style: [
|
|
910
|
-
children: /* @__PURE__ */ (0,
|
|
1128
|
+
style: [s2.retryBtn, { borderColor: colors.border, borderRadius: radius }],
|
|
1129
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, fontWeight: "600" }, font], children: rc.ui.retry })
|
|
911
1130
|
}
|
|
912
1131
|
)
|
|
913
|
-
] }) :
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
s.threadBubble,
|
|
1132
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1133
|
+
threadItems.map(
|
|
1134
|
+
(item, idx) => (0, import_reporter_ui2.isReporterConversation)(item) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1135
|
+
import_react_native3.View,
|
|
918
1136
|
{
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1137
|
+
style: [
|
|
1138
|
+
s2.threadBubble,
|
|
1139
|
+
{
|
|
1140
|
+
backgroundColor: colors.surface,
|
|
1141
|
+
alignSelf: item.kind === "reporter_comment" ? "flex-end" : "flex-start"
|
|
1142
|
+
}
|
|
1143
|
+
],
|
|
1144
|
+
children: [
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, fontSize: 11 }, font], children: item.kind === "reporter_comment" ? rc.ui.you : rc.ui.developer }),
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg }, font], children: (0, import_reporter_ui2.reporterTimelineEntryText)(item, locale) })
|
|
1147
|
+
]
|
|
1148
|
+
},
|
|
1149
|
+
`${item.kind}-${item.comment_id ?? idx}`
|
|
1150
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1151
|
+
import_react_native3.Text,
|
|
1152
|
+
{
|
|
1153
|
+
style: [{ color: colors.muted, fontSize: 12, textAlign: "center", marginVertical: 6 }, font],
|
|
1154
|
+
children: (0, import_reporter_ui2.reporterTimelineEntryText)(item, locale)
|
|
1155
|
+
},
|
|
1156
|
+
`${item.kind}-${item.at}-${idx}`
|
|
1157
|
+
)
|
|
1158
|
+
),
|
|
1159
|
+
!threadItems.some(import_reporter_ui2.isReporterConversation) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, marginBottom: 8 }, font], children: rc.ui.noReplies }) : null
|
|
1160
|
+
] }),
|
|
1161
|
+
replyState === "sending" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: [s2.threadBubble, { backgroundColor: colors.surface, alignSelf: "flex-end", opacity: 0.7 }], children: [
|
|
1162
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, fontSize: 11 }, font], children: rc.ui.sending }),
|
|
1163
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg }, font], children: replyText.trim() })
|
|
933
1164
|
] }) : null,
|
|
934
|
-
selectedView?.canVerify ? /* @__PURE__ */ (0,
|
|
935
|
-
/* @__PURE__ */ (0,
|
|
936
|
-
|
|
1165
|
+
selectedView?.canVerify ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.verifyRow, children: [
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1167
|
+
import_react_native3.TouchableOpacity,
|
|
937
1168
|
{
|
|
938
|
-
style: [
|
|
1169
|
+
style: [s2.verifyBtn, { backgroundColor: colors.accent, borderRadius: radius }],
|
|
939
1170
|
onPress: () => void submitFeedback("confirms"),
|
|
940
1171
|
disabled: feedbackSending,
|
|
941
1172
|
accessibilityRole: "button",
|
|
942
1173
|
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
943
|
-
children: /* @__PURE__ */ (0,
|
|
1174
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: colors.accentFg }, font], children: rc.ui.yes })
|
|
944
1175
|
}
|
|
945
1176
|
),
|
|
946
|
-
/* @__PURE__ */ (0,
|
|
947
|
-
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1178
|
+
import_react_native3.TouchableOpacity,
|
|
948
1179
|
{
|
|
949
|
-
style: [
|
|
1180
|
+
style: [s2.verifyBtn, { backgroundColor: colors.border, borderRadius: radius }],
|
|
950
1181
|
onPress: () => void submitFeedback("not_fixed"),
|
|
951
1182
|
disabled: feedbackSending,
|
|
952
1183
|
accessibilityRole: "button",
|
|
953
1184
|
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
954
|
-
children: /* @__PURE__ */ (0,
|
|
1185
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: colors.fg }, font], children: rc.ui.notYet })
|
|
955
1186
|
}
|
|
956
1187
|
)
|
|
957
1188
|
] }) : null,
|
|
958
|
-
feedbackError ? /* @__PURE__ */ (0,
|
|
959
|
-
/* @__PURE__ */ (0,
|
|
960
|
-
/* @__PURE__ */ (0,
|
|
961
|
-
|
|
1189
|
+
feedbackError ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.error, marginBottom: 8 }, font], accessibilityRole: "alert", children: rc.ui.sendFailed }) : null,
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.composer, children: [
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1192
|
+
import_react_native3.TextInput,
|
|
962
1193
|
{
|
|
963
1194
|
style: [
|
|
964
|
-
|
|
965
|
-
|
|
1195
|
+
s2.input,
|
|
1196
|
+
s2.composerInput,
|
|
966
1197
|
{ backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius },
|
|
967
1198
|
font
|
|
968
1199
|
],
|
|
@@ -979,11 +1210,11 @@ var MushiBottomSheet = ({
|
|
|
979
1210
|
accessibilityLabel: t.flows.thread.replyPlaceholder
|
|
980
1211
|
}
|
|
981
1212
|
),
|
|
982
|
-
/* @__PURE__ */ (0,
|
|
983
|
-
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1214
|
+
import_react_native3.TouchableOpacity,
|
|
984
1215
|
{
|
|
985
1216
|
style: [
|
|
986
|
-
|
|
1217
|
+
s2.sendBtn,
|
|
987
1218
|
{
|
|
988
1219
|
backgroundColor: replyText.trim() && replyState !== "sending" ? colors.accent : colors.disabled,
|
|
989
1220
|
borderRadius: radius
|
|
@@ -994,11 +1225,11 @@ var MushiBottomSheet = ({
|
|
|
994
1225
|
accessibilityRole: "button",
|
|
995
1226
|
accessibilityLabel: replyState === "failed" ? rc.ui.retry : t.flows.thread.send,
|
|
996
1227
|
accessibilityState: { disabled: !replyText.trim() || replyState === "sending", busy: replyState === "sending" },
|
|
997
|
-
children: /* @__PURE__ */ (0,
|
|
998
|
-
|
|
1228
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1229
|
+
import_react_native3.Text,
|
|
999
1230
|
{
|
|
1000
1231
|
style: [
|
|
1001
|
-
|
|
1232
|
+
s2.submitText,
|
|
1002
1233
|
{ color: replyText.trim() && replyState !== "sending" ? colors.accentFg : colors.disabledFg },
|
|
1003
1234
|
font
|
|
1004
1235
|
],
|
|
@@ -1008,7 +1239,7 @@ var MushiBottomSheet = ({
|
|
|
1008
1239
|
}
|
|
1009
1240
|
)
|
|
1010
1241
|
] }),
|
|
1011
|
-
replyState === "failed" ? /* @__PURE__ */ (0,
|
|
1242
|
+
replyState === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.Text, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: [
|
|
1012
1243
|
rc.ui.sendFailed,
|
|
1013
1244
|
" \xB7 ",
|
|
1014
1245
|
rc.ui.retry
|
|
@@ -1016,50 +1247,50 @@ var MushiBottomSheet = ({
|
|
|
1016
1247
|
] });
|
|
1017
1248
|
const renderInboxList = () => {
|
|
1018
1249
|
if (inboxLoading && !inboxLoaded) {
|
|
1019
|
-
return /* @__PURE__ */ (0,
|
|
1250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted }, font], children: t.flows.reports.loading });
|
|
1020
1251
|
}
|
|
1021
1252
|
if (inboxReports.length === 0) {
|
|
1022
|
-
return /* @__PURE__ */ (0,
|
|
1253
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted }, font], children: rc.ui.empty });
|
|
1023
1254
|
}
|
|
1024
1255
|
return inboxReports.map((r) => {
|
|
1025
|
-
const view = (0,
|
|
1256
|
+
const view = (0, import_reporter_ui2.reporterStatus)(r, locale);
|
|
1026
1257
|
const unread = (r.unread_count ?? 0) > 0;
|
|
1027
1258
|
const title = (r.title ?? r.summary ?? r.description ?? "Report").slice(0, 80);
|
|
1028
|
-
return /* @__PURE__ */ (0,
|
|
1029
|
-
|
|
1259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1260
|
+
import_react_native3.TouchableOpacity,
|
|
1030
1261
|
{
|
|
1031
|
-
style: [
|
|
1262
|
+
style: [s2.inboxRow, { borderColor: colors.border }],
|
|
1032
1263
|
onPress: () => void openThread(r.id),
|
|
1033
1264
|
accessibilityRole: "button",
|
|
1034
1265
|
accessibilityLabel: `${view.label}. ${title}${unread ? `. ${r.unread_count} new` : ""}`,
|
|
1035
1266
|
children: [
|
|
1036
|
-
/* @__PURE__ */ (0,
|
|
1037
|
-
/* @__PURE__ */ (0,
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, fontWeight: unread ? "700" : "600" }, font], numberOfLines: 1, children: title }),
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.Text, { style: [{ color: unread ? colors.fg : colors.muted, fontSize: 12, marginTop: 2 }, font], numberOfLines: 1, children: [
|
|
1038
1269
|
view.label,
|
|
1039
1270
|
view.othersNote ? ` \xB7 ${view.othersNote}` : ""
|
|
1040
1271
|
] }),
|
|
1041
|
-
unread && r.last_event_preview ? /* @__PURE__ */ (0,
|
|
1272
|
+
unread && r.last_event_preview ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, fontSize: 12, fontWeight: "700", marginTop: 2 }, font], numberOfLines: 1, children: r.last_event_preview }) : null
|
|
1042
1273
|
]
|
|
1043
1274
|
},
|
|
1044
1275
|
r.id
|
|
1045
1276
|
);
|
|
1046
1277
|
});
|
|
1047
1278
|
};
|
|
1048
|
-
return /* @__PURE__ */ (0,
|
|
1049
|
-
|
|
1279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, onRequestClose: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1280
|
+
import_react_native3.KeyboardAvoidingView,
|
|
1050
1281
|
{
|
|
1051
|
-
style:
|
|
1052
|
-
behavior:
|
|
1053
|
-
keyboardVerticalOffset:
|
|
1282
|
+
style: s2.flex,
|
|
1283
|
+
behavior: import_react_native3.Platform.OS === "ios" ? "padding" : "height",
|
|
1284
|
+
keyboardVerticalOffset: import_react_native3.Platform.OS === "ios" ? 0 : 20,
|
|
1054
1285
|
children: [
|
|
1055
|
-
/* @__PURE__ */ (0,
|
|
1056
|
-
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1287
|
+
import_react_native3.Animated.View,
|
|
1057
1288
|
{
|
|
1058
|
-
style: [
|
|
1059
|
-
children: /* @__PURE__ */ (0,
|
|
1060
|
-
|
|
1289
|
+
style: [s2.backdrop, { backgroundColor: colors.backdrop, opacity: backdropOpacity }],
|
|
1290
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1291
|
+
import_react_native3.TouchableOpacity,
|
|
1061
1292
|
{
|
|
1062
|
-
style:
|
|
1293
|
+
style: s2.flex,
|
|
1063
1294
|
activeOpacity: 1,
|
|
1064
1295
|
onPress: handleClose,
|
|
1065
1296
|
accessibilityRole: "button",
|
|
@@ -1068,21 +1299,21 @@ var MushiBottomSheet = ({
|
|
|
1068
1299
|
)
|
|
1069
1300
|
}
|
|
1070
1301
|
),
|
|
1071
|
-
/* @__PURE__ */ (0,
|
|
1072
|
-
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1303
|
+
import_react_native3.Animated.View,
|
|
1073
1304
|
{
|
|
1074
1305
|
accessibilityViewIsModal: true,
|
|
1075
1306
|
onAccessibilityEscape: handleClose,
|
|
1076
1307
|
style: [
|
|
1077
|
-
|
|
1308
|
+
s2.sheet,
|
|
1078
1309
|
{ backgroundColor: colors.bg, transform: [{ translateY }] }
|
|
1079
1310
|
],
|
|
1080
1311
|
children: [
|
|
1081
|
-
/* @__PURE__ */ (0,
|
|
1082
|
-
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1313
|
+
import_react_native3.View,
|
|
1083
1314
|
{
|
|
1084
1315
|
...panResponder.panHandlers,
|
|
1085
|
-
style:
|
|
1316
|
+
style: s2.handleArea,
|
|
1086
1317
|
accessible: true,
|
|
1087
1318
|
accessibilityRole: "adjustable",
|
|
1088
1319
|
accessibilityLabel: t.widget.close,
|
|
@@ -1090,57 +1321,57 @@ var MushiBottomSheet = ({
|
|
|
1090
1321
|
onAccessibilityAction: (e) => {
|
|
1091
1322
|
if (e.nativeEvent.actionName === "decrement" || e.nativeEvent.actionName === "escape") handleClose();
|
|
1092
1323
|
},
|
|
1093
|
-
children: /* @__PURE__ */ (0,
|
|
1324
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [s2.handle, { backgroundColor: colors.muted }] })
|
|
1094
1325
|
}
|
|
1095
1326
|
),
|
|
1096
|
-
/* @__PURE__ */ (0,
|
|
1097
|
-
/* @__PURE__ */ (0,
|
|
1098
|
-
|
|
1327
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [s2.header, { borderBottomColor: colors.border }], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { accessibilityRole: "header", style: [s2.headerTitle, { color: colors.fg }, font], children: headerTitle }) }),
|
|
1328
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [s2.tabRow, { borderBottomColor: colors.border }], accessibilityRole: "tablist", children: sheetTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1329
|
+
import_react_native3.TouchableOpacity,
|
|
1099
1330
|
{
|
|
1100
1331
|
onPress: () => {
|
|
1101
1332
|
setSheetTab(tab);
|
|
1102
1333
|
if (tab === "inbox") void loadInbox({ silent: inboxLoaded });
|
|
1103
1334
|
else closeThread();
|
|
1104
1335
|
},
|
|
1105
|
-
style: [
|
|
1336
|
+
style: [s2.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
1106
1337
|
accessibilityRole: "tab",
|
|
1107
1338
|
accessibilityState: { selected: sheetTab === tab },
|
|
1108
|
-
children: /* @__PURE__ */ (0,
|
|
1339
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.tabLabel, { color: sheetTab === tab ? colors.fg : colors.muted }, font], children: tab === "report" ? t.widget.trigger : tab === "inbox" ? t.flows.reports.title : assistantLabel })
|
|
1109
1340
|
},
|
|
1110
1341
|
tab
|
|
1111
1342
|
)) }),
|
|
1112
|
-
sheetTab === "assistant" ? /* @__PURE__ */ (0,
|
|
1113
|
-
assistantTurns.length === 0 ? /* @__PURE__ */ (0,
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1115
|
-
assistantSuggestions.map((chip) => /* @__PURE__ */ (0,
|
|
1116
|
-
|
|
1343
|
+
sheetTab === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", children: [
|
|
1344
|
+
assistantTurns.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1345
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, marginBottom: 12, lineHeight: 20 }, font], children: greeting }),
|
|
1346
|
+
assistantSuggestions.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1347
|
+
import_react_native3.TouchableOpacity,
|
|
1117
1348
|
{
|
|
1118
|
-
style: [
|
|
1349
|
+
style: [s2.assistantChip, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1119
1350
|
onPress: () => void sendAssistant(chip),
|
|
1120
1351
|
accessibilityRole: "button",
|
|
1121
|
-
children: /* @__PURE__ */ (0,
|
|
1352
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, fontSize: 13 }, font], children: chip })
|
|
1122
1353
|
},
|
|
1123
1354
|
chip
|
|
1124
1355
|
))
|
|
1125
|
-
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */ (0,
|
|
1126
|
-
|
|
1356
|
+
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1357
|
+
import_react_native3.View,
|
|
1127
1358
|
{
|
|
1128
1359
|
style: [
|
|
1129
|
-
|
|
1360
|
+
s2.assistantBubble,
|
|
1130
1361
|
{
|
|
1131
1362
|
alignSelf: turn.role === "user" ? "flex-end" : "flex-start",
|
|
1132
1363
|
backgroundColor: turn.role === "user" ? colors.accent : colors.surface
|
|
1133
1364
|
}
|
|
1134
1365
|
],
|
|
1135
1366
|
children: [
|
|
1136
|
-
/* @__PURE__ */ (0,
|
|
1137
|
-
turn.options?.map((opt) => /* @__PURE__ */ (0,
|
|
1138
|
-
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: turn.role === "user" ? colors.accentFg : colors.fg }, font], children: turn.text }),
|
|
1368
|
+
turn.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1369
|
+
import_react_native3.TouchableOpacity,
|
|
1139
1370
|
{
|
|
1140
1371
|
onPress: () => void sendAssistant(opt),
|
|
1141
1372
|
style: { marginTop: 8 },
|
|
1142
1373
|
accessibilityRole: "button",
|
|
1143
|
-
children: /* @__PURE__ */ (0,
|
|
1374
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.accent, fontSize: 12 }, font], children: opt })
|
|
1144
1375
|
},
|
|
1145
1376
|
opt
|
|
1146
1377
|
))
|
|
@@ -1148,13 +1379,13 @@ var MushiBottomSheet = ({
|
|
|
1148
1379
|
},
|
|
1149
1380
|
`${turn.role}-${idx}`
|
|
1150
1381
|
)),
|
|
1151
|
-
assistantSending ? /* @__PURE__ */ (0,
|
|
1152
|
-
assistantError ? /* @__PURE__ */ (0,
|
|
1153
|
-
/* @__PURE__ */ (0,
|
|
1154
|
-
/* @__PURE__ */ (0,
|
|
1155
|
-
|
|
1382
|
+
assistantSending ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, marginTop: 8 }, font], accessibilityLiveRegion: "polite", children: t.assistant.thinking }) : null,
|
|
1383
|
+
assistantError ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.error, marginTop: 8 }, font], accessibilityRole: "alert", children: assistantError }) : null,
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.assistantComposer, children: [
|
|
1385
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1386
|
+
import_react_native3.TextInput,
|
|
1156
1387
|
{
|
|
1157
|
-
style: [
|
|
1388
|
+
style: [s2.input, { flex: 1, minHeight: 44, backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius }, font],
|
|
1158
1389
|
placeholder: t.assistant.inputPlaceholder,
|
|
1159
1390
|
placeholderTextColor: colors.muted,
|
|
1160
1391
|
value: assistantInput,
|
|
@@ -1162,71 +1393,101 @@ var MushiBottomSheet = ({
|
|
|
1162
1393
|
editable: !assistantSending
|
|
1163
1394
|
}
|
|
1164
1395
|
),
|
|
1165
|
-
/* @__PURE__ */ (0,
|
|
1166
|
-
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1397
|
+
import_react_native3.TouchableOpacity,
|
|
1167
1398
|
{
|
|
1168
|
-
style: [
|
|
1399
|
+
style: [s2.submitBtn, { backgroundColor: colors.accent, paddingHorizontal: 16, borderRadius: radius }],
|
|
1169
1400
|
onPress: () => void sendAssistant(assistantInput),
|
|
1170
1401
|
disabled: !assistantInput.trim() || assistantSending,
|
|
1171
1402
|
accessibilityRole: "button",
|
|
1172
1403
|
accessibilityLabel: t.flows.thread.send,
|
|
1173
1404
|
accessibilityState: { disabled: !assistantInput.trim() || assistantSending, busy: assistantSending },
|
|
1174
|
-
children: /* @__PURE__ */ (0,
|
|
1405
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: colors.accentFg }], children: "\u2191" })
|
|
1175
1406
|
}
|
|
1176
1407
|
)
|
|
1177
1408
|
] })
|
|
1178
|
-
] }) : sheetTab === "inbox" ? /* @__PURE__ */ (0,
|
|
1179
|
-
/* @__PURE__ */ (0,
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1409
|
+
] }) : sheetTab === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", contentContainerStyle: { paddingBottom: 24 }, children: selectedReportId ? renderThread() : renderInboxList() }) : phase === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", contentContainerStyle: { paddingBottom: 24 }, children: [
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.sentWrap, accessibilityLiveRegion: "polite", children: [
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.sentEmoji], importantForAccessibility: "no", children: "\u2705" }),
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.sentText, { color: colors.fg }, font], children: rc.ui.receipt })
|
|
1413
|
+
] }),
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.verifyRow, children: [
|
|
1415
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1416
|
+
import_react_native3.TouchableOpacity,
|
|
1417
|
+
{
|
|
1418
|
+
style: [s2.verifyBtn, { backgroundColor: colors.accent, borderRadius: radius }],
|
|
1419
|
+
onPress: () => {
|
|
1420
|
+
resetForm();
|
|
1421
|
+
setSheetTab("inbox");
|
|
1422
|
+
void loadInbox();
|
|
1423
|
+
},
|
|
1424
|
+
accessibilityRole: "button",
|
|
1425
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: colors.accentFg }, font], children: rc.ui.trackIt })
|
|
1426
|
+
}
|
|
1427
|
+
),
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1429
|
+
import_react_native3.TouchableOpacity,
|
|
1430
|
+
{
|
|
1431
|
+
style: [s2.verifyBtn, { backgroundColor: colors.border, borderRadius: radius }],
|
|
1432
|
+
onPress: handleClose,
|
|
1433
|
+
accessibilityRole: "button",
|
|
1434
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: colors.fg }, font], children: rc.ui.done })
|
|
1435
|
+
}
|
|
1436
|
+
)
|
|
1437
|
+
] }),
|
|
1438
|
+
emailState === "sent" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, marginTop: 12 }, font], accessibilityLiveRegion: "polite", children: rc.ui.emailCheckInbox }) : emailState !== "hidden" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: { marginTop: 12 }, children: [
|
|
1439
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.fg, marginBottom: 6 }, font], children: rc.ui.emailOptIn }),
|
|
1440
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.composer, children: [
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1442
|
+
import_react_native3.TextInput,
|
|
1443
|
+
{
|
|
1444
|
+
style: [
|
|
1445
|
+
s2.input,
|
|
1446
|
+
s2.composerInput,
|
|
1447
|
+
{ backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius },
|
|
1448
|
+
font
|
|
1449
|
+
],
|
|
1450
|
+
value: emailInput,
|
|
1451
|
+
onChangeText: (v) => {
|
|
1452
|
+
setEmailInput(v.slice(0, 254));
|
|
1453
|
+
if (emailState === "invalid" || emailState === "failed") setEmailState("offer");
|
|
1454
|
+
},
|
|
1455
|
+
placeholder: rc.ui.emailPlaceholder,
|
|
1456
|
+
placeholderTextColor: colors.muted,
|
|
1457
|
+
keyboardType: "email-address",
|
|
1458
|
+
autoCapitalize: "none",
|
|
1459
|
+
autoComplete: "email",
|
|
1460
|
+
textContentType: "emailAddress",
|
|
1461
|
+
editable: emailState !== "sending",
|
|
1462
|
+
accessibilityLabel: rc.ui.emailOptIn
|
|
1463
|
+
}
|
|
1464
|
+
),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1466
|
+
import_react_native3.TouchableOpacity,
|
|
1467
|
+
{
|
|
1468
|
+
style: [s2.sendBtn, { backgroundColor: emailInput.trim() ? colors.accent : colors.disabled, borderRadius: radius }],
|
|
1469
|
+
onPress: () => void submitEmail(),
|
|
1470
|
+
disabled: !emailInput.trim() || emailState === "sending",
|
|
1471
|
+
accessibilityRole: "button",
|
|
1472
|
+
accessibilityState: { disabled: !emailInput.trim() || emailState === "sending", busy: emailState === "sending" },
|
|
1473
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: emailInput.trim() ? colors.accentFg : colors.disabledFg }, font], children: emailState === "sending" ? rc.ui.sending : rc.ui.emailSubmit })
|
|
1474
|
+
}
|
|
1475
|
+
)
|
|
1476
|
+
] }),
|
|
1477
|
+
emailState === "invalid" || emailState === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: emailState === "invalid" ? rc.ui.emailInvalid : rc.ui.emailFailed }) : null
|
|
1478
|
+
] }) : null
|
|
1479
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1480
|
+
import_react_native3.ScrollView,
|
|
1183
1481
|
{
|
|
1184
|
-
style:
|
|
1482
|
+
style: s2.body,
|
|
1185
1483
|
keyboardShouldPersistTaps: "handled",
|
|
1186
1484
|
contentContainerStyle: { paddingBottom: 24 },
|
|
1187
1485
|
children: [
|
|
1188
|
-
/* @__PURE__ */ (0,
|
|
1189
|
-
|
|
1190
|
-
const active = category === key;
|
|
1191
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1192
|
-
import_react_native2.TouchableOpacity,
|
|
1193
|
-
{
|
|
1194
|
-
onPress: () => setCategory(key),
|
|
1195
|
-
activeOpacity: 0.7,
|
|
1196
|
-
accessibilityRole: "radio",
|
|
1197
|
-
accessibilityState: { selected: active, checked: active },
|
|
1198
|
-
accessibilityLabel: t.step1.categories[key],
|
|
1199
|
-
style: [
|
|
1200
|
-
s.catBtn,
|
|
1201
|
-
{
|
|
1202
|
-
backgroundColor: active ? colors.accent : colors.surface,
|
|
1203
|
-
borderColor: active ? colors.accent : colors.border
|
|
1204
|
-
}
|
|
1205
|
-
],
|
|
1206
|
-
children: [
|
|
1207
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: s.catEmoji, importantForAccessibility: "no", children: CATEGORY_EMOJI[key] }),
|
|
1208
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1209
|
-
import_react_native2.Text,
|
|
1210
|
-
{
|
|
1211
|
-
numberOfLines: 1,
|
|
1212
|
-
style: [
|
|
1213
|
-
s.catLabel,
|
|
1214
|
-
{ color: active ? colors.accentFg : colors.fg },
|
|
1215
|
-
font
|
|
1216
|
-
],
|
|
1217
|
-
children: t.step1.categories[key]
|
|
1218
|
-
}
|
|
1219
|
-
)
|
|
1220
|
-
]
|
|
1221
|
-
},
|
|
1222
|
-
key
|
|
1223
|
-
);
|
|
1224
|
-
}) }),
|
|
1225
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1226
|
-
import_react_native2.TextInput,
|
|
1486
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1487
|
+
import_react_native3.TextInput,
|
|
1227
1488
|
{
|
|
1228
1489
|
style: [
|
|
1229
|
-
|
|
1490
|
+
s2.input,
|
|
1230
1491
|
{
|
|
1231
1492
|
backgroundColor: colors.surface,
|
|
1232
1493
|
color: colors.fg,
|
|
@@ -1250,22 +1511,59 @@ var MushiBottomSheet = ({
|
|
|
1250
1511
|
maxLength: 4e3
|
|
1251
1512
|
}
|
|
1252
1513
|
),
|
|
1253
|
-
submitError ? /* @__PURE__ */ (0,
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1514
|
+
submitError ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: submitError }) : null,
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [s2.catRow, { marginTop: 12 }], accessibilityRole: "radiogroup", children: import_reporter_ui2.REPORTER_CATEGORIES.map((key) => {
|
|
1516
|
+
const active = category === key;
|
|
1517
|
+
const label = (0, import_reporter_ui2.reporterCategoryLabel)(key, locale);
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1519
|
+
import_react_native3.TouchableOpacity,
|
|
1520
|
+
{
|
|
1521
|
+
onPress: () => setCategory(active ? null : key),
|
|
1522
|
+
activeOpacity: 0.7,
|
|
1523
|
+
accessibilityRole: "radio",
|
|
1524
|
+
accessibilityState: { selected: active, checked: active },
|
|
1525
|
+
accessibilityLabel: label,
|
|
1526
|
+
style: [
|
|
1527
|
+
s2.catBtn,
|
|
1528
|
+
{
|
|
1529
|
+
backgroundColor: active ? colors.accent : colors.surface,
|
|
1530
|
+
borderColor: active ? colors.accent : colors.border
|
|
1531
|
+
}
|
|
1532
|
+
],
|
|
1533
|
+
children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: s2.catEmoji, importantForAccessibility: "no", children: CATEGORY_EMOJI[key] }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1536
|
+
import_react_native3.Text,
|
|
1537
|
+
{
|
|
1538
|
+
numberOfLines: 1,
|
|
1539
|
+
style: [
|
|
1540
|
+
s2.catLabel,
|
|
1541
|
+
{ color: active ? colors.accentFg : colors.fg },
|
|
1542
|
+
font
|
|
1543
|
+
],
|
|
1544
|
+
children: label
|
|
1545
|
+
}
|
|
1546
|
+
)
|
|
1547
|
+
]
|
|
1548
|
+
},
|
|
1549
|
+
key
|
|
1550
|
+
);
|
|
1551
|
+
}) }),
|
|
1552
|
+
activeScreenshot ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.screenshotRow, children: [
|
|
1553
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1554
|
+
import_react_native3.Image,
|
|
1257
1555
|
{
|
|
1258
1556
|
source: { uri: activeScreenshot },
|
|
1259
|
-
style: [
|
|
1557
|
+
style: [s2.screenshotThumb, { backgroundColor: colors.fg }],
|
|
1260
1558
|
accessibilityLabel: t.step3.screenshotPreviewAlt
|
|
1261
1559
|
}
|
|
1262
1560
|
),
|
|
1263
|
-
/* @__PURE__ */ (0,
|
|
1264
|
-
/* @__PURE__ */ (0,
|
|
1265
|
-
/* @__PURE__ */ (0,
|
|
1561
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: s2.screenshotMeta, children: [
|
|
1562
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.screenshotLabel, { color: colors.fg }, font], children: t.step3.screenshotAttached.replace(" \u2713", "") }),
|
|
1563
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.screenshotSub, { color: colors.muted }, font], children: screenshotSensitiveHint && screenshotSensitiveHint.trim() ? `\u26A0 ${screenshotSensitiveHint}` : t.step3.screenshotSensitiveHint.split("\u2014")[0]?.trim() ?? t.step3.screenshotSensitiveHint })
|
|
1266
1564
|
] }),
|
|
1267
|
-
/* @__PURE__ */ (0,
|
|
1268
|
-
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1566
|
+
import_react_native3.TouchableOpacity,
|
|
1269
1567
|
{
|
|
1270
1568
|
onPress: () => {
|
|
1271
1569
|
setScreenshotAttached(false);
|
|
@@ -1274,13 +1572,13 @@ var MushiBottomSheet = ({
|
|
|
1274
1572
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1275
1573
|
accessibilityRole: "button",
|
|
1276
1574
|
accessibilityLabel: t.widget.close,
|
|
1277
|
-
children: /* @__PURE__ */ (0,
|
|
1575
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.screenshotRemove, { color: colors.muted }], children: "\u2715" })
|
|
1278
1576
|
}
|
|
1279
1577
|
)
|
|
1280
1578
|
] }) : null,
|
|
1281
|
-
submitHint ? /* @__PURE__ */ (0,
|
|
1282
|
-
/* @__PURE__ */ (0,
|
|
1283
|
-
|
|
1579
|
+
submitHint ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [{ color: colors.muted, fontSize: 12, marginBottom: 6 }, font], children: submitHint }) : null,
|
|
1580
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1581
|
+
import_react_native3.TouchableOpacity,
|
|
1284
1582
|
{
|
|
1285
1583
|
onPress: handleSubmit,
|
|
1286
1584
|
disabled: !canSubmit,
|
|
@@ -1290,10 +1588,10 @@ var MushiBottomSheet = ({
|
|
|
1290
1588
|
accessibilityHint: submitHint,
|
|
1291
1589
|
accessibilityState: { disabled: !canSubmit, busy: phase === "sending" },
|
|
1292
1590
|
style: [
|
|
1293
|
-
|
|
1591
|
+
s2.submitBtn,
|
|
1294
1592
|
{ backgroundColor: canSubmit ? colors.accent : colors.disabled, borderRadius: radius }
|
|
1295
1593
|
],
|
|
1296
|
-
children: /* @__PURE__ */ (0,
|
|
1594
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.Text, { style: [s2.submitText, { color: canSubmit ? colors.accentFg : colors.disabledFg }, font], children: phase === "sending" ? t.widget.submitting : t.widget.submit })
|
|
1297
1595
|
}
|
|
1298
1596
|
)
|
|
1299
1597
|
]
|
|
@@ -1306,7 +1604,7 @@ var MushiBottomSheet = ({
|
|
|
1306
1604
|
}
|
|
1307
1605
|
) });
|
|
1308
1606
|
};
|
|
1309
|
-
var
|
|
1607
|
+
var s2 = import_react_native3.StyleSheet.create({
|
|
1310
1608
|
flex: { flex: 1 },
|
|
1311
1609
|
backdrop: {
|
|
1312
1610
|
// Inlined StyleSheet.absoluteFillObject — RN 0.86 dropped it from the
|
|
@@ -1323,10 +1621,10 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1323
1621
|
left: 0,
|
|
1324
1622
|
right: 0,
|
|
1325
1623
|
minHeight: SHEET_HEIGHT,
|
|
1326
|
-
borderTopLeftRadius:
|
|
1327
|
-
borderTopRightRadius:
|
|
1328
|
-
paddingBottom:
|
|
1329
|
-
shadowColor:
|
|
1624
|
+
borderTopLeftRadius: import_core5.MUSHI_RADIUS.sheet,
|
|
1625
|
+
borderTopRightRadius: import_core5.MUSHI_RADIUS.sheet,
|
|
1626
|
+
paddingBottom: import_react_native3.Platform.OS === "ios" ? 34 : import_core5.MUSHI_SPACING.roomy,
|
|
1627
|
+
shadowColor: import_core5.MUSHI_SHADOW_INK,
|
|
1330
1628
|
shadowOffset: { width: 0, height: -3 },
|
|
1331
1629
|
shadowOpacity: 0.12,
|
|
1332
1630
|
shadowRadius: 8,
|
|
@@ -1334,17 +1632,17 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1334
1632
|
},
|
|
1335
1633
|
handleArea: {
|
|
1336
1634
|
alignItems: "center",
|
|
1337
|
-
paddingVertical:
|
|
1635
|
+
paddingVertical: import_core5.MUSHI_SPACING.comfy
|
|
1338
1636
|
},
|
|
1339
1637
|
handle: {
|
|
1340
1638
|
width: 40,
|
|
1341
1639
|
height: 5,
|
|
1342
|
-
borderRadius:
|
|
1640
|
+
borderRadius: import_core5.MUSHI_RADIUS.control,
|
|
1343
1641
|
opacity: 0.5
|
|
1344
1642
|
},
|
|
1345
1643
|
header: {
|
|
1346
|
-
paddingHorizontal:
|
|
1347
|
-
paddingBottom:
|
|
1644
|
+
paddingHorizontal: import_core5.MUSHI_SPACING.lounge,
|
|
1645
|
+
paddingBottom: import_core5.MUSHI_SPACING.comfy
|
|
1348
1646
|
},
|
|
1349
1647
|
headerTitle: {
|
|
1350
1648
|
fontSize: 18,
|
|
@@ -1352,22 +1650,22 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1352
1650
|
letterSpacing: -0.2
|
|
1353
1651
|
},
|
|
1354
1652
|
body: {
|
|
1355
|
-
paddingHorizontal:
|
|
1356
|
-
paddingTop:
|
|
1653
|
+
paddingHorizontal: import_core5.MUSHI_SPACING.lounge,
|
|
1654
|
+
paddingTop: import_core5.MUSHI_SPACING.tight
|
|
1357
1655
|
},
|
|
1358
1656
|
stepLabel: {
|
|
1359
|
-
fontSize:
|
|
1657
|
+
fontSize: import_core5.MUSHI_TYPE.sizeLabel,
|
|
1360
1658
|
fontWeight: "600",
|
|
1361
1659
|
letterSpacing: 0.2,
|
|
1362
|
-
marginTop:
|
|
1363
|
-
marginBottom:
|
|
1660
|
+
marginTop: import_core5.MUSHI_SPACING.snug,
|
|
1661
|
+
marginBottom: import_core5.MUSHI_SPACING.comfy,
|
|
1364
1662
|
textTransform: "uppercase"
|
|
1365
1663
|
},
|
|
1366
1664
|
catRow: {
|
|
1367
1665
|
flexDirection: "row",
|
|
1368
1666
|
flexWrap: "wrap",
|
|
1369
1667
|
gap: 8,
|
|
1370
|
-
marginBottom:
|
|
1668
|
+
marginBottom: import_core5.MUSHI_SPACING.roomy
|
|
1371
1669
|
},
|
|
1372
1670
|
catBtn: {
|
|
1373
1671
|
flexDirection: "row",
|
|
@@ -1391,7 +1689,7 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1391
1689
|
padding: 14,
|
|
1392
1690
|
fontSize: 15,
|
|
1393
1691
|
minHeight: 100,
|
|
1394
|
-
marginBottom:
|
|
1692
|
+
marginBottom: import_core5.MUSHI_SPACING.roomy
|
|
1395
1693
|
},
|
|
1396
1694
|
submitBtn: {
|
|
1397
1695
|
paddingVertical: 14,
|
|
@@ -1399,7 +1697,7 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1399
1697
|
minHeight: 44
|
|
1400
1698
|
},
|
|
1401
1699
|
submitText: {
|
|
1402
|
-
color:
|
|
1700
|
+
color: import_core5.MUSHI_INVERSE,
|
|
1403
1701
|
fontSize: 16,
|
|
1404
1702
|
fontWeight: "700"
|
|
1405
1703
|
},
|
|
@@ -1450,7 +1748,7 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1450
1748
|
},
|
|
1451
1749
|
tabRow: {
|
|
1452
1750
|
flexDirection: "row",
|
|
1453
|
-
borderBottomWidth:
|
|
1751
|
+
borderBottomWidth: import_react_native3.StyleSheet.hairlineWidth,
|
|
1454
1752
|
marginBottom: 8
|
|
1455
1753
|
},
|
|
1456
1754
|
tabBtn: {
|
|
@@ -1468,10 +1766,10 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1468
1766
|
inboxRow: {
|
|
1469
1767
|
paddingVertical: 12,
|
|
1470
1768
|
minHeight: 56,
|
|
1471
|
-
borderBottomWidth:
|
|
1769
|
+
borderBottomWidth: import_react_native3.StyleSheet.hairlineWidth
|
|
1472
1770
|
},
|
|
1473
1771
|
headerCard: {
|
|
1474
|
-
borderWidth:
|
|
1772
|
+
borderWidth: import_react_native3.StyleSheet.hairlineWidth,
|
|
1475
1773
|
padding: 12,
|
|
1476
1774
|
marginBottom: 12
|
|
1477
1775
|
},
|
|
@@ -1561,14 +1859,14 @@ var s = import_react_native2.StyleSheet.create({
|
|
|
1561
1859
|
});
|
|
1562
1860
|
|
|
1563
1861
|
// src/components/MushiFloatingButton.tsx
|
|
1564
|
-
var
|
|
1565
|
-
var
|
|
1566
|
-
var
|
|
1567
|
-
var
|
|
1568
|
-
var FAB_SIZE =
|
|
1862
|
+
var import_react3 = require("react");
|
|
1863
|
+
var import_react_native4 = require("react-native");
|
|
1864
|
+
var import_core6 = require("@mushi-mushi/core");
|
|
1865
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1866
|
+
var FAB_SIZE = import_core6.MUSHI_GEOMETRY.fabSize;
|
|
1569
1867
|
var EDGE_PADDING = 12;
|
|
1570
1868
|
function getScreenBounds() {
|
|
1571
|
-
const { width, height } =
|
|
1869
|
+
const { width, height } = import_react_native4.Dimensions.get("window");
|
|
1572
1870
|
return { width, height };
|
|
1573
1871
|
}
|
|
1574
1872
|
function clamp(value, min, max) {
|
|
@@ -1599,25 +1897,25 @@ var MushiFloatingButton = ({
|
|
|
1599
1897
|
config,
|
|
1600
1898
|
accent
|
|
1601
1899
|
}) => {
|
|
1602
|
-
const scheme = (0,
|
|
1900
|
+
const scheme = (0, import_react_native4.useColorScheme)();
|
|
1603
1901
|
const dark = scheme === "dark";
|
|
1604
1902
|
const draggable = config?.draggable ?? false;
|
|
1605
1903
|
const snapToEdge = config?.snapToEdge ?? true;
|
|
1606
1904
|
const persist = config?.persist ?? false;
|
|
1607
|
-
const baseBottom = inset?.bottom ?? (
|
|
1905
|
+
const baseBottom = inset?.bottom ?? (import_react_native4.Platform.OS === "ios" ? 50 : 28);
|
|
1608
1906
|
const baseX = position === "bottom-left" ? inset?.left ?? EDGE_PADDING : (() => {
|
|
1609
1907
|
const { width } = getScreenBounds();
|
|
1610
1908
|
return width - FAB_SIZE - (inset?.right ?? EDGE_PADDING);
|
|
1611
1909
|
})();
|
|
1612
|
-
const scale = (0,
|
|
1613
|
-
const posX = (0,
|
|
1614
|
-
const posY = (0,
|
|
1615
|
-
const currentX = (0,
|
|
1616
|
-
const currentY = (0,
|
|
1617
|
-
const isDragging = (0,
|
|
1618
|
-
const pal = (0,
|
|
1910
|
+
const scale = (0, import_react3.useRef)(new import_react_native4.Animated.Value(1)).current;
|
|
1911
|
+
const posX = (0, import_react3.useRef)(new import_react_native4.Animated.Value(baseX)).current;
|
|
1912
|
+
const posY = (0, import_react3.useRef)(new import_react_native4.Animated.Value(0)).current;
|
|
1913
|
+
const currentX = (0, import_react3.useRef)(baseX);
|
|
1914
|
+
const currentY = (0, import_react3.useRef)(0);
|
|
1915
|
+
const isDragging = (0, import_react3.useRef)(false);
|
|
1916
|
+
const pal = (0, import_core6.mushiPalette)(dark ? "dark" : "light");
|
|
1619
1917
|
const accentColor = accent ?? pal.accent;
|
|
1620
|
-
(0,
|
|
1918
|
+
(0, import_react3.useEffect)(() => {
|
|
1621
1919
|
if (!persist) return;
|
|
1622
1920
|
void loadStoredPos().then((pos) => {
|
|
1623
1921
|
if (!pos) return;
|
|
@@ -1627,7 +1925,7 @@ var MushiFloatingButton = ({
|
|
|
1627
1925
|
posY.setValue(pos.y);
|
|
1628
1926
|
});
|
|
1629
1927
|
}, [persist, posX, posY]);
|
|
1630
|
-
const snapAndPersist = (0,
|
|
1928
|
+
const snapAndPersist = (0, import_react3.useCallback)(
|
|
1631
1929
|
(x, y) => {
|
|
1632
1930
|
const { width, height } = getScreenBounds();
|
|
1633
1931
|
let snappedX = x;
|
|
@@ -1639,13 +1937,13 @@ var MushiFloatingButton = ({
|
|
|
1639
1937
|
const clampedY = clamp(y, -(height - FAB_SIZE - baseBottom - 60), 0);
|
|
1640
1938
|
currentX.current = clampedX;
|
|
1641
1939
|
currentY.current = clampedY;
|
|
1642
|
-
|
|
1940
|
+
import_react_native4.Animated.spring(posX, {
|
|
1643
1941
|
toValue: clampedX,
|
|
1644
1942
|
useNativeDriver: false,
|
|
1645
1943
|
damping: 18,
|
|
1646
1944
|
stiffness: 220
|
|
1647
1945
|
}).start();
|
|
1648
|
-
|
|
1946
|
+
import_react_native4.Animated.spring(posY, {
|
|
1649
1947
|
toValue: clampedY,
|
|
1650
1948
|
useNativeDriver: false,
|
|
1651
1949
|
damping: 18,
|
|
@@ -1655,8 +1953,8 @@ var MushiFloatingButton = ({
|
|
|
1655
1953
|
},
|
|
1656
1954
|
[snapToEdge, persist, posX, posY, baseBottom]
|
|
1657
1955
|
);
|
|
1658
|
-
const panResponder = (0,
|
|
1659
|
-
draggable ?
|
|
1956
|
+
const panResponder = (0, import_react3.useRef)(
|
|
1957
|
+
draggable ? import_react_native4.PanResponder.create({
|
|
1660
1958
|
onStartShouldSetPanResponder: () => true,
|
|
1661
1959
|
onMoveShouldSetPanResponder: (_, g) => Math.abs(g.dx) > 6 || Math.abs(g.dy) > 6,
|
|
1662
1960
|
onPanResponderGrant: () => {
|
|
@@ -1689,19 +1987,19 @@ var MushiFloatingButton = ({
|
|
|
1689
1987
|
}
|
|
1690
1988
|
isDragging.current = false;
|
|
1691
1989
|
}
|
|
1692
|
-
}) :
|
|
1990
|
+
}) : import_react_native4.PanResponder.create({})
|
|
1693
1991
|
).current;
|
|
1694
|
-
const handlePressIn = (0,
|
|
1992
|
+
const handlePressIn = (0, import_react3.useCallback)(() => {
|
|
1695
1993
|
if (isDragging.current) return;
|
|
1696
|
-
|
|
1994
|
+
import_react_native4.Animated.spring(scale, {
|
|
1697
1995
|
toValue: 0.85,
|
|
1698
1996
|
useNativeDriver: true,
|
|
1699
1997
|
damping: 15,
|
|
1700
1998
|
stiffness: 300
|
|
1701
1999
|
}).start();
|
|
1702
2000
|
}, [scale]);
|
|
1703
|
-
const handlePressOut = (0,
|
|
1704
|
-
|
|
2001
|
+
const handlePressOut = (0, import_react3.useCallback)(() => {
|
|
2002
|
+
import_react_native4.Animated.spring(scale, {
|
|
1705
2003
|
toValue: 1,
|
|
1706
2004
|
useNativeDriver: true,
|
|
1707
2005
|
damping: 10,
|
|
@@ -1709,15 +2007,15 @@ var MushiFloatingButton = ({
|
|
|
1709
2007
|
}).start();
|
|
1710
2008
|
if (!isDragging.current) onPress();
|
|
1711
2009
|
}, [scale, onPress]);
|
|
1712
|
-
return /* @__PURE__ */ (0,
|
|
1713
|
-
|
|
2010
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2011
|
+
import_react_native4.Animated.View,
|
|
1714
2012
|
{
|
|
1715
2013
|
...draggable ? panResponder.panHandlers : {},
|
|
1716
2014
|
style: [
|
|
1717
|
-
|
|
2015
|
+
s3.fab,
|
|
1718
2016
|
{
|
|
1719
2017
|
left: posX,
|
|
1720
|
-
bottom:
|
|
2018
|
+
bottom: import_react_native4.Animated.add(new import_react_native4.Animated.Value(baseBottom), import_react_native4.Animated.multiply(posY, -1)),
|
|
1721
2019
|
backgroundColor: accentColor,
|
|
1722
2020
|
shadowColor: dark ? accentColor : pal.ink,
|
|
1723
2021
|
transform: [{ scale }]
|
|
@@ -1726,11 +2024,11 @@ var MushiFloatingButton = ({
|
|
|
1726
2024
|
onStartShouldSetResponder: () => !draggable,
|
|
1727
2025
|
onResponderGrant: handlePressIn,
|
|
1728
2026
|
onResponderRelease: handlePressOut,
|
|
1729
|
-
children: /* @__PURE__ */ (0,
|
|
2027
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Animated.Text, { style: s3.emoji, children: import_core6.MUSHI_COPY.triggerText })
|
|
1730
2028
|
}
|
|
1731
2029
|
);
|
|
1732
2030
|
};
|
|
1733
|
-
var
|
|
2031
|
+
var s3 = import_react_native4.StyleSheet.create({
|
|
1734
2032
|
fab: {
|
|
1735
2033
|
position: "absolute",
|
|
1736
2034
|
width: FAB_SIZE,
|
|
@@ -1750,93 +2048,93 @@ var s2 = import_react_native3.StyleSheet.create({
|
|
|
1750
2048
|
});
|
|
1751
2049
|
|
|
1752
2050
|
// src/components/MushiBanner.tsx
|
|
1753
|
-
var
|
|
1754
|
-
var
|
|
1755
|
-
var
|
|
1756
|
-
var
|
|
1757
|
-
var MUSHI_BANNER_DEFAULT_HEIGHT =
|
|
2051
|
+
var import_react4 = require("react");
|
|
2052
|
+
var import_react_native5 = require("react-native");
|
|
2053
|
+
var import_core7 = require("@mushi-mushi/core");
|
|
2054
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2055
|
+
var MUSHI_BANNER_DEFAULT_HEIGHT = import_core7.MUSHI_GEOMETRY.bannerHeight;
|
|
1758
2056
|
var MushiBanner = ({
|
|
1759
2057
|
onPress,
|
|
1760
2058
|
onDismiss,
|
|
1761
|
-
message =
|
|
1762
|
-
label =
|
|
2059
|
+
message = import_core7.MUSHI_COPY.bannerMessage,
|
|
2060
|
+
label = import_core7.MUSHI_COPY.bannerLabel,
|
|
1763
2061
|
onLayoutHeight
|
|
1764
2062
|
}) => {
|
|
1765
|
-
const handleLayout = (0,
|
|
2063
|
+
const handleLayout = (0, import_react4.useCallback)(
|
|
1766
2064
|
(e) => {
|
|
1767
2065
|
onLayoutHeight?.(e.nativeEvent.layout.height);
|
|
1768
2066
|
},
|
|
1769
2067
|
[onLayoutHeight]
|
|
1770
2068
|
);
|
|
1771
|
-
return /* @__PURE__ */ (0,
|
|
1772
|
-
|
|
2069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2070
|
+
import_react_native5.View,
|
|
1773
2071
|
{
|
|
1774
|
-
style:
|
|
2072
|
+
style: s4.wrap,
|
|
1775
2073
|
onLayout: handleLayout,
|
|
1776
2074
|
accessibilityRole: "header",
|
|
1777
2075
|
accessibilityLabel: "Mushi feedback banner",
|
|
1778
2076
|
children: [
|
|
1779
|
-
/* @__PURE__ */ (0,
|
|
1780
|
-
/* @__PURE__ */ (0,
|
|
1781
|
-
/* @__PURE__ */ (0,
|
|
1782
|
-
/* @__PURE__ */ (0,
|
|
2077
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.TouchableOpacity, { style: s4.main, onPress, activeOpacity: 0.85, children: [
|
|
2078
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: s4.eyebrow, children: label.toUpperCase() }),
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: s4.message, numberOfLines: 2, children: message }),
|
|
2080
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: s4.cta, children: import_core7.MUSHI_COPY.bugCta })
|
|
1783
2081
|
] }),
|
|
1784
|
-
onDismiss ? /* @__PURE__ */ (0,
|
|
1785
|
-
|
|
2082
|
+
onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2083
|
+
import_react_native5.TouchableOpacity,
|
|
1786
2084
|
{
|
|
1787
|
-
style:
|
|
2085
|
+
style: s4.dismiss,
|
|
1788
2086
|
onPress: onDismiss,
|
|
1789
2087
|
accessibilityRole: "button",
|
|
1790
2088
|
accessibilityLabel: "Dismiss banner",
|
|
1791
2089
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1792
|
-
children: /* @__PURE__ */ (0,
|
|
2090
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.Text, { style: s4.dismissText, children: "\xD7" })
|
|
1793
2091
|
}
|
|
1794
2092
|
) : null
|
|
1795
2093
|
]
|
|
1796
2094
|
}
|
|
1797
2095
|
);
|
|
1798
2096
|
};
|
|
1799
|
-
var
|
|
2097
|
+
var s4 = import_react_native5.StyleSheet.create({
|
|
1800
2098
|
wrap: {
|
|
1801
2099
|
position: "absolute",
|
|
1802
2100
|
left: 0,
|
|
1803
2101
|
right: 0,
|
|
1804
2102
|
bottom: 0,
|
|
1805
|
-
minHeight:
|
|
2103
|
+
minHeight: import_core7.MUSHI_GEOMETRY.bannerHeight,
|
|
1806
2104
|
flexDirection: "row",
|
|
1807
2105
|
alignItems: "stretch",
|
|
1808
|
-
backgroundColor:
|
|
2106
|
+
backgroundColor: import_core7.MUSHI_BANNER_NEON.bg,
|
|
1809
2107
|
borderTopWidth: 1,
|
|
1810
|
-
borderTopColor:
|
|
1811
|
-
zIndex:
|
|
2108
|
+
borderTopColor: import_core7.MUSHI_BANNER_NEON.border,
|
|
2109
|
+
zIndex: import_core7.MUSHI_Z.banner,
|
|
1812
2110
|
elevation: 8,
|
|
1813
|
-
paddingBottom:
|
|
2111
|
+
paddingBottom: import_react_native5.Platform.OS === "ios" ? 0 : 0
|
|
1814
2112
|
},
|
|
1815
2113
|
main: {
|
|
1816
2114
|
flex: 1,
|
|
1817
2115
|
flexDirection: "row",
|
|
1818
2116
|
alignItems: "center",
|
|
1819
|
-
gap:
|
|
1820
|
-
paddingHorizontal:
|
|
1821
|
-
paddingVertical:
|
|
2117
|
+
gap: import_core7.MUSHI_SPACING.snug,
|
|
2118
|
+
paddingHorizontal: import_core7.MUSHI_SPACING.comfy,
|
|
2119
|
+
paddingVertical: import_core7.MUSHI_SPACING.snug,
|
|
1822
2120
|
minHeight: 44
|
|
1823
2121
|
},
|
|
1824
2122
|
eyebrow: {
|
|
1825
|
-
fontSize:
|
|
2123
|
+
fontSize: import_core7.MUSHI_TYPE.sizeLabel,
|
|
1826
2124
|
fontWeight: "700",
|
|
1827
2125
|
letterSpacing: 1.2,
|
|
1828
|
-
color:
|
|
2126
|
+
color: import_core7.MUSHI_BANNER_NEON.fg
|
|
1829
2127
|
},
|
|
1830
2128
|
message: {
|
|
1831
2129
|
flex: 1,
|
|
1832
2130
|
fontSize: 12,
|
|
1833
2131
|
fontWeight: "500",
|
|
1834
|
-
color:
|
|
2132
|
+
color: import_core7.MUSHI_BANNER_NEON.fg
|
|
1835
2133
|
},
|
|
1836
2134
|
cta: {
|
|
1837
2135
|
fontSize: 12,
|
|
1838
2136
|
fontWeight: "700",
|
|
1839
|
-
color:
|
|
2137
|
+
color: import_core7.MUSHI_BANNER_NEON.fg,
|
|
1840
2138
|
textDecorationLine: "underline"
|
|
1841
2139
|
},
|
|
1842
2140
|
dismiss: {
|
|
@@ -1846,13 +2144,13 @@ var s3 = import_react_native4.StyleSheet.create({
|
|
|
1846
2144
|
dismissText: {
|
|
1847
2145
|
fontSize: 20,
|
|
1848
2146
|
lineHeight: 22,
|
|
1849
|
-
color:
|
|
2147
|
+
color: import_core7.MUSHI_BANNER_NEON.fg,
|
|
1850
2148
|
opacity: 0.7
|
|
1851
2149
|
}
|
|
1852
2150
|
});
|
|
1853
2151
|
|
|
1854
2152
|
// src/analytics/event-tracker.ts
|
|
1855
|
-
var
|
|
2153
|
+
var import_core8 = require("@mushi-mushi/core");
|
|
1856
2154
|
var CONSENT_BUFFER_MAX = 50;
|
|
1857
2155
|
var SPILL_MAX = 200;
|
|
1858
2156
|
var SPILL_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -1916,7 +2214,7 @@ function createRNEventTracker(opts) {
|
|
|
1916
2214
|
const client = resolveClient();
|
|
1917
2215
|
if (!client) return;
|
|
1918
2216
|
flushing = true;
|
|
1919
|
-
const batch = buffer.splice(0,
|
|
2217
|
+
const batch = buffer.splice(0, import_core8.EVENT_PROPERTY_LIMITS.maxServerBatch);
|
|
1920
2218
|
if (pendingIdentify) {
|
|
1921
2219
|
batch.unshift({ name: "identify", ts: (/* @__PURE__ */ new Date()).toISOString(), properties: {} });
|
|
1922
2220
|
pendingIdentify = false;
|
|
@@ -1940,7 +2238,7 @@ function createRNEventTracker(opts) {
|
|
|
1940
2238
|
} finally {
|
|
1941
2239
|
flushing = false;
|
|
1942
2240
|
}
|
|
1943
|
-
if (buffer.length >=
|
|
2241
|
+
if (buffer.length >= import_core8.EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
|
|
1944
2242
|
}
|
|
1945
2243
|
function enqueue(ev) {
|
|
1946
2244
|
if (consent === "denied") return;
|
|
@@ -1949,7 +2247,7 @@ function createRNEventTracker(opts) {
|
|
|
1949
2247
|
return;
|
|
1950
2248
|
}
|
|
1951
2249
|
buffer.push(ev);
|
|
1952
|
-
if (buffer.length >=
|
|
2250
|
+
if (buffer.length >= import_core8.EVENT_PROPERTY_LIMITS.maxClientBatch) void flushNow();
|
|
1953
2251
|
}
|
|
1954
2252
|
const ready = enabled ? (async () => {
|
|
1955
2253
|
storage = await loadStorage();
|
|
@@ -1989,17 +2287,17 @@ function createRNEventTracker(opts) {
|
|
|
1989
2287
|
ready,
|
|
1990
2288
|
track(name, properties, trackOpts) {
|
|
1991
2289
|
if (!enabled || destroyed) return false;
|
|
1992
|
-
if (!(0,
|
|
1993
|
-
const { properties: props } = (0,
|
|
2290
|
+
if (!(0, import_core8.isValidEventName)(name)) return false;
|
|
2291
|
+
const { properties: props } = (0, import_core8.sanitizeEventProperties)(properties, { allowlist, scrub: opts.scrub });
|
|
1994
2292
|
let merged = props;
|
|
1995
2293
|
if (trackOpts?.reserved) {
|
|
1996
|
-
const { properties: res } = (0,
|
|
2294
|
+
const { properties: res } = (0, import_core8.sanitizeEventProperties)(trackOpts.reserved, { allowReserved: true, scrub: opts.scrub });
|
|
1997
2295
|
merged = { ...props, ...res };
|
|
1998
2296
|
}
|
|
1999
2297
|
merged.$surface = SURFACE;
|
|
2000
2298
|
const route = opts.getRoute?.();
|
|
2001
2299
|
if (route && merged.$route === void 0) merged.$route = route;
|
|
2002
|
-
if (!(0,
|
|
2300
|
+
if (!(0, import_core8.propertiesWithinByteLimit)(merged)) return false;
|
|
2003
2301
|
enqueue({
|
|
2004
2302
|
name,
|
|
2005
2303
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2068,13 +2366,13 @@ function createRNEventTracker(opts) {
|
|
|
2068
2366
|
}
|
|
2069
2367
|
|
|
2070
2368
|
// src/analytics/session-tracker.ts
|
|
2071
|
-
var
|
|
2369
|
+
var import_core9 = require("@mushi-mushi/core");
|
|
2072
2370
|
var HEARTBEAT_INTERVAL_MS = 6e4;
|
|
2073
2371
|
var RESUME_WINDOW_MS = 30 * 6e4;
|
|
2074
2372
|
function createRNSessionTracker(opts) {
|
|
2075
2373
|
const clock = opts.now ?? Date.now;
|
|
2076
2374
|
const resolveClient = () => typeof opts.client === "function" ? opts.client() : opts.client;
|
|
2077
|
-
let sessionId = opts.sessionId ?? `sess_${(0,
|
|
2375
|
+
let sessionId = opts.sessionId ?? `sess_${(0, import_core9.newUuid)()}`;
|
|
2078
2376
|
let pageViewCount = 0;
|
|
2079
2377
|
let started = false;
|
|
2080
2378
|
let allowed = false;
|
|
@@ -2142,7 +2440,7 @@ function createRNSessionTracker(opts) {
|
|
|
2142
2440
|
backgroundedAt = null;
|
|
2143
2441
|
if (!allowed) return;
|
|
2144
2442
|
if (!started || away >= RESUME_WINDOW_MS) {
|
|
2145
|
-
sessionId = `sess_${(0,
|
|
2443
|
+
sessionId = `sess_${(0, import_core9.newUuid)()}`;
|
|
2146
2444
|
startSession();
|
|
2147
2445
|
} else {
|
|
2148
2446
|
send("session_heartbeat", { route: route() });
|
|
@@ -2171,14 +2469,14 @@ function createRNSessionTracker(opts) {
|
|
|
2171
2469
|
|
|
2172
2470
|
// src/version.ts
|
|
2173
2471
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/react-native";
|
|
2174
|
-
var MUSHI_SDK_VERSION = "0.
|
|
2472
|
+
var MUSHI_SDK_VERSION = "0.24.1" ? "0.24.1" : "0.17.0";
|
|
2175
2473
|
|
|
2176
2474
|
// src/provider.tsx
|
|
2177
|
-
var
|
|
2178
|
-
var MushiContext = (0,
|
|
2475
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2476
|
+
var MushiContext = (0, import_react5.createContext)(null);
|
|
2179
2477
|
function nativeUserAgent() {
|
|
2180
|
-
const os =
|
|
2181
|
-
const version =
|
|
2478
|
+
const os = import_react_native6.Platform?.OS ?? "native";
|
|
2479
|
+
const version = import_react_native6.Platform?.Version;
|
|
2182
2480
|
return `${MUSHI_SDK_PACKAGE}/${MUSHI_SDK_VERSION} (${version != null ? `${os} ${String(version)}` : os})`;
|
|
2183
2481
|
}
|
|
2184
2482
|
var DEFAULT_SCREENSHOT_HINT = "Check the preview \u2014 remove it if any private info (balances, personal details) is visible.";
|
|
@@ -2219,28 +2517,28 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2219
2517
|
);
|
|
2220
2518
|
}
|
|
2221
2519
|
}
|
|
2222
|
-
const consoleRef = (0,
|
|
2223
|
-
const networkRef = (0,
|
|
2224
|
-
const queueRef = (0,
|
|
2225
|
-
const apiClientRef = (0,
|
|
2226
|
-
const sessionIdRef = (0,
|
|
2227
|
-
const breadcrumbsRef = (0,
|
|
2228
|
-
(0,
|
|
2520
|
+
const consoleRef = (0, import_react5.useRef)(null);
|
|
2521
|
+
const networkRef = (0, import_react5.useRef)(null);
|
|
2522
|
+
const queueRef = (0, import_react5.useRef)(null);
|
|
2523
|
+
const apiClientRef = (0, import_react5.useRef)(null);
|
|
2524
|
+
const sessionIdRef = (0, import_react5.useRef)(`sess_${(0, import_core10.newUuid)()}`);
|
|
2525
|
+
const breadcrumbsRef = (0, import_react5.useRef)(
|
|
2526
|
+
(0, import_core10.createBreadcrumbBuffer)({ max: config.capture?.maxBreadcrumbs ?? 50 })
|
|
2229
2527
|
);
|
|
2230
|
-
const [sheetVisible, setSheetVisible] = (0,
|
|
2231
|
-
const [sheetPreferredTab, setSheetPreferredTab] = (0,
|
|
2232
|
-
const [bannerDismissed, setBannerDismissed] = (0,
|
|
2233
|
-
const [sheetScreenshot, setSheetScreenshot] = (0,
|
|
2234
|
-
const reporterTokenRef = (0,
|
|
2528
|
+
const [sheetVisible, setSheetVisible] = (0, import_react5.useState)(false);
|
|
2529
|
+
const [sheetPreferredTab, setSheetPreferredTab] = (0, import_react5.useState)("report");
|
|
2530
|
+
const [bannerDismissed, setBannerDismissed] = (0, import_react5.useState)(false);
|
|
2531
|
+
const [sheetScreenshot, setSheetScreenshot] = (0, import_react5.useState)(null);
|
|
2532
|
+
const reporterTokenRef = (0, import_react5.useRef)(`rn-${config.projectId}-anon`);
|
|
2235
2533
|
let resolveReporterTokenReady = () => {
|
|
2236
2534
|
};
|
|
2237
|
-
const reporterTokenReadyRef = (0,
|
|
2535
|
+
const reporterTokenReadyRef = (0, import_react5.useRef)(
|
|
2238
2536
|
new Promise((resolve) => {
|
|
2239
2537
|
resolveReporterTokenReady = resolve;
|
|
2240
2538
|
})
|
|
2241
2539
|
);
|
|
2242
|
-
const userTokenRef = (0,
|
|
2243
|
-
const pageContextRef = (0,
|
|
2540
|
+
const userTokenRef = (0, import_react5.useRef)(null);
|
|
2541
|
+
const pageContextRef = (0, import_react5.useRef)(null);
|
|
2244
2542
|
const rawEndpoint = config.apiEndpoint ?? config.endpoint;
|
|
2245
2543
|
if (rawEndpoint !== void 0 && rawEndpoint.trim() === "") {
|
|
2246
2544
|
throw new Error(
|
|
@@ -2250,15 +2548,15 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2250
2548
|
if (config.endpoint && !config.apiEndpoint && __DEV__) {
|
|
2251
2549
|
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
2252
2550
|
}
|
|
2253
|
-
const apiEndpoint = rawEndpoint ??
|
|
2254
|
-
(0,
|
|
2551
|
+
const apiEndpoint = rawEndpoint ?? import_core10.DEFAULT_API_ENDPOINT;
|
|
2552
|
+
(0, import_react5.useEffect)(() => {
|
|
2255
2553
|
if (config.capture?.console !== false) {
|
|
2256
2554
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
2257
2555
|
}
|
|
2258
2556
|
if (config.capture?.network !== false) {
|
|
2259
2557
|
networkRef.current = setupNetworkCapture(config.capture?.maxNetworkEntries, apiEndpoint);
|
|
2260
2558
|
}
|
|
2261
|
-
apiClientRef.current = (0,
|
|
2559
|
+
apiClientRef.current = (0, import_core10.createApiClient)({
|
|
2262
2560
|
projectId: config.projectId,
|
|
2263
2561
|
apiKey: config.apiKey,
|
|
2264
2562
|
apiEndpoint,
|
|
@@ -2295,14 +2593,14 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2295
2593
|
if (existing && existing.startsWith("mushi_")) {
|
|
2296
2594
|
reporterTokenRef.current = existing;
|
|
2297
2595
|
} else {
|
|
2298
|
-
const fresh = `mushi_${(0,
|
|
2596
|
+
const fresh = `mushi_${(0, import_core10.newUuid)()}`;
|
|
2299
2597
|
reporterTokenRef.current = fresh;
|
|
2300
2598
|
await saveReporterToken(fresh, secureStorage);
|
|
2301
2599
|
}
|
|
2302
2600
|
resolveReporterTokenReady();
|
|
2303
2601
|
} catch {
|
|
2304
2602
|
if (reporterTokenRef.current === `rn-${config.projectId}-anon`) {
|
|
2305
|
-
reporterTokenRef.current = `mushi_${(0,
|
|
2603
|
+
reporterTokenRef.current = `mushi_${(0, import_core10.newUuid)()}`;
|
|
2306
2604
|
}
|
|
2307
2605
|
resolveReporterTokenReady();
|
|
2308
2606
|
}
|
|
@@ -2313,11 +2611,10 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2313
2611
|
networkRef.current?.restore();
|
|
2314
2612
|
};
|
|
2315
2613
|
}, []);
|
|
2316
|
-
(0,
|
|
2614
|
+
(0, import_react5.useEffect)(() => {
|
|
2317
2615
|
let unsubscribe;
|
|
2318
2616
|
try {
|
|
2319
|
-
|
|
2320
|
-
unsubscribe = NetInfo.addEventListener((state) => {
|
|
2617
|
+
unsubscribe = resolveNetInfo(config.netInfo)?.addEventListener((state) => {
|
|
2321
2618
|
if (state.isConnected && state.isInternetReachable) {
|
|
2322
2619
|
queueRef.current?.flush().catch(() => {
|
|
2323
2620
|
});
|
|
@@ -2326,8 +2623,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2326
2623
|
} catch {
|
|
2327
2624
|
}
|
|
2328
2625
|
return () => unsubscribe?.();
|
|
2329
|
-
}, []);
|
|
2330
|
-
const open = (0,
|
|
2626
|
+
}, [config.netInfo]);
|
|
2627
|
+
const open = (0, import_react5.useCallback)(() => {
|
|
2331
2628
|
setSheetPreferredTab("report");
|
|
2332
2629
|
breadcrumbsRef.current.add({
|
|
2333
2630
|
category: "lifecycle",
|
|
@@ -2340,11 +2637,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2340
2637
|
setSheetVisible(true);
|
|
2341
2638
|
return;
|
|
2342
2639
|
}
|
|
2343
|
-
|
|
2344
|
-
try {
|
|
2345
|
-
vshot = require("react-native-view-shot");
|
|
2346
|
-
} catch {
|
|
2347
|
-
}
|
|
2640
|
+
const vshot = resolveViewShot(config.viewShot);
|
|
2348
2641
|
if (!vshot) {
|
|
2349
2642
|
setSheetScreenshot(null);
|
|
2350
2643
|
setSheetVisible(true);
|
|
@@ -2357,16 +2650,16 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2357
2650
|
}).finally(() => {
|
|
2358
2651
|
setSheetVisible(true);
|
|
2359
2652
|
});
|
|
2360
|
-
}, [config.capture?.screenshot]);
|
|
2361
|
-
const openAssistant = (0,
|
|
2653
|
+
}, [config.capture?.screenshot, config.viewShot]);
|
|
2654
|
+
const openAssistant = (0, import_react5.useCallback)(() => {
|
|
2362
2655
|
if (!config.assistant?.enabled) return;
|
|
2363
2656
|
setSheetPreferredTab("assistant");
|
|
2364
2657
|
setSheetScreenshot(null);
|
|
2365
2658
|
setSheetVisible(true);
|
|
2366
2659
|
}, [config.assistant?.enabled]);
|
|
2367
|
-
const close = (0,
|
|
2368
|
-
const attachTo = (0,
|
|
2369
|
-
(0,
|
|
2660
|
+
const close = (0, import_react5.useCallback)(() => setSheetVisible(false), []);
|
|
2661
|
+
const attachTo = (0, import_react5.useCallback)(() => ({ onPress: open }), [open]);
|
|
2662
|
+
(0, import_react5.useEffect)(() => {
|
|
2370
2663
|
const trigger2 = config.widget?.trigger ?? "button";
|
|
2371
2664
|
if (trigger2 !== "shake" && trigger2 !== "both") return;
|
|
2372
2665
|
let disposed = false;
|
|
@@ -2374,8 +2667,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2374
2667
|
let lastShake = 0;
|
|
2375
2668
|
const threshold = config.widget?.shakeThreshold ?? 2.7;
|
|
2376
2669
|
try {
|
|
2377
|
-
const mod =
|
|
2378
|
-
if (!disposed) {
|
|
2670
|
+
const mod = resolveExpoSensors(config.expoSensors);
|
|
2671
|
+
if (mod && !disposed) {
|
|
2379
2672
|
mod.Accelerometer.setUpdateInterval(120);
|
|
2380
2673
|
const sub = mod.Accelerometer.addListener((evt) => {
|
|
2381
2674
|
const g = Math.sqrt(evt.x * evt.x + evt.y * evt.y + evt.z * evt.z);
|
|
@@ -2393,8 +2686,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2393
2686
|
disposed = true;
|
|
2394
2687
|
cleanup?.();
|
|
2395
2688
|
};
|
|
2396
|
-
}, [config.widget?.trigger, config.widget?.shakeThreshold, open]);
|
|
2397
|
-
const submitReport = (0,
|
|
2689
|
+
}, [config.widget?.trigger, config.widget?.shakeThreshold, config.expoSensors, open]);
|
|
2690
|
+
const submitReport = (0, import_react5.useCallback)(
|
|
2398
2691
|
async (data) => {
|
|
2399
2692
|
await reporterTokenReadyRef.current;
|
|
2400
2693
|
const deviceInfo = getDeviceInfo();
|
|
@@ -2422,7 +2715,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2422
2715
|
const merged = Object.keys(metadataRef.current).length > 0 ? { ...contextMeta, ...metadataRef.current } : Object.keys(contextMeta).length > 0 ? contextMeta : void 0;
|
|
2423
2716
|
const breadcrumbs = breadcrumbsRef.current.getAll().map((c) => ({
|
|
2424
2717
|
...c,
|
|
2425
|
-
message: (0,
|
|
2718
|
+
message: (0, import_core10.scrubPii)(c.message)
|
|
2426
2719
|
}));
|
|
2427
2720
|
const timeline = breadcrumbs.map((c) => ({
|
|
2428
2721
|
ts: c.timestamp,
|
|
@@ -2431,10 +2724,11 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2431
2724
|
}));
|
|
2432
2725
|
const fingerprintHash = getDeviceFingerprintHash(deviceInfo);
|
|
2433
2726
|
const report = {
|
|
2434
|
-
id: (0,
|
|
2727
|
+
id: (0, import_core10.newUuid)(),
|
|
2435
2728
|
projectId: config.projectId,
|
|
2436
2729
|
category: data.category,
|
|
2437
|
-
|
|
2730
|
+
...data.userCategory ? { userCategory: data.userCategory } : {},
|
|
2731
|
+
description: (0, import_core10.scrubPii)(data.description),
|
|
2438
2732
|
environment: {
|
|
2439
2733
|
userAgent: deviceInfo.systemName ?? "ReactNative",
|
|
2440
2734
|
platform: deviceInfo.platform ?? "mobile",
|
|
@@ -2447,7 +2741,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2447
2741
|
},
|
|
2448
2742
|
consoleLogs: (consoleRef.current?.getEntries() ?? []).map((entry) => ({
|
|
2449
2743
|
...entry,
|
|
2450
|
-
message: (0,
|
|
2744
|
+
message: (0, import_core10.scrubPii)(entry.message)
|
|
2451
2745
|
})),
|
|
2452
2746
|
networkLogs: networkRef.current?.getEntries().map((entry) => ({
|
|
2453
2747
|
...entry,
|
|
@@ -2477,7 +2771,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2477
2771
|
const code = result.error?.code ?? "";
|
|
2478
2772
|
const isCredentialError = code === "HTTP_401" || code === "HTTP_403" || code.includes("UNAUTHORIZED") || code.includes("FORBIDDEN") || code.includes("INVALID_API_KEY");
|
|
2479
2773
|
if (isCredentialError) {
|
|
2480
|
-
const where = apiEndpoint.replace(/\/$/, "") ===
|
|
2774
|
+
const where = apiEndpoint.replace(/\/$/, "") === import_core10.DEFAULT_API_ENDPOINT ? "Get the correct values at: https://kensaur.us/mushi-mushi/admin/projects" : "Get the correct values from your Mushi console's Projects page.";
|
|
2481
2775
|
console.error(
|
|
2482
2776
|
'[Mushi] Credentials rejected. Check your projectId and apiKey (must have "report:write" scope). ' + where
|
|
2483
2777
|
);
|
|
@@ -2493,17 +2787,18 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2493
2787
|
};
|
|
2494
2788
|
} else {
|
|
2495
2789
|
config.callbacks?.onReportSubmitted?.(report.id);
|
|
2790
|
+
void writeReporterFlag(config.projectId, "has_reports", "1");
|
|
2496
2791
|
return { ok: true };
|
|
2497
2792
|
}
|
|
2498
2793
|
},
|
|
2499
2794
|
[config.projectId, config.callbacks, apiEndpoint]
|
|
2500
2795
|
);
|
|
2501
|
-
const userRef = (0,
|
|
2502
|
-
const metadataRef = (0,
|
|
2503
|
-
const screenRef = (0,
|
|
2504
|
-
const activityQueueRef = (0,
|
|
2505
|
-
const rewardsFlushRef = (0,
|
|
2506
|
-
(0,
|
|
2796
|
+
const userRef = (0, import_react5.useRef)(null);
|
|
2797
|
+
const metadataRef = (0, import_react5.useRef)({});
|
|
2798
|
+
const screenRef = (0, import_react5.useRef)(null);
|
|
2799
|
+
const activityQueueRef = (0, import_react5.useRef)([]);
|
|
2800
|
+
const rewardsFlushRef = (0, import_react5.useRef)(null);
|
|
2801
|
+
(0, import_react5.useEffect)(() => {
|
|
2507
2802
|
const rewards = config.rewards;
|
|
2508
2803
|
if (!rewards?.enabled || !rewards.trackActivity) return;
|
|
2509
2804
|
const flushMs = Math.max(3e4, rewards.flushIntervalMs ?? 3e5);
|
|
@@ -2523,9 +2818,9 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2523
2818
|
if (rewardsFlushRef.current) clearInterval(rewardsFlushRef.current);
|
|
2524
2819
|
};
|
|
2525
2820
|
}, [config.rewards?.enabled, config.rewards?.trackActivity, config.rewards?.flushIntervalMs]);
|
|
2526
|
-
const eventTrackerRef = (0,
|
|
2527
|
-
const sessionTrackerRef = (0,
|
|
2528
|
-
(0,
|
|
2821
|
+
const eventTrackerRef = (0, import_react5.useRef)(null);
|
|
2822
|
+
const sessionTrackerRef = (0, import_react5.useRef)(null);
|
|
2823
|
+
(0, import_react5.useEffect)(() => {
|
|
2529
2824
|
const getRoute = () => screenRef.current?.route ?? screenRef.current?.name ?? null;
|
|
2530
2825
|
const tracker = createRNEventTracker({
|
|
2531
2826
|
projectId: config.projectId,
|
|
@@ -2538,7 +2833,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2538
2833
|
getRoute,
|
|
2539
2834
|
sdkVersion: MUSHI_SDK_VERSION,
|
|
2540
2835
|
config: config.analytics,
|
|
2541
|
-
scrub:
|
|
2836
|
+
scrub: import_core10.scrubPii
|
|
2542
2837
|
});
|
|
2543
2838
|
eventTrackerRef.current = tracker;
|
|
2544
2839
|
const sessions = config.trackSessions === false ? null : createRNSessionTracker({
|
|
@@ -2556,8 +2851,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2556
2851
|
sessionTrackerRef.current = sessions;
|
|
2557
2852
|
let sub;
|
|
2558
2853
|
try {
|
|
2559
|
-
if (typeof
|
|
2560
|
-
sub =
|
|
2854
|
+
if (typeof import_react_native6.AppState?.addEventListener === "function") {
|
|
2855
|
+
sub = import_react_native6.AppState.addEventListener("change", (state) => {
|
|
2561
2856
|
sessions?.onAppStateChange(state);
|
|
2562
2857
|
if (state !== "active") tracker.flush().catch(() => {
|
|
2563
2858
|
});
|
|
@@ -2580,7 +2875,71 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2580
2875
|
config.analytics?.flushIntervalMs,
|
|
2581
2876
|
config.trackSessions
|
|
2582
2877
|
]);
|
|
2583
|
-
const
|
|
2878
|
+
const reporterUpdatesRef = (0, import_react5.useRef)(
|
|
2879
|
+
createReporterUpdateHub(async () => {
|
|
2880
|
+
const client = apiClientRef.current;
|
|
2881
|
+
if (!client) return null;
|
|
2882
|
+
await reporterTokenReadyRef.current;
|
|
2883
|
+
const res = await (0, import_reporter_channels2.reporterChannels)(client).getUpdates(reporterTokenRef.current);
|
|
2884
|
+
return res.ok ? res.data ?? null : null;
|
|
2885
|
+
})
|
|
2886
|
+
);
|
|
2887
|
+
(0, import_react5.useEffect)(() => {
|
|
2888
|
+
let sub;
|
|
2889
|
+
try {
|
|
2890
|
+
if (typeof import_react_native6.AppState?.addEventListener === "function") {
|
|
2891
|
+
sub = import_react_native6.AppState.addEventListener("change", (state) => {
|
|
2892
|
+
if (state === "active" && reporterUpdatesRef.current.listenerCount() > 0) void reporterUpdatesRef.current.emit();
|
|
2893
|
+
});
|
|
2894
|
+
}
|
|
2895
|
+
} catch {
|
|
2896
|
+
}
|
|
2897
|
+
return () => sub?.remove();
|
|
2898
|
+
}, []);
|
|
2899
|
+
const [toast, setToast] = (0, import_react5.useState)(null);
|
|
2900
|
+
const toastShownRef = (0, import_react5.useRef)(false);
|
|
2901
|
+
const toastEnabled = config.notifications?.toast !== false;
|
|
2902
|
+
const maybeShowToast = (0, import_react5.useCallback)(async () => {
|
|
2903
|
+
if (!toastEnabled || toastShownRef.current) return;
|
|
2904
|
+
if (await readReporterFlag(config.projectId, "has_reports") !== "1") return;
|
|
2905
|
+
const updates = await reporterUpdatesRef.current.emit();
|
|
2906
|
+
if (!updates) return;
|
|
2907
|
+
const now = Date.now();
|
|
2908
|
+
const show = (0, import_reporter_ui3.reporterShouldShowToast)({
|
|
2909
|
+
enabled: toastEnabled,
|
|
2910
|
+
unreadTotal: updates.unread_total,
|
|
2911
|
+
shownThisSession: toastShownRef.current,
|
|
2912
|
+
lastShownAt: Number(await readReporterFlag(config.projectId, "toast_shown_at")) || null,
|
|
2913
|
+
now
|
|
2914
|
+
});
|
|
2915
|
+
if (!show) return;
|
|
2916
|
+
toastShownRef.current = true;
|
|
2917
|
+
void writeReporterFlag(config.projectId, "toast_shown_at", String(now));
|
|
2918
|
+
const locale = (0, import_reporter_ui3.resolveReporterLocale)(
|
|
2919
|
+
typeof navigator !== "undefined" ? navigator.language : void 0
|
|
2920
|
+
);
|
|
2921
|
+
setToast({ message: (0, import_reporter_ui3.reporterToastMessage)(updates, locale), reportId: updates.latest[0]?.report_id ?? null });
|
|
2922
|
+
}, [toastEnabled, config.projectId]);
|
|
2923
|
+
(0, import_react5.useEffect)(() => {
|
|
2924
|
+
void reporterTokenReadyRef.current.then(() => maybeShowToast());
|
|
2925
|
+
let sub;
|
|
2926
|
+
try {
|
|
2927
|
+
if (typeof import_react_native6.AppState?.addEventListener === "function") {
|
|
2928
|
+
sub = import_react_native6.AppState.addEventListener("change", (state) => {
|
|
2929
|
+
if (state === "active") void maybeShowToast();
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2932
|
+
} catch {
|
|
2933
|
+
}
|
|
2934
|
+
return () => sub?.remove();
|
|
2935
|
+
}, [maybeShowToast]);
|
|
2936
|
+
const openMyReports = (0, import_react5.useCallback)(() => {
|
|
2937
|
+
setToast(null);
|
|
2938
|
+
setSheetScreenshot(null);
|
|
2939
|
+
setSheetPreferredTab("inbox");
|
|
2940
|
+
setSheetVisible(true);
|
|
2941
|
+
}, []);
|
|
2942
|
+
const instance = (0, import_react5.useMemo)(
|
|
2584
2943
|
() => ({
|
|
2585
2944
|
open,
|
|
2586
2945
|
close,
|
|
@@ -2611,7 +2970,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2611
2970
|
identifyWithToken(token) {
|
|
2612
2971
|
userTokenRef.current = token && typeof token === "string" ? token : null;
|
|
2613
2972
|
if (userTokenRef.current) {
|
|
2614
|
-
const claims = (0,
|
|
2973
|
+
const claims = (0, import_core10.parseIdentityToken)(userTokenRef.current);
|
|
2615
2974
|
if (claims?.sub) {
|
|
2616
2975
|
userRef.current = {
|
|
2617
2976
|
id: claims.sub,
|
|
@@ -2683,6 +3042,37 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2683
3042
|
await reporterTokenReadyRef.current;
|
|
2684
3043
|
return markReporterReportRead(client, reporterTokenRef.current, reportId);
|
|
2685
3044
|
},
|
|
3045
|
+
getReporterUpdates: () => reporterUpdatesRef.current.emit(),
|
|
3046
|
+
async loadMyReportDetail(reportId) {
|
|
3047
|
+
const client = apiClientRef.current;
|
|
3048
|
+
if (!client) return null;
|
|
3049
|
+
try {
|
|
3050
|
+
await reporterTokenReadyRef.current;
|
|
3051
|
+
const res = await (0, import_reporter_channels2.reporterChannels)(client).getReport(reportId, reporterTokenRef.current);
|
|
3052
|
+
if (res.ok) return res.data ?? null;
|
|
3053
|
+
return res.error?.status === 404 && res.error.code !== "NOT_FOUND" ? "unsupported" : null;
|
|
3054
|
+
} catch {
|
|
3055
|
+
return null;
|
|
3056
|
+
}
|
|
3057
|
+
},
|
|
3058
|
+
emailPrefill() {
|
|
3059
|
+
return config.notifications?.emailFromIdentity ? userRef.current?.email ?? null : null;
|
|
3060
|
+
},
|
|
3061
|
+
openMyReports,
|
|
3062
|
+
onReporterUpdate: (cb) => reporterUpdatesRef.current.subscribe(cb),
|
|
3063
|
+
async getNotificationPrefs() {
|
|
3064
|
+
const client = apiClientRef.current;
|
|
3065
|
+
if (!client) return null;
|
|
3066
|
+
await reporterTokenReadyRef.current;
|
|
3067
|
+
const res = await (0, import_reporter_channels2.reporterChannels)(client).getPrefs(reporterTokenRef.current);
|
|
3068
|
+
return res.ok ? res.data ?? null : null;
|
|
3069
|
+
},
|
|
3070
|
+
async setNotificationPrefs(update) {
|
|
3071
|
+
const client = apiClientRef.current;
|
|
3072
|
+
if (!client) return { ok: false, error: { code: "NOT_INITIALIZED", message: "Mushi is not ready yet" } };
|
|
3073
|
+
await reporterTokenReadyRef.current;
|
|
3074
|
+
return (0, import_reporter_channels2.reporterChannels)(client).setPrefs(reporterTokenRef.current, update);
|
|
3075
|
+
},
|
|
2686
3076
|
async replyToReport(reportId, body) {
|
|
2687
3077
|
const client = apiClientRef.current;
|
|
2688
3078
|
if (!client) return null;
|
|
@@ -2753,14 +3143,14 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2753
3143
|
return res.ok ? res.data : null;
|
|
2754
3144
|
}
|
|
2755
3145
|
}),
|
|
2756
|
-
[open, close, attachTo, submitReport, openAssistant, config.rewards?.enabled, config.assistant?.enabled]
|
|
3146
|
+
[open, close, attachTo, submitReport, openAssistant, openMyReports, config.rewards?.enabled, config.assistant?.enabled, config.notifications?.emailFromIdentity]
|
|
2757
3147
|
);
|
|
2758
3148
|
const trigger = config.widget?.trigger ?? "button";
|
|
2759
3149
|
const showBanner = trigger === "banner" && !bannerDismissed;
|
|
2760
3150
|
const showFab = !showBanner && (trigger === "button" || trigger === "both" || trigger === "auto" || trigger === "edge-tab");
|
|
2761
|
-
return /* @__PURE__ */ (0,
|
|
3151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(MushiContext.Provider, { value: instance, children: [
|
|
2762
3152
|
children,
|
|
2763
|
-
showBanner ? /* @__PURE__ */ (0,
|
|
3153
|
+
showBanner ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2764
3154
|
MushiBanner,
|
|
2765
3155
|
{
|
|
2766
3156
|
onPress: open,
|
|
@@ -2769,7 +3159,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2769
3159
|
label: config.widget?.banner?.label
|
|
2770
3160
|
}
|
|
2771
3161
|
) : null,
|
|
2772
|
-
showFab && /* @__PURE__ */ (0,
|
|
3162
|
+
showFab && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2773
3163
|
MushiFloatingButton,
|
|
2774
3164
|
{
|
|
2775
3165
|
onPress: open,
|
|
@@ -2777,7 +3167,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2777
3167
|
inset: config.widget?.inset
|
|
2778
3168
|
}
|
|
2779
3169
|
),
|
|
2780
|
-
/* @__PURE__ */ (0,
|
|
3170
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2781
3171
|
MushiBottomSheet,
|
|
2782
3172
|
{
|
|
2783
3173
|
visible: sheetVisible,
|
|
@@ -2791,13 +3181,24 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2791
3181
|
assistantGreeting: config.assistant?.greeting,
|
|
2792
3182
|
assistantSuggestions: config.assistant?.suggestions,
|
|
2793
3183
|
inboxPollIntervalMs: config.widget?.inboxPollIntervalMs ?? 0,
|
|
3184
|
+
theme: config.widget?.theme,
|
|
3185
|
+
minDescriptionLength: config.widget?.minDescriptionLength,
|
|
3186
|
+
emailOptIn: config.notifications?.email !== false
|
|
3187
|
+
}
|
|
3188
|
+
),
|
|
3189
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3190
|
+
MushiUpdateToast,
|
|
3191
|
+
{
|
|
3192
|
+
message: toast.message,
|
|
3193
|
+
onView: openMyReports,
|
|
3194
|
+
onDismiss: () => setToast(null),
|
|
2794
3195
|
theme: config.widget?.theme
|
|
2795
3196
|
}
|
|
2796
|
-
)
|
|
3197
|
+
) : null
|
|
2797
3198
|
] });
|
|
2798
3199
|
}
|
|
2799
3200
|
function useMushiContext() {
|
|
2800
|
-
return (0,
|
|
3201
|
+
return (0, import_react5.useContext)(MushiContext);
|
|
2801
3202
|
}
|
|
2802
3203
|
|
|
2803
3204
|
// src/hooks/useMushi.ts
|
|
@@ -2806,10 +3207,10 @@ function useMushi() {
|
|
|
2806
3207
|
}
|
|
2807
3208
|
|
|
2808
3209
|
// src/hooks/useMushiReport.ts
|
|
2809
|
-
var
|
|
3210
|
+
var import_react6 = require("react");
|
|
2810
3211
|
function useMushiReport() {
|
|
2811
3212
|
const mushi = useMushiContext();
|
|
2812
|
-
const submitReport = (0,
|
|
3213
|
+
const submitReport = (0, import_react6.useCallback)(
|
|
2813
3214
|
async (data) => {
|
|
2814
3215
|
if (!mushi) throw new Error("MushiProvider not found");
|
|
2815
3216
|
await mushi.submitReport(data);
|
|
@@ -2820,22 +3221,22 @@ function useMushiReport() {
|
|
|
2820
3221
|
}
|
|
2821
3222
|
|
|
2822
3223
|
// src/hooks/useMushiWidget.ts
|
|
2823
|
-
var
|
|
3224
|
+
var import_react7 = require("react");
|
|
2824
3225
|
function useMushiWidget() {
|
|
2825
3226
|
const mushi = useMushiContext();
|
|
2826
3227
|
return {
|
|
2827
|
-
open: (0,
|
|
2828
|
-
close: (0,
|
|
3228
|
+
open: (0, import_react7.useCallback)(() => mushi?.open(), [mushi]),
|
|
3229
|
+
close: (0, import_react7.useCallback)(() => mushi?.close(), [mushi])
|
|
2829
3230
|
};
|
|
2830
3231
|
}
|
|
2831
3232
|
|
|
2832
3233
|
// src/components/MushiTrigger.tsx
|
|
2833
|
-
var
|
|
3234
|
+
var import_react8 = require("react");
|
|
2834
3235
|
function MushiTrigger({ children }) {
|
|
2835
3236
|
const mushi = useMushiContext();
|
|
2836
|
-
if (!(0,
|
|
3237
|
+
if (!(0, import_react8.isValidElement)(children)) return children;
|
|
2837
3238
|
const originalOnPress = children.props.onPress;
|
|
2838
|
-
return (0,
|
|
3239
|
+
return (0, import_react8.cloneElement)(children, {
|
|
2839
3240
|
onPress: () => {
|
|
2840
3241
|
originalOnPress?.();
|
|
2841
3242
|
mushi?.open();
|
|
@@ -2844,10 +3245,10 @@ function MushiTrigger({ children }) {
|
|
|
2844
3245
|
}
|
|
2845
3246
|
|
|
2846
3247
|
// src/capture/navigation-capture.ts
|
|
2847
|
-
var
|
|
3248
|
+
var import_react9 = require("react");
|
|
2848
3249
|
function useNavigationCapture(navigationRef) {
|
|
2849
|
-
const historyRef = (0,
|
|
2850
|
-
(0,
|
|
3250
|
+
const historyRef = (0, import_react9.useRef)([]);
|
|
3251
|
+
(0, import_react9.useEffect)(() => {
|
|
2851
3252
|
if (!navigationRef?.addListener || !navigationRef?.getCurrentRoute) return;
|
|
2852
3253
|
const unsubscribe = navigationRef.addListener("state", () => {
|
|
2853
3254
|
const route = navigationRef.getCurrentRoute?.();
|