docfast-support: add needs-reply command, prevent duplicate replies
This commit is contained in:
parent
5cce30d31c
commit
5dc184a33b
3 changed files with 61 additions and 1 deletions
|
|
@ -146,6 +146,44 @@ async function cmdReply(args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function cmdNeedsReply(args) {
|
||||||
|
// Show only tickets where the last non-note thread is from a customer (needs agent reply)
|
||||||
|
const page = getFlag(args, '--page') || '1';
|
||||||
|
let endpoint = `/conversations?page=${page}&status=active`;
|
||||||
|
if (MAILBOX_ID) endpoint += `&mailboxId=${MAILBOX_ID}`;
|
||||||
|
|
||||||
|
const res = await apiRequest('GET', endpoint);
|
||||||
|
if (res.status !== 200) { console.error('Error:', res.status, JSON.stringify(res.data)); process.exit(1); }
|
||||||
|
|
||||||
|
const conversations = res.data._embedded?.conversations || [];
|
||||||
|
if (conversations.length === 0) { console.log('No tickets need a reply.'); return; }
|
||||||
|
|
||||||
|
const needsReply = [];
|
||||||
|
for (const c of conversations) {
|
||||||
|
const tRes = await apiRequest('GET', `/conversations/${c.id}/threads`);
|
||||||
|
if (tRes.status !== 200) continue;
|
||||||
|
const threads = (tRes.data._embedded?.threads || [])
|
||||||
|
.filter(t => t.type !== 'note') // ignore internal notes
|
||||||
|
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
||||||
|
if (threads.length === 0) continue;
|
||||||
|
const lastThread = threads[0];
|
||||||
|
// type 'customer' = from customer, 'message' = from agent
|
||||||
|
if (lastThread.type === 'customer') {
|
||||||
|
needsReply.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsReply.length === 0) { console.log('No tickets need a reply.'); return; }
|
||||||
|
|
||||||
|
console.log('ID\tSUBJECT\tCUSTOMER\tCREATED');
|
||||||
|
for (const c of needsReply) {
|
||||||
|
const customer = c.customer?.email || c.customer?.firstName || 'unknown';
|
||||||
|
const created = c.createdAt?.split('T')[0] || '-';
|
||||||
|
console.log(`${c.id}\t${c.subject}\t${customer}\t${created}`);
|
||||||
|
}
|
||||||
|
console.log(`\n${needsReply.length} ticket(s) need a reply.`);
|
||||||
|
}
|
||||||
|
|
||||||
async function cmdClose(args) {
|
async function cmdClose(args) {
|
||||||
const id = args[0];
|
const id = args[0];
|
||||||
if (!id) { console.error('Usage: docfast-support close <ticket-id>'); process.exit(1); }
|
if (!id) { console.error('Usage: docfast-support close <ticket-id>'); process.exit(1); }
|
||||||
|
|
@ -195,6 +233,7 @@ const [cmd, ...args] = process.argv.slice(2);
|
||||||
|
|
||||||
const commands = {
|
const commands = {
|
||||||
tickets: cmdTickets,
|
tickets: cmdTickets,
|
||||||
|
'needs-reply': cmdNeedsReply,
|
||||||
view: cmdView,
|
view: cmdView,
|
||||||
reply: cmdReply,
|
reply: cmdReply,
|
||||||
close: cmdClose,
|
close: cmdClose,
|
||||||
|
|
@ -209,6 +248,7 @@ Usage: docfast-support <command> [args]
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
tickets [--status active|pending|closed|spam] List tickets (default: active)
|
tickets [--status active|pending|closed|spam] List tickets (default: active)
|
||||||
|
needs-reply Tickets waiting for agent reply
|
||||||
view <ticket-id> View ticket with all messages
|
view <ticket-id> View ticket with all messages
|
||||||
reply --ticket <id> --message "..." Send reply to customer
|
reply --ticket <id> --message "..." Send reply to customer
|
||||||
[--draft] Save as internal note instead
|
[--draft] Save as internal note instead
|
||||||
|
|
|
||||||
20
projects/business/memory/support-log.md
Normal file
20
projects/business/memory/support-log.md
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# DocFast Support Log
|
||||||
|
|
||||||
|
## 2026-02-16 20:17 UTC
|
||||||
|
|
||||||
|
**Ticket #369** - Lost API key
|
||||||
|
- Customer: dominik@superbros.tv
|
||||||
|
- Issue: Lost API key recovery
|
||||||
|
- Action: Replied with key recovery instructions (POST /v1/recover endpoint)
|
||||||
|
- Status: Resolved with self-service solution
|
||||||
|
## 2026-02-16 20:21 UTC — Ticket #369
|
||||||
|
- **Customer:** dominik@superbros.tv
|
||||||
|
- **Subject:** Lost API key
|
||||||
|
- **Action:** Replied with self-service recovery instructions (website link + API endpoint)
|
||||||
|
- **Status:** Replied, awaiting customer confirmation
|
||||||
|
|
||||||
|
## 2026-02-16 20:24 UTC
|
||||||
|
- **Ticket #369** (dominik@superbros.tv): Lost API key → Replied with recovery flow instructions. Simple case.
|
||||||
|
|
||||||
|
## 2026-02-16 20:27 UTC
|
||||||
|
- **Ticket #369** (dominik@superbros.tv): Lost API key → Replied with recovery flow instructions. Straightforward.
|
||||||
|
|
@ -1 +1 @@
|
||||||
FAIL
|
OK
|
||||||
Loading…
Add table
Add a link
Reference in a new issue