/** * Find Training Filters * * Handles filtering, searching, and geolocation functionality * for the Find Training page. * * @package HVAC_Community_Events * @since 2.2.0 */ (function($) { 'use strict'; // Namespace for filters module window.HVACTrainingFilters = { // Debounce timer for search searchTimer: null, // Current AJAX request (for aborting) currentRequest: null, // Active filters activeFilters: { state: '', certification: '', training_format: '', search: '', include_past: false }, // User location (if obtained) userLocation: null, /** * Initialize filters */ init: function() { this.bindEvents(); this.initMobileFilterToggle(); }, /** * Bind event handlers */ bindEvents: function() { const self = this; // Search input with debounce - client-side filtering for instant results $('#hvac-training-search').on('input', function() { clearTimeout(self.searchTimer); const value = $(this).val().toLowerCase().trim(); self.searchTimer = setTimeout(function() { self.activeFilters.search = value; // For empty search or server-side filters, use AJAX if (!value || self.hasActiveServerFilters()) { self.applyFilters(); } else { // Client-side filtering for instant results self.filterActiveTabList(value); } }, 150); // Faster for client-side }); // State filter $('#hvac-filter-state').on('change', function() { self.activeFilters.state = $(this).val(); self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Certification filter $('#hvac-filter-certification').on('change', function() { self.activeFilters.certification = $(this).val(); self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Training format filter $('#hvac-filter-format').on('change', function() { self.activeFilters.training_format = $(this).val(); self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Include past events checkbox $('#hvac-include-past').on('change', function() { self.activeFilters.include_past = $(this).is(':checked'); self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Mobile include past events checkbox $('#hvac-include-past-mobile').on('change', function() { const checked = $(this).is(':checked'); $('#hvac-include-past').prop('checked', checked); self.activeFilters.include_past = checked; self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Near Me button $('#hvac-near-me-btn').on('click', function() { self.handleNearMeClick($(this)); }); // Clear all filters $('.hvac-clear-filters').on('click', function() { self.clearAllFilters(); }); // Remove individual filter $(document).on('click', '.hvac-active-filter button', function() { const filterType = $(this).parent().data('filter'); self.removeFilter(filterType); }); }, /** * Apply current filters */ applyFilters: function() { const self = this; // Abort any pending request to prevent race conditions if (this.currentRequest && this.currentRequest.readyState !== 4) { this.currentRequest.abort(); } // Build filter data const filterData = { action: 'hvac_filter_training_map', nonce: hvacFindTraining.nonce, state: this.activeFilters.state, certification: this.activeFilters.certification, training_format: this.activeFilters.training_format, search: this.activeFilters.search, show_trainers: $('#hvac-show-trainers').is(':checked'), show_venues: $('#hvac-show-venues').is(':checked'), show_events: $('#hvac-show-events').is(':checked'), include_past: this.activeFilters.include_past }; // Add user location if available if (this.userLocation) { filterData.lat = this.userLocation.lat; filterData.lng = this.userLocation.lng; filterData.radius = 100; // km } // Send filter request and store reference this.currentRequest = $.ajax({ url: hvacFindTraining.ajax_url, type: 'POST', data: filterData, success: function(response) { if (response.success) { // Update map data HVACTrainingMap.trainers = response.data.trainers || []; HVACTrainingMap.venues = response.data.venues || []; HVACTrainingMap.events = response.data.events || []; // Reset visible arrays to all items HVACTrainingMap.visibleTrainers = HVACTrainingMap.trainers.slice(); HVACTrainingMap.visibleVenues = HVACTrainingMap.venues.slice(); HVACTrainingMap.visibleEvents = HVACTrainingMap.events.slice(); // Reset displayed counts HVACTrainingMap.displayedCounts = { trainers: 0, venues: 0, events: 0 }; // Update map markers HVACTrainingMap.updateMarkers(); // Update all counts HVACTrainingMap.updateAllCounts(); // Render the active tab HVACTrainingMap.renderActiveTabList(); // Note: syncSidebarWithViewport will be called by map 'idle' event } }, complete: function() { self.currentRequest = null; } }); // Show/hide clear button this.updateClearButtonVisibility(); }, /** * Handle Near Me button click */ handleNearMeClick: function($button) { const self = this; // Show loading state $button.prop('disabled', true); $button.html(' Locating...'); // Clear any previous error message this.clearLocationError(); // Get user location HVACTrainingMap.getUserLocation(function(location, error) { if (location) { self.userLocation = location; // Center map on user location HVACTrainingMap.centerOnLocation(location.lat, location.lng, 9); // Apply filters with location self.applyFilters(); // Update button state $button.html(' Near Me'); $button.addClass('active'); // Add to active filters display self.addActiveFilter('location', 'Near Me'); } else { // Show inline error instead of alert self.showLocationError(error || 'Unable to get your location. Please check browser permissions.'); // Reset button $button.html(' Near Me'); $button.prop('disabled', false); } }); }, /** * Show location error message inline */ showLocationError: function(message) { // Remove any existing error this.clearLocationError(); // Create error element const $error = $('
' + ' ' + this.escapeHtml(message) + '' + '
'); // Insert after Near Me button $('#hvac-near-me-btn').after($error); // Auto-dismiss after 5 seconds setTimeout(function() { $error.fadeOut(300, function() { $(this).remove(); }); }, 5000); // Click to dismiss $error.find('.hvac-dismiss-error').on('click', function() { $error.remove(); }); }, /** * Clear location error message */ clearLocationError: function() { $('.hvac-location-error').remove(); }, /** * Clear all filters */ clearAllFilters: function() { // Reset filter values this.activeFilters = { state: '', certification: '', training_format: '', search: '', include_past: false }; // Reset user location this.userLocation = null; // Reset form elements $('#hvac-filter-state').val(''); $('#hvac-filter-certification').val(''); $('#hvac-filter-format').val(''); $('#hvac-training-search').val(''); $('#hvac-include-past').prop('checked', false); $('#hvac-include-past-mobile').prop('checked', false); // Reset Near Me button $('#hvac-near-me-btn') .removeClass('active') .html(' Near Me') .prop('disabled', false); // Clear active filters display $('.hvac-active-filters').empty(); // Hide clear button $('.hvac-clear-filters').hide(); // Reset map to default view HVACTrainingMap.map.setCenter(HVACTrainingMap.config.defaultCenter); HVACTrainingMap.map.setZoom(HVACTrainingMap.config.defaultZoom); // Reload data without filters HVACTrainingMap.loadMapData(); }, /** * Remove a specific filter */ removeFilter: function(filterType) { switch (filterType) { case 'state': this.activeFilters.state = ''; $('#hvac-filter-state').val(''); break; case 'certification': this.activeFilters.certification = ''; $('#hvac-filter-certification').val(''); break; case 'training_format': this.activeFilters.training_format = ''; $('#hvac-filter-format').val(''); break; case 'search': this.activeFilters.search = ''; $('#hvac-training-search').val(''); break; case 'location': this.userLocation = null; $('#hvac-near-me-btn') .removeClass('active') .html(' Near Me') .prop('disabled', false); break; case 'include_past': this.activeFilters.include_past = false; $('#hvac-include-past').prop('checked', false); $('#hvac-include-past-mobile').prop('checked', false); break; } this.applyFilters(); this.updateActiveFiltersDisplay(); }, /** * Update active filters display */ updateActiveFiltersDisplay: function() { const $container = $('.hvac-active-filters'); $container.empty(); // State filter if (this.activeFilters.state) { this.addActiveFilter('state', `State: ${this.activeFilters.state}`); } // Certification filter if (this.activeFilters.certification) { this.addActiveFilter('certification', this.activeFilters.certification); } // Training format filter if (this.activeFilters.training_format) { this.addActiveFilter('training_format', this.activeFilters.training_format); } // Search filter if (this.activeFilters.search) { this.addActiveFilter('search', `"${this.activeFilters.search}"`); } // Location filter if (this.userLocation) { this.addActiveFilter('location', 'Near Me'); } // Include past events filter if (this.activeFilters.include_past) { this.addActiveFilter('include_past', 'Including Past Events'); } this.updateClearButtonVisibility(); }, /** * Add an active filter chip */ addActiveFilter: function(type, label) { const $container = $('.hvac-active-filters'); const $chip = $(` ${this.escapeHtml(label)} `); $container.append($chip); }, /** * Update clear button visibility */ updateClearButtonVisibility: function() { const hasFilters = this.activeFilters.state || this.activeFilters.certification || this.activeFilters.training_format || this.activeFilters.search || this.activeFilters.include_past || this.userLocation; if (hasFilters) { $('.hvac-clear-filters').show(); } else { $('.hvac-clear-filters').hide(); } }, /** * Check if any server-side filters are active */ hasActiveServerFilters: function() { return this.activeFilters.state || this.activeFilters.certification || this.activeFilters.training_format || this.activeFilters.include_past || this.userLocation; }, /** * Filter the active tab's list client-side for instant results */ filterActiveTabList: function(searchTerm) { const activeTab = HVACTrainingMap.activeTab; let items, filterFn; switch (activeTab) { case 'trainers': items = HVACTrainingMap.visibleTrainers.length > 0 ? HVACTrainingMap.trainers : HVACTrainingMap.trainers; filterFn = (trainer) => { const searchFields = [ trainer.name, trainer.city, trainer.state, trainer.company, ...(trainer.certifications || []) ].filter(Boolean).join(' ').toLowerCase(); return searchFields.includes(searchTerm); }; break; case 'venues': items = HVACTrainingMap.venues; filterFn = (venue) => { const searchFields = [ venue.name, venue.city, venue.state, venue.address ].filter(Boolean).join(' ').toLowerCase(); return searchFields.includes(searchTerm); }; break; case 'events': items = HVACTrainingMap.events; filterFn = (event) => { const searchFields = [ event.title, event.venue_name, event.venue_city, event.venue_state ].filter(Boolean).join(' ').toLowerCase(); return searchFields.includes(searchTerm); }; break; default: return; } // Apply filter const filteredItems = searchTerm ? items.filter(filterFn) : items; // Update the visible items for the active tab switch (activeTab) { case 'trainers': HVACTrainingMap.visibleTrainers = filteredItems; HVACTrainingMap.displayedCounts.trainers = 0; HVACTrainingMap.updateTrainerGrid(); break; case 'venues': HVACTrainingMap.visibleVenues = filteredItems; HVACTrainingMap.displayedCounts.venues = 0; HVACTrainingMap.updateVenueGrid(); break; case 'events': HVACTrainingMap.visibleEvents = filteredItems; HVACTrainingMap.displayedCounts.events = 0; HVACTrainingMap.updateEventGrid(); break; } // Update all counts HVACTrainingMap.updateAllCounts(); }, /** * Escape HTML for safe output */ escapeHtml: function(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, /** * Initialize mobile filter toggle */ initMobileFilterToggle: function() { const self = this; // Mobile filter panel toggle $(document).on('click', '.hvac-mobile-filter-toggle', function() { const $toggle = $(this); const $panel = $('#hvac-mobile-filter-panel'); const isExpanded = $toggle.attr('aria-expanded') === 'true'; if (isExpanded) { $panel.attr('hidden', ''); $toggle.attr('aria-expanded', 'false'); } else { $panel.removeAttr('hidden'); $toggle.attr('aria-expanded', 'true'); } }); // Sync mobile filter selects with desktop selects $('#hvac-filter-state-mobile').on('change', function() { const value = $(this).val(); $('#hvac-filter-state').val(value); self.activeFilters.state = value; self.applyFilters(); self.updateActiveFiltersDisplay(); }); $('#hvac-filter-certification-mobile').on('change', function() { const value = $(this).val(); $('#hvac-filter-certification').val(value); self.activeFilters.certification = value; self.applyFilters(); self.updateActiveFiltersDisplay(); }); $('#hvac-filter-format-mobile').on('change', function() { const value = $(this).val(); $('#hvac-filter-format').val(value); self.activeFilters.training_format = value; self.applyFilters(); self.updateActiveFiltersDisplay(); }); // Also sync desktop to mobile when desktop changes $('#hvac-filter-state').on('change', function() { $('#hvac-filter-state-mobile').val($(this).val()); }); $('#hvac-filter-certification').on('change', function() { $('#hvac-filter-certification-mobile').val($(this).val()); }); $('#hvac-filter-format').on('change', function() { $('#hvac-filter-format-mobile').val($(this).val()); }); } }; // Initialize when document is ready $(document).ready(function() { if ($('#hvac-training-map').length) { HVACTrainingFilters.init(); } }); })(jQuery);