/** * Find a Trainer Page JavaScript * Handles filtering, modals, and AJAX interactions * * @package HVAC_Plugin * @since 1.0.0 */ (function($) { 'use strict'; // Cache DOM elements let $filterModal, $trainerModal, $contactForm; let currentFilter = ''; let activeFilters = {}; let currentPage = 1; let isLoading = false; // Initialize on document ready $(document).ready(function() { initializeElements(); bindEvents(); // Handle direct profile URL access handleDirectProfileAccess(); // Enable MapGeo interaction handling (only if not showing direct profile) if (!hvac_find_trainer.show_direct_profile) { preventMapGeoSidebarContent(); interceptMapGeoMarkers(); // Additional MapGeo integration after map loads setTimeout(function() { initializeMapGeoEvents(); }, 2000); // Give MapGeo time to initialize } }); /** * Initialize cached elements */ function initializeElements() { $filterModal = $('#hvac-filter-modal'); $trainerModal = $('#hvac-trainer-modal'); $contactForm = $('#hvac-contact-form'); // CRITICAL: Ensure modals are hidden on initialization if ($filterModal.length) { $filterModal.removeClass('modal-active active show').css({ 'display': 'none', 'visibility': 'hidden', 'opacity': '0' }); } if ($trainerModal.length) { $trainerModal.css('display', 'none'); } } /** * Prevent MapGeo from displaying content in its sidebar * This ensures trainer cards only appear in our Container 5 */ function preventMapGeoSidebarContent() { // Remove any MapGeo sidebar content immediately $('.igm_content_right_1_3').remove(); $('.igm_content_gutter').remove(); // Watch for any dynamic content injection from MapGeo const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(function(node) { if (node.nodeType === 1) { // Element node // Remove any MapGeo sidebar that gets added if ($(node).hasClass('igm_content_right_1_3') || $(node).hasClass('igm_content_gutter')) { $(node).remove(); } // Also check children $(node).find('.igm_content_right_1_3, .igm_content_gutter').remove(); } }); } }); }); // Observe the map section for changes const mapSection = document.querySelector('.hvac-map-section'); if (mapSection) { observer.observe(mapSection, { childList: true, subtree: true }); } // Also observe the entire page for MapGeo injections observer.observe(document.body, { childList: true, subtree: true }); } /** * Initialize MapGeo-specific event handlers after map loads */ function initializeMapGeoEvents() { console.log('Initializing MapGeo events...'); // Create the main MapGeo handler function // This replaces the early version created in the page template window.hvacMainShowTrainerModal = function(data) { console.log('MapGeo custom action triggered with data:', data); // Method 1: Use profile_id if available (most reliable) let profileId = null; if (data && data.profile_id && data.profile_id.trim() !== '') { profileId = data.profile_id.trim(); } else if (data && data.id && data.id.toString().startsWith('trainer_')) { // Extract profile ID from marker ID format "trainer_123" profileId = data.id.replace('trainer_', ''); } else if (data && data.name && data.name.match(/^\d+$/)) { // Check if name field actually contains the profile ID (common case) profileId = data.name; } else if (data && data.id && data.id.match(/^\d+$/)) { // Check if id field contains just the profile ID number profileId = data.id; } console.log('Extracted profile ID:', profileId); if (profileId) { // Find trainer card by profile ID (most reliable method) const $matchingCard = $('.hvac-trainer-card[data-profile-id="' + profileId + '"]'); if ($matchingCard.length > 0 && !$matchingCard.hasClass('hvac-champion-card')) { console.log('Found matching trainer card by profile ID:', profileId); // Extract trainer data from the card const trainerData = { profile_id: profileId, name: $matchingCard.find('.hvac-trainer-name a, .hvac-trainer-name .hvac-champion-name').text().trim(), city: $matchingCard.find('.hvac-trainer-location').text().split(',')[0], state: $matchingCard.find('.hvac-trainer-location').text().split(',')[1]?.trim(), certification_type: $matchingCard.find('.hvac-trainer-certification').text(), // Legacy compatibility certifications: [], profile_image: $matchingCard.find('.hvac-trainer-image img:not(.hvac-mq-badge)').attr('src') || '', business_type: 'Independent Contractor', // Mock data event_count: parseInt($matchingCard.data('event-count')) || 0, training_formats: 'In-Person, Virtual', training_locations: 'On-site, Remote', upcoming_events: [] }; // Extract certifications from card badges $matchingCard.find('.hvac-trainer-cert-badge').each(function() { const certText = $(this).text().trim(); if (certText && certText !== 'HVAC Trainer') { trainerData.certifications.push({ type: certText, status: $(this).hasClass('hvac-cert-legacy') ? 'legacy' : 'active' }); } }); // Show the trainer modal showTrainerModal(trainerData); return; // Successfully handled } else if ($matchingCard.length > 0 && $matchingCard.hasClass('hvac-champion-card')) { console.log('Clicked marker is for a Champion, not showing modal'); return; // Champions don't get modals } else { console.warn('No trainer card found for profile ID:', profileId); } } // Fallback Method 2: Try to extract trainer name and match let trainerName = null; // Try various name fields if (data && data.name && data.name.trim() !== '+' && !data.name.match(/^\d+$/)) { trainerName = data.name.trim(); } else if (data && data.title && data.title.trim() !== '+') { trainerName = data.title.trim(); } // Try content field if (!trainerName && data && data.content) { console.log('Trying to extract trainer from content:', data.content); const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.content; const nameElements = tempDiv.querySelectorAll('h4, strong, .trainer-name, [class*="name"]'); if (nameElements.length > 0) { trainerName = nameElements[0].textContent.trim(); } } // Try tooltipContent if (!trainerName && data && data.tooltipContent) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = data.tooltipContent; const strongElements = tempDiv.querySelectorAll('strong'); if (strongElements.length > 0) { trainerName = strongElements[0].textContent.trim(); } } console.log('Extracted trainer name (fallback):', trainerName); if (trainerName && trainerName !== '+') { // Try to find matching trainer by name let $matchingCard = $('.hvac-trainer-card').filter(function() { const cardName = $(this).find('.hvac-trainer-name a, .hvac-trainer-name .hvac-champion-name').text().trim(); return cardName === trainerName; }); // If exact match not found, try partial matching if ($matchingCard.length === 0) { $matchingCard = $('.hvac-trainer-card').filter(function() { const cardName = $(this).find('.hvac-trainer-name a, .hvac-trainer-name .hvac-champion-name').text().trim(); return cardName.toLowerCase().includes(trainerName.toLowerCase()) || trainerName.toLowerCase().includes(cardName.toLowerCase()); }); } if ($matchingCard.length > 0 && !$matchingCard.hasClass('hvac-champion-card')) { console.log('Found matching trainer card by name:', trainerName); // Extract trainer data from the card const trainerData = { profile_id: $matchingCard.data('profile-id'), name: $matchingCard.find('.hvac-trainer-name a, .hvac-trainer-name .hvac-champion-name').text().trim(), city: $matchingCard.find('.hvac-trainer-location').text().split(',')[0], state: $matchingCard.find('.hvac-trainer-location').text().split(',')[1]?.trim(), certification_type: $matchingCard.find('.hvac-trainer-certification').text(), // Legacy compatibility certifications: [], profile_image: $matchingCard.find('.hvac-trainer-image img:not(.hvac-mq-badge)').attr('src') || '', business_type: 'Independent Contractor', // Mock data event_count: parseInt($matchingCard.data('event-count')) || 0, training_formats: 'In-Person, Virtual', training_locations: 'On-site, Remote', upcoming_events: [] }; // Extract certifications from card badges $matchingCard.find('.hvac-trainer-cert-badge').each(function() { const certText = $(this).text().trim(); if (certText && certText !== 'HVAC Trainer') { trainerData.certifications.push({ type: certText, status: $(this).hasClass('hvac-cert-legacy') ? 'legacy' : 'active' }); } }); // Show the trainer modal showTrainerModal(trainerData); } else if ($matchingCard.length > 0 && $matchingCard.hasClass('hvac-champion-card')) { console.log('Matched trainer is a Champion, not showing modal'); } else { console.warn('No matching trainer found for name:', trainerName); console.log('Available trainers:', $('.hvac-trainer-card .hvac-trainer-name a, .hvac-trainer-card .hvac-trainer-name .hvac-champion-name').map(function() { return $(this).text().trim(); }).get() ); } } else { console.warn('Could not extract valid trainer identifier from MapGeo data:', data); console.log('Available data properties:', Object.keys(data || {})); console.log('Available profile IDs on page:', $('.hvac-trainer-card').map(function() { return $(this).data('profile-id'); }).get() ); } }; // Replace the early function with the main one window.hvacShowTrainerModal = window.hvacMainShowTrainerModal; // Process any queued calls from before the main script loaded if (window.hvacPendingModalCalls && window.hvacPendingModalCalls.length > 0) { console.log('Processing', window.hvacPendingModalCalls.length, 'queued MapGeo calls'); window.hvacPendingModalCalls.forEach(function(data) { window.hvacMainShowTrainerModal(data); }); window.hvacPendingModalCalls = []; // Clear the queue } console.log('MapGeo custom action function created: window.hvacShowTrainerModal'); } /** * Prevent MapGeo from showing content in sidebar (if needed) */ function interceptMapGeoMarkers() { // This function now primarily handles preventing MapGeo sidebar content // The actual marker clicks are handled via the MapGeo custom action: window.hvacShowTrainerModal // Handle any legacy view profile links if they exist in tooltips/popups $(document).on('click', '.hvac-view-profile, .hvac-marker-popup button', function(e) { e.preventDefault(); e.stopPropagation(); const profileId = $(this).data('profile-id'); if (profileId) { // Find the corresponding trainer data from the cards const $trainerCard = $('.hvac-trainer-card[data-profile-id="' + profileId + '"]'); if ($trainerCard.length > 0 && !$trainerCard.hasClass('hvac-champion-card')) { // Get trainer name and trigger the MapGeo custom action const trainerName = $trainerCard.find('.hvac-trainer-name a, .hvac-trainer-name .hvac-champion-name').text().trim(); // Trigger the same function MapGeo would call if (window.hvacShowTrainerModal) { window.hvacShowTrainerModal({ name: trainerName }); } } } }); } /** * Bind all event handlers */ function bindEvents() { // Filter button clicks - handle both class variations $('.hvac-filter-btn, .hvac-filter-button').on('click', handleFilterClick); // Filter modal apply $('.hvac-filter-apply').on('click', applyFilters); // Clear all filters button $('.hvac-clear-filters').on('click', clearAllFilters); // Trainer profile clicks - using event delegation $(document).on('click', '.hvac-open-profile', handleProfileClick); // Modal close buttons and backdrop clicks $('.hvac-modal-close').on('click', closeModals); // Click on modal backdrop to close $filterModal.on('click', function(e) { if ($(e.target).is('#hvac-filter-modal')) { closeModals(); } }); $trainerModal.on('click', function(e) { if ($(e.target).is('#hvac-trainer-modal')) { closeModals(); } }); // Escape key to close modals $(document).on('keydown', function(e) { if (e.key === 'Escape') { closeModals(); } }); // Search input $('.hvac-search-input').on('input', debounce(handleSearch, 500)); // Contact form submission (both modal and direct forms) $contactForm.on('submit', handleContactSubmit); $(document).on('submit', '#hvac-direct-contact-form', handleContactSubmit); // Pagination clicks $(document).on('click', '.hvac-pagination a, .hvac-page-link', handlePagination); // Active filter removal $(document).on('click', '.hvac-active-filter button', removeActiveFilter); } /** * Handle filter button click */ function handleFilterClick(e) { e.preventDefault(); e.stopPropagation(); currentFilter = $(this).data('filter'); // Load real filter options via AJAX loadFilterOptions(currentFilter); } /** * Load filter options via AJAX */ function loadFilterOptions(filterType) { if (isLoading) return; isLoading = true; // Show loading state for filter button $(`.hvac-filter-btn[data-filter="${filterType}"]`).addClass('loading'); $.post(hvac_find_trainer.ajax_url, { action: 'hvac_get_filter_options', filter_type: filterType, nonce: hvac_find_trainer.nonce }) .done(function(response) { if (response.success && response.data.options) { // Convert the different response formats to standard format let options = []; if (filterType === 'business_type') { // Business types have {value, label, count} format options = response.data.options; } else { // States and other simple arrays need to be converted to {value, label} format options = response.data.options.map(function(option) { if (typeof option === 'string') { return {value: option, label: option}; } return option; }); } showFilterModal({options: options}); } else { console.error('Failed to load filter options:', response); // Fallback to empty options showFilterModal({options: []}); } }) .fail(function(xhr, status, error) { console.error('AJAX error loading filter options:', status, error); // Fallback to empty options showFilterModal({options: []}); }) .always(function() { isLoading = false; $(`.hvac-filter-btn[data-filter="${filterType}"]`).removeClass('loading'); }); } /** * Get mock filter options (kept as fallback) */ function getMockFilterOptions(filterType) { const options = { state: [ {value: 'Alabama', label: 'Alabama'}, {value: 'Alaska', label: 'Alaska'}, {value: 'Arizona', label: 'Arizona'}, {value: 'Arkansas', label: 'Arkansas'}, {value: 'California', label: 'California'}, {value: 'Colorado', label: 'Colorado'}, {value: 'Florida', label: 'Florida'}, {value: 'Georgia', label: 'Georgia'}, {value: 'Illinois', label: 'Illinois'}, {value: 'Michigan', label: 'Michigan'}, {value: 'Minnesota', label: 'Minnesota'}, {value: 'Ohio', label: 'Ohio'}, {value: 'Texas', label: 'Texas'}, {value: 'Wisconsin', label: 'Wisconsin'} ], business_type: [ {value: 'Independent Contractor', label: 'Independent Contractor'}, {value: 'Small Business', label: 'Small Business'}, {value: 'Corporation', label: 'Corporation'}, {value: 'Non-Profit', label: 'Non-Profit'} ], training_format: [ {value: 'In-Person', label: 'In-Person'}, {value: 'Virtual', label: 'Virtual'}, {value: 'Hybrid', label: 'Hybrid'}, {value: 'Self-Paced', label: 'Self-Paced'} ], training_resources: [ {value: 'Video Tutorials', label: 'Video Tutorials'}, {value: 'Written Guides', label: 'Written Guides'}, {value: 'Hands-On Training', label: 'Hands-On Training'}, {value: 'Certification Programs', label: 'Certification Programs'} ] }; return { options: options[filterType] || [] }; } /** * Show filter modal with options */ function showFilterModal(data) { const $modalTitle = $filterModal.find('.hvac-filter-modal-title'); const $modalOptions = $filterModal.find('.hvac-filter-options'); // Set title let title = currentFilter.replace(/_/g, ' '); title = title.charAt(0).toUpperCase() + title.slice(1); $modalTitle.text(title); // Build options HTML let optionsHtml = ''; const currentValues = activeFilters[currentFilter] || []; data.options.forEach(function(option) { const checked = currentValues.includes(option.value) ? 'checked' : ''; optionsHtml += `
No trainers found matching your criteria. Please try adjusting your filters.
Error loading trainers. Please try again.