@tmls-ai/support 0.1.1 → 0.1.2
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 +50 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -75,6 +75,16 @@ var SupportApi = class {
|
|
|
75
75
|
const res = await fetch(`${this.apiUrl}/v1/conversations/${conversationId}/messages`, { headers: await this.auth() });
|
|
76
76
|
return res.ok ? res.json() : [];
|
|
77
77
|
}
|
|
78
|
+
/** Full thread: meta (type/severity/status) + messages + attachments. */
|
|
79
|
+
async getConversation(conversationId) {
|
|
80
|
+
const res = await fetch(`${this.apiUrl}/v1/conversations/${conversationId}`, { headers: await this.auth() });
|
|
81
|
+
return res.ok ? res.json() : null;
|
|
82
|
+
}
|
|
83
|
+
/** Fetch a screenshot the user owns; returns an object URL (auth header can't ride an <img src>). */
|
|
84
|
+
async getScreenshot(r2Key) {
|
|
85
|
+
const res = await fetch(`${this.apiUrl}/v1/screenshots/${r2Key}`, { headers: await this.auth() });
|
|
86
|
+
return res.ok ? URL.createObjectURL(await res.blob()) : null;
|
|
87
|
+
}
|
|
78
88
|
async reply(conversationId, body) {
|
|
79
89
|
await fetch(`${this.apiUrl}/v1/conversations/${conversationId}/messages`, {
|
|
80
90
|
method: "POST",
|
|
@@ -110,7 +120,9 @@ function SupportWidget(props) {
|
|
|
110
120
|
const [lastTicket, setLastTicket] = useState(null);
|
|
111
121
|
const [threads, setThreads] = useState([]);
|
|
112
122
|
const [activeId, setActiveId] = useState(null);
|
|
123
|
+
const [activeConvo, setActiveConvo] = useState(null);
|
|
113
124
|
const [messages, setMessages] = useState([]);
|
|
125
|
+
const [shotUrls, setShotUrls] = useState({});
|
|
114
126
|
const [reply, setReply] = useState("");
|
|
115
127
|
useEffect(() => {
|
|
116
128
|
installErrorCapture();
|
|
@@ -166,14 +178,28 @@ function SupportWidget(props) {
|
|
|
166
178
|
}, [api]);
|
|
167
179
|
const openThread = useCallback(async (id) => {
|
|
168
180
|
setActiveId(id);
|
|
169
|
-
|
|
181
|
+
setActiveConvo(null);
|
|
182
|
+
setMessages([]);
|
|
183
|
+
setShotUrls({});
|
|
170
184
|
setView("thread");
|
|
185
|
+
const detail = await api.getConversation(id);
|
|
186
|
+
if (!detail) return;
|
|
187
|
+
setActiveConvo(detail);
|
|
188
|
+
setMessages(detail.messages);
|
|
189
|
+
for (const att of detail.attachments) {
|
|
190
|
+
const url = await api.getScreenshot(att.r2_key);
|
|
191
|
+
if (url) setShotUrls((prev) => ({ ...prev, [att.r2_key]: url }));
|
|
192
|
+
}
|
|
171
193
|
}, [api]);
|
|
172
194
|
const sendReply = useCallback(async () => {
|
|
173
195
|
if (!reply.trim() || !activeId) return;
|
|
174
196
|
await api.reply(activeId, reply.trim());
|
|
175
197
|
setReply("");
|
|
176
|
-
|
|
198
|
+
const detail = await api.getConversation(activeId);
|
|
199
|
+
if (detail) {
|
|
200
|
+
setActiveConvo(detail);
|
|
201
|
+
setMessages(detail.messages);
|
|
202
|
+
}
|
|
177
203
|
}, [api, reply, activeId]);
|
|
178
204
|
const chip = (active) => ({
|
|
179
205
|
padding: "6px 12px",
|
|
@@ -260,6 +286,15 @@ function SupportWidget(props) {
|
|
|
260
286
|
] }, t.id))
|
|
261
287
|
] }),
|
|
262
288
|
view === "thread" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: [
|
|
289
|
+
activeConvo && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", paddingBottom: 8, borderBottom: "0.5px solid rgba(255,255,255,0.08)" }, children: [
|
|
290
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: 13, fontWeight: 600 }, children: [
|
|
291
|
+
"#",
|
|
292
|
+
activeConvo.ticket_number
|
|
293
|
+
] }),
|
|
294
|
+
/* @__PURE__ */ jsx("span", { style: metaPill("#c8c8d0"), children: activeConvo.type }),
|
|
295
|
+
/* @__PURE__ */ jsx("span", { style: metaPill(SEV_COLOR[activeConvo.severity]), children: activeConvo.severity }),
|
|
296
|
+
/* @__PURE__ */ jsx("span", { style: metaPill(activeConvo.status === "resolved" ? "#30d158" : accent), children: activeConvo.status })
|
|
297
|
+
] }),
|
|
263
298
|
messages.map((m) => /* @__PURE__ */ jsx("div", { style: {
|
|
264
299
|
alignSelf: m.author === "user" ? "flex-end" : "flex-start",
|
|
265
300
|
maxWidth: "85%",
|
|
@@ -269,6 +304,7 @@ function SupportWidget(props) {
|
|
|
269
304
|
borderRadius: 12,
|
|
270
305
|
fontSize: 13
|
|
271
306
|
}, children: m.body }, m.id)),
|
|
307
|
+
activeConvo?.attachments.map((att) => shotUrls[att.r2_key] ? /* @__PURE__ */ jsx("a", { href: shotUrls[att.r2_key], target: "_blank", rel: "noreferrer", style: { display: "block" }, children: /* @__PURE__ */ jsx("img", { src: shotUrls[att.r2_key], alt: "Attached screenshot", style: { width: "100%", borderRadius: 8, border: "0.5px solid #3a3a42" } }) }, att.id) : /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "#8a8a92" }, children: "Loading screenshot\u2026" }, att.id)),
|
|
272
308
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
273
309
|
/* @__PURE__ */ jsx(
|
|
274
310
|
"input",
|
|
@@ -327,6 +363,18 @@ var primary = (accent) => ({
|
|
|
327
363
|
fontWeight: 600,
|
|
328
364
|
cursor: "pointer"
|
|
329
365
|
});
|
|
366
|
+
var SEV_COLOR = { blocking: "#ff453a", annoying: "#ff9f0a", minor: "#8e8e93" };
|
|
367
|
+
var metaPill = (color) => ({
|
|
368
|
+
padding: "1px 8px",
|
|
369
|
+
borderRadius: 100,
|
|
370
|
+
fontSize: 10.5,
|
|
371
|
+
fontWeight: 700,
|
|
372
|
+
textTransform: "uppercase",
|
|
373
|
+
letterSpacing: "0.03em",
|
|
374
|
+
color,
|
|
375
|
+
border: `1px solid ${color}55`,
|
|
376
|
+
background: "transparent"
|
|
377
|
+
});
|
|
330
378
|
|
|
331
379
|
// src/index.ts
|
|
332
380
|
function mountSupportWidget(props) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tmls-ai/support",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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",
|