// Main JavaScript functionality for Ticket Collection System document.addEventListener('DOMContentLoaded', function() { initializeAdmin(); }); // Initialize admin dashboard functionality function initializeAdmin() { if (window.location.pathname === '/admin') { initializeTableFeatures(); initializeSearch(); initializeFilters(); updateLastUpdated(); } } // Initialize table sorting and filtering features function initializeTableFeatures() { const table = document.getElementById('ticketsTable'); if (!table) return; // Store original table data for filtering window.originalTableData = Array.from(table.querySelectorAll('tbody tr')); updateShowingCount(); } // Table sorting functionality let sortDirection = {}; function sortTable(columnIndex) { const table = document.getElementById('ticketsTable'); const tbody = table.querySelector('tbody'); const rows = Array.from(tbody.querySelectorAll('tr')); // Determine sort direction const currentDir = sortDirection[columnIndex] || 'asc'; const newDir = currentDir === 'asc' ? 'desc' : 'asc'; sortDirection[columnIndex] = newDir; // Update sort icons updateSortIcons(columnIndex, newDir); // Sort rows rows.sort((a, b) => { const aText = a.cells[columnIndex].textContent.trim(); const bText = b.cells[columnIndex].textContent.trim(); // Handle numeric columns if (columnIndex === 3) { // Tickets column const aNum = parseInt(aText) || 0; const bNum = parseInt(bText) || 0; return newDir === 'asc' ? aNum - bNum : bNum - aNum; } // Handle date columns if (columnIndex === 7) { // Timestamp column const aDate = new Date(aText); const bDate = new Date(bText); return newDir === 'asc' ? aDate - bDate : bDate - aDate; } // Handle text columns const comparison = aText.localeCompare(bText); return newDir === 'asc' ? comparison : -comparison; }); // Rebuild table rows.forEach(row => tbody.appendChild(row)); updateShowingCount(); } // Update sort direction icons function updateSortIcons(activeColumn, direction) { const headers = document.querySelectorAll('#ticketsTable thead th'); headers.forEach((header, index) => { const icon = header.querySelector('i.fa-sort, i.fa-sort-up, i.fa-sort-down'); if (icon) { if (index === activeColumn) { icon.className = direction === 'asc' ? 'fas fa-sort-up' : 'fas fa-sort-down'; } else { icon.className = 'fas fa-sort'; } } }); } // Search functionality function initializeSearch() { const searchInput = document.getElementById('searchInput'); if (!searchInput) return; searchInput.addEventListener('input', function() { const searchTerm = this.value.toLowerCase(); filterTable(); }); } // Filter functionality function initializeFilters() { const countryFilter = document.getElementById('countryFilter'); if (!countryFilter) return; countryFilter.addEventListener('change', function() { filterTable(); }); } // Combined filter and search function function filterTable() { if (!window.originalTableData) return; const searchTerm = document.getElementById('searchInput')?.value.toLowerCase() || ''; const countryFilter = document.getElementById('countryFilter')?.value || ''; const tbody = document.querySelector('#ticketsTable tbody'); // Clear current table tbody.innerHTML = ''; let visibleCount = 0; window.originalTableData.forEach(row => { const rowText = row.textContent.toLowerCase(); const countryCell = row.cells[5].textContent.trim(); const matchesSearch = searchTerm === '' || rowText.includes(searchTerm); const matchesCountry = countryFilter === '' || countryCell === countryFilter; if (matchesSearch && matchesCountry) { tbody.appendChild(row.cloneNode(true)); visibleCount++; } }); // Update showing count document.getElementById('showingCount').textContent = visibleCount; // Show empty state if no results if (visibleCount === 0) { showEmptySearchResults(); } } // Show empty search results function showEmptySearchResults() { const tbody = document.querySelector('#ticketsTable tbody'); const emptyRow = document.createElement('tr'); emptyRow.innerHTML = `

No tickets match your search criteria

`; tbody.appendChild(emptyRow); } // Update showing count function updateShowingCount() { const tbody = document.querySelector('#ticketsTable tbody'); if (!tbody) return; const visibleRows = tbody.querySelectorAll('tr').length; const showingElement = document.getElementById('showingCount'); if (showingElement) { showingElement.textContent = visibleRows; } } // Refresh data function function refreshData() { const refreshBtn = document.querySelector('button[onclick="refreshData()"]'); if (refreshBtn) { refreshBtn.innerHTML = ' Refreshing...'; refreshBtn.disabled = true; } // Simulate refresh delay setTimeout(() => { location.reload(); }, 500); } // Export visible data function function exportVisible() { const table = document.getElementById('ticketsTable'); if (!table) return; const visibleRows = Array.from(table.querySelectorAll('tbody tr')); if (visibleRows.length === 0) { alert('No data to export'); return; } // Create CSV content let csvContent = 'Email,Phone,Name,Tickets,Ticket Number,Country,Region,Timestamp\n'; visibleRows.forEach(row => { const cells = Array.from(row.cells).slice(0, 8); // Exclude actions column const rowData = cells.map(cell => { let text = cell.textContent.trim(); // Clean up badge text if (cell.querySelector('.badge')) { text = cell.querySelector('.badge').textContent.trim(); } // Clean up code text if (cell.querySelector('code')) { text = cell.querySelector('code').textContent.trim(); } // Escape quotes and commas if (text.includes(',') || text.includes('"')) { text = '"' + text.replace(/"/g, '""') + '"'; } return text; }); csvContent += rowData.join(',') + '\n'; }); // Download CSV const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); if (link.download !== undefined) { const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `ticket_data_filtered_${new Date().toISOString().split('T')[0]}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } // Update last updated timestamp function updateLastUpdated() { const element = document.getElementById('lastUpdated'); if (element) { const now = new Date(); element.textContent = now.toISOString().slice(0, 19).replace('T', ' '); } } // Utility function to show notifications function showNotification(message, type = 'info') { const alertDiv = document.createElement('div'); alertDiv.className = `alert alert-${type} alert-dismissible fade show position-fixed`; alertDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;'; alertDiv.innerHTML = ` ${message} `; document.body.appendChild(alertDiv); // Auto-remove after 5 seconds setTimeout(() => { if (alertDiv.parentNode) { alertDiv.parentNode.removeChild(alertDiv); } }, 5000); } // Handle form submissions with loading states document.addEventListener('submit', function(e) { const form = e.target; if (form.tagName === 'FORM') { const submitBtn = form.querySelector('button[type="submit"]'); if (submitBtn) { submitBtn.disabled = true; const originalHtml = submitBtn.innerHTML; submitBtn.innerHTML = ' Processing...'; // Re-enable after 3 seconds (fallback) setTimeout(() => { submitBtn.disabled = false; submitBtn.innerHTML = originalHtml; }, 3000); } } }); // Add keyboard shortcuts document.addEventListener('keydown', function(e) { // Ctrl+R or F5 for refresh if ((e.ctrlKey && e.key === 'r') || e.key === 'F5') { if (window.location.pathname === '/admin') { e.preventDefault(); refreshData(); } } // Ctrl+F for search focus if (e.ctrlKey && e.key === 'f') { const searchInput = document.getElementById('searchInput'); if (searchInput) { e.preventDefault(); searchInput.focus(); searchInput.select(); } } // Escape to clear search if (e.key === 'Escape') { const searchInput = document.getElementById('searchInput'); if (searchInput && searchInput.value) { searchInput.value = ''; filterTable(); } } }); // Add smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); });