/** * Advanced Search Functionality * Handles complex search queries with date ranges, user filters, and multiple criteria */ // Open advanced search modal function openAdvancedSearch() { const modal = document.getElementById('advancedSearchModal'); if (modal) { lt.modal.open('advancedSearchModal'); loadUsersForSearch(); populateCurrentFilters(); loadSavedFilters(); } } // Close advanced search modal function closeAdvancedSearch() { lt.modal.close('advancedSearchModal'); } // Close modal when clicking on backdrop function closeOnAdvancedSearchBackdropClick(event) { const modal = document.getElementById('advancedSearchModal'); if (event.target === modal) { closeAdvancedSearch(); } } // Load users for dropdown async function loadUsersForSearch() { try { const data = await lt.api.get('/api/get_users.php'); if (data.success && data.users) { const createdBySelect = document.getElementById('adv-created-by'); const assignedToSelect = document.getElementById('adv-assigned-to'); // Clear existing options (except first default option) while (createdBySelect.options.length > 1) { createdBySelect.remove(1); } while (assignedToSelect.options.length > 2) { // Keep "Any" and "Unassigned" assignedToSelect.remove(2); } // Add users to both dropdowns data.users.forEach(user => { const displayName = user.display_name || user.username; const option1 = document.createElement('option'); option1.value = user.user_id; option1.textContent = displayName; createdBySelect.appendChild(option1); const option2 = document.createElement('option'); option2.value = user.user_id; option2.textContent = displayName; assignedToSelect.appendChild(option2); }); } } catch (error) { lt.toast.error('Error loading users'); } } // Populate form with current URL parameters function populateCurrentFilters() { const urlParams = new URLSearchParams(window.location.search); // Search text if (urlParams.has('search')) { document.getElementById('adv-search-text').value = urlParams.get('search'); } // Status if (urlParams.has('status')) { const statuses = urlParams.get('status').split(','); const statusSelect = document.getElementById('adv-status'); Array.from(statusSelect.options).forEach(option => { option.selected = statuses.includes(option.value); }); } } // Perform advanced search function performAdvancedSearch(event) { event.preventDefault(); const params = new URLSearchParams(); // Search text const searchText = document.getElementById('adv-search-text').value.trim(); if (searchText) { params.set('search', searchText); } // Date ranges const createdFrom = document.getElementById('adv-created-from').value; const createdTo = document.getElementById('adv-created-to').value; const updatedFrom = document.getElementById('adv-updated-from').value; const updatedTo = document.getElementById('adv-updated-to').value; if (createdFrom) params.set('created_from', createdFrom); if (createdTo) params.set('created_to', createdTo); if (updatedFrom) params.set('updated_from', updatedFrom); if (updatedTo) params.set('updated_to', updatedTo); // Status (multi-select) const statusSelect = document.getElementById('adv-status'); const selectedStatuses = Array.from(statusSelect.selectedOptions).map(opt => opt.value); if (selectedStatuses.length > 0) { params.set('status', selectedStatuses.join(',')); } // Priority range const priorityMin = document.getElementById('adv-priority-min').value; const priorityMax = document.getElementById('adv-priority-max').value; if (priorityMin) params.set('priority_min', priorityMin); if (priorityMax) params.set('priority_max', priorityMax); // Users const createdBy = document.getElementById('adv-created-by').value; const assignedTo = document.getElementById('adv-assigned-to').value; if (createdBy) params.set('created_by', createdBy); if (assignedTo) params.set('assigned_to', assignedTo); // Redirect to dashboard with params window.location.href = '/?' + params.toString(); } // Reset advanced search form function resetAdvancedSearch() { document.getElementById('advancedSearchForm').reset(); // Unselect all multi-select options const statusSelect = document.getElementById('adv-status'); Array.from(statusSelect.options).forEach(option => { option.selected = false; }); } // Save current search as a filter async function saveCurrentFilter() { showInputModal( 'Save Search Filter', 'Enter a name for this filter:', 'My Filter', async (filterName) => { if (!filterName || filterName.trim() === '') { lt.toast.warning('Filter name cannot be empty', 2000); return; } const filterCriteria = getCurrentFilterCriteria(); try { await lt.api.post('/api/saved_filters.php', { filter_name: filterName.trim(), filter_criteria: filterCriteria }); lt.toast.success(`Filter "${filterName}" saved successfully!`, 3000); loadSavedFilters(); } catch (error) { lt.toast.error('Error saving filter: ' + (error.message || 'Unknown error'), 4000); } } ); } // Get current filter criteria from form function getCurrentFilterCriteria() { const criteria = {}; const searchText = document.getElementById('adv-search-text').value.trim(); if (searchText) criteria.search = searchText; const createdFrom = document.getElementById('adv-created-from').value; if (createdFrom) criteria.created_from = createdFrom; const createdTo = document.getElementById('adv-created-to').value; if (createdTo) criteria.created_to = createdTo; const updatedFrom = document.getElementById('adv-updated-from').value; if (updatedFrom) criteria.updated_from = updatedFrom; const updatedTo = document.getElementById('adv-updated-to').value; if (updatedTo) criteria.updated_to = updatedTo; const statusSelect = document.getElementById('adv-status'); const selectedStatuses = Array.from(statusSelect.selectedOptions).map(opt => opt.value); if (selectedStatuses.length > 0) criteria.status = selectedStatuses.join(','); const priorityMin = document.getElementById('adv-priority-min').value; if (priorityMin) criteria.priority_min = priorityMin; const priorityMax = document.getElementById('adv-priority-max').value; if (priorityMax) criteria.priority_max = priorityMax; const createdBy = document.getElementById('adv-created-by').value; if (createdBy) criteria.created_by = createdBy; const assignedTo = document.getElementById('adv-assigned-to').value; if (assignedTo) criteria.assigned_to = assignedTo; return criteria; } // Load saved filters async function loadSavedFilters() { try { const data = await lt.api.get('/api/saved_filters.php'); if (data.success && data.filters) { populateSavedFiltersDropdown(data.filters); } } catch (error) { lt.toast.error('Error loading saved filters'); } } // Populate saved filters dropdown function populateSavedFiltersDropdown(filters) { const dropdown = document.getElementById('saved-filters-select'); if (!dropdown) return; // Clear existing options except the first (placeholder) while (dropdown.options.length > 1) { dropdown.remove(1); } // Add saved filters filters.forEach(filter => { const option = document.createElement('option'); option.value = filter.filter_id; option.textContent = filter.filter_name + (filter.is_default ? ' ⭐' : ''); option.dataset.criteria = JSON.stringify(filter.filter_criteria); dropdown.appendChild(option); }); } // Load a saved filter function loadSavedFilter() { const dropdown = document.getElementById('saved-filters-select'); const selectedOption = dropdown.options[dropdown.selectedIndex]; if (!selectedOption || !selectedOption.dataset.criteria) return; try { const criteria = JSON.parse(selectedOption.dataset.criteria); applySavedFilterCriteria(criteria); } catch (error) { lt.toast.error('Error loading filter'); } } // Apply saved filter criteria to form function applySavedFilterCriteria(criteria) { // Search text document.getElementById('adv-search-text').value = criteria.search || ''; // Date ranges document.getElementById('adv-created-from').value = criteria.created_from || ''; document.getElementById('adv-created-to').value = criteria.created_to || ''; document.getElementById('adv-updated-from').value = criteria.updated_from || ''; document.getElementById('adv-updated-to').value = criteria.updated_to || ''; // Status const statusSelect = document.getElementById('adv-status'); const statuses = criteria.status ? criteria.status.split(',') : []; Array.from(statusSelect.options).forEach(option => { option.selected = statuses.includes(option.value); }); // Priority document.getElementById('adv-priority-min').value = criteria.priority_min || ''; document.getElementById('adv-priority-max').value = criteria.priority_max || ''; // Users document.getElementById('adv-created-by').value = criteria.created_by || ''; document.getElementById('adv-assigned-to').value = criteria.assigned_to || ''; } // Delete saved filter async function deleteSavedFilter() { const dropdown = document.getElementById('saved-filters-select'); const selectedOption = dropdown.options[dropdown.selectedIndex]; if (!selectedOption || selectedOption.value === '') { lt.toast.error('Please select a filter to delete'); return; } const filterId = selectedOption.value; const filterName = selectedOption.textContent; showConfirmModal( `Delete Filter "${filterName}"?`, 'This action cannot be undone.', 'error', async () => { try { await lt.api.delete('/api/saved_filters.php', { filter_id: filterId }); lt.toast.success('Filter deleted successfully', 3000); loadSavedFilters(); resetAdvancedSearch(); } catch (error) { lt.toast.error('Error deleting filter', 4000); } } ); } // Keyboard shortcut (Ctrl+Shift+F) — ESC is handled globally by lt.keys.initDefaults() document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'F') { e.preventDefault(); openAdvancedSearch(); } });