/** * Admin Panel Logic - Payment Verification + Complaint Tickets * Aadhaar Pro */ // ── State ────────────────────────────────────────────────────────── let _allTickets = []; let _activeFilter = 'all'; let _activeTicketId = null; // ── Init ─────────────────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { loadTransactions(); loadTickets(); // preload so badge count shows on page load // If URL hash is #support, switch tab automatically if (window.location.hash === '#support') switchTab('support'); }); // ══════════════════════════════════════════════════════════════════ // TAB SWITCHING // ══════════════════════════════════════════════════════════════════ function switchTab(tab) { // Update tab buttons document.querySelectorAll('.admin-tab-btn').forEach(b => b.classList.remove('active')); document.getElementById(`tab-btn-${tab}`)?.classList.add('active'); // Show/hide sections document.querySelectorAll('.admin-section').forEach(s => s.classList.remove('active')); document.getElementById(`section-${tab}`)?.classList.add('active'); // Update breadcrumb const labels = { payments: 'Payment Queue', support: 'Complaints' }; const bc = document.getElementById('breadcrumb-active'); if (bc) bc.textContent = labels[tab] || tab; // Load data for the activated tab if (tab === 'support') loadTickets(); if (tab === 'payments') loadTransactions(); } // ══════════════════════════════════════════════════════════════════ // PAYMENT VERIFICATION (existing logic preserved) // ══════════════════════════════════════════════════════════════════ async function loadTransactions() { const tableBody = document.getElementById('tx-table-body'); if (!tableBody) return; try { const res = await fetch('/api/admin/transactions'); const transactions = await res.json(); if (transactions.length === 0) { tableBody.innerHTML = 'No transactions found.'; return; } tableBody.innerHTML = transactions.map(t => { const statusClass = `status-${t.status.toLowerCase()}`; const actions = t.status === 'pending' ? `
` : ` Complete`; return ` ${t.date}
${t.user} ${t.phone}
₹${t.amount} ${t.utr} ${t.screenshot ? ` View Proof` : 'N/A'} ${t.status.toUpperCase()} ${actions} `; }).join(''); } catch (err) { console.error('Failed to load transactions:', err); tableBody.innerHTML = 'Failed to fetch transactions.'; } } function showConfirmModal(action) { return new Promise((resolve) => { const modal = document.getElementById('custom-confirm-modal'); const title = document.getElementById('modal-title'); const message = document.getElementById('modal-message'); const confirmBtn = document.getElementById('modal-confirm-btn'); const cancelBtn = document.getElementById('modal-cancel-btn'); const icon = document.getElementById('modal-icon'); const iconCont = document.getElementById('modal-icon-container'); if (!modal) { resolve(confirm(`Are you sure you want to ${action} this transaction?`)); return; } if (action === 'approve') { title.innerText = 'Approve Payment?'; message.innerHTML = 'This will securely add the
requested funds to the user profile.'; icon.className = 'fa-solid fa-check-circle'; iconCont.style.color = '#00b894'; confirmBtn.style.background = '#00b894'; confirmBtn.style.boxShadow = '0 10px 25px rgba(0,184,148,0.3)'; confirmBtn.innerText = 'Yes, Approve'; } else { title.innerText = 'Reject Payment?'; message.innerHTML = 'This request will be permanently
declined and user will not get funds.'; icon.className = 'fa-solid fa-triangle-exclamation'; iconCont.style.color = '#ff7675'; confirmBtn.style.background = '#ff7675'; confirmBtn.style.boxShadow = '0 10px 25px rgba(255,118,117,0.3)'; confirmBtn.innerText = 'Yes, Reject'; } modal.style.display = 'flex'; const cleanup = () => { confirmBtn.onclick = null; cancelBtn.onclick = null; modal.style.display = 'none'; }; confirmBtn.onclick = () => { cleanup(); resolve(true); }; cancelBtn.onclick = () => { cleanup(); resolve(false); }; }); } async function verifyTransaction(tx_id, action) { const confirmed = await showConfirmModal(action); if (!confirmed) return; try { const res = await fetch('/api/admin/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tx_id, action }) }); const data = await res.json(); if (data.success) loadTransactions(); else alert(data.error || 'Verification failed'); } catch (err) { console.error('Verification error:', err); alert('A network error occurred.'); } } window.verifyTransaction = verifyTransaction; // ══════════════════════════════════════════════════════════════════ // COMPLAINT / TICKET MANAGEMENT // ══════════════════════════════════════════════════════════════════ async function loadTickets() { try { const res = await fetch('/api/admin/tickets'); _allTickets = await res.json(); renderTicketList(); updateTicketBadge(); } catch (err) { console.error('Failed to load tickets:', err); document.getElementById('ticket-items').innerHTML = '

Tickets load nahi hue.

'; } } function updateTicketBadge() { const openCount = _allTickets.filter(t => t.status === 'open').length; const badge = document.getElementById('tab-badge'); const navBadge = document.getElementById('open-ticket-count'); [badge, navBadge].forEach(el => { if (!el) return; if (openCount > 0) { el.style.display = 'inline'; el.textContent = openCount; } else { el.style.display = 'none'; } }); } function filterTkts(filter, el) { _activeFilter = filter; _activeTicketId = null; document.querySelectorAll('.tf-tab').forEach(t => t.classList.remove('on')); el.classList.add('on'); renderTicketList(); // Reset detail panel document.getElementById('ticket-detail-col').innerHTML = '
Koi ticket select karein
'; } function renderTicketList() { const container = document.getElementById('ticket-items'); if (!container) return; const list = _activeFilter === 'all' ? _allTickets : _allTickets.filter(t => t.status === _activeFilter); if (list.length === 0) { container.innerHTML = '

Koi ticket nahi mila.

'; return; } container.innerHTML = list.map(t => `
${t.ticket_number} ${t.user_name} ${t.date.split(',')[0]}
${t.subject} ${statusLabel(t.status)}
`).join(''); } async function openTicket(ticketId) { _activeTicketId = ticketId; renderTicketList(); // highlight active row const col = document.getElementById('ticket-detail-col'); col.innerHTML = '
'; try { const res = await fetch(`/api/admin/tickets/${ticketId}`); const ticket = await res.json(); if (ticket.error) { col.innerHTML = `
${ticket.error}
`; return; } renderTicketDetail(ticket); } catch (err) { col.innerHTML = '
Load karne mein error aaya.
'; } } function renderTicketDetail(ticket) { const col = document.getElementById('ticket-detail-col'); const isResolved = ticket.status === 'resolved' || ticket.status === 'closed'; const msgHtml = ticket.messages.map(m => `
${escapeHtml(m.message)}
${m.sender === 'admin' ? 'Support Team' : ticket.user_name} · ${m.time}
`).join(''); const replySection = isResolved ? ` ` : ` `; col.innerHTML = `
${ticket.ticket_number} ${ticket.user_name} ${statusLabel(ticket.status)}
${ticket.subject} ${categoryLabel(ticket.category)} ${ticket.priority} priority · ${ticket.user_phone} · ${ticket.date}
${msgHtml}
${replySection} `; // Scroll chat to bottom const cw = document.getElementById(`chat-window-${ticket.id}`); if (cw) cw.scrollTop = cw.scrollHeight; } async function sendAdminReply(ticketId) { const input = document.getElementById('admin-reply-input'); const msg = input?.value.trim(); if (!msg) { alert('Reply khali nahi ho sakta.'); return; } try { const res = await fetch(`/api/admin/tickets/${ticketId}/reply`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: msg }) }); const data = await res.json(); if (data.success) { await loadTickets(); openTicket(ticketId); } else { alert(data.error || 'Reply send nahi hua.'); } } catch (err) { alert('Network error.'); } } async function updateTicketStatus(ticketId, status, priority) { const payload = { status }; if (priority) payload.priority = priority; try { const res = await fetch(`/api/admin/tickets/${ticketId}/status`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await res.json(); if (data.success) { await loadTickets(); openTicket(ticketId); } else { alert(data.error || 'Status update nahi hua.'); } } catch (err) { alert('Network error.'); } } // ── Helpers ──────────────────────────────────────────────────────── function statusLabel(s) { return { open: 'Open', pending: 'Pending', resolved: 'Resolved', closed: 'Closed' }[s] || s; } function categoryLabel(c) { return { payment: 'Payment', wallet: 'Wallet', refund: 'Refund', other: 'Other' }[c] || c; } function escapeHtml(text) { return String(text) .replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function sendPromptAboutTicket(id) { const t = _allTickets.find(x => x.id === id); if (t) alert(`Wallet adjust ke liye: Admin > Wallet > User search karein (${t.user_name}, ${t.user_phone})`); } window.filterTkts = filterTkts; window.openTicket = openTicket; window.sendAdminReply = sendAdminReply; window.updateTicketStatus = updateTicketStatus; window.switchTab = switchTab;