@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.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
1
|
|
|
8
2
|
// src/provider.tsx
|
|
9
3
|
import {
|
|
10
4
|
createContext,
|
|
11
5
|
useContext,
|
|
12
|
-
useEffect as
|
|
6
|
+
useEffect as useEffect4,
|
|
13
7
|
useRef as useRef3,
|
|
14
8
|
useState as useState2,
|
|
15
9
|
useCallback as useCallback4,
|
|
@@ -24,6 +18,180 @@ import {
|
|
|
24
18
|
parseIdentityToken,
|
|
25
19
|
scrubPii as scrubPii3
|
|
26
20
|
} from "@mushi-mushi/core";
|
|
21
|
+
import {
|
|
22
|
+
reporterChannels as reporterChannels2
|
|
23
|
+
} from "@mushi-mushi/core/reporter-channels";
|
|
24
|
+
import { reporterShouldShowToast, reporterToastMessage, resolveReporterLocale as resolveReporterLocale3 } from "@mushi-mushi/core/reporter-ui";
|
|
25
|
+
|
|
26
|
+
// src/storage/reporter-flags.ts
|
|
27
|
+
async function readReporterFlag(projectId, flag) {
|
|
28
|
+
try {
|
|
29
|
+
const store = (await import("@react-native-async-storage/async-storage")).default;
|
|
30
|
+
return await store.getItem(`@mushi:${flag}:${projectId}`);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function writeReporterFlag(projectId, flag, value) {
|
|
36
|
+
try {
|
|
37
|
+
const store = (await import("@react-native-async-storage/async-storage")).default;
|
|
38
|
+
await store.setItem(`@mushi:${flag}:${projectId}`, value);
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/components/MushiUpdateToast.tsx
|
|
44
|
+
import { useEffect } from "react";
|
|
45
|
+
import { Text, TouchableOpacity, View, StyleSheet, useColorScheme } from "react-native";
|
|
46
|
+
import { MUSHI_SHADOW_INK } from "@mushi-mushi/core";
|
|
47
|
+
import { reporterCopy, resolveReporterLocale } from "@mushi-mushi/core/reporter-ui";
|
|
48
|
+
|
|
49
|
+
// src/theme.ts
|
|
50
|
+
import { mushiPalette, MUSHI_CONTROL_DISABLED, MUSHI_RADIUS } from "@mushi-mushi/core";
|
|
51
|
+
function hexToRgb(hex) {
|
|
52
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})([0-9a-f]{2})?$/i.exec(hex.trim());
|
|
53
|
+
if (!m) return null;
|
|
54
|
+
const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
|
|
55
|
+
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
56
|
+
}
|
|
57
|
+
function luminance([r, g, b]) {
|
|
58
|
+
const lin = (c) => {
|
|
59
|
+
const s5 = c / 255;
|
|
60
|
+
return s5 <= 0.03928 ? s5 / 12.92 : ((s5 + 0.055) / 1.055) ** 2.4;
|
|
61
|
+
};
|
|
62
|
+
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
63
|
+
}
|
|
64
|
+
function contrastingText(bg, fallback) {
|
|
65
|
+
const rgb = hexToRgb(bg);
|
|
66
|
+
if (!rgb) return fallback;
|
|
67
|
+
const l = luminance(rgb);
|
|
68
|
+
return 1.05 / (l + 0.05) >= (l + 0.05) / 0.05 ? "#FFFFFF" : "#000000";
|
|
69
|
+
}
|
|
70
|
+
function resolveRNTheme(dark, override = {}) {
|
|
71
|
+
const pal = mushiPalette(dark ? "dark" : "light");
|
|
72
|
+
const base = {
|
|
73
|
+
bg: dark ? pal.paper : pal.paperRaised,
|
|
74
|
+
fg: pal.ink,
|
|
75
|
+
muted: pal.inkMuted,
|
|
76
|
+
surface: dark ? pal.paperRaised : pal.paper,
|
|
77
|
+
border: pal.ruleStrong,
|
|
78
|
+
accent: pal.ink,
|
|
79
|
+
accentFg: dark ? pal.paper : pal.paperRaised,
|
|
80
|
+
success: pal.ok,
|
|
81
|
+
error: pal.danger,
|
|
82
|
+
fontFamily: void 0,
|
|
83
|
+
radius: MUSHI_RADIUS.card
|
|
84
|
+
};
|
|
85
|
+
const defined = Object.fromEntries(
|
|
86
|
+
Object.entries(override).filter(([, v]) => v !== void 0 && v !== null && v !== "")
|
|
87
|
+
);
|
|
88
|
+
const merged = { ...base, ...defined };
|
|
89
|
+
if (defined.accent && !defined.accentFg) merged.accentFg = contrastingText(defined.accent, base.accentFg);
|
|
90
|
+
return {
|
|
91
|
+
...merged,
|
|
92
|
+
backdrop: dark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.35)",
|
|
93
|
+
disabled: dark ? MUSHI_CONTROL_DISABLED.dark : MUSHI_CONTROL_DISABLED.light,
|
|
94
|
+
disabledFg: pal.inkFaint
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/components/MushiUpdateToast.tsx
|
|
99
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
100
|
+
var AUTO_HIDE_MS = 8e3;
|
|
101
|
+
var MushiUpdateToast = ({ message, onView, onDismiss, theme }) => {
|
|
102
|
+
const colors = resolveRNTheme(useColorScheme() === "dark", theme);
|
|
103
|
+
const copy = reporterCopy(
|
|
104
|
+
resolveReporterLocale(typeof navigator !== "undefined" ? navigator.language : void 0)
|
|
105
|
+
).ui;
|
|
106
|
+
const font = colors.fontFamily ? { fontFamily: colors.fontFamily } : null;
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
const timer = setTimeout(onDismiss, AUTO_HIDE_MS);
|
|
109
|
+
return () => clearTimeout(timer);
|
|
110
|
+
}, [onDismiss]);
|
|
111
|
+
return /* @__PURE__ */ jsxs(
|
|
112
|
+
View,
|
|
113
|
+
{
|
|
114
|
+
style: [s.toast, { backgroundColor: colors.bg, borderColor: colors.border, borderRadius: colors.radius }],
|
|
115
|
+
accessibilityLiveRegion: "polite",
|
|
116
|
+
accessibilityRole: "alert",
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Text, { style: [s.text, { color: colors.fg }, font], numberOfLines: 2, children: message }),
|
|
119
|
+
/* @__PURE__ */ jsx(
|
|
120
|
+
TouchableOpacity,
|
|
121
|
+
{
|
|
122
|
+
onPress: onView,
|
|
123
|
+
accessibilityRole: "button",
|
|
124
|
+
style: [s.btn, { backgroundColor: colors.accent, borderRadius: colors.radius }],
|
|
125
|
+
children: /* @__PURE__ */ jsx(Text, { style: [{ color: colors.accentFg, fontWeight: "600" }, font], children: copy.view })
|
|
126
|
+
}
|
|
127
|
+
),
|
|
128
|
+
/* @__PURE__ */ jsx(
|
|
129
|
+
TouchableOpacity,
|
|
130
|
+
{
|
|
131
|
+
onPress: onDismiss,
|
|
132
|
+
accessibilityRole: "button",
|
|
133
|
+
accessibilityLabel: copy.done,
|
|
134
|
+
hitSlop: { top: 10, bottom: 10, left: 10, right: 10 },
|
|
135
|
+
children: /* @__PURE__ */ jsx(Text, { style: [{ color: colors.muted, fontSize: 18 }, font], children: "\xD7" })
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
var s = StyleSheet.create({
|
|
143
|
+
toast: {
|
|
144
|
+
position: "absolute",
|
|
145
|
+
left: 16,
|
|
146
|
+
right: 16,
|
|
147
|
+
bottom: 32,
|
|
148
|
+
flexDirection: "row",
|
|
149
|
+
alignItems: "center",
|
|
150
|
+
gap: 10,
|
|
151
|
+
paddingVertical: 10,
|
|
152
|
+
paddingHorizontal: 14,
|
|
153
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
154
|
+
shadowColor: MUSHI_SHADOW_INK,
|
|
155
|
+
shadowOpacity: 0.18,
|
|
156
|
+
shadowRadius: 12,
|
|
157
|
+
shadowOffset: { width: 0, height: 6 },
|
|
158
|
+
elevation: 6
|
|
159
|
+
},
|
|
160
|
+
text: { flex: 1, fontSize: 14 },
|
|
161
|
+
btn: { paddingHorizontal: 12, paddingVertical: 6 }
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// src/optional-modules.ts
|
|
165
|
+
function unwrap(mod, key) {
|
|
166
|
+
if (!mod || typeof mod !== "object" && typeof mod !== "function") return null;
|
|
167
|
+
if (key in mod) return mod;
|
|
168
|
+
const def = mod.default;
|
|
169
|
+
return def && (typeof def === "object" || typeof def === "function") && key in def ? def : null;
|
|
170
|
+
}
|
|
171
|
+
function resolveNetInfo(injected) {
|
|
172
|
+
if (injected) return unwrap(injected, "addEventListener");
|
|
173
|
+
try {
|
|
174
|
+
return unwrap(require("@react-native-community/netinfo"), "addEventListener");
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function resolveViewShot(injected) {
|
|
180
|
+
if (injected) return unwrap(injected, "captureScreen");
|
|
181
|
+
try {
|
|
182
|
+
return unwrap(require("react-native-view-shot"), "captureScreen");
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function resolveExpoSensors(injected) {
|
|
188
|
+
if (injected) return unwrap(injected, "Accelerometer");
|
|
189
|
+
try {
|
|
190
|
+
return unwrap(require("expo-sensors"), "Accelerometer");
|
|
191
|
+
} catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
27
195
|
|
|
28
196
|
// src/capture/console-capture.ts
|
|
29
197
|
import { scrubPii } from "@mushi-mushi/core";
|
|
@@ -456,86 +624,50 @@ function sleep(ms) {
|
|
|
456
624
|
import {
|
|
457
625
|
useRef,
|
|
458
626
|
useState,
|
|
459
|
-
useEffect,
|
|
627
|
+
useEffect as useEffect2,
|
|
460
628
|
useCallback
|
|
461
629
|
} from "react";
|
|
462
630
|
import {
|
|
463
631
|
Modal,
|
|
464
|
-
View,
|
|
465
|
-
Text,
|
|
632
|
+
View as View2,
|
|
633
|
+
Text as Text2,
|
|
466
634
|
TextInput,
|
|
467
635
|
Image,
|
|
468
|
-
TouchableOpacity,
|
|
636
|
+
TouchableOpacity as TouchableOpacity2,
|
|
469
637
|
Animated,
|
|
470
638
|
PanResponder,
|
|
471
|
-
StyleSheet,
|
|
639
|
+
StyleSheet as StyleSheet2,
|
|
472
640
|
Dimensions as Dimensions2,
|
|
473
641
|
Platform as Platform2,
|
|
474
642
|
KeyboardAvoidingView,
|
|
475
643
|
ScrollView,
|
|
476
|
-
|
|
644
|
+
AccessibilityInfo,
|
|
645
|
+
useColorScheme as useColorScheme2
|
|
477
646
|
} from "react-native";
|
|
478
647
|
import {
|
|
479
648
|
MUSHI_COPY,
|
|
480
649
|
MUSHI_INVERSE,
|
|
481
650
|
MUSHI_RADIUS as MUSHI_RADIUS2,
|
|
482
|
-
MUSHI_SHADOW_INK,
|
|
651
|
+
MUSHI_SHADOW_INK as MUSHI_SHADOW_INK2,
|
|
483
652
|
MUSHI_SPACING,
|
|
484
653
|
MUSHI_TYPE
|
|
485
654
|
} from "@mushi-mushi/core";
|
|
486
|
-
import {
|
|
655
|
+
import {
|
|
656
|
+
REPORTER_CATEGORIES,
|
|
657
|
+
isPlausibleReporterEmail,
|
|
658
|
+
isReporterConversation,
|
|
659
|
+
reporterCanSend,
|
|
660
|
+
reporterCategoryLabel,
|
|
661
|
+
reporterChipToReport,
|
|
662
|
+
reporterCopy as reporterCopy2,
|
|
663
|
+
reporterStatus,
|
|
664
|
+
reporterTimelineEntryText,
|
|
665
|
+
resolveReporterLocale as resolveReporterLocale2
|
|
666
|
+
} from "@mushi-mushi/core/reporter-ui";
|
|
487
667
|
import { getLocale } from "@mushi-mushi/web/i18n";
|
|
488
668
|
|
|
489
|
-
// src/theme.ts
|
|
490
|
-
import { mushiPalette, MUSHI_CONTROL_DISABLED, MUSHI_RADIUS } from "@mushi-mushi/core";
|
|
491
|
-
function hexToRgb(hex) {
|
|
492
|
-
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})([0-9a-f]{2})?$/i.exec(hex.trim());
|
|
493
|
-
if (!m) return null;
|
|
494
|
-
const h = m[1].length === 3 ? m[1].split("").map((c) => c + c).join("") : m[1];
|
|
495
|
-
return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
|
|
496
|
-
}
|
|
497
|
-
function luminance([r, g, b]) {
|
|
498
|
-
const lin = (c) => {
|
|
499
|
-
const s4 = c / 255;
|
|
500
|
-
return s4 <= 0.03928 ? s4 / 12.92 : ((s4 + 0.055) / 1.055) ** 2.4;
|
|
501
|
-
};
|
|
502
|
-
return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
|
|
503
|
-
}
|
|
504
|
-
function contrastingText(bg, fallback) {
|
|
505
|
-
const rgb = hexToRgb(bg);
|
|
506
|
-
if (!rgb) return fallback;
|
|
507
|
-
const l = luminance(rgb);
|
|
508
|
-
return 1.05 / (l + 0.05) >= (l + 0.05) / 0.05 ? "#FFFFFF" : "#000000";
|
|
509
|
-
}
|
|
510
|
-
function resolveRNTheme(dark, override = {}) {
|
|
511
|
-
const pal = mushiPalette(dark ? "dark" : "light");
|
|
512
|
-
const base = {
|
|
513
|
-
bg: dark ? pal.paper : pal.paperRaised,
|
|
514
|
-
fg: pal.ink,
|
|
515
|
-
muted: pal.inkMuted,
|
|
516
|
-
surface: dark ? pal.paperRaised : pal.paper,
|
|
517
|
-
border: pal.ruleStrong,
|
|
518
|
-
accent: pal.ink,
|
|
519
|
-
accentFg: dark ? pal.paper : pal.paperRaised,
|
|
520
|
-
success: pal.ok,
|
|
521
|
-
error: pal.danger,
|
|
522
|
-
fontFamily: void 0,
|
|
523
|
-
radius: MUSHI_RADIUS.card
|
|
524
|
-
};
|
|
525
|
-
const defined = Object.fromEntries(
|
|
526
|
-
Object.entries(override).filter(([, v]) => v !== void 0 && v !== null && v !== "")
|
|
527
|
-
);
|
|
528
|
-
const merged = { ...base, ...defined };
|
|
529
|
-
if (defined.accent && !defined.accentFg) merged.accentFg = contrastingText(defined.accent, base.accentFg);
|
|
530
|
-
return {
|
|
531
|
-
...merged,
|
|
532
|
-
backdrop: dark ? "rgba(0,0,0,0.6)" : "rgba(0,0,0,0.35)",
|
|
533
|
-
disabled: dark ? MUSHI_CONTROL_DISABLED.dark : MUSHI_CONTROL_DISABLED.light,
|
|
534
|
-
disabledFg: pal.inkFaint
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
|
|
538
669
|
// src/reporter-thread.ts
|
|
670
|
+
import { reporterChannels } from "@mushi-mushi/core/reporter-channels";
|
|
539
671
|
var THREAD_LOAD_TIMEOUT_MS = 12e3;
|
|
540
672
|
function settleWithin(p, ms) {
|
|
541
673
|
return new Promise((resolve) => {
|
|
@@ -563,6 +695,9 @@ function loadReporterThread(load, reportId, timeoutMs = THREAD_LOAD_TIMEOUT_MS)
|
|
|
563
695
|
}
|
|
564
696
|
async function markReporterReportRead(client, reporterToken, reportId) {
|
|
565
697
|
try {
|
|
698
|
+
const v2 = await reporterChannels(client).markReportRead(reportId, reporterToken);
|
|
699
|
+
if (v2.ok) return v2.data?.marked_read ?? 0;
|
|
700
|
+
if (v2.error?.status !== 404) return 0;
|
|
566
701
|
const res = await client.listNotifications(reporterToken, { limit: 100 });
|
|
567
702
|
if (!res.ok) return 0;
|
|
568
703
|
const rows = res.data?.notifications ?? [];
|
|
@@ -577,21 +712,59 @@ async function markReporterReportRead(client, reporterToken, reportId) {
|
|
|
577
712
|
return 0;
|
|
578
713
|
}
|
|
579
714
|
}
|
|
715
|
+
function createReporterUpdateHub(fetchUpdates) {
|
|
716
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
717
|
+
async function emit() {
|
|
718
|
+
let updates = null;
|
|
719
|
+
try {
|
|
720
|
+
updates = await fetchUpdates();
|
|
721
|
+
} catch {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
if (updates) {
|
|
725
|
+
for (const cb of listeners) {
|
|
726
|
+
try {
|
|
727
|
+
cb(updates);
|
|
728
|
+
} catch {
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return updates;
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
subscribe(cb) {
|
|
736
|
+
listeners.add(cb);
|
|
737
|
+
void emit();
|
|
738
|
+
return () => {
|
|
739
|
+
listeners.delete(cb);
|
|
740
|
+
};
|
|
741
|
+
},
|
|
742
|
+
emit,
|
|
743
|
+
listenerCount: () => listeners.size
|
|
744
|
+
};
|
|
745
|
+
}
|
|
580
746
|
|
|
581
747
|
// src/components/MushiBottomSheet.tsx
|
|
582
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
748
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
583
749
|
var { height: SCREEN_HEIGHT } = Dimensions2.get("window");
|
|
584
750
|
var SHEET_HEIGHT = SCREEN_HEIGHT * 0.55;
|
|
585
751
|
var DISMISS_THRESHOLD = 80;
|
|
586
|
-
var MIN_DESCRIPTION = 20;
|
|
587
|
-
var CATEGORY_KEYS = ["bug", "slow", "visual", "confusing", "other"];
|
|
588
752
|
var CATEGORY_EMOJI = {
|
|
589
753
|
bug: "\u{1F41B}",
|
|
590
754
|
slow: "\u{1F422}",
|
|
591
755
|
visual: "\u{1F3A8}",
|
|
592
756
|
confusing: "\u{1F615}",
|
|
593
|
-
|
|
757
|
+
idea: "\u{1F4A1}"
|
|
594
758
|
};
|
|
759
|
+
function commentsToTimeline(comments) {
|
|
760
|
+
return comments.map((c) => ({
|
|
761
|
+
kind: c.author_kind === "reporter" ? "reporter_comment" : "comment",
|
|
762
|
+
at: c.created_at,
|
|
763
|
+
text: c.body,
|
|
764
|
+
body: c.body,
|
|
765
|
+
comment_id: c.id
|
|
766
|
+
}));
|
|
767
|
+
}
|
|
595
768
|
var MushiBottomSheet = ({
|
|
596
769
|
visible,
|
|
597
770
|
onClose,
|
|
@@ -604,16 +777,18 @@ var MushiBottomSheet = ({
|
|
|
604
777
|
assistantGreeting,
|
|
605
778
|
assistantSuggestions = [],
|
|
606
779
|
inboxPollIntervalMs = 0,
|
|
607
|
-
theme
|
|
780
|
+
theme,
|
|
781
|
+
minDescriptionLength,
|
|
782
|
+
emailOptIn = true
|
|
608
783
|
}) => {
|
|
609
784
|
const mushi = useMushiContext();
|
|
610
785
|
const t = getLocale();
|
|
611
|
-
const locale =
|
|
786
|
+
const locale = resolveReporterLocale2(
|
|
612
787
|
typeof navigator !== "undefined" ? navigator.language : void 0
|
|
613
788
|
);
|
|
614
|
-
const rc =
|
|
789
|
+
const rc = reporterCopy2(locale);
|
|
615
790
|
const greeting = assistantGreeting ?? t.assistant.defaultGreeting;
|
|
616
|
-
const scheme =
|
|
791
|
+
const scheme = useColorScheme2();
|
|
617
792
|
const dark = scheme === "dark";
|
|
618
793
|
const translateY = useRef(new Animated.Value(SHEET_HEIGHT)).current;
|
|
619
794
|
const backdropOpacity = useRef(new Animated.Value(0)).current;
|
|
@@ -627,7 +802,7 @@ var MushiBottomSheet = ({
|
|
|
627
802
|
const [inboxLoading, setInboxLoading] = useState(false);
|
|
628
803
|
const [selectedReportId, setSelectedReportId] = useState(null);
|
|
629
804
|
const selectedRef = useRef(null);
|
|
630
|
-
const [
|
|
805
|
+
const [threadItems, setThreadItems] = useState([]);
|
|
631
806
|
const [threadStatus, setThreadStatus] = useState("idle");
|
|
632
807
|
const [replyText, setReplyText] = useState("");
|
|
633
808
|
const [replyState, setReplyState] = useState("idle");
|
|
@@ -639,6 +814,18 @@ var MushiBottomSheet = ({
|
|
|
639
814
|
const [assistantError, setAssistantError] = useState(null);
|
|
640
815
|
const [assistantTurns, setAssistantTurns] = useState([]);
|
|
641
816
|
const [screenshotAttached, setScreenshotAttached] = useState(true);
|
|
817
|
+
const [emailState, setEmailState] = useState("hidden");
|
|
818
|
+
const [emailInput, setEmailInput] = useState("");
|
|
819
|
+
const [reduceMotion, setReduceMotion] = useState(false);
|
|
820
|
+
useEffect2(() => {
|
|
821
|
+
let alive = true;
|
|
822
|
+
AccessibilityInfo?.isReduceMotionEnabled?.().then((on) => alive && setReduceMotion(Boolean(on))).catch(() => void 0);
|
|
823
|
+
const sub = AccessibilityInfo?.addEventListener?.("reduceMotionChanged", (on) => setReduceMotion(Boolean(on)));
|
|
824
|
+
return () => {
|
|
825
|
+
alive = false;
|
|
826
|
+
sub?.remove?.();
|
|
827
|
+
};
|
|
828
|
+
}, []);
|
|
642
829
|
const loadInbox = useCallback(
|
|
643
830
|
async (opts = {}) => {
|
|
644
831
|
if (!mushi?.listMyReports) return;
|
|
@@ -654,14 +841,14 @@ var MushiBottomSheet = ({
|
|
|
654
841
|
},
|
|
655
842
|
[mushi, locale]
|
|
656
843
|
);
|
|
657
|
-
|
|
844
|
+
useEffect2(() => {
|
|
658
845
|
if (visible) {
|
|
659
846
|
setScreenshotAttached(true);
|
|
660
847
|
setSheetTab(preferredTab);
|
|
661
848
|
if (preferredTab === "inbox") void loadInbox();
|
|
662
849
|
}
|
|
663
850
|
}, [visible, preferredTab, loadInbox]);
|
|
664
|
-
|
|
851
|
+
useEffect2(() => {
|
|
665
852
|
if (!visible || sheetTab !== "inbox" || inboxPollIntervalMs <= 0) return;
|
|
666
853
|
const timer = setInterval(() => {
|
|
667
854
|
void loadInbox({ silent: true });
|
|
@@ -673,19 +860,26 @@ var MushiBottomSheet = ({
|
|
|
673
860
|
selectedRef.current = reportId;
|
|
674
861
|
setSelectedReportId(reportId);
|
|
675
862
|
if (!opts.silent) {
|
|
676
|
-
|
|
863
|
+
setThreadItems([]);
|
|
677
864
|
setThreadStatus("loading");
|
|
678
865
|
setReplyState("idle");
|
|
679
866
|
setFeedbackError(false);
|
|
680
867
|
}
|
|
681
|
-
|
|
682
|
-
const
|
|
868
|
+
let items = null;
|
|
869
|
+
const detail = mushi?.loadMyReportDetail ? await settleWithin(mushi.loadMyReportDetail(reportId), THREAD_LOAD_TIMEOUT_MS) : "unsupported";
|
|
870
|
+
if (detail && detail !== "unsupported") {
|
|
871
|
+
items = detail.timeline;
|
|
872
|
+
} else if (detail === "unsupported") {
|
|
873
|
+
const load = mushi?.loadMyThread ?? mushi?.listMyComments;
|
|
874
|
+
const comments = load ? await loadReporterThread(load, reportId) : null;
|
|
875
|
+
items = comments ? commentsToTimeline(comments) : null;
|
|
876
|
+
}
|
|
683
877
|
if (selectedRef.current !== reportId) return;
|
|
684
|
-
if (
|
|
878
|
+
if (items === null) {
|
|
685
879
|
setThreadStatus((prev) => opts.silent && prev === "ready" ? "ready" : "error");
|
|
686
880
|
return;
|
|
687
881
|
}
|
|
688
|
-
|
|
882
|
+
setThreadItems(items);
|
|
689
883
|
setThreadStatus("ready");
|
|
690
884
|
if (!opts.silent && mushi?.markReportRead) {
|
|
691
885
|
mushi.markReportRead(reportId).then((marked) => {
|
|
@@ -716,7 +910,10 @@ var MushiBottomSheet = ({
|
|
|
716
910
|
setReplyText("");
|
|
717
911
|
setReplyState("idle");
|
|
718
912
|
if (selectedRef.current === reportId) {
|
|
719
|
-
|
|
913
|
+
setThreadItems((prev) => [
|
|
914
|
+
...prev,
|
|
915
|
+
{ kind: "reporter_comment", at: comment.created_at, text: comment.body, body: comment.body, comment_id: comment.id }
|
|
916
|
+
]);
|
|
720
917
|
void openThread(reportId, { silent: true });
|
|
721
918
|
}
|
|
722
919
|
} catch {
|
|
@@ -774,8 +971,15 @@ var MushiBottomSheet = ({
|
|
|
774
971
|
setCategory(null);
|
|
775
972
|
setDescription("");
|
|
776
973
|
setPhase("form");
|
|
974
|
+
setEmailState("hidden");
|
|
975
|
+
setEmailInput("");
|
|
777
976
|
}, []);
|
|
778
977
|
const animateIn = useCallback(() => {
|
|
978
|
+
if (reduceMotion) {
|
|
979
|
+
translateY.setValue(0);
|
|
980
|
+
backdropOpacity.setValue(1);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
779
983
|
Animated.parallel([
|
|
780
984
|
Animated.spring(translateY, {
|
|
781
985
|
toValue: 0,
|
|
@@ -789,18 +993,18 @@ var MushiBottomSheet = ({
|
|
|
789
993
|
useNativeDriver: true
|
|
790
994
|
})
|
|
791
995
|
]).start();
|
|
792
|
-
}, [translateY, backdropOpacity]);
|
|
996
|
+
}, [translateY, backdropOpacity, reduceMotion]);
|
|
793
997
|
const animateOut = useCallback(
|
|
794
998
|
(cb) => {
|
|
795
999
|
Animated.parallel([
|
|
796
1000
|
Animated.timing(translateY, {
|
|
797
1001
|
toValue: SHEET_HEIGHT,
|
|
798
|
-
duration: 220,
|
|
1002
|
+
duration: reduceMotion ? 0 : 220,
|
|
799
1003
|
useNativeDriver: true
|
|
800
1004
|
}),
|
|
801
1005
|
Animated.timing(backdropOpacity, {
|
|
802
1006
|
toValue: 0,
|
|
803
|
-
duration: 200,
|
|
1007
|
+
duration: reduceMotion ? 0 : 200,
|
|
804
1008
|
useNativeDriver: true
|
|
805
1009
|
})
|
|
806
1010
|
]).start(() => {
|
|
@@ -808,9 +1012,9 @@ var MushiBottomSheet = ({
|
|
|
808
1012
|
cb?.();
|
|
809
1013
|
});
|
|
810
1014
|
},
|
|
811
|
-
[translateY, backdropOpacity, resetForm]
|
|
1015
|
+
[translateY, backdropOpacity, resetForm, reduceMotion]
|
|
812
1016
|
);
|
|
813
|
-
|
|
1017
|
+
useEffect2(() => {
|
|
814
1018
|
if (visible) animateIn();
|
|
815
1019
|
}, [visible, animateIn]);
|
|
816
1020
|
const handleClose = useCallback(() => {
|
|
@@ -837,20 +1041,43 @@ var MushiBottomSheet = ({
|
|
|
837
1041
|
}
|
|
838
1042
|
})
|
|
839
1043
|
).current;
|
|
840
|
-
const
|
|
841
|
-
if (!
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1044
|
+
const offerEmail = useCallback(async () => {
|
|
1045
|
+
if (!emailOptIn || !mushi?.getNotificationPrefs) return;
|
|
1046
|
+
try {
|
|
1047
|
+
const prefs = await mushi.getNotificationPrefs();
|
|
1048
|
+
if (prefs?.available.email && !prefs.email_verified && !prefs.email_pending) {
|
|
1049
|
+
setEmailInput(mushi.emailPrefill?.() ?? "");
|
|
1050
|
+
setEmailState("offer");
|
|
1051
|
+
}
|
|
1052
|
+
} catch {
|
|
1053
|
+
}
|
|
1054
|
+
}, [emailOptIn, mushi]);
|
|
1055
|
+
const submitEmail = useCallback(async () => {
|
|
1056
|
+
const email = emailInput.trim();
|
|
1057
|
+
if (!isPlausibleReporterEmail(email)) {
|
|
1058
|
+
setEmailState("invalid");
|
|
845
1059
|
return;
|
|
846
1060
|
}
|
|
1061
|
+
if (!mushi?.setNotificationPrefs) return;
|
|
1062
|
+
setEmailState("sending");
|
|
1063
|
+
try {
|
|
1064
|
+
const res = await mushi.setNotificationPrefs({ email });
|
|
1065
|
+
setEmailState(res.ok ? "sent" : res.error?.status === 422 ? "invalid" : "failed");
|
|
1066
|
+
} catch {
|
|
1067
|
+
setEmailState("failed");
|
|
1068
|
+
}
|
|
1069
|
+
}, [emailInput, mushi]);
|
|
1070
|
+
const handleSubmit = async () => {
|
|
1071
|
+
const hasAttachment = Boolean(screenshotDataUrl && screenshotAttached);
|
|
1072
|
+
if (!mushi || !reporterCanSend(description, hasAttachment, minDescriptionLength)) return;
|
|
1073
|
+
const trimmed = description.trim();
|
|
847
1074
|
setSubmitError(null);
|
|
848
1075
|
setPhase("sending");
|
|
849
1076
|
try {
|
|
850
1077
|
const outcome = await mushi.submitReport({
|
|
851
|
-
category,
|
|
1078
|
+
...reporterChipToReport(category),
|
|
852
1079
|
description: trimmed,
|
|
853
|
-
screenshotDataUrl:
|
|
1080
|
+
screenshotDataUrl: hasAttachment ? screenshotDataUrl : void 0
|
|
854
1081
|
});
|
|
855
1082
|
if (!outcome.ok) {
|
|
856
1083
|
if (outcome.failureKind === "credentials" || outcome.failureKind === "quota") {
|
|
@@ -868,7 +1095,7 @@ var MushiBottomSheet = ({
|
|
|
868
1095
|
return;
|
|
869
1096
|
}
|
|
870
1097
|
setPhase("sent");
|
|
871
|
-
|
|
1098
|
+
void offerEmail();
|
|
872
1099
|
} catch {
|
|
873
1100
|
setSubmitError("Something went wrong. Please try again.");
|
|
874
1101
|
setPhase("error");
|
|
@@ -879,94 +1106,106 @@ var MushiBottomSheet = ({
|
|
|
879
1106
|
const font = colors.fontFamily ? { fontFamily: colors.fontFamily } : null;
|
|
880
1107
|
const radius = colors.radius;
|
|
881
1108
|
const sheetTabs = ["report", "inbox", ...assistantEnabled ? ["assistant"] : []];
|
|
882
|
-
const canSubmit =
|
|
883
|
-
const submitHint = canSubmit || phase === "sending" ? void 0 :
|
|
1109
|
+
const canSubmit = reporterCanSend(description, Boolean(activeScreenshot), minDescriptionLength) && (phase === "form" || phase === "error");
|
|
1110
|
+
const submitHint = canSubmit || phase === "sending" ? void 0 : rc.ui.addWords;
|
|
884
1111
|
const selectedReport = selectedReportId ? inboxReports.find((r) => r.id === selectedReportId) ?? null : null;
|
|
885
1112
|
const selectedView = selectedReport ? reporterStatus(selectedReport, locale) : null;
|
|
886
1113
|
const headerTitle = sheetTab === "assistant" ? assistantLabel : sheetTab === "inbox" ? t.flows.reports.title : t.widget.title;
|
|
887
|
-
const renderThread = () => /* @__PURE__ */
|
|
888
|
-
/* @__PURE__ */
|
|
889
|
-
|
|
1114
|
+
const renderThread = () => /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1115
|
+
/* @__PURE__ */ jsx2(
|
|
1116
|
+
TouchableOpacity2,
|
|
890
1117
|
{
|
|
891
1118
|
onPress: closeThread,
|
|
892
1119
|
accessibilityRole: "button",
|
|
893
1120
|
accessibilityLabel: t.widget.back,
|
|
894
1121
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
895
|
-
children: /* @__PURE__ */
|
|
1122
|
+
children: /* @__PURE__ */ jsxs2(Text2, { style: [{ color: colors.accent, marginBottom: 8 }, font], children: [
|
|
896
1123
|
"\u2190 ",
|
|
897
1124
|
t.widget.back
|
|
898
1125
|
] })
|
|
899
1126
|
}
|
|
900
1127
|
),
|
|
901
|
-
selectedReport && selectedView ? /* @__PURE__ */
|
|
902
|
-
/* @__PURE__ */
|
|
903
|
-
/* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
1128
|
+
selectedReport && selectedView ? /* @__PURE__ */ jsxs2(View2, { style: [s2.headerCard, { backgroundColor: colors.surface, borderRadius: radius, borderColor: colors.border }], children: [
|
|
1129
|
+
/* @__PURE__ */ jsx2(Text2, { style: [s2.pill, { color: colors.fg, borderColor: colors.border }, font], children: selectedView.label }),
|
|
1130
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, fontSize: 12, marginTop: 4 }, font], children: selectedView.detail }),
|
|
1131
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, marginTop: 8 }, font], numberOfLines: 4, children: selectedReport.title ?? selectedReport.summary ?? selectedReport.description ?? "" })
|
|
905
1132
|
] }) : null,
|
|
906
|
-
threadStatus === "loading" ? /* @__PURE__ */
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
/* @__PURE__ */
|
|
909
|
-
|
|
1133
|
+
threadStatus === "loading" ? /* @__PURE__ */ jsx2(View2, { accessibilityLabel: t.flows.reports.loading, accessibilityLiveRegion: "polite", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx2(View2, { style: [s2.skeleton, { backgroundColor: colors.surface, width: `${90 - i * 18}%` }] }, i)) }) : threadStatus === "error" ? /* @__PURE__ */ jsxs2(View2, { style: s2.errorRow, accessibilityLiveRegion: "polite", children: [
|
|
1134
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.error, flex: 1 }, font], accessibilityRole: "alert", children: rc.ui.loadError }),
|
|
1135
|
+
/* @__PURE__ */ jsx2(
|
|
1136
|
+
TouchableOpacity2,
|
|
910
1137
|
{
|
|
911
1138
|
onPress: () => selectedReportId && void openThread(selectedReportId),
|
|
912
1139
|
accessibilityRole: "button",
|
|
913
|
-
style: [
|
|
914
|
-
children: /* @__PURE__ */
|
|
1140
|
+
style: [s2.retryBtn, { borderColor: colors.border, borderRadius: radius }],
|
|
1141
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, fontWeight: "600" }, font], children: rc.ui.retry })
|
|
915
1142
|
}
|
|
916
1143
|
)
|
|
917
|
-
] }) :
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
s.threadBubble,
|
|
1144
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1145
|
+
threadItems.map(
|
|
1146
|
+
(item, idx) => isReporterConversation(item) ? /* @__PURE__ */ jsxs2(
|
|
1147
|
+
View2,
|
|
922
1148
|
{
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1149
|
+
style: [
|
|
1150
|
+
s2.threadBubble,
|
|
1151
|
+
{
|
|
1152
|
+
backgroundColor: colors.surface,
|
|
1153
|
+
alignSelf: item.kind === "reporter_comment" ? "flex-end" : "flex-start"
|
|
1154
|
+
}
|
|
1155
|
+
],
|
|
1156
|
+
children: [
|
|
1157
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, fontSize: 11 }, font], children: item.kind === "reporter_comment" ? rc.ui.you : rc.ui.developer }),
|
|
1158
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg }, font], children: reporterTimelineEntryText(item, locale) })
|
|
1159
|
+
]
|
|
1160
|
+
},
|
|
1161
|
+
`${item.kind}-${item.comment_id ?? idx}`
|
|
1162
|
+
) : /* @__PURE__ */ jsx2(
|
|
1163
|
+
Text2,
|
|
1164
|
+
{
|
|
1165
|
+
style: [{ color: colors.muted, fontSize: 12, textAlign: "center", marginVertical: 6 }, font],
|
|
1166
|
+
children: reporterTimelineEntryText(item, locale)
|
|
1167
|
+
},
|
|
1168
|
+
`${item.kind}-${item.at}-${idx}`
|
|
1169
|
+
)
|
|
1170
|
+
),
|
|
1171
|
+
!threadItems.some(isReporterConversation) ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, marginBottom: 8 }, font], children: rc.ui.noReplies }) : null
|
|
1172
|
+
] }),
|
|
1173
|
+
replyState === "sending" ? /* @__PURE__ */ jsxs2(View2, { style: [s2.threadBubble, { backgroundColor: colors.surface, alignSelf: "flex-end", opacity: 0.7 }], children: [
|
|
1174
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, fontSize: 11 }, font], children: rc.ui.sending }),
|
|
1175
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg }, font], children: replyText.trim() })
|
|
937
1176
|
] }) : null,
|
|
938
|
-
selectedView?.canVerify ? /* @__PURE__ */
|
|
939
|
-
/* @__PURE__ */
|
|
940
|
-
|
|
1177
|
+
selectedView?.canVerify ? /* @__PURE__ */ jsxs2(View2, { style: s2.verifyRow, children: [
|
|
1178
|
+
/* @__PURE__ */ jsx2(
|
|
1179
|
+
TouchableOpacity2,
|
|
941
1180
|
{
|
|
942
|
-
style: [
|
|
1181
|
+
style: [s2.verifyBtn, { backgroundColor: colors.accent, borderRadius: radius }],
|
|
943
1182
|
onPress: () => void submitFeedback("confirms"),
|
|
944
1183
|
disabled: feedbackSending,
|
|
945
1184
|
accessibilityRole: "button",
|
|
946
1185
|
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
947
|
-
children: /* @__PURE__ */
|
|
1186
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.accentFg }, font], children: rc.ui.yes })
|
|
948
1187
|
}
|
|
949
1188
|
),
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
|
|
1189
|
+
/* @__PURE__ */ jsx2(
|
|
1190
|
+
TouchableOpacity2,
|
|
952
1191
|
{
|
|
953
|
-
style: [
|
|
1192
|
+
style: [s2.verifyBtn, { backgroundColor: colors.border, borderRadius: radius }],
|
|
954
1193
|
onPress: () => void submitFeedback("not_fixed"),
|
|
955
1194
|
disabled: feedbackSending,
|
|
956
1195
|
accessibilityRole: "button",
|
|
957
1196
|
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
958
|
-
children: /* @__PURE__ */
|
|
1197
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.fg }, font], children: rc.ui.notYet })
|
|
959
1198
|
}
|
|
960
1199
|
)
|
|
961
1200
|
] }) : null,
|
|
962
|
-
feedbackError ? /* @__PURE__ */
|
|
963
|
-
/* @__PURE__ */
|
|
964
|
-
/* @__PURE__ */
|
|
1201
|
+
feedbackError ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.error, marginBottom: 8 }, font], accessibilityRole: "alert", children: rc.ui.sendFailed }) : null,
|
|
1202
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.composer, children: [
|
|
1203
|
+
/* @__PURE__ */ jsx2(
|
|
965
1204
|
TextInput,
|
|
966
1205
|
{
|
|
967
1206
|
style: [
|
|
968
|
-
|
|
969
|
-
|
|
1207
|
+
s2.input,
|
|
1208
|
+
s2.composerInput,
|
|
970
1209
|
{ backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius },
|
|
971
1210
|
font
|
|
972
1211
|
],
|
|
@@ -983,11 +1222,11 @@ var MushiBottomSheet = ({
|
|
|
983
1222
|
accessibilityLabel: t.flows.thread.replyPlaceholder
|
|
984
1223
|
}
|
|
985
1224
|
),
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
|
|
1225
|
+
/* @__PURE__ */ jsx2(
|
|
1226
|
+
TouchableOpacity2,
|
|
988
1227
|
{
|
|
989
1228
|
style: [
|
|
990
|
-
|
|
1229
|
+
s2.sendBtn,
|
|
991
1230
|
{
|
|
992
1231
|
backgroundColor: replyText.trim() && replyState !== "sending" ? colors.accent : colors.disabled,
|
|
993
1232
|
borderRadius: radius
|
|
@@ -998,11 +1237,11 @@ var MushiBottomSheet = ({
|
|
|
998
1237
|
accessibilityRole: "button",
|
|
999
1238
|
accessibilityLabel: replyState === "failed" ? rc.ui.retry : t.flows.thread.send,
|
|
1000
1239
|
accessibilityState: { disabled: !replyText.trim() || replyState === "sending", busy: replyState === "sending" },
|
|
1001
|
-
children: /* @__PURE__ */
|
|
1002
|
-
|
|
1240
|
+
children: /* @__PURE__ */ jsx2(
|
|
1241
|
+
Text2,
|
|
1003
1242
|
{
|
|
1004
1243
|
style: [
|
|
1005
|
-
|
|
1244
|
+
s2.submitText,
|
|
1006
1245
|
{ color: replyText.trim() && replyState !== "sending" ? colors.accentFg : colors.disabledFg },
|
|
1007
1246
|
font
|
|
1008
1247
|
],
|
|
@@ -1012,7 +1251,7 @@ var MushiBottomSheet = ({
|
|
|
1012
1251
|
}
|
|
1013
1252
|
)
|
|
1014
1253
|
] }),
|
|
1015
|
-
replyState === "failed" ? /* @__PURE__ */
|
|
1254
|
+
replyState === "failed" ? /* @__PURE__ */ jsxs2(Text2, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: [
|
|
1016
1255
|
rc.ui.sendFailed,
|
|
1017
1256
|
" \xB7 ",
|
|
1018
1257
|
rc.ui.retry
|
|
@@ -1020,50 +1259,50 @@ var MushiBottomSheet = ({
|
|
|
1020
1259
|
] });
|
|
1021
1260
|
const renderInboxList = () => {
|
|
1022
1261
|
if (inboxLoading && !inboxLoaded) {
|
|
1023
|
-
return /* @__PURE__ */
|
|
1262
|
+
return /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted }, font], children: t.flows.reports.loading });
|
|
1024
1263
|
}
|
|
1025
1264
|
if (inboxReports.length === 0) {
|
|
1026
|
-
return /* @__PURE__ */
|
|
1265
|
+
return /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted }, font], children: rc.ui.empty });
|
|
1027
1266
|
}
|
|
1028
1267
|
return inboxReports.map((r) => {
|
|
1029
1268
|
const view = reporterStatus(r, locale);
|
|
1030
1269
|
const unread = (r.unread_count ?? 0) > 0;
|
|
1031
1270
|
const title = (r.title ?? r.summary ?? r.description ?? "Report").slice(0, 80);
|
|
1032
|
-
return /* @__PURE__ */
|
|
1033
|
-
|
|
1271
|
+
return /* @__PURE__ */ jsxs2(
|
|
1272
|
+
TouchableOpacity2,
|
|
1034
1273
|
{
|
|
1035
|
-
style: [
|
|
1274
|
+
style: [s2.inboxRow, { borderColor: colors.border }],
|
|
1036
1275
|
onPress: () => void openThread(r.id),
|
|
1037
1276
|
accessibilityRole: "button",
|
|
1038
1277
|
accessibilityLabel: `${view.label}. ${title}${unread ? `. ${r.unread_count} new` : ""}`,
|
|
1039
1278
|
children: [
|
|
1040
|
-
/* @__PURE__ */
|
|
1041
|
-
/* @__PURE__ */
|
|
1279
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, fontWeight: unread ? "700" : "600" }, font], numberOfLines: 1, children: title }),
|
|
1280
|
+
/* @__PURE__ */ jsxs2(Text2, { style: [{ color: unread ? colors.fg : colors.muted, fontSize: 12, marginTop: 2 }, font], numberOfLines: 1, children: [
|
|
1042
1281
|
view.label,
|
|
1043
1282
|
view.othersNote ? ` \xB7 ${view.othersNote}` : ""
|
|
1044
1283
|
] }),
|
|
1045
|
-
unread && r.last_event_preview ? /* @__PURE__ */
|
|
1284
|
+
unread && r.last_event_preview ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, fontSize: 12, fontWeight: "700", marginTop: 2 }, font], numberOfLines: 1, children: r.last_event_preview }) : null
|
|
1046
1285
|
]
|
|
1047
1286
|
},
|
|
1048
1287
|
r.id
|
|
1049
1288
|
);
|
|
1050
1289
|
});
|
|
1051
1290
|
};
|
|
1052
|
-
return /* @__PURE__ */
|
|
1291
|
+
return /* @__PURE__ */ jsx2(Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, onRequestClose: handleClose, children: /* @__PURE__ */ jsxs2(
|
|
1053
1292
|
KeyboardAvoidingView,
|
|
1054
1293
|
{
|
|
1055
|
-
style:
|
|
1294
|
+
style: s2.flex,
|
|
1056
1295
|
behavior: Platform2.OS === "ios" ? "padding" : "height",
|
|
1057
1296
|
keyboardVerticalOffset: Platform2.OS === "ios" ? 0 : 20,
|
|
1058
1297
|
children: [
|
|
1059
|
-
/* @__PURE__ */
|
|
1298
|
+
/* @__PURE__ */ jsx2(
|
|
1060
1299
|
Animated.View,
|
|
1061
1300
|
{
|
|
1062
|
-
style: [
|
|
1063
|
-
children: /* @__PURE__ */
|
|
1064
|
-
|
|
1301
|
+
style: [s2.backdrop, { backgroundColor: colors.backdrop, opacity: backdropOpacity }],
|
|
1302
|
+
children: /* @__PURE__ */ jsx2(
|
|
1303
|
+
TouchableOpacity2,
|
|
1065
1304
|
{
|
|
1066
|
-
style:
|
|
1305
|
+
style: s2.flex,
|
|
1067
1306
|
activeOpacity: 1,
|
|
1068
1307
|
onPress: handleClose,
|
|
1069
1308
|
accessibilityRole: "button",
|
|
@@ -1072,21 +1311,21 @@ var MushiBottomSheet = ({
|
|
|
1072
1311
|
)
|
|
1073
1312
|
}
|
|
1074
1313
|
),
|
|
1075
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsxs2(
|
|
1076
1315
|
Animated.View,
|
|
1077
1316
|
{
|
|
1078
1317
|
accessibilityViewIsModal: true,
|
|
1079
1318
|
onAccessibilityEscape: handleClose,
|
|
1080
1319
|
style: [
|
|
1081
|
-
|
|
1320
|
+
s2.sheet,
|
|
1082
1321
|
{ backgroundColor: colors.bg, transform: [{ translateY }] }
|
|
1083
1322
|
],
|
|
1084
1323
|
children: [
|
|
1085
|
-
/* @__PURE__ */
|
|
1086
|
-
|
|
1324
|
+
/* @__PURE__ */ jsx2(
|
|
1325
|
+
View2,
|
|
1087
1326
|
{
|
|
1088
1327
|
...panResponder.panHandlers,
|
|
1089
|
-
style:
|
|
1328
|
+
style: s2.handleArea,
|
|
1090
1329
|
accessible: true,
|
|
1091
1330
|
accessibilityRole: "adjustable",
|
|
1092
1331
|
accessibilityLabel: t.widget.close,
|
|
@@ -1094,57 +1333,57 @@ var MushiBottomSheet = ({
|
|
|
1094
1333
|
onAccessibilityAction: (e) => {
|
|
1095
1334
|
if (e.nativeEvent.actionName === "decrement" || e.nativeEvent.actionName === "escape") handleClose();
|
|
1096
1335
|
},
|
|
1097
|
-
children: /* @__PURE__ */
|
|
1336
|
+
children: /* @__PURE__ */ jsx2(View2, { style: [s2.handle, { backgroundColor: colors.muted }] })
|
|
1098
1337
|
}
|
|
1099
1338
|
),
|
|
1100
|
-
/* @__PURE__ */
|
|
1101
|
-
/* @__PURE__ */
|
|
1102
|
-
|
|
1339
|
+
/* @__PURE__ */ jsx2(View2, { style: [s2.header, { borderBottomColor: colors.border }], children: /* @__PURE__ */ jsx2(Text2, { accessibilityRole: "header", style: [s2.headerTitle, { color: colors.fg }, font], children: headerTitle }) }),
|
|
1340
|
+
/* @__PURE__ */ jsx2(View2, { style: [s2.tabRow, { borderBottomColor: colors.border }], accessibilityRole: "tablist", children: sheetTabs.map((tab) => /* @__PURE__ */ jsx2(
|
|
1341
|
+
TouchableOpacity2,
|
|
1103
1342
|
{
|
|
1104
1343
|
onPress: () => {
|
|
1105
1344
|
setSheetTab(tab);
|
|
1106
1345
|
if (tab === "inbox") void loadInbox({ silent: inboxLoaded });
|
|
1107
1346
|
else closeThread();
|
|
1108
1347
|
},
|
|
1109
|
-
style: [
|
|
1348
|
+
style: [s2.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
1110
1349
|
accessibilityRole: "tab",
|
|
1111
1350
|
accessibilityState: { selected: sheetTab === tab },
|
|
1112
|
-
children: /* @__PURE__ */
|
|
1351
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.tabLabel, { color: sheetTab === tab ? colors.fg : colors.muted }, font], children: tab === "report" ? t.widget.trigger : tab === "inbox" ? t.flows.reports.title : assistantLabel })
|
|
1113
1352
|
},
|
|
1114
1353
|
tab
|
|
1115
1354
|
)) }),
|
|
1116
|
-
sheetTab === "assistant" ? /* @__PURE__ */
|
|
1117
|
-
assistantTurns.length === 0 ? /* @__PURE__ */
|
|
1118
|
-
/* @__PURE__ */
|
|
1119
|
-
assistantSuggestions.map((chip) => /* @__PURE__ */
|
|
1120
|
-
|
|
1355
|
+
sheetTab === "assistant" ? /* @__PURE__ */ jsxs2(ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", children: [
|
|
1356
|
+
assistantTurns.length === 0 ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1357
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, marginBottom: 12, lineHeight: 20 }, font], children: greeting }),
|
|
1358
|
+
assistantSuggestions.map((chip) => /* @__PURE__ */ jsx2(
|
|
1359
|
+
TouchableOpacity2,
|
|
1121
1360
|
{
|
|
1122
|
-
style: [
|
|
1361
|
+
style: [s2.assistantChip, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
1123
1362
|
onPress: () => void sendAssistant(chip),
|
|
1124
1363
|
accessibilityRole: "button",
|
|
1125
|
-
children: /* @__PURE__ */
|
|
1364
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, fontSize: 13 }, font], children: chip })
|
|
1126
1365
|
},
|
|
1127
1366
|
chip
|
|
1128
1367
|
))
|
|
1129
|
-
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */
|
|
1130
|
-
|
|
1368
|
+
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */ jsxs2(
|
|
1369
|
+
View2,
|
|
1131
1370
|
{
|
|
1132
1371
|
style: [
|
|
1133
|
-
|
|
1372
|
+
s2.assistantBubble,
|
|
1134
1373
|
{
|
|
1135
1374
|
alignSelf: turn.role === "user" ? "flex-end" : "flex-start",
|
|
1136
1375
|
backgroundColor: turn.role === "user" ? colors.accent : colors.surface
|
|
1137
1376
|
}
|
|
1138
1377
|
],
|
|
1139
1378
|
children: [
|
|
1140
|
-
/* @__PURE__ */
|
|
1141
|
-
turn.options?.map((opt) => /* @__PURE__ */
|
|
1142
|
-
|
|
1379
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: turn.role === "user" ? colors.accentFg : colors.fg }, font], children: turn.text }),
|
|
1380
|
+
turn.options?.map((opt) => /* @__PURE__ */ jsx2(
|
|
1381
|
+
TouchableOpacity2,
|
|
1143
1382
|
{
|
|
1144
1383
|
onPress: () => void sendAssistant(opt),
|
|
1145
1384
|
style: { marginTop: 8 },
|
|
1146
1385
|
accessibilityRole: "button",
|
|
1147
|
-
children: /* @__PURE__ */
|
|
1386
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.accent, fontSize: 12 }, font], children: opt })
|
|
1148
1387
|
},
|
|
1149
1388
|
opt
|
|
1150
1389
|
))
|
|
@@ -1152,13 +1391,13 @@ var MushiBottomSheet = ({
|
|
|
1152
1391
|
},
|
|
1153
1392
|
`${turn.role}-${idx}`
|
|
1154
1393
|
)),
|
|
1155
|
-
assistantSending ? /* @__PURE__ */
|
|
1156
|
-
assistantError ? /* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
/* @__PURE__ */
|
|
1394
|
+
assistantSending ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, marginTop: 8 }, font], accessibilityLiveRegion: "polite", children: t.assistant.thinking }) : null,
|
|
1395
|
+
assistantError ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.error, marginTop: 8 }, font], accessibilityRole: "alert", children: assistantError }) : null,
|
|
1396
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.assistantComposer, children: [
|
|
1397
|
+
/* @__PURE__ */ jsx2(
|
|
1159
1398
|
TextInput,
|
|
1160
1399
|
{
|
|
1161
|
-
style: [
|
|
1400
|
+
style: [s2.input, { flex: 1, minHeight: 44, backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius }, font],
|
|
1162
1401
|
placeholder: t.assistant.inputPlaceholder,
|
|
1163
1402
|
placeholderTextColor: colors.muted,
|
|
1164
1403
|
value: assistantInput,
|
|
@@ -1166,71 +1405,101 @@ var MushiBottomSheet = ({
|
|
|
1166
1405
|
editable: !assistantSending
|
|
1167
1406
|
}
|
|
1168
1407
|
),
|
|
1169
|
-
/* @__PURE__ */
|
|
1170
|
-
|
|
1408
|
+
/* @__PURE__ */ jsx2(
|
|
1409
|
+
TouchableOpacity2,
|
|
1171
1410
|
{
|
|
1172
|
-
style: [
|
|
1411
|
+
style: [s2.submitBtn, { backgroundColor: colors.accent, paddingHorizontal: 16, borderRadius: radius }],
|
|
1173
1412
|
onPress: () => void sendAssistant(assistantInput),
|
|
1174
1413
|
disabled: !assistantInput.trim() || assistantSending,
|
|
1175
1414
|
accessibilityRole: "button",
|
|
1176
1415
|
accessibilityLabel: t.flows.thread.send,
|
|
1177
1416
|
accessibilityState: { disabled: !assistantInput.trim() || assistantSending, busy: assistantSending },
|
|
1178
|
-
children: /* @__PURE__ */
|
|
1417
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.accentFg }], children: "\u2191" })
|
|
1179
1418
|
}
|
|
1180
1419
|
)
|
|
1181
1420
|
] })
|
|
1182
|
-
] }) : sheetTab === "inbox" ? /* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1184
|
-
|
|
1185
|
-
|
|
1421
|
+
] }) : sheetTab === "inbox" ? /* @__PURE__ */ jsx2(ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", contentContainerStyle: { paddingBottom: 24 }, children: selectedReportId ? renderThread() : renderInboxList() }) : phase === "sent" ? /* @__PURE__ */ jsxs2(ScrollView, { style: s2.body, keyboardShouldPersistTaps: "handled", contentContainerStyle: { paddingBottom: 24 }, children: [
|
|
1422
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.sentWrap, accessibilityLiveRegion: "polite", children: [
|
|
1423
|
+
/* @__PURE__ */ jsx2(Text2, { style: [s2.sentEmoji], importantForAccessibility: "no", children: "\u2705" }),
|
|
1424
|
+
/* @__PURE__ */ jsx2(Text2, { style: [s2.sentText, { color: colors.fg }, font], children: rc.ui.receipt })
|
|
1425
|
+
] }),
|
|
1426
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.verifyRow, children: [
|
|
1427
|
+
/* @__PURE__ */ jsx2(
|
|
1428
|
+
TouchableOpacity2,
|
|
1429
|
+
{
|
|
1430
|
+
style: [s2.verifyBtn, { backgroundColor: colors.accent, borderRadius: radius }],
|
|
1431
|
+
onPress: () => {
|
|
1432
|
+
resetForm();
|
|
1433
|
+
setSheetTab("inbox");
|
|
1434
|
+
void loadInbox();
|
|
1435
|
+
},
|
|
1436
|
+
accessibilityRole: "button",
|
|
1437
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.accentFg }, font], children: rc.ui.trackIt })
|
|
1438
|
+
}
|
|
1439
|
+
),
|
|
1440
|
+
/* @__PURE__ */ jsx2(
|
|
1441
|
+
TouchableOpacity2,
|
|
1442
|
+
{
|
|
1443
|
+
style: [s2.verifyBtn, { backgroundColor: colors.border, borderRadius: radius }],
|
|
1444
|
+
onPress: handleClose,
|
|
1445
|
+
accessibilityRole: "button",
|
|
1446
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.fg }, font], children: rc.ui.done })
|
|
1447
|
+
}
|
|
1448
|
+
)
|
|
1449
|
+
] }),
|
|
1450
|
+
emailState === "sent" ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, marginTop: 12 }, font], accessibilityLiveRegion: "polite", children: rc.ui.emailCheckInbox }) : emailState !== "hidden" ? /* @__PURE__ */ jsxs2(View2, { style: { marginTop: 12 }, children: [
|
|
1451
|
+
/* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, marginBottom: 6 }, font], children: rc.ui.emailOptIn }),
|
|
1452
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.composer, children: [
|
|
1453
|
+
/* @__PURE__ */ jsx2(
|
|
1454
|
+
TextInput,
|
|
1455
|
+
{
|
|
1456
|
+
style: [
|
|
1457
|
+
s2.input,
|
|
1458
|
+
s2.composerInput,
|
|
1459
|
+
{ backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius },
|
|
1460
|
+
font
|
|
1461
|
+
],
|
|
1462
|
+
value: emailInput,
|
|
1463
|
+
onChangeText: (v) => {
|
|
1464
|
+
setEmailInput(v.slice(0, 254));
|
|
1465
|
+
if (emailState === "invalid" || emailState === "failed") setEmailState("offer");
|
|
1466
|
+
},
|
|
1467
|
+
placeholder: rc.ui.emailPlaceholder,
|
|
1468
|
+
placeholderTextColor: colors.muted,
|
|
1469
|
+
keyboardType: "email-address",
|
|
1470
|
+
autoCapitalize: "none",
|
|
1471
|
+
autoComplete: "email",
|
|
1472
|
+
textContentType: "emailAddress",
|
|
1473
|
+
editable: emailState !== "sending",
|
|
1474
|
+
accessibilityLabel: rc.ui.emailOptIn
|
|
1475
|
+
}
|
|
1476
|
+
),
|
|
1477
|
+
/* @__PURE__ */ jsx2(
|
|
1478
|
+
TouchableOpacity2,
|
|
1479
|
+
{
|
|
1480
|
+
style: [s2.sendBtn, { backgroundColor: emailInput.trim() ? colors.accent : colors.disabled, borderRadius: radius }],
|
|
1481
|
+
onPress: () => void submitEmail(),
|
|
1482
|
+
disabled: !emailInput.trim() || emailState === "sending",
|
|
1483
|
+
accessibilityRole: "button",
|
|
1484
|
+
accessibilityState: { disabled: !emailInput.trim() || emailState === "sending", busy: emailState === "sending" },
|
|
1485
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: emailInput.trim() ? colors.accentFg : colors.disabledFg }, font], children: emailState === "sending" ? rc.ui.sending : rc.ui.emailSubmit })
|
|
1486
|
+
}
|
|
1487
|
+
)
|
|
1488
|
+
] }),
|
|
1489
|
+
emailState === "invalid" || emailState === "failed" ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: emailState === "invalid" ? rc.ui.emailInvalid : rc.ui.emailFailed }) : null
|
|
1490
|
+
] }) : null
|
|
1491
|
+
] }) : /* @__PURE__ */ jsxs2(
|
|
1186
1492
|
ScrollView,
|
|
1187
1493
|
{
|
|
1188
|
-
style:
|
|
1494
|
+
style: s2.body,
|
|
1189
1495
|
keyboardShouldPersistTaps: "handled",
|
|
1190
1496
|
contentContainerStyle: { paddingBottom: 24 },
|
|
1191
1497
|
children: [
|
|
1192
|
-
/* @__PURE__ */
|
|
1193
|
-
/* @__PURE__ */ jsx(View, { style: s.catRow, accessibilityRole: "radiogroup", children: CATEGORY_KEYS.map((key) => {
|
|
1194
|
-
const active = category === key;
|
|
1195
|
-
return /* @__PURE__ */ jsxs(
|
|
1196
|
-
TouchableOpacity,
|
|
1197
|
-
{
|
|
1198
|
-
onPress: () => setCategory(key),
|
|
1199
|
-
activeOpacity: 0.7,
|
|
1200
|
-
accessibilityRole: "radio",
|
|
1201
|
-
accessibilityState: { selected: active, checked: active },
|
|
1202
|
-
accessibilityLabel: t.step1.categories[key],
|
|
1203
|
-
style: [
|
|
1204
|
-
s.catBtn,
|
|
1205
|
-
{
|
|
1206
|
-
backgroundColor: active ? colors.accent : colors.surface,
|
|
1207
|
-
borderColor: active ? colors.accent : colors.border
|
|
1208
|
-
}
|
|
1209
|
-
],
|
|
1210
|
-
children: [
|
|
1211
|
-
/* @__PURE__ */ jsx(Text, { style: s.catEmoji, importantForAccessibility: "no", children: CATEGORY_EMOJI[key] }),
|
|
1212
|
-
/* @__PURE__ */ jsx(
|
|
1213
|
-
Text,
|
|
1214
|
-
{
|
|
1215
|
-
numberOfLines: 1,
|
|
1216
|
-
style: [
|
|
1217
|
-
s.catLabel,
|
|
1218
|
-
{ color: active ? colors.accentFg : colors.fg },
|
|
1219
|
-
font
|
|
1220
|
-
],
|
|
1221
|
-
children: t.step1.categories[key]
|
|
1222
|
-
}
|
|
1223
|
-
)
|
|
1224
|
-
]
|
|
1225
|
-
},
|
|
1226
|
-
key
|
|
1227
|
-
);
|
|
1228
|
-
}) }),
|
|
1229
|
-
/* @__PURE__ */ jsx(
|
|
1498
|
+
/* @__PURE__ */ jsx2(
|
|
1230
1499
|
TextInput,
|
|
1231
1500
|
{
|
|
1232
1501
|
style: [
|
|
1233
|
-
|
|
1502
|
+
s2.input,
|
|
1234
1503
|
{
|
|
1235
1504
|
backgroundColor: colors.surface,
|
|
1236
1505
|
color: colors.fg,
|
|
@@ -1254,22 +1523,59 @@ var MushiBottomSheet = ({
|
|
|
1254
1523
|
maxLength: 4e3
|
|
1255
1524
|
}
|
|
1256
1525
|
),
|
|
1257
|
-
submitError ? /* @__PURE__ */
|
|
1258
|
-
|
|
1259
|
-
|
|
1526
|
+
submitError ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: submitError }) : null,
|
|
1527
|
+
/* @__PURE__ */ jsx2(View2, { style: [s2.catRow, { marginTop: 12 }], accessibilityRole: "radiogroup", children: REPORTER_CATEGORIES.map((key) => {
|
|
1528
|
+
const active = category === key;
|
|
1529
|
+
const label = reporterCategoryLabel(key, locale);
|
|
1530
|
+
return /* @__PURE__ */ jsxs2(
|
|
1531
|
+
TouchableOpacity2,
|
|
1532
|
+
{
|
|
1533
|
+
onPress: () => setCategory(active ? null : key),
|
|
1534
|
+
activeOpacity: 0.7,
|
|
1535
|
+
accessibilityRole: "radio",
|
|
1536
|
+
accessibilityState: { selected: active, checked: active },
|
|
1537
|
+
accessibilityLabel: label,
|
|
1538
|
+
style: [
|
|
1539
|
+
s2.catBtn,
|
|
1540
|
+
{
|
|
1541
|
+
backgroundColor: active ? colors.accent : colors.surface,
|
|
1542
|
+
borderColor: active ? colors.accent : colors.border
|
|
1543
|
+
}
|
|
1544
|
+
],
|
|
1545
|
+
children: [
|
|
1546
|
+
/* @__PURE__ */ jsx2(Text2, { style: s2.catEmoji, importantForAccessibility: "no", children: CATEGORY_EMOJI[key] }),
|
|
1547
|
+
/* @__PURE__ */ jsx2(
|
|
1548
|
+
Text2,
|
|
1549
|
+
{
|
|
1550
|
+
numberOfLines: 1,
|
|
1551
|
+
style: [
|
|
1552
|
+
s2.catLabel,
|
|
1553
|
+
{ color: active ? colors.accentFg : colors.fg },
|
|
1554
|
+
font
|
|
1555
|
+
],
|
|
1556
|
+
children: label
|
|
1557
|
+
}
|
|
1558
|
+
)
|
|
1559
|
+
]
|
|
1560
|
+
},
|
|
1561
|
+
key
|
|
1562
|
+
);
|
|
1563
|
+
}) }),
|
|
1564
|
+
activeScreenshot ? /* @__PURE__ */ jsxs2(View2, { style: s2.screenshotRow, children: [
|
|
1565
|
+
/* @__PURE__ */ jsx2(
|
|
1260
1566
|
Image,
|
|
1261
1567
|
{
|
|
1262
1568
|
source: { uri: activeScreenshot },
|
|
1263
|
-
style: [
|
|
1569
|
+
style: [s2.screenshotThumb, { backgroundColor: colors.fg }],
|
|
1264
1570
|
accessibilityLabel: t.step3.screenshotPreviewAlt
|
|
1265
1571
|
}
|
|
1266
1572
|
),
|
|
1267
|
-
/* @__PURE__ */
|
|
1268
|
-
/* @__PURE__ */
|
|
1269
|
-
/* @__PURE__ */
|
|
1573
|
+
/* @__PURE__ */ jsxs2(View2, { style: s2.screenshotMeta, children: [
|
|
1574
|
+
/* @__PURE__ */ jsx2(Text2, { style: [s2.screenshotLabel, { color: colors.fg }, font], children: t.step3.screenshotAttached.replace(" \u2713", "") }),
|
|
1575
|
+
/* @__PURE__ */ jsx2(Text2, { style: [s2.screenshotSub, { color: colors.muted }, font], children: screenshotSensitiveHint && screenshotSensitiveHint.trim() ? `\u26A0 ${screenshotSensitiveHint}` : t.step3.screenshotSensitiveHint.split("\u2014")[0]?.trim() ?? t.step3.screenshotSensitiveHint })
|
|
1270
1576
|
] }),
|
|
1271
|
-
/* @__PURE__ */
|
|
1272
|
-
|
|
1577
|
+
/* @__PURE__ */ jsx2(
|
|
1578
|
+
TouchableOpacity2,
|
|
1273
1579
|
{
|
|
1274
1580
|
onPress: () => {
|
|
1275
1581
|
setScreenshotAttached(false);
|
|
@@ -1278,13 +1584,13 @@ var MushiBottomSheet = ({
|
|
|
1278
1584
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1279
1585
|
accessibilityRole: "button",
|
|
1280
1586
|
accessibilityLabel: t.widget.close,
|
|
1281
|
-
children: /* @__PURE__ */
|
|
1587
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.screenshotRemove, { color: colors.muted }], children: "\u2715" })
|
|
1282
1588
|
}
|
|
1283
1589
|
)
|
|
1284
1590
|
] }) : null,
|
|
1285
|
-
submitHint ? /* @__PURE__ */
|
|
1286
|
-
/* @__PURE__ */
|
|
1287
|
-
|
|
1591
|
+
submitHint ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, fontSize: 12, marginBottom: 6 }, font], children: submitHint }) : null,
|
|
1592
|
+
/* @__PURE__ */ jsx2(
|
|
1593
|
+
TouchableOpacity2,
|
|
1288
1594
|
{
|
|
1289
1595
|
onPress: handleSubmit,
|
|
1290
1596
|
disabled: !canSubmit,
|
|
@@ -1294,10 +1600,10 @@ var MushiBottomSheet = ({
|
|
|
1294
1600
|
accessibilityHint: submitHint,
|
|
1295
1601
|
accessibilityState: { disabled: !canSubmit, busy: phase === "sending" },
|
|
1296
1602
|
style: [
|
|
1297
|
-
|
|
1603
|
+
s2.submitBtn,
|
|
1298
1604
|
{ backgroundColor: canSubmit ? colors.accent : colors.disabled, borderRadius: radius }
|
|
1299
1605
|
],
|
|
1300
|
-
children: /* @__PURE__ */
|
|
1606
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: canSubmit ? colors.accentFg : colors.disabledFg }, font], children: phase === "sending" ? t.widget.submitting : t.widget.submit })
|
|
1301
1607
|
}
|
|
1302
1608
|
)
|
|
1303
1609
|
]
|
|
@@ -1310,7 +1616,7 @@ var MushiBottomSheet = ({
|
|
|
1310
1616
|
}
|
|
1311
1617
|
) });
|
|
1312
1618
|
};
|
|
1313
|
-
var
|
|
1619
|
+
var s2 = StyleSheet2.create({
|
|
1314
1620
|
flex: { flex: 1 },
|
|
1315
1621
|
backdrop: {
|
|
1316
1622
|
// Inlined StyleSheet.absoluteFillObject — RN 0.86 dropped it from the
|
|
@@ -1330,7 +1636,7 @@ var s = StyleSheet.create({
|
|
|
1330
1636
|
borderTopLeftRadius: MUSHI_RADIUS2.sheet,
|
|
1331
1637
|
borderTopRightRadius: MUSHI_RADIUS2.sheet,
|
|
1332
1638
|
paddingBottom: Platform2.OS === "ios" ? 34 : MUSHI_SPACING.roomy,
|
|
1333
|
-
shadowColor:
|
|
1639
|
+
shadowColor: MUSHI_SHADOW_INK2,
|
|
1334
1640
|
shadowOffset: { width: 0, height: -3 },
|
|
1335
1641
|
shadowOpacity: 0.12,
|
|
1336
1642
|
shadowRadius: 8,
|
|
@@ -1454,7 +1760,7 @@ var s = StyleSheet.create({
|
|
|
1454
1760
|
},
|
|
1455
1761
|
tabRow: {
|
|
1456
1762
|
flexDirection: "row",
|
|
1457
|
-
borderBottomWidth:
|
|
1763
|
+
borderBottomWidth: StyleSheet2.hairlineWidth,
|
|
1458
1764
|
marginBottom: 8
|
|
1459
1765
|
},
|
|
1460
1766
|
tabBtn: {
|
|
@@ -1472,10 +1778,10 @@ var s = StyleSheet.create({
|
|
|
1472
1778
|
inboxRow: {
|
|
1473
1779
|
paddingVertical: 12,
|
|
1474
1780
|
minHeight: 56,
|
|
1475
|
-
borderBottomWidth:
|
|
1781
|
+
borderBottomWidth: StyleSheet2.hairlineWidth
|
|
1476
1782
|
},
|
|
1477
1783
|
headerCard: {
|
|
1478
|
-
borderWidth:
|
|
1784
|
+
borderWidth: StyleSheet2.hairlineWidth,
|
|
1479
1785
|
padding: 12,
|
|
1480
1786
|
marginBottom: 12
|
|
1481
1787
|
},
|
|
@@ -1565,17 +1871,17 @@ var s = StyleSheet.create({
|
|
|
1565
1871
|
});
|
|
1566
1872
|
|
|
1567
1873
|
// src/components/MushiFloatingButton.tsx
|
|
1568
|
-
import { useRef as useRef2, useCallback as useCallback2, useEffect as
|
|
1874
|
+
import { useRef as useRef2, useCallback as useCallback2, useEffect as useEffect3 } from "react";
|
|
1569
1875
|
import {
|
|
1570
1876
|
Animated as Animated2,
|
|
1571
1877
|
PanResponder as PanResponder2,
|
|
1572
|
-
StyleSheet as
|
|
1878
|
+
StyleSheet as StyleSheet3,
|
|
1573
1879
|
Platform as Platform3,
|
|
1574
1880
|
Dimensions as Dimensions3,
|
|
1575
|
-
useColorScheme as
|
|
1881
|
+
useColorScheme as useColorScheme3
|
|
1576
1882
|
} from "react-native";
|
|
1577
1883
|
import { mushiPalette as mushiPalette2, MUSHI_COPY as MUSHI_COPY2, MUSHI_GEOMETRY } from "@mushi-mushi/core";
|
|
1578
|
-
import { jsx as
|
|
1884
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1579
1885
|
var FAB_SIZE = MUSHI_GEOMETRY.fabSize;
|
|
1580
1886
|
var EDGE_PADDING = 12;
|
|
1581
1887
|
function getScreenBounds() {
|
|
@@ -1610,7 +1916,7 @@ var MushiFloatingButton = ({
|
|
|
1610
1916
|
config,
|
|
1611
1917
|
accent
|
|
1612
1918
|
}) => {
|
|
1613
|
-
const scheme =
|
|
1919
|
+
const scheme = useColorScheme3();
|
|
1614
1920
|
const dark = scheme === "dark";
|
|
1615
1921
|
const draggable = config?.draggable ?? false;
|
|
1616
1922
|
const snapToEdge = config?.snapToEdge ?? true;
|
|
@@ -1628,7 +1934,7 @@ var MushiFloatingButton = ({
|
|
|
1628
1934
|
const isDragging = useRef2(false);
|
|
1629
1935
|
const pal = mushiPalette2(dark ? "dark" : "light");
|
|
1630
1936
|
const accentColor = accent ?? pal.accent;
|
|
1631
|
-
|
|
1937
|
+
useEffect3(() => {
|
|
1632
1938
|
if (!persist) return;
|
|
1633
1939
|
void loadStoredPos().then((pos) => {
|
|
1634
1940
|
if (!pos) return;
|
|
@@ -1720,12 +2026,12 @@ var MushiFloatingButton = ({
|
|
|
1720
2026
|
}).start();
|
|
1721
2027
|
if (!isDragging.current) onPress();
|
|
1722
2028
|
}, [scale, onPress]);
|
|
1723
|
-
return /* @__PURE__ */
|
|
2029
|
+
return /* @__PURE__ */ jsx3(
|
|
1724
2030
|
Animated2.View,
|
|
1725
2031
|
{
|
|
1726
2032
|
...draggable ? panResponder.panHandlers : {},
|
|
1727
2033
|
style: [
|
|
1728
|
-
|
|
2034
|
+
s3.fab,
|
|
1729
2035
|
{
|
|
1730
2036
|
left: posX,
|
|
1731
2037
|
bottom: Animated2.add(new Animated2.Value(baseBottom), Animated2.multiply(posY, -1)),
|
|
@@ -1737,11 +2043,11 @@ var MushiFloatingButton = ({
|
|
|
1737
2043
|
onStartShouldSetResponder: () => !draggable,
|
|
1738
2044
|
onResponderGrant: handlePressIn,
|
|
1739
2045
|
onResponderRelease: handlePressOut,
|
|
1740
|
-
children: /* @__PURE__ */
|
|
2046
|
+
children: /* @__PURE__ */ jsx3(Animated2.Text, { style: s3.emoji, children: MUSHI_COPY2.triggerText })
|
|
1741
2047
|
}
|
|
1742
2048
|
);
|
|
1743
2049
|
};
|
|
1744
|
-
var
|
|
2050
|
+
var s3 = StyleSheet3.create({
|
|
1745
2051
|
fab: {
|
|
1746
2052
|
position: "absolute",
|
|
1747
2053
|
width: FAB_SIZE,
|
|
@@ -1763,14 +2069,14 @@ var s2 = StyleSheet2.create({
|
|
|
1763
2069
|
// src/components/MushiBanner.tsx
|
|
1764
2070
|
import { useCallback as useCallback3 } from "react";
|
|
1765
2071
|
import {
|
|
1766
|
-
View as
|
|
1767
|
-
Text as
|
|
1768
|
-
TouchableOpacity as
|
|
1769
|
-
StyleSheet as
|
|
2072
|
+
View as View3,
|
|
2073
|
+
Text as Text3,
|
|
2074
|
+
TouchableOpacity as TouchableOpacity3,
|
|
2075
|
+
StyleSheet as StyleSheet4,
|
|
1770
2076
|
Platform as Platform4
|
|
1771
2077
|
} from "react-native";
|
|
1772
2078
|
import { MUSHI_BANNER_NEON, MUSHI_COPY as MUSHI_COPY3, MUSHI_GEOMETRY as MUSHI_GEOMETRY2, MUSHI_SPACING as MUSHI_SPACING2, MUSHI_TYPE as MUSHI_TYPE2, MUSHI_Z } from "@mushi-mushi/core";
|
|
1773
|
-
import { jsx as
|
|
2079
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1774
2080
|
var MUSHI_BANNER_DEFAULT_HEIGHT = MUSHI_GEOMETRY2.bannerHeight;
|
|
1775
2081
|
var MushiBanner = ({
|
|
1776
2082
|
onPress,
|
|
@@ -1785,35 +2091,35 @@ var MushiBanner = ({
|
|
|
1785
2091
|
},
|
|
1786
2092
|
[onLayoutHeight]
|
|
1787
2093
|
);
|
|
1788
|
-
return /* @__PURE__ */
|
|
1789
|
-
|
|
2094
|
+
return /* @__PURE__ */ jsxs3(
|
|
2095
|
+
View3,
|
|
1790
2096
|
{
|
|
1791
|
-
style:
|
|
2097
|
+
style: s4.wrap,
|
|
1792
2098
|
onLayout: handleLayout,
|
|
1793
2099
|
accessibilityRole: "header",
|
|
1794
2100
|
accessibilityLabel: "Mushi feedback banner",
|
|
1795
2101
|
children: [
|
|
1796
|
-
/* @__PURE__ */
|
|
1797
|
-
/* @__PURE__ */
|
|
1798
|
-
/* @__PURE__ */
|
|
1799
|
-
/* @__PURE__ */
|
|
2102
|
+
/* @__PURE__ */ jsxs3(TouchableOpacity3, { style: s4.main, onPress, activeOpacity: 0.85, children: [
|
|
2103
|
+
/* @__PURE__ */ jsx4(Text3, { style: s4.eyebrow, children: label.toUpperCase() }),
|
|
2104
|
+
/* @__PURE__ */ jsx4(Text3, { style: s4.message, numberOfLines: 2, children: message }),
|
|
2105
|
+
/* @__PURE__ */ jsx4(Text3, { style: s4.cta, children: MUSHI_COPY3.bugCta })
|
|
1800
2106
|
] }),
|
|
1801
|
-
onDismiss ? /* @__PURE__ */
|
|
1802
|
-
|
|
2107
|
+
onDismiss ? /* @__PURE__ */ jsx4(
|
|
2108
|
+
TouchableOpacity3,
|
|
1803
2109
|
{
|
|
1804
|
-
style:
|
|
2110
|
+
style: s4.dismiss,
|
|
1805
2111
|
onPress: onDismiss,
|
|
1806
2112
|
accessibilityRole: "button",
|
|
1807
2113
|
accessibilityLabel: "Dismiss banner",
|
|
1808
2114
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1809
|
-
children: /* @__PURE__ */
|
|
2115
|
+
children: /* @__PURE__ */ jsx4(Text3, { style: s4.dismissText, children: "\xD7" })
|
|
1810
2116
|
}
|
|
1811
2117
|
) : null
|
|
1812
2118
|
]
|
|
1813
2119
|
}
|
|
1814
2120
|
);
|
|
1815
2121
|
};
|
|
1816
|
-
var
|
|
2122
|
+
var s4 = StyleSheet4.create({
|
|
1817
2123
|
wrap: {
|
|
1818
2124
|
position: "absolute",
|
|
1819
2125
|
left: 0,
|
|
@@ -2193,10 +2499,10 @@ function createRNSessionTracker(opts) {
|
|
|
2193
2499
|
|
|
2194
2500
|
// src/version.ts
|
|
2195
2501
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/react-native";
|
|
2196
|
-
var MUSHI_SDK_VERSION = "0.
|
|
2502
|
+
var MUSHI_SDK_VERSION = "0.24.1" ? "0.24.1" : "0.17.0";
|
|
2197
2503
|
|
|
2198
2504
|
// src/provider.tsx
|
|
2199
|
-
import { jsx as
|
|
2505
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2200
2506
|
var MushiContext = createContext(null);
|
|
2201
2507
|
function nativeUserAgent() {
|
|
2202
2508
|
const os = Platform5?.OS ?? "native";
|
|
@@ -2273,7 +2579,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2273
2579
|
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
2274
2580
|
}
|
|
2275
2581
|
const apiEndpoint = rawEndpoint ?? DEFAULT_API_ENDPOINT;
|
|
2276
|
-
|
|
2582
|
+
useEffect4(() => {
|
|
2277
2583
|
if (config.capture?.console !== false) {
|
|
2278
2584
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
2279
2585
|
}
|
|
@@ -2335,11 +2641,10 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2335
2641
|
networkRef.current?.restore();
|
|
2336
2642
|
};
|
|
2337
2643
|
}, []);
|
|
2338
|
-
|
|
2644
|
+
useEffect4(() => {
|
|
2339
2645
|
let unsubscribe;
|
|
2340
2646
|
try {
|
|
2341
|
-
|
|
2342
|
-
unsubscribe = NetInfo.addEventListener((state) => {
|
|
2647
|
+
unsubscribe = resolveNetInfo(config.netInfo)?.addEventListener((state) => {
|
|
2343
2648
|
if (state.isConnected && state.isInternetReachable) {
|
|
2344
2649
|
queueRef.current?.flush().catch(() => {
|
|
2345
2650
|
});
|
|
@@ -2348,7 +2653,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2348
2653
|
} catch {
|
|
2349
2654
|
}
|
|
2350
2655
|
return () => unsubscribe?.();
|
|
2351
|
-
}, []);
|
|
2656
|
+
}, [config.netInfo]);
|
|
2352
2657
|
const open = useCallback4(() => {
|
|
2353
2658
|
setSheetPreferredTab("report");
|
|
2354
2659
|
breadcrumbsRef.current.add({
|
|
@@ -2362,11 +2667,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2362
2667
|
setSheetVisible(true);
|
|
2363
2668
|
return;
|
|
2364
2669
|
}
|
|
2365
|
-
|
|
2366
|
-
try {
|
|
2367
|
-
vshot = __require("react-native-view-shot");
|
|
2368
|
-
} catch {
|
|
2369
|
-
}
|
|
2670
|
+
const vshot = resolveViewShot(config.viewShot);
|
|
2370
2671
|
if (!vshot) {
|
|
2371
2672
|
setSheetScreenshot(null);
|
|
2372
2673
|
setSheetVisible(true);
|
|
@@ -2379,7 +2680,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2379
2680
|
}).finally(() => {
|
|
2380
2681
|
setSheetVisible(true);
|
|
2381
2682
|
});
|
|
2382
|
-
}, [config.capture?.screenshot]);
|
|
2683
|
+
}, [config.capture?.screenshot, config.viewShot]);
|
|
2383
2684
|
const openAssistant = useCallback4(() => {
|
|
2384
2685
|
if (!config.assistant?.enabled) return;
|
|
2385
2686
|
setSheetPreferredTab("assistant");
|
|
@@ -2388,7 +2689,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2388
2689
|
}, [config.assistant?.enabled]);
|
|
2389
2690
|
const close = useCallback4(() => setSheetVisible(false), []);
|
|
2390
2691
|
const attachTo = useCallback4(() => ({ onPress: open }), [open]);
|
|
2391
|
-
|
|
2692
|
+
useEffect4(() => {
|
|
2392
2693
|
const trigger2 = config.widget?.trigger ?? "button";
|
|
2393
2694
|
if (trigger2 !== "shake" && trigger2 !== "both") return;
|
|
2394
2695
|
let disposed = false;
|
|
@@ -2396,8 +2697,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2396
2697
|
let lastShake = 0;
|
|
2397
2698
|
const threshold = config.widget?.shakeThreshold ?? 2.7;
|
|
2398
2699
|
try {
|
|
2399
|
-
const mod =
|
|
2400
|
-
if (!disposed) {
|
|
2700
|
+
const mod = resolveExpoSensors(config.expoSensors);
|
|
2701
|
+
if (mod && !disposed) {
|
|
2401
2702
|
mod.Accelerometer.setUpdateInterval(120);
|
|
2402
2703
|
const sub = mod.Accelerometer.addListener((evt) => {
|
|
2403
2704
|
const g = Math.sqrt(evt.x * evt.x + evt.y * evt.y + evt.z * evt.z);
|
|
@@ -2415,7 +2716,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2415
2716
|
disposed = true;
|
|
2416
2717
|
cleanup?.();
|
|
2417
2718
|
};
|
|
2418
|
-
}, [config.widget?.trigger, config.widget?.shakeThreshold, open]);
|
|
2719
|
+
}, [config.widget?.trigger, config.widget?.shakeThreshold, config.expoSensors, open]);
|
|
2419
2720
|
const submitReport = useCallback4(
|
|
2420
2721
|
async (data) => {
|
|
2421
2722
|
await reporterTokenReadyRef.current;
|
|
@@ -2456,6 +2757,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2456
2757
|
id: newUuid2(),
|
|
2457
2758
|
projectId: config.projectId,
|
|
2458
2759
|
category: data.category,
|
|
2760
|
+
...data.userCategory ? { userCategory: data.userCategory } : {},
|
|
2459
2761
|
description: scrubPii3(data.description),
|
|
2460
2762
|
environment: {
|
|
2461
2763
|
userAgent: deviceInfo.systemName ?? "ReactNative",
|
|
@@ -2515,6 +2817,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2515
2817
|
};
|
|
2516
2818
|
} else {
|
|
2517
2819
|
config.callbacks?.onReportSubmitted?.(report.id);
|
|
2820
|
+
void writeReporterFlag(config.projectId, "has_reports", "1");
|
|
2518
2821
|
return { ok: true };
|
|
2519
2822
|
}
|
|
2520
2823
|
},
|
|
@@ -2525,7 +2828,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2525
2828
|
const screenRef = useRef3(null);
|
|
2526
2829
|
const activityQueueRef = useRef3([]);
|
|
2527
2830
|
const rewardsFlushRef = useRef3(null);
|
|
2528
|
-
|
|
2831
|
+
useEffect4(() => {
|
|
2529
2832
|
const rewards = config.rewards;
|
|
2530
2833
|
if (!rewards?.enabled || !rewards.trackActivity) return;
|
|
2531
2834
|
const flushMs = Math.max(3e4, rewards.flushIntervalMs ?? 3e5);
|
|
@@ -2547,7 +2850,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2547
2850
|
}, [config.rewards?.enabled, config.rewards?.trackActivity, config.rewards?.flushIntervalMs]);
|
|
2548
2851
|
const eventTrackerRef = useRef3(null);
|
|
2549
2852
|
const sessionTrackerRef = useRef3(null);
|
|
2550
|
-
|
|
2853
|
+
useEffect4(() => {
|
|
2551
2854
|
const getRoute = () => screenRef.current?.route ?? screenRef.current?.name ?? null;
|
|
2552
2855
|
const tracker = createRNEventTracker({
|
|
2553
2856
|
projectId: config.projectId,
|
|
@@ -2602,6 +2905,70 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2602
2905
|
config.analytics?.flushIntervalMs,
|
|
2603
2906
|
config.trackSessions
|
|
2604
2907
|
]);
|
|
2908
|
+
const reporterUpdatesRef = useRef3(
|
|
2909
|
+
createReporterUpdateHub(async () => {
|
|
2910
|
+
const client = apiClientRef.current;
|
|
2911
|
+
if (!client) return null;
|
|
2912
|
+
await reporterTokenReadyRef.current;
|
|
2913
|
+
const res = await reporterChannels2(client).getUpdates(reporterTokenRef.current);
|
|
2914
|
+
return res.ok ? res.data ?? null : null;
|
|
2915
|
+
})
|
|
2916
|
+
);
|
|
2917
|
+
useEffect4(() => {
|
|
2918
|
+
let sub;
|
|
2919
|
+
try {
|
|
2920
|
+
if (typeof AppState?.addEventListener === "function") {
|
|
2921
|
+
sub = AppState.addEventListener("change", (state) => {
|
|
2922
|
+
if (state === "active" && reporterUpdatesRef.current.listenerCount() > 0) void reporterUpdatesRef.current.emit();
|
|
2923
|
+
});
|
|
2924
|
+
}
|
|
2925
|
+
} catch {
|
|
2926
|
+
}
|
|
2927
|
+
return () => sub?.remove();
|
|
2928
|
+
}, []);
|
|
2929
|
+
const [toast, setToast] = useState2(null);
|
|
2930
|
+
const toastShownRef = useRef3(false);
|
|
2931
|
+
const toastEnabled = config.notifications?.toast !== false;
|
|
2932
|
+
const maybeShowToast = useCallback4(async () => {
|
|
2933
|
+
if (!toastEnabled || toastShownRef.current) return;
|
|
2934
|
+
if (await readReporterFlag(config.projectId, "has_reports") !== "1") return;
|
|
2935
|
+
const updates = await reporterUpdatesRef.current.emit();
|
|
2936
|
+
if (!updates) return;
|
|
2937
|
+
const now = Date.now();
|
|
2938
|
+
const show = reporterShouldShowToast({
|
|
2939
|
+
enabled: toastEnabled,
|
|
2940
|
+
unreadTotal: updates.unread_total,
|
|
2941
|
+
shownThisSession: toastShownRef.current,
|
|
2942
|
+
lastShownAt: Number(await readReporterFlag(config.projectId, "toast_shown_at")) || null,
|
|
2943
|
+
now
|
|
2944
|
+
});
|
|
2945
|
+
if (!show) return;
|
|
2946
|
+
toastShownRef.current = true;
|
|
2947
|
+
void writeReporterFlag(config.projectId, "toast_shown_at", String(now));
|
|
2948
|
+
const locale = resolveReporterLocale3(
|
|
2949
|
+
typeof navigator !== "undefined" ? navigator.language : void 0
|
|
2950
|
+
);
|
|
2951
|
+
setToast({ message: reporterToastMessage(updates, locale), reportId: updates.latest[0]?.report_id ?? null });
|
|
2952
|
+
}, [toastEnabled, config.projectId]);
|
|
2953
|
+
useEffect4(() => {
|
|
2954
|
+
void reporterTokenReadyRef.current.then(() => maybeShowToast());
|
|
2955
|
+
let sub;
|
|
2956
|
+
try {
|
|
2957
|
+
if (typeof AppState?.addEventListener === "function") {
|
|
2958
|
+
sub = AppState.addEventListener("change", (state) => {
|
|
2959
|
+
if (state === "active") void maybeShowToast();
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2962
|
+
} catch {
|
|
2963
|
+
}
|
|
2964
|
+
return () => sub?.remove();
|
|
2965
|
+
}, [maybeShowToast]);
|
|
2966
|
+
const openMyReports = useCallback4(() => {
|
|
2967
|
+
setToast(null);
|
|
2968
|
+
setSheetScreenshot(null);
|
|
2969
|
+
setSheetPreferredTab("inbox");
|
|
2970
|
+
setSheetVisible(true);
|
|
2971
|
+
}, []);
|
|
2605
2972
|
const instance = useMemo(
|
|
2606
2973
|
() => ({
|
|
2607
2974
|
open,
|
|
@@ -2705,6 +3072,37 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2705
3072
|
await reporterTokenReadyRef.current;
|
|
2706
3073
|
return markReporterReportRead(client, reporterTokenRef.current, reportId);
|
|
2707
3074
|
},
|
|
3075
|
+
getReporterUpdates: () => reporterUpdatesRef.current.emit(),
|
|
3076
|
+
async loadMyReportDetail(reportId) {
|
|
3077
|
+
const client = apiClientRef.current;
|
|
3078
|
+
if (!client) return null;
|
|
3079
|
+
try {
|
|
3080
|
+
await reporterTokenReadyRef.current;
|
|
3081
|
+
const res = await reporterChannels2(client).getReport(reportId, reporterTokenRef.current);
|
|
3082
|
+
if (res.ok) return res.data ?? null;
|
|
3083
|
+
return res.error?.status === 404 && res.error.code !== "NOT_FOUND" ? "unsupported" : null;
|
|
3084
|
+
} catch {
|
|
3085
|
+
return null;
|
|
3086
|
+
}
|
|
3087
|
+
},
|
|
3088
|
+
emailPrefill() {
|
|
3089
|
+
return config.notifications?.emailFromIdentity ? userRef.current?.email ?? null : null;
|
|
3090
|
+
},
|
|
3091
|
+
openMyReports,
|
|
3092
|
+
onReporterUpdate: (cb) => reporterUpdatesRef.current.subscribe(cb),
|
|
3093
|
+
async getNotificationPrefs() {
|
|
3094
|
+
const client = apiClientRef.current;
|
|
3095
|
+
if (!client) return null;
|
|
3096
|
+
await reporterTokenReadyRef.current;
|
|
3097
|
+
const res = await reporterChannels2(client).getPrefs(reporterTokenRef.current);
|
|
3098
|
+
return res.ok ? res.data ?? null : null;
|
|
3099
|
+
},
|
|
3100
|
+
async setNotificationPrefs(update) {
|
|
3101
|
+
const client = apiClientRef.current;
|
|
3102
|
+
if (!client) return { ok: false, error: { code: "NOT_INITIALIZED", message: "Mushi is not ready yet" } };
|
|
3103
|
+
await reporterTokenReadyRef.current;
|
|
3104
|
+
return reporterChannels2(client).setPrefs(reporterTokenRef.current, update);
|
|
3105
|
+
},
|
|
2708
3106
|
async replyToReport(reportId, body) {
|
|
2709
3107
|
const client = apiClientRef.current;
|
|
2710
3108
|
if (!client) return null;
|
|
@@ -2775,14 +3173,14 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2775
3173
|
return res.ok ? res.data : null;
|
|
2776
3174
|
}
|
|
2777
3175
|
}),
|
|
2778
|
-
[open, close, attachTo, submitReport, openAssistant, config.rewards?.enabled, config.assistant?.enabled]
|
|
3176
|
+
[open, close, attachTo, submitReport, openAssistant, openMyReports, config.rewards?.enabled, config.assistant?.enabled, config.notifications?.emailFromIdentity]
|
|
2779
3177
|
);
|
|
2780
3178
|
const trigger = config.widget?.trigger ?? "button";
|
|
2781
3179
|
const showBanner = trigger === "banner" && !bannerDismissed;
|
|
2782
3180
|
const showFab = !showBanner && (trigger === "button" || trigger === "both" || trigger === "auto" || trigger === "edge-tab");
|
|
2783
|
-
return /* @__PURE__ */
|
|
3181
|
+
return /* @__PURE__ */ jsxs4(MushiContext.Provider, { value: instance, children: [
|
|
2784
3182
|
children,
|
|
2785
|
-
showBanner ? /* @__PURE__ */
|
|
3183
|
+
showBanner ? /* @__PURE__ */ jsx5(
|
|
2786
3184
|
MushiBanner,
|
|
2787
3185
|
{
|
|
2788
3186
|
onPress: open,
|
|
@@ -2791,7 +3189,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2791
3189
|
label: config.widget?.banner?.label
|
|
2792
3190
|
}
|
|
2793
3191
|
) : null,
|
|
2794
|
-
showFab && /* @__PURE__ */
|
|
3192
|
+
showFab && /* @__PURE__ */ jsx5(
|
|
2795
3193
|
MushiFloatingButton,
|
|
2796
3194
|
{
|
|
2797
3195
|
onPress: open,
|
|
@@ -2799,7 +3197,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2799
3197
|
inset: config.widget?.inset
|
|
2800
3198
|
}
|
|
2801
3199
|
),
|
|
2802
|
-
/* @__PURE__ */
|
|
3200
|
+
/* @__PURE__ */ jsx5(
|
|
2803
3201
|
MushiBottomSheet,
|
|
2804
3202
|
{
|
|
2805
3203
|
visible: sheetVisible,
|
|
@@ -2813,9 +3211,20 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2813
3211
|
assistantGreeting: config.assistant?.greeting,
|
|
2814
3212
|
assistantSuggestions: config.assistant?.suggestions,
|
|
2815
3213
|
inboxPollIntervalMs: config.widget?.inboxPollIntervalMs ?? 0,
|
|
3214
|
+
theme: config.widget?.theme,
|
|
3215
|
+
minDescriptionLength: config.widget?.minDescriptionLength,
|
|
3216
|
+
emailOptIn: config.notifications?.email !== false
|
|
3217
|
+
}
|
|
3218
|
+
),
|
|
3219
|
+
toast ? /* @__PURE__ */ jsx5(
|
|
3220
|
+
MushiUpdateToast,
|
|
3221
|
+
{
|
|
3222
|
+
message: toast.message,
|
|
3223
|
+
onView: openMyReports,
|
|
3224
|
+
onDismiss: () => setToast(null),
|
|
2816
3225
|
theme: config.widget?.theme
|
|
2817
3226
|
}
|
|
2818
|
-
)
|
|
3227
|
+
) : null
|
|
2819
3228
|
] });
|
|
2820
3229
|
}
|
|
2821
3230
|
function useMushiContext() {
|
|
@@ -2866,10 +3275,10 @@ function MushiTrigger({ children }) {
|
|
|
2866
3275
|
}
|
|
2867
3276
|
|
|
2868
3277
|
// src/capture/navigation-capture.ts
|
|
2869
|
-
import { useEffect as
|
|
3278
|
+
import { useEffect as useEffect5, useRef as useRef4 } from "react";
|
|
2870
3279
|
function useNavigationCapture(navigationRef) {
|
|
2871
3280
|
const historyRef = useRef4([]);
|
|
2872
|
-
|
|
3281
|
+
useEffect5(() => {
|
|
2873
3282
|
if (!navigationRef?.addListener || !navigationRef?.getCurrentRoute) return;
|
|
2874
3283
|
const unsubscribe = navigationRef.addListener("state", () => {
|
|
2875
3284
|
const route = navigationRef.getCurrentRoute?.();
|