Agent Performance Dashboard

Performance Snapshot

Top Performers

Agent Comparison Charts

All Tickets

IDCustomerAgentStatusCSATActions

Required libraries failed to load. Please check your connection and ad-blockers, then refresh.

`; errorWrapper.style.display = 'block'; contentWrapper.style.display = 'none'; return; } // --- CUSTOMIZABLE DATA SOURCE --- const AGENTS = [ {id: 1, name: 'Alex Ray'}, {id: 2, name: 'Jordan Lee'}, {id: 3, name: 'Casey Garcia'}, {id: 4, name: 'Taylor Ward'} ]; let tickets = [ { id: 1, agentId: 1, customer: 'Innovate LLC', issue: 'API connection failing', createdDate: new Date('2025-06-25T10:00:00Z'), resolvedDate: new Date('2025-06-25T14:30:00Z'), csatScore: 5, wasFCR: true }, { id: 2, agentId: 2, customer: 'Global Corp', issue: 'Billing question for June', createdDate: new Date('2025-06-24T11:00:00Z'), resolvedDate: new Date('2025-06-24T12:00:00Z'), csatScore: 4, wasFCR: true }, { id: 3, agentId: 1, customer: 'Solutions Co.', issue: 'Cannot reset password', createdDate: new Date('2025-06-26T09:00:00Z'), resolvedDate: null, csatScore: null, wasFCR: false }, { id: 4, agentId: 3, customer: 'Tech Forward', issue: 'Feature request: dark mode', createdDate: new Date('2025-06-20T15:00:00Z'), resolvedDate: new Date('2025-06-20T15:30:00Z'), csatScore: 5, wasFCR: true }, { id: 5, agentId: 2, customer: 'NextGen Inc.', issue: 'Slow loading times on dashboard', createdDate: new Date('2025-06-27T08:00:00Z'), resolvedDate: null, csatScore: null, wasFCR: false }, ]; let activeTabIndex = 0; let resolvedChart, csatChart; // --- DOM ELEMENTS --- const tabButtons = document.querySelectorAll('.apd-tab-button'); const tabPanes = document.querySelectorAll('.apd-tab-pane'); const timeFilterEl = document.getElementById('time-filter'); const ticketModal = document.getElementById('ticket-modal'); // --- INITIALIZATION --- function initialize() { initCharts(); populateModalDropdowns(); render(); attachEventListeners(); } function initCharts() { resolvedChart = new Chart(document.getElementById('resolvedChart'), { type: 'bar', options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Tickets Resolved' }}} }); csatChart = new Chart(document.getElementById('csatChart'), { type: 'bar', options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: 'Average CSAT Score' }}, scales: { y: { beginAtZero: false, min: 1, max: 5 }} } }); } function populateModalDropdowns() { const agentSelect = document.getElementById('ticket-agent'); agentSelect.innerHTML = AGENTS.map(a => ``).join(''); } // --- DATA PROCESSING & RENDERING --- function render() { const period = timeFilterEl.value; const now = new Date(); const cutoffDate = new Date(); if (period === '7d') cutoffDate.setDate(now.getDate() - 7); if (period === '30d') cutoffDate.setDate(now.getDate() - 30); const filteredTickets = (period === 'all') ? tickets : tickets.filter(t => new Date(t.createdDate) >= cutoffDate); const performanceData = AGENTS.map(agent => { const agentTickets = filteredTickets.filter(t => t.agentId === agent.id); const resolvedTickets = agentTickets.filter(t => t.resolvedDate); const ratedTickets = resolvedTickets.filter(t => t.csatScore); const fcrTickets = resolvedTickets.filter(t => t.wasFCR); const totalResTime = resolvedTickets.reduce((sum, t) => sum + (new Date(t.resolvedDate) - new Date(t.createdDate)), 0); const avgResTime = resolvedTickets.length > 0 ? totalResTime / resolvedTickets.length / 3600000 : 0; const avgCsat = ratedTickets.length > 0 ? ratedTickets.reduce((sum, t) => sum + t.csatScore, 0) / ratedTickets.length : 0; const fcrRate = resolvedTickets.length > 0 ? fcrTickets.length / resolvedTickets.length : 0; return { id: agent.id, name: agent.name, ticketsResolved: resolvedTickets.length, avgResTime: avgResTime, avgCsat: avgCsat, fcrRate: fcrRate }; }); renderLeaderboard(performanceData); renderCharts(performanceData); renderTicketTable(); } function renderLeaderboard(data) { const topCsat = [...data].sort((a,b) => b.avgCsat - a.avgCsat)[0] || {name: 'N/A', avgCsat: 0}; const topResolved = [...data].sort((a,b) => b.ticketsResolved - a.ticketsResolved)[0] || {name: 'N/A', ticketsResolved: 0}; document.getElementById('leaderboard').innerHTML = `

HIGHEST CSAT

${topCsat.name}

${topCsat.avgCsat.toFixed(2)}

MOST RESOLVED

${topResolved.name}

${topResolved.ticketsResolved}
`; } function renderCharts(data) { const labels = data.map(d => d.name); resolvedChart.data = { labels, datasets: [{ label: 'Tickets Resolved', data: data.map(d => d.ticketsResolved), backgroundColor: '#007bff' }]}; csatChart.data = { labels, datasets: [{ label: 'Average CSAT', data: data.map(d => d.avgCsat), backgroundColor: '#28a745' }]}; resolvedChart.update(); csatChart.update(); } function renderTicketTable() { const tableBody = document.getElementById('ticket-table-body'); tableBody.innerHTML = ''; tickets.forEach(ticket => { const agent = AGENTS.find(a => a.id === ticket.agentId); const status = ticket.resolvedDate ? 'Resolved' : 'Open'; tableBody.innerHTML += ` ${ticket.id} ${ticket.customer} ${agent ? agent.name : 'Unassigned'} ${status} ${ticket.csatScore || 'N/A'} ${status === 'Open' ? '' : ''} `; }); } // --- MODAL & CRUD --- function openTicketModal(ticketId = null) { const form = document.getElementById('ticket-form'); form.reset(); document.getElementById('modal-title').textContent = ticketId ? 'Edit Ticket' : 'Add New Ticket'; document.getElementById('ticket-id').value = ticketId || ''; if (ticketId) { const ticket = tickets.find(t => t.id === ticketId); if (ticket) { document.getElementById('ticket-customer').value = ticket.customer; document.getElementById('ticket-issue').value = ticket.issue; document.getElementById('ticket-agent').value = ticket.agentId; document.getElementById('ticket-status').value = ticket.resolvedDate ? 'Resolved' : 'Open'; document.getElementById('ticket-csat').value = ticket.csatScore || ''; document.getElementById('ticket-fcr').value = ticket.wasFCR.toString(); } } ticketModal.style.display = 'block'; } function handleFormSubmit(e) { e.preventDefault(); const id = parseInt(document.getElementById('ticket-id').value); const now = new Date(); const ticketData = { customer: document.getElementById('ticket-customer').value, issue: document.getElementById('ticket-issue').value, agentId: parseInt(document.getElementById('ticket-agent').value), resolvedDate: document.getElementById('ticket-status').value === 'Resolved' ? now : null, csatScore: parseInt(document.getElementById('ticket-csat').value) || null, wasFCR: document.getElementById('ticket-fcr').value === 'true', }; if (id) { const index = tickets.findIndex(t => t.id === id); tickets[index] = { ...tickets[index], ...ticketData }; } else { const newId = tickets.length > 0 ? Math.max(...tickets.map(t => t.id)) + 1 : 1; tickets.push({ id: newId, createdDate: now, ...ticketData }); } ticketModal.style.display = 'none'; render(); } // --- EVENT HANDLERS --- function attachEventListeners() { timeFilterEl.addEventListener('change', render); document.getElementById('add-ticket-btn').addEventListener('click', () => openTicketModal()); document.getElementById('modal-cancel-btn').addEventListener('click', () => ticketModal.style.display = 'none'); document.getElementById('ticket-form').addEventListener('submit', handleFormSubmit); document.getElementById('download-pdf-btn').addEventListener('click', generatePdf); document.getElementById('ticket-table-body').addEventListener('click', e => { const ticketId = parseInt(e.target.closest('tr')?.dataset.ticketId); if (!ticketId) return; if (e.target.classList.contains('edit-btn')) { openTicketModal(ticketId); } else if (e.target.classList.contains('delete-btn')) { if (confirm(`Are you sure you want to delete ticket ${ticketId}?`)) { tickets = tickets.filter(t => t.id !== ticketId); render(); } } else if (e.target.classList.contains('resolve-btn')) { const index = tickets.findIndex(t => t.id === ticketId); tickets[index].resolvedDate = new Date(); render(); } }); tabButtons.forEach((button, index) => button.addEventListener('click', () => { activeTabIndex = index; tabButtons.forEach(btn => btn.classList.remove('active')); tabPanes.forEach(pane => pane.classList.remove('active')); button.classList.add('active'); document.getElementById(`tab-pane-${index}`).classList.add('active'); })); } // --- PDF --- function generatePdf() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.setFontSize(18); doc.text(`Agent Performance Report`, 14, 22); if (activeTabIndex === 0) { doc.autoTable({ startY: 30, html: document.querySelector('.apd-leaderboard') }); } else { doc.autoTable({ startY: 30, html: document.getElementById('ticket-table-body').parentElement }); } doc.save(`Agent_Performance_Report.pdf`); } initialize(); });
Scroll to Top