Support Inbox Admin

← Dashboard
function getCookie(n){for(var c=document.cookie.split(";"),i=0;i/g,'>').replace(/"/g,'"'); } function timeAgo(dateStr) { var d = new Date(dateStr); var diff = Date.now() - d.getTime(); var mins = Math.floor(diff / 60000); if (mins < 1) return 'just now'; if (mins < 60) return mins + 'm ago'; var hrs = Math.floor(mins / 60); if (hrs < 24) return hrs + 'h ago'; var days = Math.floor(hrs / 24); if (days < 30) return days + 'd ago'; return d.toLocaleDateString(); } var categoryLabels = { billing: ' Billing', account: ' Account', bug: ' Bug Report', escalation_request: ' Human Requested', feature: ' Feature Request', other: ' General' }; function buildTicketCard(ticket) { var div = document.createElement('div'); div.className = 'ticket-card status-' + (ticket.status || 'open'); div.dataset.id = ticket.id; var sourceLabel = ticket.source === 'ai_chat' ? ' AI Chat' : ' Direct'; var sourcePill = ticket.source === 'ai_chat' ? 'pill-source-ai' : 'pill-source-direct'; var catLabel = categoryLabels[ticket.issue_category] || ticket.issue_category || 'General'; var tierPill = (ticket.subscription_tier && ticket.subscription_tier !== 'free') ? 'pill-tier-pro' : 'pill-tier-free'; var tierLabel = ticket.subscription_tier || 'free'; var statusPill = 'pill-status-' + (ticket.status || 'open'); var statusLabel = (ticket.status || 'open').replace('_', ' '); var displayName = ticket.user_display_name || ticket.user_name || ''; var adminNoteHtml = ticket.admin_notes ? '
' + esc(ticket.admin_notes) + '
' : ''; // Transcript var transcriptHtml = ''; var msgs = []; try { msgs = typeof ticket.conversation_transcript === 'string' ? JSON.parse(ticket.conversation_transcript) : (ticket.conversation_transcript || []); } catch(_) {} if (msgs.length > 0) { var msgHtml = msgs.map(function (m) { return '
' + esc(m.role) + '
' + esc(m.content || '') + '
'; }).join(''); transcriptHtml = '' + '
' + msgHtml + '
'; } div.innerHTML = '
' + '
' + (displayName ? '
' + esc(displayName) + '
' : '') + '
' + esc(ticket.user_email || 'Unknown user') + '
' + '
' + '
' + timeAgo(ticket.created_at) + '
' + '
' + '
' + '' + sourceLabel + '' + '' + esc(catLabel) + '' + '' + esc(tierLabel) + '' + '' + esc(statusLabel) + '' + '
' + '
' + esc(ticket.message) + '
' + transcriptHtml + adminNoteHtml + '
' + '' + '' + '' + '' + 'Saved ' + '
'; return div; } // ── Toggle transcript ─────────────────────────────────────────────────── window.toggleTranscript = function (btn) { var body = btn.nextElementSibling; if (!body) return; var isOpen = body.classList.contains('open'); body.classList.toggle('open', !isOpen); btn.textContent = isOpen ? btn.textContent.replace('Hide', 'View') : btn.textContent.replace('View', 'Hide'); }; // ── Update ticket ─────────────────────────────────────────────────────── window.updateTicket = function (btn) { var card = btn.closest('.ticket-card'); var id = card.dataset.id; var status = card.querySelector('.status-select').value; var notes = card.querySelector('.ticket-notes-input').value; var flash = card.querySelector('.saved-flash'); btn.textContent = 'Saving…'; btn.disabled = true; fetch('/api/admin/support-tickets/' + id, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ status: status, admin_notes: notes }) }) .then(function (r) { return r.json(); }) .then(function (d) { btn.textContent = 'Save'; btn.disabled = false; if (d.success) { // Update local data var t = allTickets.find(function (t) { return t.id == id; }); if (t) { t.status = status; t.admin_notes = notes; } // Update card class card.className = card.className.replace(/status-\S+/, 'status-' + status); if (flash) { flash.classList.add('show'); setTimeout(function () { flash.classList.remove('show'); }, 2000); } } }) .catch(function () { btn.textContent = 'Save'; btn.disabled = false; }); }; // ── Delete ticket ───────────────────────────────────────────────────── window.deleteTicket = function (btn) { if (!await confirmSheet('Delete this support ticket?', { danger: true, confirmLabel: 'Delete', icon: '' })) return; var card = btn.closest('.ticket-card'); var id = card.dataset.id; fetch('/api/admin/support-tickets/' + id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token } }) .then(function (r) { return r.json(); }) .then(function (d) { if (d.success) { allTickets = allTickets.filter(function (t) { return t.id != id; }); card.style.opacity = '0'; card.style.transition = 'opacity 0.3s'; setTimeout(function () { card.remove(); }, 300); } }) .catch(function () {}); }; })();