document.addEventListener('DOMContentLoaded', function() { // Only initialize filters if we're on the dashboard if (document.querySelector('table')) { initSearch(); initStatusFilter(); } // Keep theme toggle for all pages initThemeToggle(); createHamburgerMenu(); // Load saved theme preference const savedTheme = localStorage.getItem('theme') || 'light'; document.documentElement.setAttribute('data-theme', savedTheme); // Add sorting functionality const tableHeaders = document.querySelectorAll('th'); tableHeaders.forEach(header => { header.addEventListener('click', () => { const table = header.closest('table'); const index = Array.from(header.parentElement.children).indexOf(header); sortTable(table, index); }); }); // Add settings modal functionality const settingsIcon = document.querySelector('.settings-icon'); if (settingsIcon) { settingsIcon.addEventListener('click', function(e) { e.preventDefault(); createSettingsModal(); }); } }); function sortTable(table, column) { // Remove existing sort indicators from all headers const headers = table.querySelectorAll('th'); headers.forEach(header => { header.classList.remove('sort-asc', 'sort-desc'); }); const rows = Array.from(table.querySelectorAll('tbody tr')); // Determine current sort direction const currentDirection = table.dataset.sortColumn === column ? (table.dataset.sortDirection === 'asc' ? 'desc' : 'asc') : 'asc'; // Store current sorting column and direction table.dataset.sortColumn = column; table.dataset.sortDirection = currentDirection; rows.sort((a, b) => { const aValue = a.children[column].textContent.trim(); const bValue = b.children[column].textContent.trim(); // Try numeric sorting first, fallback to string comparison const numA = parseFloat(aValue); const numB = parseFloat(bValue); if (!isNaN(numA) && !isNaN(numB)) { return currentDirection === 'asc' ? numA - numB : numB - numA; } // String comparison return currentDirection === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); }); // Add sort indicator to the current header const currentHeader = headers[column]; currentHeader.classList.add(currentDirection === 'asc' ? 'sort-asc' : 'sort-desc'); // Reorder rows in the tbody const tbody = table.querySelector('tbody'); rows.forEach(row => tbody.appendChild(row)); } // Add this to the DOMContentLoaded event listener to persist sorting on page load document.addEventListener('DOMContentLoaded', function() { const table = document.querySelector('table'); if (table) { const savedSortColumn = localStorage.getItem('sortColumn'); const savedSortDirection = localStorage.getItem('sortDirection'); if (savedSortColumn !== null && savedSortDirection !== null) { const headers = table.querySelectorAll('th'); const columnIndex = Array.from(headers).findIndex(header => header.textContent.toLowerCase().replace(' ', '_') === savedSortColumn ); if (columnIndex !== -1) { table.dataset.sortColumn = columnIndex; table.dataset.sortDirection = savedSortDirection; const header = headers[columnIndex]; header.classList.add(savedSortDirection === 'asc' ? 'sort-asc' : 'sort-desc'); } } } }); // Modify the existing event listeners for table headers document.addEventListener('DOMContentLoaded', function() { const tableHeaders = document.querySelectorAll('th'); tableHeaders.forEach((header, index) => { header.addEventListener('click', () => { const table = header.closest('table'); sortTable(table, index); // Save sorting preferences const columnName = header.textContent.toLowerCase().replace(' ', '_'); localStorage.setItem('sortColumn', columnName); localStorage.setItem('sortDirection', table.dataset.sortDirection); }); }); }); function createSettingsModal() { // Create modal backdrop const backdrop = document.createElement('div'); backdrop.className = 'settings-modal-backdrop'; backdrop.innerHTML = `

Dashboard Settings

Toggle Columns

Rows per Page

`; // Add to body document.body.appendChild(backdrop); // Load saved column visibility settings const savedColumnSettings = JSON.parse(localStorage.getItem('columnVisibility') || '{}'); const checkboxes = backdrop.querySelectorAll('.column-toggles input'); checkboxes.forEach(checkbox => { checkbox.checked = savedColumnSettings[checkbox.value] !== false; }); // Load saved rows per page setting const savedRowsPerPage = localStorage.getItem('ticketsPerPage') || '5'; const rowsPerPageSelect = backdrop.querySelector('#rows-per-page'); rowsPerPageSelect.value = savedRowsPerPage; // Close modal events backdrop.querySelector('.close-modal').addEventListener('click', closeSettingsModal); backdrop.querySelector('.cancel-settings').addEventListener('click', closeSettingsModal); backdrop.querySelector('.save-settings').addEventListener('click', saveSettings); // Close modal on backdrop click backdrop.addEventListener('click', (e) => { if (e.target === backdrop) { closeSettingsModal(); } }); } function closeSettingsModal() { const backdrop = document.querySelector('.settings-modal-backdrop'); if (backdrop) { backdrop.remove(); } } function saveSettings() { // Save column visibility const checkboxes = document.querySelectorAll('.column-toggles input'); const columnVisibility = {}; checkboxes.forEach(checkbox => { columnVisibility[checkbox.value] = checkbox.checked; }); localStorage.setItem('columnVisibility', JSON.stringify(columnVisibility)); // Save rows per page const rowsPerPage = document.querySelector('#rows-per-page').value; localStorage.setItem('ticketsPerPage', rowsPerPage); // Set cookie for PHP to read document.cookie = `ticketsPerPage=${rowsPerPage}; path=/`; // Apply column visibility applyColumnVisibility(); // Reload page to apply pagination changes window.location.reload(); // Close modal closeSettingsModal(); } function applyColumnVisibility() { const savedColumnSettings = JSON.parse(localStorage.getItem('columnVisibility') || '{}'); const table = document.querySelector('table'); if (table) { const headers = table.querySelectorAll('th'); const rows = table.querySelectorAll('tbody tr'); headers.forEach((header, index) => { const columnValue = header.textContent.toLowerCase().replace(' ', '_'); const isVisible = savedColumnSettings[columnValue] !== false; header.style.display = isVisible ? '' : 'none'; rows.forEach(row => { row.children[index].style.display = isVisible ? '' : 'none'; }); }); } } // Apply column visibility on page load document.addEventListener('DOMContentLoaded', applyColumnVisibility); // Dark mode toggle function initThemeToggle() { const toggle = document.createElement('button'); toggle.className = 'theme-toggle'; toggle.innerHTML = '🌓'; toggle.onclick = () => { document.documentElement.setAttribute('data-theme', document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' ); localStorage.setItem('theme', document.documentElement.getAttribute('data-theme')); }; document.body.appendChild(toggle); } // Search functionality function initSearch() { const searchBox = document.createElement('input'); searchBox.type = 'text'; searchBox.placeholder = 'Search tickets...'; searchBox.className = 'search-box'; searchBox.oninput = (e) => { const searchTerm = e.target.value.toLowerCase(); const rows = document.querySelectorAll('tbody tr'); rows.forEach(row => { const text = row.textContent.toLowerCase(); row.style.display = text.includes(searchTerm) ? '' : 'none'; }); }; document.querySelector('h1').after(searchBox); } // Filter by status function initStatusFilter() { const filterContainer = document.createElement('div'); filterContainer.className = 'status-filter-container'; // Create dropdown container const dropdown = document.createElement('div'); dropdown.className = 'status-dropdown'; // Create dropdown header const dropdownHeader = document.createElement('div'); dropdownHeader.className = 'dropdown-header'; dropdownHeader.textContent = 'Status Filter'; // Create dropdown content const dropdownContent = document.createElement('div'); dropdownContent.className = 'dropdown-content'; const statuses = ['Open', 'Closed']; statuses.forEach(status => { const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = status; checkbox.id = `status-${status.toLowerCase()}`; const urlParams = new URLSearchParams(window.location.search); const currentStatuses = urlParams.get('status') ? urlParams.get('status').split(',') : []; checkbox.checked = currentStatuses.includes(status); label.appendChild(checkbox); label.appendChild(document.createTextNode(status)); dropdownContent.appendChild(label); }); const saveButton = document.createElement('button'); saveButton.className = 'btn save-filter'; saveButton.textContent = 'Apply Filter'; saveButton.onclick = () => { const checkedBoxes = dropdownContent.querySelectorAll('input:checked'); const selectedStatuses = Array.from(checkedBoxes).map(cb => cb.value); localStorage.setItem('statusFilter', selectedStatuses.join(',')); window.location.href = selectedStatuses.length ? `?status=${selectedStatuses.join(',')}` : '?'; dropdown.classList.remove('active'); }; // Toggle dropdown on header click dropdownHeader.onclick = () => { dropdown.classList.toggle('active'); }; dropdown.appendChild(dropdownHeader); dropdown.appendChild(dropdownContent); dropdownContent.appendChild(saveButton); filterContainer.appendChild(dropdown); document.querySelector('.table-controls .table-actions').prepend(filterContainer); } function sortTable(table, column) { const headers = table.querySelectorAll('th'); headers.forEach(header => { header.classList.remove('sort-asc', 'sort-desc'); }); const rows = Array.from(table.querySelectorAll('tbody tr')); const currentDirection = table.dataset.sortColumn == column ? (table.dataset.sortDirection === 'asc' ? 'desc' : 'asc') : 'asc'; table.dataset.sortColumn = column; table.dataset.sortDirection = currentDirection; rows.sort((a, b) => { const aValue = a.children[column].textContent.trim(); const bValue = b.children[column].textContent.trim(); // Check if this is a date column (Created or Updated) const headerText = headers[column].textContent.toLowerCase(); if (headerText === 'created' || headerText === 'updated') { const dateA = new Date(aValue); const dateB = new Date(bValue); return currentDirection === 'asc' ? dateA - dateB : dateB - dateA; } // Existing numeric and string comparison logic const numA = parseFloat(aValue); const numB = parseFloat(bValue); if (!isNaN(numA) && !isNaN(numB)) { return currentDirection === 'asc' ? numA - numB : numB - numA; } return currentDirection === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); }); const currentHeader = headers[column]; currentHeader.classList.add(currentDirection === 'asc' ? 'sort-asc' : 'sort-desc'); const tbody = table.querySelector('tbody'); rows.forEach(row => tbody.appendChild(row)); } // Modify the CSS to ensure arrows are more visible document.addEventListener('DOMContentLoaded', function() { const tableHeaders = document.querySelectorAll('th'); tableHeaders.forEach((header, index) => { header.style.cursor = 'pointer'; // Make headers look clickable header.addEventListener('click', () => { const table = header.closest('table'); sortTable(table, index); }); }); }); function saveTicket() { const editables = document.querySelectorAll('.editable'); const data = {}; const ticketId = window.location.href.split('id=')[1]; editables.forEach(field => { if (field.dataset.field) { data[field.dataset.field] = field.value; } }); fetch('update_ticket.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ticket_id: ticketId, ...data }) }) .then(response => response.json()) .then(data => { if(data.success) { const statusDisplay = document.getElementById('statusDisplay'); statusDisplay.className = `status-${data.status}`; statusDisplay.textContent = data.status; } }); } function toggleHamburgerEditMode() { const editButton = document.getElementById('hamburgerEditButton'); const editables = document.querySelectorAll('.hamburger-content .editable'); const cancelButton = document.getElementById('hamburgerCancelButton'); // Get cancel button const isEditing = editButton.classList.contains('editing'); if (!isEditing) { // Switch to edit mode editButton.textContent = 'Save Changes'; editButton.classList.add('editing'); editables.forEach(field => { field.disabled = false; // Store original values for potential cancel field.dataset.originalValue = field.value; }); // Create and append cancel button only if it doesn't exist if (!cancelButton) { const newCancelButton = document.createElement('button'); newCancelButton.id = 'hamburgerCancelButton'; newCancelButton.className = 'btn'; newCancelButton.textContent = 'Cancel'; newCancelButton.onclick = cancelHamburgerEdit; editButton.parentNode.appendChild(newCancelButton); } } else { // Save changes saveHamburgerChanges(); } } function saveHamburgerChanges() { try { saveTicket(); resetHamburgerEditMode(); } catch (error) { console.error('Error saving changes:', error); } } function cancelHamburgerEdit() { // Revert all fields to their original values const editables = document.querySelectorAll('.hamburger-content .editable'); editables.forEach(field => { if (field.dataset.originalValue) { field.value = field.dataset.originalValue; } }); resetHamburgerEditMode(); } function resetHamburgerEditMode() { const editButton = document.getElementById('hamburgerEditButton'); const cancelButton = document.getElementById('hamburgerCancelButton'); const editables = document.querySelectorAll('.hamburger-content .editable'); // Reset button text and remove editing class editButton.textContent = 'Edit Ticket'; editButton.classList.remove('editing'); // Disable all editable fields editables.forEach(field => field.disabled = true); // Remove cancel button if it exists if (cancelButton) cancelButton.remove(); } function createHamburgerMenu() { const hamburgerMenu = document.createElement('div'); hamburgerMenu.className = 'hamburger-menu'; const isTicketPage = window.location.pathname.includes('ticket.php') || window.location.pathname.includes('/ticket/'); if (isTicketPage && window.ticketData) { // Use the ticket data from the global variable const values = window.ticketData; hamburgerMenu.innerHTML = `

Ticket Controls

`; const hamburgerEditButton = hamburgerMenu.querySelector('#hamburgerEditButton'); if (hamburgerEditButton) { hamburgerEditButton.addEventListener('click', toggleHamburgerEditMode); } document.addEventListener('keydown', (event) => { if (event.key === 'Escape') { cancelHamburgerEdit(); } }); } else { hamburgerMenu.innerHTML = `

Filters

Categories

Types

`; // Populate categories and types from data attributes const categoriesContainer = hamburgerMenu.querySelector('#category-filters'); const typesContainer = hamburgerMenu.querySelector('#type-filters'); const categories = JSON.parse(document.body.dataset.categories || '[]'); const types = JSON.parse(document.body.dataset.types || '[]'); // Create checkboxes for categories categories.forEach(category => { const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = category; checkbox.name = 'category'; label.appendChild(checkbox); label.appendChild(document.createTextNode(category)); categoriesContainer.appendChild(label); }); // Create checkboxes for types types.forEach(type => { const label = document.createElement('label'); const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = type; checkbox.name = 'type'; label.appendChild(checkbox); label.appendChild(document.createTextNode(type)); typesContainer.appendChild(label); }); // Apply filters const applyFiltersBtn = hamburgerMenu.querySelector('#apply-filters'); applyFiltersBtn.addEventListener('click', () => { const selectedCategories = Array.from( categoriesContainer.querySelectorAll('input:checked') ).map(cb => cb.value); const selectedTypes = Array.from( typesContainer.querySelectorAll('input:checked') ).map(cb => cb.value); // Construct URL with filters const params = new URLSearchParams(window.location.search); if (selectedCategories.length > 0) { params.set('category', selectedCategories.join(',')); } else { params.delete('category'); } if (selectedTypes.length > 0) { params.set('type', selectedTypes.join(',')); } else { params.delete('type'); } // Reload with new filters window.location.search = params.toString(); }); // Clear filters const clearFiltersBtn = hamburgerMenu.querySelector('#clear-filters'); clearFiltersBtn.addEventListener('click', () => { const params = new URLSearchParams(window.location.search); params.delete('category'); params.delete('type'); window.location.search = params.toString(); }); } // Add to body document.body.appendChild(hamburgerMenu); // Toggle hamburger menu const hamburgerIcon = hamburgerMenu.querySelector('.hamburger-icon'); const hamburgerContent = hamburgerMenu.querySelector('.hamburger-content'); hamburgerIcon.addEventListener('click', () => { hamburgerContent.classList.toggle('open'); document.body.classList.toggle('menu-open'); }); // Close hamburger menu const closeButton = hamburgerMenu.querySelector('.close-hamburger'); closeButton.addEventListener('click', () => { hamburgerContent.classList.remove('open'); document.body.classList.remove('menu-open'); }); } // Add to DOMContentLoaded document.addEventListener('DOMContentLoaded', createHamburgerMenu);