Secure email tracking and assignment system
System configuration, user management & email assignment
Email processing, task management & monitoring
| Agent | Subject | Sender | Received | Assigned | Completed | Duration | Status |
|---|---|---|---|---|---|---|---|
| ${row.agent_name} | ${row.subject} | ${row.sender_email} | ${new Date(row.received_at).toLocaleString()} | ${new Date(row.assigned_at).toLocaleString()} | ${row.completed_at ? new Date(row.completed_at).toLocaleString() : '-'} | ${row.handling_time_formatted} | ${row.email_status} |
No records found for the selected criteria.
'; } } catch (e) { container.innerHTML = 'Error loading report.
'; } finally { loading.style.display = 'none'; } } function exportReportToCSV() { const table = document.getElementById('reportTable'); if (!table) { alert('No data to export'); return; } let csv = []; const rows = table.querySelectorAll('tr'); for (let i = 0; i < rows.length; i++) { let row = [], cols = rows[i].querySelectorAll('td, th'); for (let j = 0; j < cols.length; j++) { let data = cols[j].innerText.replace(/(\r\n|\n|\r)/gm, '').replace(/(\s\s)/gm, ' '); data = data.replace(/"/g, '""'); row.push('"' + data + '"'); } csv.push(row.join(',')); } const csvFile = new Blob([csv.join('\n')], {type: 'text/csv'}); const downloadLink = document.createElement('a'); downloadLink.download = 'email_report_' + new Date().toISOString().slice(0,10) + '.csv'; downloadLink.href = window.URL.createObjectURL(csvFile); downloadLink.style.display = 'none'; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); } // --- Chat Logic --- async function loadChatContacts(silent = false) { try { const res = await fetch(`${API_BASE}?action=get_chat_contacts`, { headers: { 'Authorization': `Bearer ${authToken}` } }); const data = await res.json(); if (data.success) { const list = document.getElementById('chatContactsList'); let html = 'Error loading group details.
'; } } catch (e) { membersListDiv.innerHTML = 'Network error.
'; } } async function updateGroup() { const groupId = document.getElementById('editGroupId').value; const name = document.getElementById('editGroupName').value; const checks = document.querySelectorAll('.edit-group-member-check:checked'); const members = Array.from(checks).map(c => parseInt(c.value)); if (!name) return alert('Group name is required.'); try { const res = await fetch(`${API_BASE}?action=update_chat_group`, { method: 'POST', headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ group_id: groupId, name, members }) }); const data = await res.json(); if (data.success) { document.getElementById('editGroupModal').style.display = 'none'; loadChatContacts(); // If the currently open chat was this group, update its header if (currentChat.id == groupId && currentChat.type === 'group') { currentChat.name = name; document.getElementById('chatHeader').textContent = 'Group: ' + name; } } else { alert(data.error || 'Failed to update group.'); } } catch (e) { alert('Network error.'); } } async function deleteGroup() { const groupId = document.getElementById('editGroupId').value; const groupName = document.getElementById('editGroupName').value; if (!confirm(`Are you sure you want to delete the group "${groupName}"? This cannot be undone.`)) return; try { const res = await fetch(`${API_BASE}?action=delete_chat_group`, { method: 'POST', headers: { 'Authorization': `Bearer ${authToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ group_id: groupId }) }); const data = await res.json(); if (data.success) { document.getElementById('editGroupModal').style.display = 'none'; loadChatContacts(); // If the deleted group was the open chat, reset the chat view if (currentChat.id == groupId && currentChat.type === 'group') { currentChat = { id: null, type: null, name: null }; document.getElementById('chatHeader').textContent = 'Select a contact'; document.getElementById('chatMessages').innerHTML = ''; } } else { alert(data.error || 'Failed to delete group.'); } } catch (e) { alert('Network error.'); } } // Forgot Password Functions function openForgotModal() { document.getElementById('forgotModal').style.display = 'flex'; document.getElementById('forgotEmail').value = ''; } function closeForgotModal() { document.getElementById('forgotModal').style.display = 'none'; } async function handleForgotSubmit(e) { e.preventDefault(); const email = document.getElementById('forgotEmail').value; const btn = document.getElementById('forgotBtn'); btn.disabled = true; btn.textContent = 'Sending...'; try { const res = await fetch(`${API_BASE}?action=request_password_reset`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }) }); const data = await res.json(); if (data.success) { alert('Reset link sent to your email.'); closeForgotModal(); } else { alert(data.error || 'Failed to send link'); } } catch (err) { alert('Network error'); } finally { btn.disabled = false; btn.textContent = 'Send Reset Link'; } } // Utility functions function showMessage(form, type, message) { const element = document.getElementById(`${form}${type.charAt(0).toUpperCase() + type.slice(1)}`); element.textContent = message; element.style.display = 'block'; if (type === 'error') { element.style.background = '#fee'; element.style.color = '#d33'; } else { element.style.background = '#e8f7ee'; element.style.color = '#28a745'; } } function clearMessages(form) { document.getElementById(`${form}Error`).style.display = 'none'; document.getElementById(`${form}Success`).style.display = 'none'; } // NEW: Load recent assignment history async function loadRecentHistory() { if (!authToken) return; const dateFilter = document.getElementById('historyDateFilter').value; const loadingElement = document.getElementById('recentHistoryLoading'); const listElement = document.getElementById('recentHistoryList'); loadingElement.style.display = 'block'; listElement.innerHTML = ''; try { let url = `${API_BASE}?action=get_recent_history`; if (dateFilter) url += `&date=${dateFilter}`; const response = await fetch(url, { headers: { 'Authorization': `Bearer ${authToken}` } }); const data = await response.json(); if (data.success && data.history.length > 0) { let html = 'No recent history found.
'; } } catch (error) { listElement.innerHTML = 'Error loading history.
'; } finally { loadingElement.style.display = 'none'; } } // NEW: Fetch Gmail Emails async function fetchGmailEmails(btn) { if (!authToken) return; if (!confirm('Fetch new unseen emails from Gmail? This might take a moment.')) return; const originalText = btn.textContent; btn.disabled = true; btn.innerHTML = ' Fetching...'; try { const response = await fetch(`${API_BASE}?action=fetch_gmail`, { headers: { 'Authorization': `Bearer ${authToken}` } }); const data = await response.json(); if (data.success) { alert(`Successfully fetched ${data.count} new emails.`); refreshDashboard(); } else { alert('Error: ' + (data.error || 'Unknown error')); } } catch (e) { alert('Network error'); } finally { btn.disabled = false; btn.innerHTML = ' ' + originalText; } } // Initialize the application document.addEventListener('DOMContentLoaded', function() { // Dashboard init if (!authToken) { // Load sample agents for filter dropdown const agentFilter = document.getElementById('agentFilter'); const sampleAgents = [ /*{id: 1, name: 'John Doe'}, {id: 2, name: 'Jane Smith'}, {id: 3, name: 'Bob Johnson'} */ ]; sampleAgents.forEach(agent => { const option = document.createElement('option'); option.value = agent.id; option.textContent = agent.name; agentFilter.appendChild(option); }); } });