@mushi-mushi/react-native 0.22.0 → 0.24.0
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 +19 -2
- package/dist/index.cjs +1269 -479
- package/dist/index.d.cts +170 -7
- package/dist/index.d.ts +170 -7
- package/dist/index.js +1118 -323
- package/package.json +3 -9
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,78 +624,147 @@ 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
|
-
mushiPalette,
|
|
480
|
-
MUSHI_BANNER_NEON,
|
|
481
648
|
MUSHI_COPY,
|
|
482
|
-
MUSHI_CONTROL_DISABLED,
|
|
483
649
|
MUSHI_INVERSE,
|
|
484
|
-
MUSHI_RADIUS,
|
|
485
|
-
MUSHI_SHADOW_INK,
|
|
650
|
+
MUSHI_RADIUS as MUSHI_RADIUS2,
|
|
651
|
+
MUSHI_SHADOW_INK as MUSHI_SHADOW_INK2,
|
|
486
652
|
MUSHI_SPACING,
|
|
487
653
|
MUSHI_TYPE
|
|
488
654
|
} from "@mushi-mushi/core";
|
|
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";
|
|
489
667
|
import { getLocale } from "@mushi-mushi/web/i18n";
|
|
490
668
|
|
|
491
|
-
// src/reporter-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
669
|
+
// src/reporter-thread.ts
|
|
670
|
+
import { reporterChannels } from "@mushi-mushi/core/reporter-channels";
|
|
671
|
+
var THREAD_LOAD_TIMEOUT_MS = 12e3;
|
|
672
|
+
function settleWithin(p, ms) {
|
|
673
|
+
return new Promise((resolve) => {
|
|
674
|
+
const timer = setTimeout(() => resolve(null), ms);
|
|
675
|
+
p.then(
|
|
676
|
+
(value) => {
|
|
677
|
+
clearTimeout(timer);
|
|
678
|
+
resolve(value);
|
|
679
|
+
},
|
|
680
|
+
() => {
|
|
681
|
+
clearTimeout(timer);
|
|
682
|
+
resolve(null);
|
|
683
|
+
}
|
|
684
|
+
);
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function loadReporterThread(load, reportId, timeoutMs = THREAD_LOAD_TIMEOUT_MS) {
|
|
688
|
+
let started;
|
|
689
|
+
try {
|
|
690
|
+
started = load(reportId);
|
|
691
|
+
} catch {
|
|
692
|
+
return Promise.resolve(null);
|
|
693
|
+
}
|
|
694
|
+
return settleWithin(started, timeoutMs);
|
|
695
|
+
}
|
|
696
|
+
async function markReporterReportRead(client, reporterToken, reportId) {
|
|
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;
|
|
701
|
+
const res = await client.listNotifications(reporterToken, { limit: 100 });
|
|
702
|
+
if (!res.ok) return 0;
|
|
703
|
+
const rows = res.data?.notifications ?? [];
|
|
704
|
+
const ids = rows.filter((n) => !n.read_at && n.payload?.reportId === reportId).map((n) => String(n.id));
|
|
705
|
+
let marked = 0;
|
|
706
|
+
for (const id of ids) {
|
|
707
|
+
const r = await client.markNotificationRead(id, reporterToken);
|
|
708
|
+
if (r.ok) marked++;
|
|
709
|
+
}
|
|
710
|
+
return marked;
|
|
711
|
+
} catch {
|
|
712
|
+
return 0;
|
|
514
713
|
}
|
|
515
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
|
+
}
|
|
516
746
|
|
|
517
747
|
// src/components/MushiBottomSheet.tsx
|
|
518
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
748
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
519
749
|
var { height: SCREEN_HEIGHT } = Dimensions2.get("window");
|
|
520
750
|
var SHEET_HEIGHT = SCREEN_HEIGHT * 0.55;
|
|
521
751
|
var DISMISS_THRESHOLD = 80;
|
|
522
|
-
var CATEGORY_KEYS = ["bug", "slow", "visual", "confusing", "other"];
|
|
523
752
|
var CATEGORY_EMOJI = {
|
|
524
753
|
bug: "\u{1F41B}",
|
|
525
754
|
slow: "\u{1F422}",
|
|
526
755
|
visual: "\u{1F3A8}",
|
|
527
756
|
confusing: "\u{1F615}",
|
|
528
|
-
|
|
757
|
+
idea: "\u{1F4A1}"
|
|
529
758
|
};
|
|
530
|
-
|
|
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
|
+
}
|
|
531
768
|
var MushiBottomSheet = ({
|
|
532
769
|
visible,
|
|
533
770
|
onClose,
|
|
@@ -539,12 +776,19 @@ var MushiBottomSheet = ({
|
|
|
539
776
|
assistantLabel = MUSHI_COPY.assistantTab,
|
|
540
777
|
assistantGreeting,
|
|
541
778
|
assistantSuggestions = [],
|
|
542
|
-
inboxPollIntervalMs = 0
|
|
779
|
+
inboxPollIntervalMs = 0,
|
|
780
|
+
theme,
|
|
781
|
+
minDescriptionLength,
|
|
782
|
+
emailOptIn = true
|
|
543
783
|
}) => {
|
|
544
784
|
const mushi = useMushiContext();
|
|
545
785
|
const t = getLocale();
|
|
786
|
+
const locale = resolveReporterLocale2(
|
|
787
|
+
typeof navigator !== "undefined" ? navigator.language : void 0
|
|
788
|
+
);
|
|
789
|
+
const rc = reporterCopy2(locale);
|
|
546
790
|
const greeting = assistantGreeting ?? t.assistant.defaultGreeting;
|
|
547
|
-
const scheme =
|
|
791
|
+
const scheme = useColorScheme2();
|
|
548
792
|
const dark = scheme === "dark";
|
|
549
793
|
const translateY = useRef(new Animated.Value(SHEET_HEIGHT)).current;
|
|
550
794
|
const backdropOpacity = useRef(new Animated.Value(0)).current;
|
|
@@ -554,58 +798,150 @@ var MushiBottomSheet = ({
|
|
|
554
798
|
const [submitError, setSubmitError] = useState(null);
|
|
555
799
|
const [sheetTab, setSheetTab] = useState("report");
|
|
556
800
|
const [inboxReports, setInboxReports] = useState([]);
|
|
801
|
+
const [inboxLoaded, setInboxLoaded] = useState(false);
|
|
557
802
|
const [inboxLoading, setInboxLoading] = useState(false);
|
|
558
803
|
const [selectedReportId, setSelectedReportId] = useState(null);
|
|
559
|
-
const
|
|
804
|
+
const selectedRef = useRef(null);
|
|
805
|
+
const [threadItems, setThreadItems] = useState([]);
|
|
806
|
+
const [threadStatus, setThreadStatus] = useState("idle");
|
|
560
807
|
const [replyText, setReplyText] = useState("");
|
|
808
|
+
const [replyState, setReplyState] = useState("idle");
|
|
809
|
+
const [feedbackSending, setFeedbackSending] = useState(false);
|
|
810
|
+
const [feedbackError, setFeedbackError] = useState(false);
|
|
561
811
|
const [assistantInput, setAssistantInput] = useState("");
|
|
562
812
|
const [assistantThreadId, setAssistantThreadId] = useState(null);
|
|
563
813
|
const [assistantSending, setAssistantSending] = useState(false);
|
|
564
814
|
const [assistantError, setAssistantError] = useState(null);
|
|
565
815
|
const [assistantTurns, setAssistantTurns] = useState([]);
|
|
566
816
|
const [screenshotAttached, setScreenshotAttached] = useState(true);
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
+
}, []);
|
|
829
|
+
const loadInbox = useCallback(
|
|
830
|
+
async (opts = {}) => {
|
|
831
|
+
if (!mushi?.listMyReports) return;
|
|
832
|
+
if (!opts.silent) setInboxLoading(true);
|
|
833
|
+
try {
|
|
834
|
+
const rows = await mushi.listMyReports();
|
|
835
|
+
setInboxReports(rows.filter((r) => !reporterStatus(r, locale).hidden));
|
|
836
|
+
setInboxLoaded(true);
|
|
837
|
+
} catch {
|
|
838
|
+
} finally {
|
|
839
|
+
if (!opts.silent) setInboxLoading(false);
|
|
840
|
+
}
|
|
841
|
+
},
|
|
842
|
+
[mushi, locale]
|
|
843
|
+
);
|
|
844
|
+
useEffect2(() => {
|
|
578
845
|
if (visible) {
|
|
579
846
|
setScreenshotAttached(true);
|
|
580
847
|
setSheetTab(preferredTab);
|
|
581
848
|
if (preferredTab === "inbox") void loadInbox();
|
|
582
849
|
}
|
|
583
850
|
}, [visible, preferredTab, loadInbox]);
|
|
584
|
-
|
|
851
|
+
useEffect2(() => {
|
|
585
852
|
if (!visible || sheetTab !== "inbox" || inboxPollIntervalMs <= 0) return;
|
|
586
853
|
const timer = setInterval(() => {
|
|
587
|
-
void loadInbox();
|
|
854
|
+
void loadInbox({ silent: true });
|
|
588
855
|
}, inboxPollIntervalMs);
|
|
589
856
|
return () => clearInterval(timer);
|
|
590
857
|
}, [visible, sheetTab, inboxPollIntervalMs, loadInbox]);
|
|
591
|
-
const openThread = useCallback(
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
858
|
+
const openThread = useCallback(
|
|
859
|
+
async (reportId, opts = {}) => {
|
|
860
|
+
selectedRef.current = reportId;
|
|
861
|
+
setSelectedReportId(reportId);
|
|
862
|
+
if (!opts.silent) {
|
|
863
|
+
setThreadItems([]);
|
|
864
|
+
setThreadStatus("loading");
|
|
865
|
+
setReplyState("idle");
|
|
866
|
+
setFeedbackError(false);
|
|
867
|
+
}
|
|
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
|
+
}
|
|
877
|
+
if (selectedRef.current !== reportId) return;
|
|
878
|
+
if (items === null) {
|
|
879
|
+
setThreadStatus((prev) => opts.silent && prev === "ready" ? "ready" : "error");
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
setThreadItems(items);
|
|
883
|
+
setThreadStatus("ready");
|
|
884
|
+
if (!opts.silent && mushi?.markReportRead) {
|
|
885
|
+
mushi.markReportRead(reportId).then((marked) => {
|
|
886
|
+
if (marked > 0) {
|
|
887
|
+
setInboxReports((rows) => rows.map((r) => r.id === reportId ? { ...r, unread_count: 0 } : r));
|
|
888
|
+
}
|
|
889
|
+
}).catch(() => void 0);
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
[mushi]
|
|
893
|
+
);
|
|
894
|
+
const closeThread = useCallback(() => {
|
|
895
|
+
selectedRef.current = null;
|
|
896
|
+
setSelectedReportId(null);
|
|
897
|
+
setThreadStatus("idle");
|
|
898
|
+
}, []);
|
|
597
899
|
const sendReply = useCallback(async () => {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
900
|
+
const body = replyText.trim();
|
|
901
|
+
const reportId = selectedReportId;
|
|
902
|
+
if (!mushi?.replyToReport || !reportId || !body || replyState === "sending") return;
|
|
903
|
+
setReplyState("sending");
|
|
904
|
+
try {
|
|
905
|
+
const comment = await settleWithin(mushi.replyToReport(reportId, body), THREAD_LOAD_TIMEOUT_MS);
|
|
906
|
+
if (!comment) {
|
|
907
|
+
setReplyState("failed");
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
setReplyText("");
|
|
911
|
+
setReplyState("idle");
|
|
912
|
+
if (selectedRef.current === reportId) {
|
|
913
|
+
setThreadItems((prev) => [
|
|
914
|
+
...prev,
|
|
915
|
+
{ kind: "reporter_comment", at: comment.created_at, text: comment.body, body: comment.body, comment_id: comment.id }
|
|
916
|
+
]);
|
|
917
|
+
void openThread(reportId, { silent: true });
|
|
918
|
+
}
|
|
919
|
+
} catch {
|
|
920
|
+
setReplyState("failed");
|
|
921
|
+
}
|
|
922
|
+
}, [mushi, selectedReportId, replyText, replyState, openThread]);
|
|
923
|
+
const submitFeedback = useCallback(
|
|
924
|
+
async (signal) => {
|
|
925
|
+
const reportId = selectedReportId;
|
|
926
|
+
if (!mushi?.submitFeedbackSignal || !reportId || feedbackSending) return;
|
|
927
|
+
setFeedbackSending(true);
|
|
928
|
+
setFeedbackError(false);
|
|
929
|
+
try {
|
|
930
|
+
const outcome = await mushi.submitFeedbackSignal(reportId, signal);
|
|
931
|
+
if (!outcome) {
|
|
932
|
+
setFeedbackError(true);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
await loadInbox({ silent: true });
|
|
936
|
+
await openThread(reportId, { silent: true });
|
|
937
|
+
} catch {
|
|
938
|
+
setFeedbackError(true);
|
|
939
|
+
} finally {
|
|
940
|
+
setFeedbackSending(false);
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
[mushi, selectedReportId, feedbackSending, loadInbox, openThread]
|
|
944
|
+
);
|
|
609
945
|
const sendAssistant = useCallback(async (message) => {
|
|
610
946
|
if (!mushi?.askAssistant || !message.trim() || assistantSending) return;
|
|
611
947
|
const trimmed = message.trim();
|
|
@@ -635,8 +971,15 @@ var MushiBottomSheet = ({
|
|
|
635
971
|
setCategory(null);
|
|
636
972
|
setDescription("");
|
|
637
973
|
setPhase("form");
|
|
974
|
+
setEmailState("hidden");
|
|
975
|
+
setEmailInput("");
|
|
638
976
|
}, []);
|
|
639
977
|
const animateIn = useCallback(() => {
|
|
978
|
+
if (reduceMotion) {
|
|
979
|
+
translateY.setValue(0);
|
|
980
|
+
backdropOpacity.setValue(1);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
640
983
|
Animated.parallel([
|
|
641
984
|
Animated.spring(translateY, {
|
|
642
985
|
toValue: 0,
|
|
@@ -650,18 +993,18 @@ var MushiBottomSheet = ({
|
|
|
650
993
|
useNativeDriver: true
|
|
651
994
|
})
|
|
652
995
|
]).start();
|
|
653
|
-
}, [translateY, backdropOpacity]);
|
|
996
|
+
}, [translateY, backdropOpacity, reduceMotion]);
|
|
654
997
|
const animateOut = useCallback(
|
|
655
998
|
(cb) => {
|
|
656
999
|
Animated.parallel([
|
|
657
1000
|
Animated.timing(translateY, {
|
|
658
1001
|
toValue: SHEET_HEIGHT,
|
|
659
|
-
duration: 220,
|
|
1002
|
+
duration: reduceMotion ? 0 : 220,
|
|
660
1003
|
useNativeDriver: true
|
|
661
1004
|
}),
|
|
662
1005
|
Animated.timing(backdropOpacity, {
|
|
663
1006
|
toValue: 0,
|
|
664
|
-
duration: 200,
|
|
1007
|
+
duration: reduceMotion ? 0 : 200,
|
|
665
1008
|
useNativeDriver: true
|
|
666
1009
|
})
|
|
667
1010
|
]).start(() => {
|
|
@@ -669,9 +1012,9 @@ var MushiBottomSheet = ({
|
|
|
669
1012
|
cb?.();
|
|
670
1013
|
});
|
|
671
1014
|
},
|
|
672
|
-
[translateY, backdropOpacity, resetForm]
|
|
1015
|
+
[translateY, backdropOpacity, resetForm, reduceMotion]
|
|
673
1016
|
);
|
|
674
|
-
|
|
1017
|
+
useEffect2(() => {
|
|
675
1018
|
if (visible) animateIn();
|
|
676
1019
|
}, [visible, animateIn]);
|
|
677
1020
|
const handleClose = useCallback(() => {
|
|
@@ -698,20 +1041,43 @@ var MushiBottomSheet = ({
|
|
|
698
1041
|
}
|
|
699
1042
|
})
|
|
700
1043
|
).current;
|
|
701
|
-
const
|
|
702
|
-
if (!
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
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");
|
|
706
1059
|
return;
|
|
707
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();
|
|
708
1074
|
setSubmitError(null);
|
|
709
1075
|
setPhase("sending");
|
|
710
1076
|
try {
|
|
711
1077
|
const outcome = await mushi.submitReport({
|
|
712
|
-
category,
|
|
1078
|
+
...reporterChipToReport(category),
|
|
713
1079
|
description: trimmed,
|
|
714
|
-
screenshotDataUrl:
|
|
1080
|
+
screenshotDataUrl: hasAttachment ? screenshotDataUrl : void 0
|
|
715
1081
|
});
|
|
716
1082
|
if (!outcome.ok) {
|
|
717
1083
|
if (outcome.failureKind === "credentials" || outcome.failureKind === "quota") {
|
|
@@ -729,174 +1095,465 @@ var MushiBottomSheet = ({
|
|
|
729
1095
|
return;
|
|
730
1096
|
}
|
|
731
1097
|
setPhase("sent");
|
|
732
|
-
|
|
1098
|
+
void offerEmail();
|
|
733
1099
|
} catch {
|
|
734
1100
|
setSubmitError("Something went wrong. Please try again.");
|
|
735
1101
|
setPhase("error");
|
|
736
1102
|
}
|
|
737
1103
|
};
|
|
738
1104
|
const activeScreenshot = screenshotDataUrl && screenshotAttached ? screenshotDataUrl : null;
|
|
739
|
-
const
|
|
740
|
-
const
|
|
1105
|
+
const colors = resolveRNTheme(dark, theme);
|
|
1106
|
+
const font = colors.fontFamily ? { fontFamily: colors.fontFamily } : null;
|
|
1107
|
+
const radius = colors.radius;
|
|
741
1108
|
const sheetTabs = ["report", "inbox", ...assistantEnabled ? ["assistant"] : []];
|
|
742
|
-
const canSubmit =
|
|
743
|
-
|
|
1109
|
+
const canSubmit = reporterCanSend(description, Boolean(activeScreenshot), minDescriptionLength) && (phase === "form" || phase === "error");
|
|
1110
|
+
const submitHint = canSubmit || phase === "sending" ? void 0 : rc.ui.addWords;
|
|
1111
|
+
const selectedReport = selectedReportId ? inboxReports.find((r) => r.id === selectedReportId) ?? null : null;
|
|
1112
|
+
const selectedView = selectedReport ? reporterStatus(selectedReport, locale) : null;
|
|
1113
|
+
const headerTitle = sheetTab === "assistant" ? assistantLabel : sheetTab === "inbox" ? t.flows.reports.title : t.widget.title;
|
|
1114
|
+
const renderThread = () => /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1115
|
+
/* @__PURE__ */ jsx2(
|
|
1116
|
+
TouchableOpacity2,
|
|
1117
|
+
{
|
|
1118
|
+
onPress: closeThread,
|
|
1119
|
+
accessibilityRole: "button",
|
|
1120
|
+
accessibilityLabel: t.widget.back,
|
|
1121
|
+
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1122
|
+
children: /* @__PURE__ */ jsxs2(Text2, { style: [{ color: colors.accent, marginBottom: 8 }, font], children: [
|
|
1123
|
+
"\u2190 ",
|
|
1124
|
+
t.widget.back
|
|
1125
|
+
] })
|
|
1126
|
+
}
|
|
1127
|
+
),
|
|
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 ?? "" })
|
|
1132
|
+
] }) : null,
|
|
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,
|
|
1137
|
+
{
|
|
1138
|
+
onPress: () => selectedReportId && void openThread(selectedReportId),
|
|
1139
|
+
accessibilityRole: "button",
|
|
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 })
|
|
1142
|
+
}
|
|
1143
|
+
)
|
|
1144
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1145
|
+
threadItems.map(
|
|
1146
|
+
(item, idx) => isReporterConversation(item) ? /* @__PURE__ */ jsxs2(
|
|
1147
|
+
View2,
|
|
1148
|
+
{
|
|
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() })
|
|
1176
|
+
] }) : null,
|
|
1177
|
+
selectedView?.canVerify ? /* @__PURE__ */ jsxs2(View2, { style: s2.verifyRow, children: [
|
|
1178
|
+
/* @__PURE__ */ jsx2(
|
|
1179
|
+
TouchableOpacity2,
|
|
1180
|
+
{
|
|
1181
|
+
style: [s2.verifyBtn, { backgroundColor: colors.accent, borderRadius: radius }],
|
|
1182
|
+
onPress: () => void submitFeedback("confirms"),
|
|
1183
|
+
disabled: feedbackSending,
|
|
1184
|
+
accessibilityRole: "button",
|
|
1185
|
+
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
1186
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.accentFg }, font], children: rc.ui.yes })
|
|
1187
|
+
}
|
|
1188
|
+
),
|
|
1189
|
+
/* @__PURE__ */ jsx2(
|
|
1190
|
+
TouchableOpacity2,
|
|
1191
|
+
{
|
|
1192
|
+
style: [s2.verifyBtn, { backgroundColor: colors.border, borderRadius: radius }],
|
|
1193
|
+
onPress: () => void submitFeedback("not_fixed"),
|
|
1194
|
+
disabled: feedbackSending,
|
|
1195
|
+
accessibilityRole: "button",
|
|
1196
|
+
accessibilityState: { disabled: feedbackSending, busy: feedbackSending },
|
|
1197
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.fg }, font], children: rc.ui.notYet })
|
|
1198
|
+
}
|
|
1199
|
+
)
|
|
1200
|
+
] }) : null,
|
|
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(
|
|
1204
|
+
TextInput,
|
|
1205
|
+
{
|
|
1206
|
+
style: [
|
|
1207
|
+
s2.input,
|
|
1208
|
+
s2.composerInput,
|
|
1209
|
+
{ backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius },
|
|
1210
|
+
font
|
|
1211
|
+
],
|
|
1212
|
+
placeholder: t.flows.thread.replyPlaceholder,
|
|
1213
|
+
placeholderTextColor: colors.muted,
|
|
1214
|
+
value: replyText,
|
|
1215
|
+
onChangeText: (text) => {
|
|
1216
|
+
setReplyText(text.slice(0, 2e3));
|
|
1217
|
+
if (replyState === "failed") setReplyState("idle");
|
|
1218
|
+
},
|
|
1219
|
+
multiline: true,
|
|
1220
|
+
maxLength: 2e3,
|
|
1221
|
+
editable: replyState !== "sending",
|
|
1222
|
+
accessibilityLabel: t.flows.thread.replyPlaceholder
|
|
1223
|
+
}
|
|
1224
|
+
),
|
|
1225
|
+
/* @__PURE__ */ jsx2(
|
|
1226
|
+
TouchableOpacity2,
|
|
1227
|
+
{
|
|
1228
|
+
style: [
|
|
1229
|
+
s2.sendBtn,
|
|
1230
|
+
{
|
|
1231
|
+
backgroundColor: replyText.trim() && replyState !== "sending" ? colors.accent : colors.disabled,
|
|
1232
|
+
borderRadius: radius
|
|
1233
|
+
}
|
|
1234
|
+
],
|
|
1235
|
+
onPress: () => void sendReply(),
|
|
1236
|
+
disabled: !replyText.trim() || replyState === "sending",
|
|
1237
|
+
accessibilityRole: "button",
|
|
1238
|
+
accessibilityLabel: replyState === "failed" ? rc.ui.retry : t.flows.thread.send,
|
|
1239
|
+
accessibilityState: { disabled: !replyText.trim() || replyState === "sending", busy: replyState === "sending" },
|
|
1240
|
+
children: /* @__PURE__ */ jsx2(
|
|
1241
|
+
Text2,
|
|
1242
|
+
{
|
|
1243
|
+
style: [
|
|
1244
|
+
s2.submitText,
|
|
1245
|
+
{ color: replyText.trim() && replyState !== "sending" ? colors.accentFg : colors.disabledFg },
|
|
1246
|
+
font
|
|
1247
|
+
],
|
|
1248
|
+
children: replyState === "failed" ? rc.ui.retry : t.flows.thread.send
|
|
1249
|
+
}
|
|
1250
|
+
)
|
|
1251
|
+
}
|
|
1252
|
+
)
|
|
1253
|
+
] }),
|
|
1254
|
+
replyState === "failed" ? /* @__PURE__ */ jsxs2(Text2, { style: [{ color: colors.error, marginTop: 6, fontSize: 12 }, font], accessibilityRole: "alert", children: [
|
|
1255
|
+
rc.ui.sendFailed,
|
|
1256
|
+
" \xB7 ",
|
|
1257
|
+
rc.ui.retry
|
|
1258
|
+
] }) : null
|
|
1259
|
+
] });
|
|
1260
|
+
const renderInboxList = () => {
|
|
1261
|
+
if (inboxLoading && !inboxLoaded) {
|
|
1262
|
+
return /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted }, font], children: t.flows.reports.loading });
|
|
1263
|
+
}
|
|
1264
|
+
if (inboxReports.length === 0) {
|
|
1265
|
+
return /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted }, font], children: rc.ui.empty });
|
|
1266
|
+
}
|
|
1267
|
+
return inboxReports.map((r) => {
|
|
1268
|
+
const view = reporterStatus(r, locale);
|
|
1269
|
+
const unread = (r.unread_count ?? 0) > 0;
|
|
1270
|
+
const title = (r.title ?? r.summary ?? r.description ?? "Report").slice(0, 80);
|
|
1271
|
+
return /* @__PURE__ */ jsxs2(
|
|
1272
|
+
TouchableOpacity2,
|
|
1273
|
+
{
|
|
1274
|
+
style: [s2.inboxRow, { borderColor: colors.border }],
|
|
1275
|
+
onPress: () => void openThread(r.id),
|
|
1276
|
+
accessibilityRole: "button",
|
|
1277
|
+
accessibilityLabel: `${view.label}. ${title}${unread ? `. ${r.unread_count} new` : ""}`,
|
|
1278
|
+
children: [
|
|
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: [
|
|
1281
|
+
view.label,
|
|
1282
|
+
view.othersNote ? ` \xB7 ${view.othersNote}` : ""
|
|
1283
|
+
] }),
|
|
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
|
|
1285
|
+
]
|
|
1286
|
+
},
|
|
1287
|
+
r.id
|
|
1288
|
+
);
|
|
1289
|
+
});
|
|
1290
|
+
};
|
|
1291
|
+
return /* @__PURE__ */ jsx2(Modal, { visible, transparent: true, animationType: "none", statusBarTranslucent: true, onRequestClose: handleClose, children: /* @__PURE__ */ jsxs2(
|
|
744
1292
|
KeyboardAvoidingView,
|
|
745
1293
|
{
|
|
746
|
-
style:
|
|
1294
|
+
style: s2.flex,
|
|
747
1295
|
behavior: Platform2.OS === "ios" ? "padding" : "height",
|
|
748
1296
|
keyboardVerticalOffset: Platform2.OS === "ios" ? 0 : 20,
|
|
749
1297
|
children: [
|
|
750
|
-
/* @__PURE__ */
|
|
1298
|
+
/* @__PURE__ */ jsx2(
|
|
751
1299
|
Animated.View,
|
|
752
1300
|
{
|
|
753
|
-
style: [
|
|
754
|
-
children: /* @__PURE__ */
|
|
1301
|
+
style: [s2.backdrop, { backgroundColor: colors.backdrop, opacity: backdropOpacity }],
|
|
1302
|
+
children: /* @__PURE__ */ jsx2(
|
|
1303
|
+
TouchableOpacity2,
|
|
1304
|
+
{
|
|
1305
|
+
style: s2.flex,
|
|
1306
|
+
activeOpacity: 1,
|
|
1307
|
+
onPress: handleClose,
|
|
1308
|
+
accessibilityRole: "button",
|
|
1309
|
+
accessibilityLabel: t.widget.close
|
|
1310
|
+
}
|
|
1311
|
+
)
|
|
755
1312
|
}
|
|
756
1313
|
),
|
|
757
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsxs2(
|
|
758
1315
|
Animated.View,
|
|
759
1316
|
{
|
|
1317
|
+
accessibilityViewIsModal: true,
|
|
1318
|
+
onAccessibilityEscape: handleClose,
|
|
760
1319
|
style: [
|
|
761
|
-
|
|
1320
|
+
s2.sheet,
|
|
762
1321
|
{ backgroundColor: colors.bg, transform: [{ translateY }] }
|
|
763
1322
|
],
|
|
764
1323
|
children: [
|
|
765
|
-
/* @__PURE__ */
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1324
|
+
/* @__PURE__ */ jsx2(
|
|
1325
|
+
View2,
|
|
1326
|
+
{
|
|
1327
|
+
...panResponder.panHandlers,
|
|
1328
|
+
style: s2.handleArea,
|
|
1329
|
+
accessible: true,
|
|
1330
|
+
accessibilityRole: "adjustable",
|
|
1331
|
+
accessibilityLabel: t.widget.close,
|
|
1332
|
+
accessibilityActions: [{ name: "decrement", label: t.widget.close }, { name: "escape" }],
|
|
1333
|
+
onAccessibilityAction: (e) => {
|
|
1334
|
+
if (e.nativeEvent.actionName === "decrement" || e.nativeEvent.actionName === "escape") handleClose();
|
|
1335
|
+
},
|
|
1336
|
+
children: /* @__PURE__ */ jsx2(View2, { style: [s2.handle, { backgroundColor: colors.muted }] })
|
|
1337
|
+
}
|
|
1338
|
+
),
|
|
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,
|
|
772
1342
|
{
|
|
773
1343
|
onPress: () => {
|
|
774
1344
|
setSheetTab(tab);
|
|
775
|
-
if (tab === "inbox") void loadInbox();
|
|
776
|
-
else
|
|
1345
|
+
if (tab === "inbox") void loadInbox({ silent: inboxLoaded });
|
|
1346
|
+
else closeThread();
|
|
777
1347
|
},
|
|
778
|
-
style: [
|
|
779
|
-
|
|
1348
|
+
style: [s2.tabBtn, sheetTab === tab && { borderBottomColor: colors.accent }],
|
|
1349
|
+
accessibilityRole: "tab",
|
|
1350
|
+
accessibilityState: { selected: sheetTab === tab },
|
|
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 })
|
|
780
1352
|
},
|
|
781
1353
|
tab
|
|
782
1354
|
)) }),
|
|
783
|
-
sheetTab === "assistant" ? /* @__PURE__ */
|
|
784
|
-
assistantTurns.length === 0 ? /* @__PURE__ */
|
|
785
|
-
/* @__PURE__ */
|
|
786
|
-
assistantSuggestions.map((chip) => /* @__PURE__ */
|
|
787
|
-
|
|
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,
|
|
788
1360
|
{
|
|
789
|
-
style: [
|
|
1361
|
+
style: [s2.assistantChip, { borderColor: colors.border, backgroundColor: colors.surface }],
|
|
790
1362
|
onPress: () => void sendAssistant(chip),
|
|
791
|
-
|
|
1363
|
+
accessibilityRole: "button",
|
|
1364
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.fg, fontSize: 13 }, font], children: chip })
|
|
792
1365
|
},
|
|
793
1366
|
chip
|
|
794
1367
|
))
|
|
795
|
-
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */
|
|
796
|
-
|
|
1368
|
+
] }) : assistantTurns.map((turn, idx) => /* @__PURE__ */ jsxs2(
|
|
1369
|
+
View2,
|
|
797
1370
|
{
|
|
798
1371
|
style: [
|
|
799
|
-
|
|
1372
|
+
s2.assistantBubble,
|
|
800
1373
|
{
|
|
801
1374
|
alignSelf: turn.role === "user" ? "flex-end" : "flex-start",
|
|
802
|
-
backgroundColor: turn.role === "user" ? colors.accent : colors.
|
|
1375
|
+
backgroundColor: turn.role === "user" ? colors.accent : colors.surface
|
|
803
1376
|
}
|
|
804
1377
|
],
|
|
805
1378
|
children: [
|
|
806
|
-
/* @__PURE__ */
|
|
807
|
-
turn.options?.map((opt) => /* @__PURE__ */
|
|
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,
|
|
1382
|
+
{
|
|
1383
|
+
onPress: () => void sendAssistant(opt),
|
|
1384
|
+
style: { marginTop: 8 },
|
|
1385
|
+
accessibilityRole: "button",
|
|
1386
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.accent, fontSize: 12 }, font], children: opt })
|
|
1387
|
+
},
|
|
1388
|
+
opt
|
|
1389
|
+
))
|
|
808
1390
|
]
|
|
809
1391
|
},
|
|
810
1392
|
`${turn.role}-${idx}`
|
|
811
1393
|
)),
|
|
812
|
-
assistantSending ? /* @__PURE__ */
|
|
813
|
-
assistantError ? /* @__PURE__ */
|
|
814
|
-
/* @__PURE__ */
|
|
815
|
-
/* @__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(
|
|
816
1398
|
TextInput,
|
|
817
1399
|
{
|
|
818
|
-
style: [
|
|
1400
|
+
style: [s2.input, { flex: 1, minHeight: 44, backgroundColor: colors.surface, color: colors.fg, borderColor: colors.border, borderRadius: radius }, font],
|
|
819
1401
|
placeholder: t.assistant.inputPlaceholder,
|
|
820
|
-
placeholderTextColor: colors.
|
|
1402
|
+
placeholderTextColor: colors.muted,
|
|
821
1403
|
value: assistantInput,
|
|
822
1404
|
onChangeText: setAssistantInput,
|
|
823
1405
|
editable: !assistantSending
|
|
824
1406
|
}
|
|
825
1407
|
),
|
|
826
|
-
/* @__PURE__ */
|
|
827
|
-
|
|
1408
|
+
/* @__PURE__ */ jsx2(
|
|
1409
|
+
TouchableOpacity2,
|
|
828
1410
|
{
|
|
829
|
-
style: [
|
|
1411
|
+
style: [s2.submitBtn, { backgroundColor: colors.accent, paddingHorizontal: 16, borderRadius: radius }],
|
|
830
1412
|
onPress: () => void sendAssistant(assistantInput),
|
|
831
1413
|
disabled: !assistantInput.trim() || assistantSending,
|
|
832
|
-
|
|
1414
|
+
accessibilityRole: "button",
|
|
1415
|
+
accessibilityLabel: t.flows.thread.send,
|
|
1416
|
+
accessibilityState: { disabled: !assistantInput.trim() || assistantSending, busy: assistantSending },
|
|
1417
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.submitText, { color: colors.accentFg }], children: "\u2191" })
|
|
833
1418
|
}
|
|
834
1419
|
)
|
|
835
1420
|
] })
|
|
836
|
-
] }) : sheetTab === "inbox" ? /* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
"\
|
|
839
|
-
|
|
840
|
-
] }) }),
|
|
841
|
-
threadComments.map((c) => /* @__PURE__ */ jsxs(View, { style: [s.threadBubble, { backgroundColor: colors.card }], children: [
|
|
842
|
-
/* @__PURE__ */ jsx(Text, { style: { color: colors.sub, fontSize: 11 }, children: c.author_kind }),
|
|
843
|
-
/* @__PURE__ */ jsx(Text, { style: { color: colors.text }, children: c.body })
|
|
844
|
-
] }, c.id)),
|
|
845
|
-
VERIFIABLE_STATUSES.has(
|
|
846
|
-
inboxReports.find((r) => r.id === selectedReportId)?.status ?? ""
|
|
847
|
-
) && /* @__PURE__ */ jsxs(View, { style: s.verifyRow, children: [
|
|
848
|
-
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.accent }], onPress: () => submitFeedback("confirms"), children: /* @__PURE__ */ jsx(Text, { style: [s.submitText, { color: colors.accentInk }], children: t.flows.thread.confirmFixed }) }),
|
|
849
|
-
/* @__PURE__ */ jsx(TouchableOpacity, { style: [s.verifyBtn, { backgroundColor: colors.border }], onPress: () => submitFeedback("not_fixed"), children: /* @__PURE__ */ jsx(Text, { style: [s.submitText, { color: colors.text }], children: t.flows.thread.notFixed }) })
|
|
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 })
|
|
850
1425
|
] }),
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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(
|
|
869
1492
|
ScrollView,
|
|
870
1493
|
{
|
|
871
|
-
style:
|
|
1494
|
+
style: s2.body,
|
|
872
1495
|
keyboardShouldPersistTaps: "handled",
|
|
873
1496
|
contentContainerStyle: { paddingBottom: 24 },
|
|
874
1497
|
children: [
|
|
875
|
-
/* @__PURE__ */
|
|
876
|
-
|
|
1498
|
+
/* @__PURE__ */ jsx2(
|
|
1499
|
+
TextInput,
|
|
1500
|
+
{
|
|
1501
|
+
style: [
|
|
1502
|
+
s2.input,
|
|
1503
|
+
{
|
|
1504
|
+
backgroundColor: colors.surface,
|
|
1505
|
+
color: colors.fg,
|
|
1506
|
+
borderColor: colors.border,
|
|
1507
|
+
borderRadius: radius
|
|
1508
|
+
},
|
|
1509
|
+
font
|
|
1510
|
+
],
|
|
1511
|
+
placeholder: t.step3.descriptionPlaceholder,
|
|
1512
|
+
placeholderTextColor: colors.muted,
|
|
1513
|
+
accessibilityLabel: t.step3.descriptionPlaceholder,
|
|
1514
|
+
multiline: true,
|
|
1515
|
+
textAlignVertical: "top",
|
|
1516
|
+
value: description,
|
|
1517
|
+
onChangeText: (text) => {
|
|
1518
|
+
setDescription(text.slice(0, 4e3));
|
|
1519
|
+
if (submitError) setSubmitError(null);
|
|
1520
|
+
if (phase === "error") setPhase("form");
|
|
1521
|
+
},
|
|
1522
|
+
editable: phase === "form" || phase === "error",
|
|
1523
|
+
maxLength: 4e3
|
|
1524
|
+
}
|
|
1525
|
+
),
|
|
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) => {
|
|
877
1528
|
const active = category === key;
|
|
878
|
-
|
|
879
|
-
|
|
1529
|
+
const label = reporterCategoryLabel(key, locale);
|
|
1530
|
+
return /* @__PURE__ */ jsxs2(
|
|
1531
|
+
TouchableOpacity2,
|
|
880
1532
|
{
|
|
881
|
-
onPress: () => setCategory(key),
|
|
1533
|
+
onPress: () => setCategory(active ? null : key),
|
|
882
1534
|
activeOpacity: 0.7,
|
|
1535
|
+
accessibilityRole: "radio",
|
|
1536
|
+
accessibilityState: { selected: active, checked: active },
|
|
1537
|
+
accessibilityLabel: label,
|
|
883
1538
|
style: [
|
|
884
|
-
|
|
1539
|
+
s2.catBtn,
|
|
885
1540
|
{
|
|
886
|
-
backgroundColor: active ? colors.accent : colors.
|
|
1541
|
+
backgroundColor: active ? colors.accent : colors.surface,
|
|
887
1542
|
borderColor: active ? colors.accent : colors.border
|
|
888
1543
|
}
|
|
889
1544
|
],
|
|
890
1545
|
children: [
|
|
891
|
-
/* @__PURE__ */
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
|
|
1546
|
+
/* @__PURE__ */ jsx2(Text2, { style: s2.catEmoji, importantForAccessibility: "no", children: CATEGORY_EMOJI[key] }),
|
|
1547
|
+
/* @__PURE__ */ jsx2(
|
|
1548
|
+
Text2,
|
|
894
1549
|
{
|
|
1550
|
+
numberOfLines: 1,
|
|
895
1551
|
style: [
|
|
896
|
-
|
|
897
|
-
{ color: active ? colors.
|
|
1552
|
+
s2.catLabel,
|
|
1553
|
+
{ color: active ? colors.accentFg : colors.fg },
|
|
1554
|
+
font
|
|
898
1555
|
],
|
|
899
|
-
children:
|
|
1556
|
+
children: label
|
|
900
1557
|
}
|
|
901
1558
|
)
|
|
902
1559
|
]
|
|
@@ -904,69 +1561,49 @@ var MushiBottomSheet = ({
|
|
|
904
1561
|
key
|
|
905
1562
|
);
|
|
906
1563
|
}) }),
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
|
|
909
|
-
{
|
|
910
|
-
style: [
|
|
911
|
-
s.input,
|
|
912
|
-
{
|
|
913
|
-
backgroundColor: colors.card,
|
|
914
|
-
color: colors.text,
|
|
915
|
-
borderColor: colors.border
|
|
916
|
-
}
|
|
917
|
-
],
|
|
918
|
-
placeholder: t.step3.descriptionPlaceholder,
|
|
919
|
-
placeholderTextColor: colors.sub,
|
|
920
|
-
multiline: true,
|
|
921
|
-
textAlignVertical: "top",
|
|
922
|
-
value: description,
|
|
923
|
-
onChangeText: (text) => {
|
|
924
|
-
setDescription(text.slice(0, 4e3));
|
|
925
|
-
if (submitError) setSubmitError(null);
|
|
926
|
-
if (phase === "error") setPhase("form");
|
|
927
|
-
},
|
|
928
|
-
editable: phase === "form" || phase === "error",
|
|
929
|
-
maxLength: 4e3
|
|
930
|
-
}
|
|
931
|
-
),
|
|
932
|
-
submitError ? /* @__PURE__ */ jsx(Text, { style: { color: colors.accent, marginTop: 6, fontSize: 12 }, children: submitError }) : null,
|
|
933
|
-
activeScreenshot ? /* @__PURE__ */ jsxs(View, { style: s.screenshotRow, children: [
|
|
934
|
-
/* @__PURE__ */ jsx(
|
|
1564
|
+
activeScreenshot ? /* @__PURE__ */ jsxs2(View2, { style: s2.screenshotRow, children: [
|
|
1565
|
+
/* @__PURE__ */ jsx2(
|
|
935
1566
|
Image,
|
|
936
1567
|
{
|
|
937
1568
|
source: { uri: activeScreenshot },
|
|
938
|
-
style: [
|
|
1569
|
+
style: [s2.screenshotThumb, { backgroundColor: colors.fg }],
|
|
939
1570
|
accessibilityLabel: t.step3.screenshotPreviewAlt
|
|
940
1571
|
}
|
|
941
1572
|
),
|
|
942
|
-
/* @__PURE__ */
|
|
943
|
-
/* @__PURE__ */
|
|
944
|
-
/* @__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 })
|
|
945
1576
|
] }),
|
|
946
|
-
/* @__PURE__ */
|
|
947
|
-
|
|
1577
|
+
/* @__PURE__ */ jsx2(
|
|
1578
|
+
TouchableOpacity2,
|
|
948
1579
|
{
|
|
949
1580
|
onPress: () => {
|
|
950
1581
|
setScreenshotAttached(false);
|
|
951
1582
|
onClearScreenshot?.();
|
|
952
1583
|
},
|
|
953
1584
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1585
|
+
accessibilityRole: "button",
|
|
954
1586
|
accessibilityLabel: t.widget.close,
|
|
955
|
-
children: /* @__PURE__ */
|
|
1587
|
+
children: /* @__PURE__ */ jsx2(Text2, { style: [s2.screenshotRemove, { color: colors.muted }], children: "\u2715" })
|
|
956
1588
|
}
|
|
957
1589
|
)
|
|
958
1590
|
] }) : null,
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
|
|
1591
|
+
submitHint ? /* @__PURE__ */ jsx2(Text2, { style: [{ color: colors.muted, fontSize: 12, marginBottom: 6 }, font], children: submitHint }) : null,
|
|
1592
|
+
/* @__PURE__ */ jsx2(
|
|
1593
|
+
TouchableOpacity2,
|
|
961
1594
|
{
|
|
962
1595
|
onPress: handleSubmit,
|
|
963
1596
|
disabled: !canSubmit,
|
|
964
1597
|
activeOpacity: 0.8,
|
|
1598
|
+
accessibilityRole: "button",
|
|
1599
|
+
accessibilityLabel: phase === "sending" ? t.widget.submitting : t.widget.submit,
|
|
1600
|
+
accessibilityHint: submitHint,
|
|
1601
|
+
accessibilityState: { disabled: !canSubmit, busy: phase === "sending" },
|
|
965
1602
|
style: [
|
|
966
|
-
|
|
967
|
-
{ backgroundColor: canSubmit ? colors.accent : colors.disabled }
|
|
1603
|
+
s2.submitBtn,
|
|
1604
|
+
{ backgroundColor: canSubmit ? colors.accent : colors.disabled, borderRadius: radius }
|
|
968
1605
|
],
|
|
969
|
-
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 })
|
|
970
1607
|
}
|
|
971
1608
|
)
|
|
972
1609
|
]
|
|
@@ -979,7 +1616,7 @@ var MushiBottomSheet = ({
|
|
|
979
1616
|
}
|
|
980
1617
|
) });
|
|
981
1618
|
};
|
|
982
|
-
var
|
|
1619
|
+
var s2 = StyleSheet2.create({
|
|
983
1620
|
flex: { flex: 1 },
|
|
984
1621
|
backdrop: {
|
|
985
1622
|
// Inlined StyleSheet.absoluteFillObject — RN 0.86 dropped it from the
|
|
@@ -996,10 +1633,10 @@ var s = StyleSheet.create({
|
|
|
996
1633
|
left: 0,
|
|
997
1634
|
right: 0,
|
|
998
1635
|
minHeight: SHEET_HEIGHT,
|
|
999
|
-
borderTopLeftRadius:
|
|
1000
|
-
borderTopRightRadius:
|
|
1636
|
+
borderTopLeftRadius: MUSHI_RADIUS2.sheet,
|
|
1637
|
+
borderTopRightRadius: MUSHI_RADIUS2.sheet,
|
|
1001
1638
|
paddingBottom: Platform2.OS === "ios" ? 34 : MUSHI_SPACING.roomy,
|
|
1002
|
-
shadowColor:
|
|
1639
|
+
shadowColor: MUSHI_SHADOW_INK2,
|
|
1003
1640
|
shadowOffset: { width: 0, height: -3 },
|
|
1004
1641
|
shadowOpacity: 0.12,
|
|
1005
1642
|
shadowRadius: 8,
|
|
@@ -1012,36 +1649,22 @@ var s = StyleSheet.create({
|
|
|
1012
1649
|
handle: {
|
|
1013
1650
|
width: 40,
|
|
1014
1651
|
height: 5,
|
|
1015
|
-
borderRadius:
|
|
1652
|
+
borderRadius: MUSHI_RADIUS2.control,
|
|
1016
1653
|
opacity: 0.5
|
|
1017
1654
|
},
|
|
1018
|
-
|
|
1655
|
+
header: {
|
|
1019
1656
|
paddingHorizontal: MUSHI_SPACING.lounge,
|
|
1020
|
-
|
|
1021
|
-
paddingBottom: MUSHI_SPACING.comfy,
|
|
1022
|
-
borderBottomWidth: 1.5
|
|
1657
|
+
paddingBottom: MUSHI_SPACING.comfy
|
|
1023
1658
|
},
|
|
1024
|
-
|
|
1025
|
-
fontSize: MUSHI_TYPE.sizeLabel,
|
|
1026
|
-
fontWeight: "700",
|
|
1027
|
-
letterSpacing: 1.2,
|
|
1028
|
-
marginBottom: 2,
|
|
1029
|
-
opacity: 0.7
|
|
1030
|
-
},
|
|
1031
|
-
brandTitle: {
|
|
1659
|
+
headerTitle: {
|
|
1032
1660
|
fontSize: 18,
|
|
1033
|
-
fontWeight: "
|
|
1661
|
+
fontWeight: "700",
|
|
1034
1662
|
letterSpacing: -0.2
|
|
1035
1663
|
},
|
|
1036
1664
|
body: {
|
|
1037
1665
|
paddingHorizontal: MUSHI_SPACING.lounge,
|
|
1038
1666
|
paddingTop: MUSHI_SPACING.tight
|
|
1039
1667
|
},
|
|
1040
|
-
title: {
|
|
1041
|
-
fontSize: 20,
|
|
1042
|
-
fontWeight: "700",
|
|
1043
|
-
marginBottom: MUSHI_SPACING.roomy
|
|
1044
|
-
},
|
|
1045
1668
|
stepLabel: {
|
|
1046
1669
|
fontSize: MUSHI_TYPE.sizeLabel,
|
|
1047
1670
|
fontWeight: "600",
|
|
@@ -1052,37 +1675,35 @@ var s = StyleSheet.create({
|
|
|
1052
1675
|
},
|
|
1053
1676
|
catRow: {
|
|
1054
1677
|
flexDirection: "row",
|
|
1055
|
-
|
|
1678
|
+
flexWrap: "wrap",
|
|
1679
|
+
gap: 8,
|
|
1056
1680
|
marginBottom: MUSHI_SPACING.roomy
|
|
1057
1681
|
},
|
|
1058
1682
|
catBtn: {
|
|
1683
|
+
flexDirection: "row",
|
|
1059
1684
|
alignItems: "center",
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1685
|
+
gap: 6,
|
|
1686
|
+
paddingVertical: 8,
|
|
1687
|
+
paddingHorizontal: 12,
|
|
1688
|
+
borderRadius: 999,
|
|
1063
1689
|
borderWidth: 1,
|
|
1064
|
-
flex: 1,
|
|
1065
|
-
marginHorizontal: 3,
|
|
1066
1690
|
minHeight: 44
|
|
1067
1691
|
},
|
|
1068
1692
|
catEmoji: {
|
|
1069
|
-
fontSize:
|
|
1070
|
-
marginBottom: MUSHI_SPACING.tight
|
|
1693
|
+
fontSize: 16
|
|
1071
1694
|
},
|
|
1072
1695
|
catLabel: {
|
|
1073
|
-
fontSize:
|
|
1696
|
+
fontSize: 14,
|
|
1074
1697
|
fontWeight: "600"
|
|
1075
1698
|
},
|
|
1076
1699
|
input: {
|
|
1077
1700
|
borderWidth: 1,
|
|
1078
|
-
borderRadius: MUSHI_RADIUS.card,
|
|
1079
1701
|
padding: 14,
|
|
1080
1702
|
fontSize: 15,
|
|
1081
1703
|
minHeight: 100,
|
|
1082
1704
|
marginBottom: MUSHI_SPACING.roomy
|
|
1083
1705
|
},
|
|
1084
1706
|
submitBtn: {
|
|
1085
|
-
borderRadius: MUSHI_RADIUS.card,
|
|
1086
1707
|
paddingVertical: 14,
|
|
1087
1708
|
alignItems: "center",
|
|
1088
1709
|
minHeight: 44
|
|
@@ -1139,7 +1760,7 @@ var s = StyleSheet.create({
|
|
|
1139
1760
|
},
|
|
1140
1761
|
tabRow: {
|
|
1141
1762
|
flexDirection: "row",
|
|
1142
|
-
borderBottomWidth:
|
|
1763
|
+
borderBottomWidth: StyleSheet2.hairlineWidth,
|
|
1143
1764
|
marginBottom: 8
|
|
1144
1765
|
},
|
|
1145
1766
|
tabBtn: {
|
|
@@ -1147,7 +1768,8 @@ var s = StyleSheet.create({
|
|
|
1147
1768
|
alignItems: "center",
|
|
1148
1769
|
paddingVertical: 10,
|
|
1149
1770
|
borderBottomWidth: 2,
|
|
1150
|
-
borderBottomColor: "transparent"
|
|
1771
|
+
borderBottomColor: "transparent",
|
|
1772
|
+
minHeight: 44
|
|
1151
1773
|
},
|
|
1152
1774
|
tabLabel: {
|
|
1153
1775
|
fontSize: 14,
|
|
@@ -1155,12 +1777,47 @@ var s = StyleSheet.create({
|
|
|
1155
1777
|
},
|
|
1156
1778
|
inboxRow: {
|
|
1157
1779
|
paddingVertical: 12,
|
|
1158
|
-
|
|
1780
|
+
minHeight: 56,
|
|
1781
|
+
borderBottomWidth: StyleSheet2.hairlineWidth
|
|
1782
|
+
},
|
|
1783
|
+
headerCard: {
|
|
1784
|
+
borderWidth: StyleSheet2.hairlineWidth,
|
|
1785
|
+
padding: 12,
|
|
1786
|
+
marginBottom: 12
|
|
1787
|
+
},
|
|
1788
|
+
pill: {
|
|
1789
|
+
alignSelf: "flex-start",
|
|
1790
|
+
borderWidth: 1,
|
|
1791
|
+
borderRadius: 999,
|
|
1792
|
+
paddingHorizontal: 8,
|
|
1793
|
+
paddingVertical: 2,
|
|
1794
|
+
fontSize: 12,
|
|
1795
|
+
fontWeight: "600",
|
|
1796
|
+
overflow: "hidden"
|
|
1797
|
+
},
|
|
1798
|
+
skeleton: {
|
|
1799
|
+
height: 14,
|
|
1800
|
+
borderRadius: 6,
|
|
1801
|
+
marginBottom: 10
|
|
1802
|
+
},
|
|
1803
|
+
errorRow: {
|
|
1804
|
+
flexDirection: "row",
|
|
1805
|
+
alignItems: "center",
|
|
1806
|
+
gap: 8,
|
|
1807
|
+
marginBottom: 12
|
|
1808
|
+
},
|
|
1809
|
+
retryBtn: {
|
|
1810
|
+
borderWidth: 1,
|
|
1811
|
+
paddingHorizontal: 12,
|
|
1812
|
+
paddingVertical: 8,
|
|
1813
|
+
minHeight: 44,
|
|
1814
|
+
justifyContent: "center"
|
|
1159
1815
|
},
|
|
1160
1816
|
threadBubble: {
|
|
1161
1817
|
borderRadius: 10,
|
|
1162
1818
|
padding: 10,
|
|
1163
|
-
marginBottom: 8
|
|
1819
|
+
marginBottom: 8,
|
|
1820
|
+
maxWidth: "88%"
|
|
1164
1821
|
},
|
|
1165
1822
|
verifyRow: {
|
|
1166
1823
|
flexDirection: "row",
|
|
@@ -1169,9 +1826,26 @@ var s = StyleSheet.create({
|
|
|
1169
1826
|
},
|
|
1170
1827
|
verifyBtn: {
|
|
1171
1828
|
flex: 1,
|
|
1172
|
-
borderRadius: 10,
|
|
1173
1829
|
paddingVertical: 10,
|
|
1174
|
-
alignItems: "center"
|
|
1830
|
+
alignItems: "center",
|
|
1831
|
+
minHeight: 44
|
|
1832
|
+
},
|
|
1833
|
+
composer: {
|
|
1834
|
+
flexDirection: "row",
|
|
1835
|
+
alignItems: "flex-end",
|
|
1836
|
+
gap: 8
|
|
1837
|
+
},
|
|
1838
|
+
composerInput: {
|
|
1839
|
+
flex: 1,
|
|
1840
|
+
minHeight: 44,
|
|
1841
|
+
maxHeight: 120,
|
|
1842
|
+
marginBottom: 0
|
|
1843
|
+
},
|
|
1844
|
+
sendBtn: {
|
|
1845
|
+
paddingHorizontal: 16,
|
|
1846
|
+
paddingVertical: 12,
|
|
1847
|
+
minHeight: 44,
|
|
1848
|
+
justifyContent: "center"
|
|
1175
1849
|
},
|
|
1176
1850
|
assistantBubble: {
|
|
1177
1851
|
maxWidth: "88%",
|
|
@@ -1197,17 +1871,17 @@ var s = StyleSheet.create({
|
|
|
1197
1871
|
});
|
|
1198
1872
|
|
|
1199
1873
|
// src/components/MushiFloatingButton.tsx
|
|
1200
|
-
import { useRef as useRef2, useCallback as useCallback2, useEffect as
|
|
1874
|
+
import { useRef as useRef2, useCallback as useCallback2, useEffect as useEffect3 } from "react";
|
|
1201
1875
|
import {
|
|
1202
1876
|
Animated as Animated2,
|
|
1203
1877
|
PanResponder as PanResponder2,
|
|
1204
|
-
StyleSheet as
|
|
1878
|
+
StyleSheet as StyleSheet3,
|
|
1205
1879
|
Platform as Platform3,
|
|
1206
1880
|
Dimensions as Dimensions3,
|
|
1207
|
-
useColorScheme as
|
|
1881
|
+
useColorScheme as useColorScheme3
|
|
1208
1882
|
} from "react-native";
|
|
1209
1883
|
import { mushiPalette as mushiPalette2, MUSHI_COPY as MUSHI_COPY2, MUSHI_GEOMETRY } from "@mushi-mushi/core";
|
|
1210
|
-
import { jsx as
|
|
1884
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1211
1885
|
var FAB_SIZE = MUSHI_GEOMETRY.fabSize;
|
|
1212
1886
|
var EDGE_PADDING = 12;
|
|
1213
1887
|
function getScreenBounds() {
|
|
@@ -1242,7 +1916,7 @@ var MushiFloatingButton = ({
|
|
|
1242
1916
|
config,
|
|
1243
1917
|
accent
|
|
1244
1918
|
}) => {
|
|
1245
|
-
const scheme =
|
|
1919
|
+
const scheme = useColorScheme3();
|
|
1246
1920
|
const dark = scheme === "dark";
|
|
1247
1921
|
const draggable = config?.draggable ?? false;
|
|
1248
1922
|
const snapToEdge = config?.snapToEdge ?? true;
|
|
@@ -1260,7 +1934,7 @@ var MushiFloatingButton = ({
|
|
|
1260
1934
|
const isDragging = useRef2(false);
|
|
1261
1935
|
const pal = mushiPalette2(dark ? "dark" : "light");
|
|
1262
1936
|
const accentColor = accent ?? pal.accent;
|
|
1263
|
-
|
|
1937
|
+
useEffect3(() => {
|
|
1264
1938
|
if (!persist) return;
|
|
1265
1939
|
void loadStoredPos().then((pos) => {
|
|
1266
1940
|
if (!pos) return;
|
|
@@ -1352,12 +2026,12 @@ var MushiFloatingButton = ({
|
|
|
1352
2026
|
}).start();
|
|
1353
2027
|
if (!isDragging.current) onPress();
|
|
1354
2028
|
}, [scale, onPress]);
|
|
1355
|
-
return /* @__PURE__ */
|
|
2029
|
+
return /* @__PURE__ */ jsx3(
|
|
1356
2030
|
Animated2.View,
|
|
1357
2031
|
{
|
|
1358
2032
|
...draggable ? panResponder.panHandlers : {},
|
|
1359
2033
|
style: [
|
|
1360
|
-
|
|
2034
|
+
s3.fab,
|
|
1361
2035
|
{
|
|
1362
2036
|
left: posX,
|
|
1363
2037
|
bottom: Animated2.add(new Animated2.Value(baseBottom), Animated2.multiply(posY, -1)),
|
|
@@ -1369,11 +2043,11 @@ var MushiFloatingButton = ({
|
|
|
1369
2043
|
onStartShouldSetResponder: () => !draggable,
|
|
1370
2044
|
onResponderGrant: handlePressIn,
|
|
1371
2045
|
onResponderRelease: handlePressOut,
|
|
1372
|
-
children: /* @__PURE__ */
|
|
2046
|
+
children: /* @__PURE__ */ jsx3(Animated2.Text, { style: s3.emoji, children: MUSHI_COPY2.triggerText })
|
|
1373
2047
|
}
|
|
1374
2048
|
);
|
|
1375
2049
|
};
|
|
1376
|
-
var
|
|
2050
|
+
var s3 = StyleSheet3.create({
|
|
1377
2051
|
fab: {
|
|
1378
2052
|
position: "absolute",
|
|
1379
2053
|
width: FAB_SIZE,
|
|
@@ -1395,14 +2069,14 @@ var s2 = StyleSheet2.create({
|
|
|
1395
2069
|
// src/components/MushiBanner.tsx
|
|
1396
2070
|
import { useCallback as useCallback3 } from "react";
|
|
1397
2071
|
import {
|
|
1398
|
-
View as
|
|
1399
|
-
Text as
|
|
1400
|
-
TouchableOpacity as
|
|
1401
|
-
StyleSheet as
|
|
2072
|
+
View as View3,
|
|
2073
|
+
Text as Text3,
|
|
2074
|
+
TouchableOpacity as TouchableOpacity3,
|
|
2075
|
+
StyleSheet as StyleSheet4,
|
|
1402
2076
|
Platform as Platform4
|
|
1403
2077
|
} from "react-native";
|
|
1404
|
-
import { MUSHI_BANNER_NEON
|
|
1405
|
-
import { jsx as
|
|
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";
|
|
2079
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1406
2080
|
var MUSHI_BANNER_DEFAULT_HEIGHT = MUSHI_GEOMETRY2.bannerHeight;
|
|
1407
2081
|
var MushiBanner = ({
|
|
1408
2082
|
onPress,
|
|
@@ -1417,35 +2091,35 @@ var MushiBanner = ({
|
|
|
1417
2091
|
},
|
|
1418
2092
|
[onLayoutHeight]
|
|
1419
2093
|
);
|
|
1420
|
-
return /* @__PURE__ */
|
|
1421
|
-
|
|
2094
|
+
return /* @__PURE__ */ jsxs3(
|
|
2095
|
+
View3,
|
|
1422
2096
|
{
|
|
1423
|
-
style:
|
|
2097
|
+
style: s4.wrap,
|
|
1424
2098
|
onLayout: handleLayout,
|
|
1425
2099
|
accessibilityRole: "header",
|
|
1426
2100
|
accessibilityLabel: "Mushi feedback banner",
|
|
1427
2101
|
children: [
|
|
1428
|
-
/* @__PURE__ */
|
|
1429
|
-
/* @__PURE__ */
|
|
1430
|
-
/* @__PURE__ */
|
|
1431
|
-
/* @__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 })
|
|
1432
2106
|
] }),
|
|
1433
|
-
onDismiss ? /* @__PURE__ */
|
|
1434
|
-
|
|
2107
|
+
onDismiss ? /* @__PURE__ */ jsx4(
|
|
2108
|
+
TouchableOpacity3,
|
|
1435
2109
|
{
|
|
1436
|
-
style:
|
|
2110
|
+
style: s4.dismiss,
|
|
1437
2111
|
onPress: onDismiss,
|
|
1438
2112
|
accessibilityRole: "button",
|
|
1439
2113
|
accessibilityLabel: "Dismiss banner",
|
|
1440
2114
|
hitSlop: { top: 8, bottom: 8, left: 8, right: 8 },
|
|
1441
|
-
children: /* @__PURE__ */
|
|
2115
|
+
children: /* @__PURE__ */ jsx4(Text3, { style: s4.dismissText, children: "\xD7" })
|
|
1442
2116
|
}
|
|
1443
2117
|
) : null
|
|
1444
2118
|
]
|
|
1445
2119
|
}
|
|
1446
2120
|
);
|
|
1447
2121
|
};
|
|
1448
|
-
var
|
|
2122
|
+
var s4 = StyleSheet4.create({
|
|
1449
2123
|
wrap: {
|
|
1450
2124
|
position: "absolute",
|
|
1451
2125
|
left: 0,
|
|
@@ -1454,9 +2128,9 @@ var s3 = StyleSheet3.create({
|
|
|
1454
2128
|
minHeight: MUSHI_GEOMETRY2.bannerHeight,
|
|
1455
2129
|
flexDirection: "row",
|
|
1456
2130
|
alignItems: "stretch",
|
|
1457
|
-
backgroundColor:
|
|
2131
|
+
backgroundColor: MUSHI_BANNER_NEON.bg,
|
|
1458
2132
|
borderTopWidth: 1,
|
|
1459
|
-
borderTopColor:
|
|
2133
|
+
borderTopColor: MUSHI_BANNER_NEON.border,
|
|
1460
2134
|
zIndex: MUSHI_Z.banner,
|
|
1461
2135
|
elevation: 8,
|
|
1462
2136
|
paddingBottom: Platform4.OS === "ios" ? 0 : 0
|
|
@@ -1474,18 +2148,18 @@ var s3 = StyleSheet3.create({
|
|
|
1474
2148
|
fontSize: MUSHI_TYPE2.sizeLabel,
|
|
1475
2149
|
fontWeight: "700",
|
|
1476
2150
|
letterSpacing: 1.2,
|
|
1477
|
-
color:
|
|
2151
|
+
color: MUSHI_BANNER_NEON.fg
|
|
1478
2152
|
},
|
|
1479
2153
|
message: {
|
|
1480
2154
|
flex: 1,
|
|
1481
2155
|
fontSize: 12,
|
|
1482
2156
|
fontWeight: "500",
|
|
1483
|
-
color:
|
|
2157
|
+
color: MUSHI_BANNER_NEON.fg
|
|
1484
2158
|
},
|
|
1485
2159
|
cta: {
|
|
1486
2160
|
fontSize: 12,
|
|
1487
2161
|
fontWeight: "700",
|
|
1488
|
-
color:
|
|
2162
|
+
color: MUSHI_BANNER_NEON.fg,
|
|
1489
2163
|
textDecorationLine: "underline"
|
|
1490
2164
|
},
|
|
1491
2165
|
dismiss: {
|
|
@@ -1495,7 +2169,7 @@ var s3 = StyleSheet3.create({
|
|
|
1495
2169
|
dismissText: {
|
|
1496
2170
|
fontSize: 20,
|
|
1497
2171
|
lineHeight: 22,
|
|
1498
|
-
color:
|
|
2172
|
+
color: MUSHI_BANNER_NEON.fg,
|
|
1499
2173
|
opacity: 0.7
|
|
1500
2174
|
}
|
|
1501
2175
|
});
|
|
@@ -1825,10 +2499,10 @@ function createRNSessionTracker(opts) {
|
|
|
1825
2499
|
|
|
1826
2500
|
// src/version.ts
|
|
1827
2501
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/react-native";
|
|
1828
|
-
var MUSHI_SDK_VERSION = "0.
|
|
2502
|
+
var MUSHI_SDK_VERSION = "0.24.0" ? "0.24.0" : "0.17.0";
|
|
1829
2503
|
|
|
1830
2504
|
// src/provider.tsx
|
|
1831
|
-
import { jsx as
|
|
2505
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1832
2506
|
var MushiContext = createContext(null);
|
|
1833
2507
|
function nativeUserAgent() {
|
|
1834
2508
|
const os = Platform5?.OS ?? "native";
|
|
@@ -1905,7 +2579,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1905
2579
|
console.warn("[MushiProvider] `endpoint` is deprecated \u2014 use `apiEndpoint` instead.");
|
|
1906
2580
|
}
|
|
1907
2581
|
const apiEndpoint = rawEndpoint ?? DEFAULT_API_ENDPOINT;
|
|
1908
|
-
|
|
2582
|
+
useEffect4(() => {
|
|
1909
2583
|
if (config.capture?.console !== false) {
|
|
1910
2584
|
consoleRef.current = setupConsoleCapture(config.capture?.maxConsoleEntries);
|
|
1911
2585
|
}
|
|
@@ -1967,11 +2641,10 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1967
2641
|
networkRef.current?.restore();
|
|
1968
2642
|
};
|
|
1969
2643
|
}, []);
|
|
1970
|
-
|
|
2644
|
+
useEffect4(() => {
|
|
1971
2645
|
let unsubscribe;
|
|
1972
2646
|
try {
|
|
1973
|
-
|
|
1974
|
-
unsubscribe = NetInfo.addEventListener((state) => {
|
|
2647
|
+
unsubscribe = resolveNetInfo(config.netInfo)?.addEventListener((state) => {
|
|
1975
2648
|
if (state.isConnected && state.isInternetReachable) {
|
|
1976
2649
|
queueRef.current?.flush().catch(() => {
|
|
1977
2650
|
});
|
|
@@ -1980,7 +2653,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1980
2653
|
} catch {
|
|
1981
2654
|
}
|
|
1982
2655
|
return () => unsubscribe?.();
|
|
1983
|
-
}, []);
|
|
2656
|
+
}, [config.netInfo]);
|
|
1984
2657
|
const open = useCallback4(() => {
|
|
1985
2658
|
setSheetPreferredTab("report");
|
|
1986
2659
|
breadcrumbsRef.current.add({
|
|
@@ -1994,11 +2667,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
1994
2667
|
setSheetVisible(true);
|
|
1995
2668
|
return;
|
|
1996
2669
|
}
|
|
1997
|
-
|
|
1998
|
-
try {
|
|
1999
|
-
vshot = __require("react-native-view-shot");
|
|
2000
|
-
} catch {
|
|
2001
|
-
}
|
|
2670
|
+
const vshot = resolveViewShot(config.viewShot);
|
|
2002
2671
|
if (!vshot) {
|
|
2003
2672
|
setSheetScreenshot(null);
|
|
2004
2673
|
setSheetVisible(true);
|
|
@@ -2011,7 +2680,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2011
2680
|
}).finally(() => {
|
|
2012
2681
|
setSheetVisible(true);
|
|
2013
2682
|
});
|
|
2014
|
-
}, [config.capture?.screenshot]);
|
|
2683
|
+
}, [config.capture?.screenshot, config.viewShot]);
|
|
2015
2684
|
const openAssistant = useCallback4(() => {
|
|
2016
2685
|
if (!config.assistant?.enabled) return;
|
|
2017
2686
|
setSheetPreferredTab("assistant");
|
|
@@ -2020,7 +2689,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2020
2689
|
}, [config.assistant?.enabled]);
|
|
2021
2690
|
const close = useCallback4(() => setSheetVisible(false), []);
|
|
2022
2691
|
const attachTo = useCallback4(() => ({ onPress: open }), [open]);
|
|
2023
|
-
|
|
2692
|
+
useEffect4(() => {
|
|
2024
2693
|
const trigger2 = config.widget?.trigger ?? "button";
|
|
2025
2694
|
if (trigger2 !== "shake" && trigger2 !== "both") return;
|
|
2026
2695
|
let disposed = false;
|
|
@@ -2028,8 +2697,8 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2028
2697
|
let lastShake = 0;
|
|
2029
2698
|
const threshold = config.widget?.shakeThreshold ?? 2.7;
|
|
2030
2699
|
try {
|
|
2031
|
-
const mod =
|
|
2032
|
-
if (!disposed) {
|
|
2700
|
+
const mod = resolveExpoSensors(config.expoSensors);
|
|
2701
|
+
if (mod && !disposed) {
|
|
2033
2702
|
mod.Accelerometer.setUpdateInterval(120);
|
|
2034
2703
|
const sub = mod.Accelerometer.addListener((evt) => {
|
|
2035
2704
|
const g = Math.sqrt(evt.x * evt.x + evt.y * evt.y + evt.z * evt.z);
|
|
@@ -2047,7 +2716,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2047
2716
|
disposed = true;
|
|
2048
2717
|
cleanup?.();
|
|
2049
2718
|
};
|
|
2050
|
-
}, [config.widget?.trigger, config.widget?.shakeThreshold, open]);
|
|
2719
|
+
}, [config.widget?.trigger, config.widget?.shakeThreshold, config.expoSensors, open]);
|
|
2051
2720
|
const submitReport = useCallback4(
|
|
2052
2721
|
async (data) => {
|
|
2053
2722
|
await reporterTokenReadyRef.current;
|
|
@@ -2088,6 +2757,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2088
2757
|
id: newUuid2(),
|
|
2089
2758
|
projectId: config.projectId,
|
|
2090
2759
|
category: data.category,
|
|
2760
|
+
...data.userCategory ? { userCategory: data.userCategory } : {},
|
|
2091
2761
|
description: scrubPii3(data.description),
|
|
2092
2762
|
environment: {
|
|
2093
2763
|
userAgent: deviceInfo.systemName ?? "ReactNative",
|
|
@@ -2147,6 +2817,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2147
2817
|
};
|
|
2148
2818
|
} else {
|
|
2149
2819
|
config.callbacks?.onReportSubmitted?.(report.id);
|
|
2820
|
+
void writeReporterFlag(config.projectId, "has_reports", "1");
|
|
2150
2821
|
return { ok: true };
|
|
2151
2822
|
}
|
|
2152
2823
|
},
|
|
@@ -2157,7 +2828,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2157
2828
|
const screenRef = useRef3(null);
|
|
2158
2829
|
const activityQueueRef = useRef3([]);
|
|
2159
2830
|
const rewardsFlushRef = useRef3(null);
|
|
2160
|
-
|
|
2831
|
+
useEffect4(() => {
|
|
2161
2832
|
const rewards = config.rewards;
|
|
2162
2833
|
if (!rewards?.enabled || !rewards.trackActivity) return;
|
|
2163
2834
|
const flushMs = Math.max(3e4, rewards.flushIntervalMs ?? 3e5);
|
|
@@ -2179,7 +2850,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2179
2850
|
}, [config.rewards?.enabled, config.rewards?.trackActivity, config.rewards?.flushIntervalMs]);
|
|
2180
2851
|
const eventTrackerRef = useRef3(null);
|
|
2181
2852
|
const sessionTrackerRef = useRef3(null);
|
|
2182
|
-
|
|
2853
|
+
useEffect4(() => {
|
|
2183
2854
|
const getRoute = () => screenRef.current?.route ?? screenRef.current?.name ?? null;
|
|
2184
2855
|
const tracker = createRNEventTracker({
|
|
2185
2856
|
projectId: config.projectId,
|
|
@@ -2234,6 +2905,70 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2234
2905
|
config.analytics?.flushIntervalMs,
|
|
2235
2906
|
config.trackSessions
|
|
2236
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
|
+
}, []);
|
|
2237
2972
|
const instance = useMemo(
|
|
2238
2973
|
() => ({
|
|
2239
2974
|
open,
|
|
@@ -2320,6 +3055,54 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2320
3055
|
const res = await client.listReporterComments(reportId, reporterTokenRef.current);
|
|
2321
3056
|
return res.ok ? res.data.comments ?? [] : [];
|
|
2322
3057
|
},
|
|
3058
|
+
async loadMyThread(reportId) {
|
|
3059
|
+
const client = apiClientRef.current;
|
|
3060
|
+
if (!client) return null;
|
|
3061
|
+
try {
|
|
3062
|
+
await reporterTokenReadyRef.current;
|
|
3063
|
+
const res = await client.listReporterComments(reportId, reporterTokenRef.current);
|
|
3064
|
+
return res.ok ? res.data?.comments ?? [] : null;
|
|
3065
|
+
} catch {
|
|
3066
|
+
return null;
|
|
3067
|
+
}
|
|
3068
|
+
},
|
|
3069
|
+
async markReportRead(reportId) {
|
|
3070
|
+
const client = apiClientRef.current;
|
|
3071
|
+
if (!client) return 0;
|
|
3072
|
+
await reporterTokenReadyRef.current;
|
|
3073
|
+
return markReporterReportRead(client, reporterTokenRef.current, reportId);
|
|
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
|
+
},
|
|
2323
3106
|
async replyToReport(reportId, body) {
|
|
2324
3107
|
const client = apiClientRef.current;
|
|
2325
3108
|
if (!client) return null;
|
|
@@ -2390,14 +3173,14 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2390
3173
|
return res.ok ? res.data : null;
|
|
2391
3174
|
}
|
|
2392
3175
|
}),
|
|
2393
|
-
[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]
|
|
2394
3177
|
);
|
|
2395
3178
|
const trigger = config.widget?.trigger ?? "button";
|
|
2396
3179
|
const showBanner = trigger === "banner" && !bannerDismissed;
|
|
2397
3180
|
const showFab = !showBanner && (trigger === "button" || trigger === "both" || trigger === "auto" || trigger === "edge-tab");
|
|
2398
|
-
return /* @__PURE__ */
|
|
3181
|
+
return /* @__PURE__ */ jsxs4(MushiContext.Provider, { value: instance, children: [
|
|
2399
3182
|
children,
|
|
2400
|
-
showBanner ? /* @__PURE__ */
|
|
3183
|
+
showBanner ? /* @__PURE__ */ jsx5(
|
|
2401
3184
|
MushiBanner,
|
|
2402
3185
|
{
|
|
2403
3186
|
onPress: open,
|
|
@@ -2406,7 +3189,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2406
3189
|
label: config.widget?.banner?.label
|
|
2407
3190
|
}
|
|
2408
3191
|
) : null,
|
|
2409
|
-
showFab && /* @__PURE__ */
|
|
3192
|
+
showFab && /* @__PURE__ */ jsx5(
|
|
2410
3193
|
MushiFloatingButton,
|
|
2411
3194
|
{
|
|
2412
3195
|
onPress: open,
|
|
@@ -2414,7 +3197,7 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2414
3197
|
inset: config.widget?.inset
|
|
2415
3198
|
}
|
|
2416
3199
|
),
|
|
2417
|
-
/* @__PURE__ */
|
|
3200
|
+
/* @__PURE__ */ jsx5(
|
|
2418
3201
|
MushiBottomSheet,
|
|
2419
3202
|
{
|
|
2420
3203
|
visible: sheetVisible,
|
|
@@ -2427,9 +3210,21 @@ function MushiProvider({ children, config: configProp, ...barePropConfig }) {
|
|
|
2427
3210
|
assistantLabel: config.assistant?.label,
|
|
2428
3211
|
assistantGreeting: config.assistant?.greeting,
|
|
2429
3212
|
assistantSuggestions: config.assistant?.suggestions,
|
|
2430
|
-
inboxPollIntervalMs: config.widget?.inboxPollIntervalMs ?? 0
|
|
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),
|
|
3225
|
+
theme: config.widget?.theme
|
|
2431
3226
|
}
|
|
2432
|
-
)
|
|
3227
|
+
) : null
|
|
2433
3228
|
] });
|
|
2434
3229
|
}
|
|
2435
3230
|
function useMushiContext() {
|
|
@@ -2480,10 +3275,10 @@ function MushiTrigger({ children }) {
|
|
|
2480
3275
|
}
|
|
2481
3276
|
|
|
2482
3277
|
// src/capture/navigation-capture.ts
|
|
2483
|
-
import { useEffect as
|
|
3278
|
+
import { useEffect as useEffect5, useRef as useRef4 } from "react";
|
|
2484
3279
|
function useNavigationCapture(navigationRef) {
|
|
2485
3280
|
const historyRef = useRef4([]);
|
|
2486
|
-
|
|
3281
|
+
useEffect5(() => {
|
|
2487
3282
|
if (!navigationRef?.addListener || !navigationRef?.getCurrentRoute) return;
|
|
2488
3283
|
const unsubscribe = navigationRef.addListener("state", () => {
|
|
2489
3284
|
const route = navigationRef.getCurrentRoute?.();
|