From cf2d596219d4dada9273373d2a04bf2857d32b9c Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 7 Jan 2026 17:47:11 -0500 Subject: [PATCH] Sidebar with no hamburger menu --- assets/css/dashboard.css | 477 ++++++++++++++++++++-------------- assets/js/dashboard.js | 544 ++++++--------------------------------- views/DashboardView.php | 321 +++++++++++++---------- 3 files changed, 534 insertions(+), 808 deletions(-) diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css index 7d51967..45696a6 100644 --- a/assets/css/dashboard.css +++ b/assets/css/dashboard.css @@ -90,7 +90,6 @@ h1 { .user-header { background: var(--bg-secondary); padding: 0.5rem 1rem; - margin-left: 50px; /* Space for hamburger menu */ color: var(--terminal-green); display: flex; justify-content: space-between; @@ -1163,223 +1162,307 @@ input[type="checkbox"]:checked { cursor: pointer; } -/* ===== HAMBURGER MENU STYLES - TERMINAL EDITION ===== */ -.hamburger-menu { - position: absolute; - top: 20px; - left: 20px; - z-index: 100; -} - -.hamburger-icon { - cursor: pointer; - font-size: 24px; +/* ===== COLLAPSIBLE ASCII BANNER ===== */ +.ascii-banner-wrapper { + max-width: 1600px; + margin: 0 auto 1rem auto; + border: 2px solid var(--terminal-green); background: var(--bg-secondary); - padding: 12px; - border: 2px solid var(--terminal-green); - border-radius: 0; - box-shadow: none; - font-family: var(--font-mono); - color: var(--terminal-green); } -.hamburger-icon::before { - content: '['; - margin-right: 4px; +.ascii-banner-wrapper.collapsed .banner-content { + display: none; } -.hamburger-icon::after { - content: ']'; - margin-left: 4px; -} - -.hamburger-content { - position: fixed; - top: 0; - left: -300px; - width: 250px; - height: 100%; - background: var(--bg-primary); - border-right: 3px double var(--terminal-green); - transition: left 0.3s ease; - padding: 20px; - overflow-y: auto; - z-index: 99; - font-family: var(--font-mono); - box-shadow: 0 0 30px rgba(0, 255, 65, 0.3); -} - -/* ASCII decoration at top */ -.hamburger-content::before { - content: '╔═══════════════════╗\A║ MENU SYSTEM ║\A╚═══════════════════╝'; - white-space: pre; - display: block; - color: var(--terminal-green); - font-family: var(--font-mono); - font-size: 0.8rem; - margin-bottom: 20px; - line-height: 1.2; -} - -.hamburger-content.open { - left: 0; -} - -.hamburger-content h3 { - color: var(--terminal-amber); - text-shadow: var(--glow-amber); - font-family: var(--font-mono); - text-transform: uppercase; - margin-top: 20px; - margin-bottom: 10px; -} - -.hamburger-content h3::before { - content: '> '; - color: var(--terminal-green); -} - -.close-hamburger { - position: absolute; - top: 10px; - right: 10px; - cursor: pointer; - font-size: 24px; - background: transparent; - padding: 10px; - border: 2px solid var(--terminal-green); - border-radius: 0; - box-shadow: none; - color: var(--terminal-green); - font-family: var(--font-mono); -} - -.close-hamburger::before { - content: '['; -} - -.close-hamburger::after { - content: ']'; -} - -.close-hamburger:hover { - color: var(--priority-1); - border-color: var(--priority-1); - text-shadow: var(--glow-red); -} - -/* Hamburger menu inline editing styles - TERMINAL */ -.ticket-info-editable { - padding: 10px 0; -} - -.editable-field, .info-field { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 15px; - position: relative; - padding: 10px; - border: 1px solid var(--terminal-green); - background: rgba(0, 255, 65, 0.03); -} - -.editable-field label, .info-field label { - flex: 0 0 auto; - margin-right: 10px; - color: var(--terminal-green); - font-family: var(--font-mono); -} - -.editable-value { - flex: 1; - text-align: right; - min-height: 20px; - display: inline-block; - cursor: pointer; - padding: 4px 8px; - border-radius: 0; - transition: all 0.2s; - color: var(--terminal-amber); -} - -.editable-value::before { - content: '[ '; - color: var(--terminal-green); -} - -.editable-value::after { - content: ' ]'; - color: var(--terminal-green); -} - -.editable-value:hover { - background-color: rgba(0, 255, 65, 0.1) !important; - text-shadow: var(--glow-amber); -} - -.edit-dropdown { - position: absolute; - top: 100%; - right: 0; - background: var(--bg-primary); - border: 2px solid var(--terminal-green); - border-radius: 0; - padding: 8px; - box-shadow: 0 0 20px rgba(0, 255, 65, 0.3); - z-index: 1000; - min-width: 150px; -} - -.field-select { +.banner-toggle { width: 100%; - padding: 4px 8px; + background: var(--bg-secondary); + border: none; + color: var(--terminal-amber); + padding: 0.5rem 1rem; + cursor: pointer; + font-family: var(--font-mono); + text-align: left; + font-size: 0.9rem; + text-shadow: var(--glow-amber); + transition: all 0.2s ease; +} + +.banner-toggle:hover { + background: var(--hover-bg); + box-shadow: inset 0 0 20px rgba(255, 176, 0, 0.2); +} + +.toggle-icon { + display: inline-block; + width: 1rem; + text-align: center; + color: var(--terminal-green); + transition: transform 0.3s ease; +} + +.banner-content { + padding: 1rem; + text-align: center; +} + +/* ===== CONDENSED TOOLBAR ===== */ +.dashboard-toolbar { + display: flex; + flex-wrap: wrap; + gap: 1rem; + align-items: center; + justify-content: space-between; + padding: 1rem; + background: var(--bg-secondary); border: 2px solid var(--terminal-green); + margin-bottom: 1rem; + box-shadow: var(--glow-green); +} + +.toolbar-left { + display: flex; + align-items: center; + gap: 1rem; + flex: 1; + min-width: 300px; +} + +.dashboard-title { + font-family: var(--font-mono); + color: var(--terminal-green); + text-shadow: var(--glow-green); + font-size: 1.5rem; + margin: 0; + white-space: nowrap; +} + +.toolbar-search { + display: flex; + gap: 0.5rem; + flex: 1; +} + +.toolbar-center { + display: flex; + align-items: center; + gap: 1rem; +} + +.toolbar-right { + display: flex; + align-items: center; +} + +.ticket-count { + font-family: var(--font-mono); + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + font-size: 0.9rem; + white-space: nowrap; +} + +.clear-search-btn { + background: var(--bg-primary); + color: var(--priority-1); + border: 2px solid var(--priority-1); + padding: 0.5rem 0.75rem; + font-family: var(--font-mono); + text-decoration: none; + cursor: pointer; + transition: all 0.2s ease; +} + +.clear-search-btn:hover { + background: var(--priority-1); + color: var(--bg-primary); + box-shadow: var(--glow-red); +} + +.search-results-info { + background: var(--bg-secondary); + border: 2px solid var(--terminal-amber); + padding: 0.75rem 1rem; + margin-bottom: 1rem; + font-family: var(--font-mono); + color: var(--terminal-amber); + text-shadow: var(--glow-amber); +} + +/* Inline Bulk Actions */ +.bulk-actions-inline { + padding: 0.75rem 1rem; + background: var(--bg-primary); + border: 2px solid var(--terminal-amber); border-radius: 0; - margin-bottom: 8px; + margin-bottom: 1rem; + display: flex; + gap: 1rem; + align-items: center; + font-family: var(--font-mono); + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + box-shadow: inset 0 0 20px rgba(255, 176, 0, 0.2); +} + +.bulk-actions-inline .btn { + padding: 0.4rem 0.8rem; + font-size: 0.85rem; +} + +/* Mobile: Stack toolbar items */ +@media (max-width: 1024px) { + .dashboard-toolbar { + flex-direction: column; + align-items: stretch; + } + + .toolbar-left, + .toolbar-center, + .toolbar-right { + width: 100%; + justify-content: space-between; + } + + .toolbar-search { + min-width: 100%; + } + + .dashboard-title { + font-size: 1.2rem; + } +} + +@media (max-width: 768px) { + .toolbar-left { + flex-direction: column; + align-items: stretch; + } + + .dashboard-title { + text-align: center; + } +} + +/* ===== DASHBOARD SIDEBAR LAYOUT ===== */ +.dashboard-layout { + display: flex; + gap: 1.5rem; + max-width: 1600px; + margin: 0 auto; + padding: 0 1rem; +} + +.dashboard-sidebar { + width: 250px; + flex-shrink: 0; + position: sticky; + top: 1rem; + max-height: calc(100vh - 2rem); + overflow-y: auto; +} + +.dashboard-sidebar .ascii-frame-inner { + background: var(--bg-secondary); + padding: 1rem; + border: 2px solid var(--terminal-green); + box-shadow: var(--glow-green); +} + +.dashboard-sidebar .ascii-subsection-header { + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + font-family: var(--font-mono); + font-size: 1.1rem; + text-transform: uppercase; + margin-bottom: 1rem; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--terminal-green); +} + +.filter-group { + margin-bottom: 1.5rem; +} + +.filter-group h4 { + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + margin: 0 0 0.5rem 0; + font-size: 0.9rem; + text-transform: uppercase; + font-family: var(--font-mono); +} + +.filter-group label { + display: block; + margin: 0.4rem 0; + color: var(--terminal-green); + cursor: pointer; + font-size: 0.85rem; + font-family: var(--font-mono); + transition: all 0.2s ease; +} + +.filter-group label:hover { + color: var(--terminal-amber); + text-shadow: var(--glow-amber); + padding-left: 4px; +} + +.filter-group input[type="checkbox"] { + margin-right: 0.5rem; + cursor: pointer; + accent-color: var(--terminal-green); +} + +.dashboard-sidebar .btn { + width: 100%; + margin-top: 0.5rem; + padding: 0.5rem; background: var(--bg-primary); color: var(--terminal-green); + border: 2px solid var(--terminal-green); font-family: var(--font-mono); - color: var(--text-primary); -} - -.edit-actions { - display: flex; - gap: 4px; - justify-content: flex-end; -} - -.save-btn, .cancel-btn { - padding: 4px 8px; - border: none; - border-radius: 0; cursor: pointer; - font-size: 12px; - min-width: 24px; + transition: all 0.2s ease; } -.save-btn { - background: #28a745; - color: white; +.dashboard-sidebar .btn:hover { + background: var(--terminal-green); + color: var(--bg-primary); + box-shadow: var(--glow-green); } -.save-btn:hover { - background: #218838; +.dashboard-sidebar .btn-secondary { + background: transparent; + color: var(--terminal-amber); + border-color: var(--terminal-amber); } -.cancel-btn { - background: #dc3545; - color: white; +.dashboard-sidebar .btn-secondary:hover { + background: var(--terminal-amber); + color: var(--bg-primary); + box-shadow: var(--glow-amber); } -.cancel-btn:hover { - background: #c82333; -} - -.info-field span { +.dashboard-main { flex: 1; - text-align: right; - color: var(--text-secondary); + min-width: 0; +} + +/* Mobile: Stack sidebar above content */ +@media (max-width: 768px) { + .dashboard-layout { + flex-direction: column; + padding: 0 0.5rem; + } + + .dashboard-sidebar { + width: 100%; + position: static; + max-height: none; + margin-bottom: 1rem; + } } /* ===== UTILITY STYLES ===== */ diff --git a/assets/js/dashboard.js b/assets/js/dashboard.js index 3ad1a2d..ec3e066 100644 --- a/assets/js/dashboard.js +++ b/assets/js/dashboard.js @@ -17,23 +17,7 @@ document.addEventListener('DOMContentLoaded', function() { // Dashboard-specific initialization initStatusFilter(); initTableSorting(); - - console.log('Creating hamburger menu for dashboard...'); - try { - createHamburgerMenu(); - console.log('Hamburger menu created successfully'); - } catch (error) { - console.error('Error creating hamburger menu:', error); - } - } else if (isTicketPage) { - // Ticket page initialization - console.log('Creating hamburger menu for ticket page...'); - try { - createHamburgerMenu(); - console.log('Hamburger menu created successfully'); - } catch (error) { - console.error('Error creating hamburger menu:', error); - } + initSidebarFilters(); } // Initialize for all pages @@ -55,6 +39,72 @@ function initTableSorting() { }); } +function initSidebarFilters() { + const applyFiltersBtn = document.getElementById('apply-filters-btn'); + const clearFiltersBtn = document.getElementById('clear-filters-btn'); + + if (applyFiltersBtn) { + applyFiltersBtn.addEventListener('click', () => { + const params = new URLSearchParams(window.location.search); + + // Collect selected statuses + const selectedStatuses = Array.from( + document.querySelectorAll('.filter-group input[name="status"]:checked') + ).map(cb => cb.value); + + // Collect selected categories + const selectedCategories = Array.from( + document.querySelectorAll('.filter-group input[name="category"]:checked') + ).map(cb => cb.value); + + // Collect selected types + const selectedTypes = Array.from( + document.querySelectorAll('.filter-group input[name="type"]:checked') + ).map(cb => cb.value); + + // Update URL parameters + if (selectedStatuses.length > 0) { + params.set('status', selectedStatuses.join(',')); + } else { + params.delete('status'); + } + + 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'); + } + + // Reset to page 1 when filters change + params.set('page', '1'); + + // Reload with new parameters + window.location.search = params.toString(); + }); + } + + if (clearFiltersBtn) { + clearFiltersBtn.addEventListener('click', () => { + const params = new URLSearchParams(window.location.search); + + // Remove filter parameters + params.delete('status'); + params.delete('category'); + params.delete('type'); + params.set('page', '1'); + + // Reload with cleared filters + window.location.search = params.toString(); + }); + } +} + function initSettingsModal() { const settingsIcon = document.querySelector('.settings-icon'); if (settingsIcon) { @@ -354,452 +404,6 @@ function quickSave() { }); } -function createHamburgerMenu() { - console.log('createHamburgerMenu called'); - - // Remove any existing hamburger menu first - const existingMenu = document.querySelector('.hamburger-menu'); - if (existingMenu) { - console.log('Removing existing menu'); - existingMenu.remove(); - } - - const hamburgerMenu = document.createElement('div'); - hamburgerMenu.className = 'hamburger-menu'; - - // Better detection for ticket pages - const isTicketPage = window.location.pathname.includes('/ticket/') || - window.location.href.includes('ticket.php') || - document.querySelector('.ticket-details') !== null; - - console.log('Is ticket page:', isTicketPage); - console.log('Has ticketData:', !!window.ticketData); - console.log('TicketData contents:', window.ticketData); - - if (isTicketPage) { - // Wait for ticketData if it's not loaded yet - if (!window.ticketData) { - console.log('Waiting for ticket data...'); - setTimeout(() => { - if (window.ticketData) { - console.log('Ticket data now available, recreating menu'); - createHamburgerMenu(); - } - }, 100); - return; - } - - console.log('Creating ticket hamburger menu with data:', window.ticketData); - - // Ticket page hamburger menu with inline editing - hamburgerMenu.innerHTML = ` -
-
-
- -
Ticket Actions
- -
-
-
- - P${window.ticketData.priority} - -
- -
- - ${window.ticketData.category} - -
- -
- - ${window.ticketData.type} - -
-
-
-
- `; - - console.log('Ticket hamburger menu HTML created'); - - // Add inline editing functionality - setupInlineEditing(hamburgerMenu); - } else { - console.log('Creating dashboard hamburger menu'); - - // Dashboard hamburger menu (your existing code) - hamburgerMenu.innerHTML = ` -
-
-
- -
Filters
- -
-
-
-

Categories

-
-
-
-

Types

-
-
-
- - -
-
-
-
- `; - - // Get current URL parameters - const urlParams = new URLSearchParams(window.location.search); - const currentCategories = urlParams.get('category') ? urlParams.get('category').split(',') : []; - const currentTypes = urlParams.get('type') ? urlParams.get('type').split(',') : []; - - // Get containers - const categoriesContainer = hamburgerMenu.querySelector('#category-filters'); - const typesContainer = hamburgerMenu.querySelector('#type-filters'); - - // Get data from body attributes - 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'); - label.style.display = 'block'; - label.style.marginBottom = '5px'; - - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.value = category; - checkbox.name = 'category'; - - const isChecked = currentCategories.includes(category); - - label.appendChild(checkbox); - label.appendChild(document.createTextNode(' ' + category)); - categoriesContainer.appendChild(label); - - checkbox.checked = isChecked; - }); - - // Create checkboxes for types - types.forEach(type => { - const label = document.createElement('label'); - label.style.display = 'block'; - label.style.marginBottom = '5px'; - - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.value = type; - checkbox.name = 'type'; - - const isChecked = currentTypes.includes(type); - - label.appendChild(checkbox); - label.appendChild(document.createTextNode(' ' + type)); - typesContainer.appendChild(label); - - checkbox.checked = isChecked; - }); - - // Apply filters event - 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); - - 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'); - } - - params.set('page', '1'); - window.location.search = params.toString(); - }); - - // Clear filters event - const clearFiltersBtn = hamburgerMenu.querySelector('#clear-filters'); - clearFiltersBtn.addEventListener('click', () => { - const params = new URLSearchParams(window.location.search); - params.delete('category'); - params.delete('type'); - params.set('page', '1'); - window.location.search = params.toString(); - }); - } - - console.log('Adding hamburger menu to body'); - - // Add to body - document.body.appendChild(hamburgerMenu); - - console.log('Hamburger menu added, setting up event listeners'); - - // Toggle hamburger menu - const hamburgerIcon = hamburgerMenu.querySelector('.hamburger-icon'); - const hamburgerContent = hamburgerMenu.querySelector('.hamburger-content'); - - if (hamburgerIcon && hamburgerContent) { - hamburgerIcon.addEventListener('click', () => { - console.log('Hamburger icon clicked'); - hamburgerContent.classList.toggle('open'); - document.body.classList.toggle('menu-open'); - }); - - // Close hamburger menu - const closeButton = hamburgerMenu.querySelector('.close-hamburger'); - if (closeButton) { - closeButton.addEventListener('click', () => { - console.log('Close button clicked'); - hamburgerContent.classList.remove('open'); - document.body.classList.remove('menu-open'); - }); - } - - console.log('Hamburger menu created successfully'); - } else { - console.error('Failed to find hamburger icon or content'); - } -} - -function setupInlineEditing(hamburgerMenu) { - const editableFields = hamburgerMenu.querySelectorAll('.editable-field'); - - editableFields.forEach(field => { - const valueSpan = field.querySelector('.editable-value'); - const dropdown = field.querySelector('.edit-dropdown'); - const select = field.querySelector('.field-select'); - const saveBtn = field.querySelector('.save-btn'); - const cancelBtn = field.querySelector('.cancel-btn'); - const fieldName = field.dataset.field; - - // Make value span clickable - valueSpan.style.cursor = 'pointer'; - valueSpan.style.padding = '4px 8px'; - valueSpan.style.borderRadius = '4px'; - valueSpan.style.transition = 'background-color 0.2s'; - - // Hover effect - valueSpan.addEventListener('mouseenter', () => { - valueSpan.style.backgroundColor = 'var(--hover-bg, #f0f0f0)'; - }); - - valueSpan.addEventListener('mouseleave', () => { - if (dropdown.style.display === 'none') { - valueSpan.style.backgroundColor = 'transparent'; - } - }); - - // Click to edit - valueSpan.addEventListener('click', () => { - dropdown.style.display = 'block'; - valueSpan.style.backgroundColor = 'var(--hover-bg, #f0f0f0)'; - select.focus(); - }); - - // Save changes - saveBtn.addEventListener('click', () => { - const newValue = select.value; - const oldValue = valueSpan.dataset.current; - - if (newValue !== oldValue) { - saveFieldChange(fieldName, newValue, valueSpan, dropdown); - } else { - cancelEdit(valueSpan, dropdown); - } - }); - - // Cancel changes - cancelBtn.addEventListener('click', () => { - select.value = valueSpan.dataset.current; - cancelEdit(valueSpan, dropdown); - }); - - // Cancel on escape key - select.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - select.value = valueSpan.dataset.current; - cancelEdit(valueSpan, dropdown); - } else if (e.key === 'Enter') { - saveBtn.click(); - } - }); - - // Cancel when clicking outside - document.addEventListener('click', (e) => { - if (!field.contains(e.target) && dropdown.style.display === 'block') { - select.value = valueSpan.dataset.current; - cancelEdit(valueSpan, dropdown); - } - }); - }); -} - -function saveFieldChange(fieldName, newValue, valueSpan, dropdown) { - if (!window.ticketData) { - console.error('No ticket data available'); - return; - } - - const data = { - ticket_id: parseInt(window.ticketData.id), - [fieldName]: fieldName === 'priority' ? parseInt(newValue) : newValue - }; - - console.log('Saving field change:', data); - - // Show loading state - valueSpan.style.opacity = '0.6'; - - fetch('/api/update_ticket.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }) - .then(response => { - return response.text().then(text => { - try { - return JSON.parse(text); - } catch (e) { - throw new Error('Invalid JSON response: ' + text); - } - }); - }) - .then(result => { - console.log('Update result:', result); - if (result.success) { - // Update the hamburger menu display - if (fieldName === 'priority') { - valueSpan.textContent = 'P' + newValue; - } else { - valueSpan.textContent = newValue; - } - - valueSpan.dataset.current = newValue; - - // Update window.ticketData - window.ticketData[fieldName] = fieldName === 'priority' ? parseInt(newValue) : newValue; - - // Update main page elements - if (fieldName === 'status') { - const statusDisplay = document.getElementById('statusDisplay'); - if (statusDisplay) { - // Remove all existing status classes - statusDisplay.className = statusDisplay.className.replace(/status-\S+/g, '').trim(); - - // Create the correct CSS class name to match your CSS - // "Open" -> "status-Open" - // "In Progress" -> "status-In-Progress" - // "Closed" -> "status-Closed" - const cssClass = newValue.replace(/\s+/g, '-'); // "In Progress" -> "In-Progress" - const fullClassName = `status-${cssClass}`; - - statusDisplay.className = fullClassName; - statusDisplay.textContent = newValue; - - console.log('Updated status display class to:', fullClassName); - console.log('Status display element:', statusDisplay); - } - } - - if (fieldName === 'priority') { - const priorityDisplay = document.querySelector('.priority-indicator'); - if (priorityDisplay) { - // Remove all priority classes first - priorityDisplay.className = priorityDisplay.className.replace(/priority-\d+/g, ''); - priorityDisplay.className = `priority-indicator priority-${newValue}`; - priorityDisplay.textContent = 'P' + newValue; - } - - // Update the ticket container's data-priority attribute for styling - const ticketContainer = document.querySelector('.ticket-container'); - if (ticketContainer) { - ticketContainer.setAttribute('data-priority', newValue); - } - } - - console.log('Field updated successfully'); - cancelEdit(valueSpan, dropdown); - - } else { - console.error('Error updating field:', result.error || 'Unknown error'); - alert('Error updating ' + fieldName + ': ' + (result.error || 'Unknown error')); - cancelEdit(valueSpan, dropdown); - } - }) - .catch(error => { - console.error('Error updating field:', error); - alert('Error updating ' + fieldName + ': ' + error.message); - cancelEdit(valueSpan, dropdown); - }) - .finally(() => { - valueSpan.style.opacity = '1'; - }); -} - -function cancelEdit(valueSpan, dropdown) { - dropdown.style.display = 'none'; - valueSpan.style.backgroundColor = 'transparent'; -} - // Ticket page functions (if needed) function saveTicket() { @@ -921,14 +525,16 @@ function toggleSelectAll() { function updateSelectionCount() { const checkboxes = document.querySelectorAll('.ticket-checkbox:checked'); const count = checkboxes.length; - const toolbar = document.querySelector('.bulk-actions-toolbar'); + const toolbar = document.querySelector('.bulk-actions-inline'); const countDisplay = document.getElementById('selected-count'); - if (count > 0) { - toolbar.style.display = 'flex'; - countDisplay.textContent = count; - } else { - toolbar.style.display = 'none'; + if (toolbar && countDisplay) { + if (count > 0) { + toolbar.style.display = 'flex'; + countDisplay.textContent = count; + } else { + toolbar.style.display = 'none'; + } } } diff --git a/views/DashboardView.php b/views/DashboardView.php index cd40ced..ea5b662 100644 --- a/views/DashboardView.php +++ b/views/DashboardView.php @@ -28,158 +28,195 @@ - -
+ + - + +
+ + + + +
+ + +
+ +
+

🎫 Tickets

+ +
+ + +
+ + Total: +
+ + +
+ +
+
+ + +
+ Showing results for: "" + ( ticket found) +
+ + +
- -
Dashboard Control Center
-
-
-
-

Ticket Dashboard

- -
-
-
- - -
- - -
Search & Filter
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - Clear - -
- -
- Showing results for: "" - ( ticket found) -
- -
-
- - -
- - -
Table Controls
-
-
-
-
- Total Tickets: -
-
- -
- - - - -
-
-
-
-
- - -
- - - -
Bulk Operations
-
-
- -
-
- - -
- - -
Ticket List
+ + + + + +