@tmls-ai/support 0.1.3 → 0.1.5
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/dist/index.js +40 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -106,6 +106,16 @@ var SEVERITIES = [
|
|
|
106
106
|
{ id: "annoying", label: "Annoying" },
|
|
107
107
|
{ id: "minor", label: "Minor" }
|
|
108
108
|
];
|
|
109
|
+
var deeplinkTicket = (() => {
|
|
110
|
+
if (typeof window === "undefined") return null;
|
|
111
|
+
const params = new URLSearchParams(window.location.search);
|
|
112
|
+
const tn = params.get("support");
|
|
113
|
+
if (!tn) return null;
|
|
114
|
+
params.delete("support");
|
|
115
|
+
const qs = params.toString();
|
|
116
|
+
window.history.replaceState({}, "", window.location.pathname + (qs ? `?${qs}` : "") + window.location.hash);
|
|
117
|
+
return tn;
|
|
118
|
+
})();
|
|
109
119
|
function SupportWidget(props) {
|
|
110
120
|
const { productId, apiUrl, getToken, accent = "#0a84ff", getContext, appVersion } = props;
|
|
111
121
|
const api = useMemo(() => new SupportApi(apiUrl, getToken), [apiUrl, getToken]);
|
|
@@ -116,6 +126,7 @@ function SupportWidget(props) {
|
|
|
116
126
|
const [message, setMessage] = useState("");
|
|
117
127
|
const [withShot, setWithShot] = useState(true);
|
|
118
128
|
const [shotPreview, setShotPreview] = useState(null);
|
|
129
|
+
const [capturing, setCapturing] = useState(false);
|
|
119
130
|
const [sending, setSending] = useState(false);
|
|
120
131
|
const [lastTicket, setLastTicket] = useState(null);
|
|
121
132
|
const [threads, setThreads] = useState([]);
|
|
@@ -128,9 +139,15 @@ function SupportWidget(props) {
|
|
|
128
139
|
installErrorCapture();
|
|
129
140
|
}, []);
|
|
130
141
|
const captureShot = useCallback(async () => {
|
|
142
|
+
setCapturing(true);
|
|
143
|
+
await new Promise((resolve) => {
|
|
144
|
+
const ric = window.requestIdleCallback;
|
|
145
|
+
if (ric) ric(() => resolve(), { timeout: 600 });
|
|
146
|
+
else setTimeout(resolve, 150);
|
|
147
|
+
});
|
|
131
148
|
try {
|
|
132
149
|
const root = document.documentElement;
|
|
133
|
-
const
|
|
150
|
+
const shoot = () => domToBlob(root, {
|
|
134
151
|
quality: 0.8,
|
|
135
152
|
scale: 0.75,
|
|
136
153
|
width: root.clientWidth || window.innerWidth,
|
|
@@ -140,9 +157,16 @@ function SupportWidget(props) {
|
|
|
140
157
|
features: { restoreScrollPosition: true },
|
|
141
158
|
filter: (node) => !(node instanceof HTMLElement && node.dataset.tmlsSupportRoot === "true")
|
|
142
159
|
});
|
|
160
|
+
let blob = await shoot();
|
|
161
|
+
if (blob.size < 1024) {
|
|
162
|
+
await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));
|
|
163
|
+
blob = await shoot();
|
|
164
|
+
}
|
|
143
165
|
setShotPreview(URL.createObjectURL(blob));
|
|
144
166
|
captureShot._blob = blob;
|
|
145
167
|
} catch {
|
|
168
|
+
} finally {
|
|
169
|
+
setCapturing(false);
|
|
146
170
|
}
|
|
147
171
|
}, []);
|
|
148
172
|
const submit = useCallback(async () => {
|
|
@@ -150,6 +174,7 @@ function SupportWidget(props) {
|
|
|
150
174
|
setSending(true);
|
|
151
175
|
try {
|
|
152
176
|
let attachmentKeys = [];
|
|
177
|
+
if (withShot && !captureShot._blob) await captureShot();
|
|
153
178
|
const blob = withShot ? captureShot._blob : void 0;
|
|
154
179
|
if (blob) {
|
|
155
180
|
try {
|
|
@@ -204,6 +229,18 @@ function SupportWidget(props) {
|
|
|
204
229
|
setMessages(detail.messages);
|
|
205
230
|
}
|
|
206
231
|
}, [api, reply, activeId]);
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
if (!deeplinkTicket) return;
|
|
234
|
+
const tn = deeplinkTicket;
|
|
235
|
+
(async () => {
|
|
236
|
+
setOpen(true);
|
|
237
|
+
const convos = await api.listConversations();
|
|
238
|
+
setThreads(convos);
|
|
239
|
+
const match = convos.find((c) => String(c.ticket_number) === tn);
|
|
240
|
+
if (match) await openThread(match.id);
|
|
241
|
+
else setView("threads");
|
|
242
|
+
})();
|
|
243
|
+
}, [api, openThread]);
|
|
207
244
|
const chip = (active) => ({
|
|
208
245
|
padding: "6px 12px",
|
|
209
246
|
borderRadius: 999,
|
|
@@ -259,6 +296,7 @@ function SupportWidget(props) {
|
|
|
259
296
|
} }),
|
|
260
297
|
"Attach a screenshot"
|
|
261
298
|
] }),
|
|
299
|
+
withShot && capturing && !shotPreview && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#8a8a92", padding: "10px 0", textAlign: "center" }, children: "Capturing screenshot\u2026" }),
|
|
262
300
|
shotPreview && /* @__PURE__ */ jsx("img", { src: shotPreview, alt: "", style: { width: "100%", borderRadius: 8, border: "0.5px solid #3a3a42" } }),
|
|
263
301
|
/* @__PURE__ */ jsx("button", { onClick: submit, disabled: !message.trim() || sending, style: { ...primary(accent), opacity: !message.trim() || sending ? 0.5 : 1 }, children: sending ? "Sending\u2026" : "Send report" })
|
|
264
302
|
] }),
|
|
@@ -328,6 +366,7 @@ function SupportWidget(props) {
|
|
|
328
366
|
"button",
|
|
329
367
|
{
|
|
330
368
|
onClick: () => {
|
|
369
|
+
if (open) deeplinkTicket = null;
|
|
331
370
|
setOpen((o) => !o);
|
|
332
371
|
if (!open && withShot) captureShot();
|
|
333
372
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tmls-ai/support",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Embeddable Timeless support widget — bottom-right report overlay (type / severity / screenshot) + ticket thread. Auto-captures context, talks to tmls-support-api.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|