/**
* 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;