upskill-event-manager/assets/js/find-trainer.js
Ben Reed cdc5ea85f4 feat: Add comprehensive CSS, JavaScript and theme asset infrastructure
Add massive collection of CSS, JavaScript and theme assets that were previously excluded:

**CSS Files (681 total):**
- HVAC plugin-specific styles (hvac-*.css): 34 files including dashboard, certificates, registration, mobile nav, accessibility fixes, animations, and welcome popup
- Theme framework files (Astra, builder systems, layouts): 200+ files
- Plugin compatibility styles (WooCommerce, WPForms, Elementor, Contact Form 7): 150+ files
- WordPress core and editor styles: 50+ files
- Responsive and RTL language support: 200+ files

**JavaScript Files (400+ total):**
- HVAC plugin functionality (hvac-*.js): 27 files including menu systems, dashboard enhancements, profile sharing, mobile responsive features, accessibility, and animations
- Framework and library files: jQuery plugins, GSAP, AOS, Swiper, Chart.js, Lottie, Isotope
- Plugin compatibility scripts: WPForms, WooCommerce, Elementor, Contact Form 7, LifterLMS
- WordPress core functionality: customizer, admin, block editor compatibility
- Third-party integrations: Stripe, SMTP, analytics, search functionality

**Assets:**
- Certificate background images and logos
- Comprehensive theme styling infrastructure
- Mobile-responsive design systems
- Cross-browser compatibility assets
- Performance-optimized minified versions

**Updated .gitignore:**
- Fixed asset directory whitelisting patterns to properly include CSS/JS/images
- Added proper directory structure recognition (!/assets/css/, !/assets/js/, etc.)
- Maintains security by excluding sensitive files while including essential assets

This commit provides the complete frontend infrastructure needed for:
- Full theme functionality and styling
- Plugin feature implementations
- Mobile responsiveness and accessibility
- Cross-browser compatibility
- Performance optimization
- Developer workflow support
2025-08-11 16:20:31 -03:00

832 lines
No EOL
33 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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(),
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: []
};
// 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(),
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: []
};
// 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
$('.hvac-filter-btn').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-trainer-search').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');
// For now, show mock filter options
showFilterModal(getMockFilterOptions(currentFilter));
}
/**
* Get mock filter options (replace with AJAX later)
*/
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 += `
<div class="hvac-filter-option">
<input type="checkbox" id="filter_${option.value.replace(/\s+/g, '_')}" value="${option.value}" ${checked}>
<label for="filter_${option.value.replace(/\s+/g, '_')}">${option.label}</label>
</div>
`;
});
$modalOptions.html(optionsHtml);
// Use the new modal-active class for proper visibility control
$filterModal.addClass('modal-active').css('display', 'flex').fadeIn(300);
}
/**
* Apply selected filters
*/
function applyFilters() {
const selectedValues = [];
$filterModal.find('.hvac-filter-option input:checked').each(function() {
selectedValues.push($(this).val());
});
if (selectedValues.length > 0) {
activeFilters[currentFilter] = selectedValues;
} else {
delete activeFilters[currentFilter];
}
updateActiveFiltersDisplay();
updateClearButtonVisibility();
currentPage = 1;
loadFilteredTrainers();
closeModals();
}
/**
* Update active filters display
*/
function updateActiveFiltersDisplay() {
const $container = $('.hvac-active-filters');
let html = '';
for (const [filter, values] of Object.entries(activeFilters)) {
values.forEach(function(value) {
html += `
<div class="hvac-active-filter" data-filter="${filter}" data-value="${value}">
${value}
<button type="button" aria-label="Remove filter">×</button>
</div>
`;
});
}
$container.html(html);
}
/**
* Remove active filter
*/
function removeActiveFilter(e) {
e.preventDefault();
const $filter = $(this).parent();
const filter = $filter.data('filter');
const value = $filter.data('value');
if (activeFilters[filter]) {
activeFilters[filter] = activeFilters[filter].filter(v => v !== value);
if (activeFilters[filter].length === 0) {
delete activeFilters[filter];
}
}
updateActiveFiltersDisplay();
updateClearButtonVisibility();
currentPage = 1;
loadFilteredTrainers();
}
/**
* Handle trainer profile click
*/
function handleProfileClick(e) {
e.preventDefault();
e.stopPropagation();
const $card = $(this).closest('.hvac-trainer-card');
// Don't allow clicks on Champion cards
if ($card.hasClass('hvac-champion-card')) {
return false;
}
const profileId = $(this).data('profile-id');
// Get trainer data from the card
const trainerData = {
profile_id: profileId,
name: $card.find('.hvac-trainer-name a').text(),
city: $card.find('.hvac-trainer-location').text().split(',')[0],
state: $card.find('.hvac-trainer-location').text().split(',')[1]?.trim(),
certification_type: $card.find('.hvac-trainer-certification').text(),
profile_image: $card.find('.hvac-trainer-image img').attr('src') || '',
business_type: 'Independent Contractor', // Mock data
event_count: parseInt($card.data('event-count')) || 0, // Real event count from data attribute
training_formats: 'In-Person, Virtual',
training_locations: 'On-site, Remote',
upcoming_events: [] // Mock empty events
};
showTrainerModal(trainerData);
}
/**
* Show trainer profile modal
* Made global so MapGeo can access it
*/
function showTrainerModal(trainer) {
// Update modal title
$trainerModal.find('.hvac-modal-title').text(trainer.name);
// Update profile image
const $imgContainer = $trainerModal.find('.hvac-modal-image');
let imageHtml = '';
if (trainer.profile_image) {
imageHtml = `<img src="${trainer.profile_image}" alt="${trainer.name}">`;
} else {
imageHtml = '<div class="hvac-trainer-avatar"><span class="dashicons dashicons-businessperson"></span></div>';
}
// Add mQ badge overlay for certified trainers
if (trainer.certification_type === 'Certified measureQuick Trainer') {
imageHtml += '<div class="hvac-mq-badge-overlay"><img src="/wp-content/uploads/2025/08/mQ-Certified-trainer.png" alt="measureQuick Certified Trainer" class="hvac-mq-badge"></div>';
}
$imgContainer.html(imageHtml);
// Update profile info
$trainerModal.find('.hvac-modal-location').text(`${trainer.city}, ${trainer.state}`);
$trainerModal.find('.hvac-modal-certification').text(trainer.certification_type || 'HVAC Trainer');
$trainerModal.find('.hvac-modal-business').text(trainer.business_type || '');
$trainerModal.find('.hvac-modal-events span').text(trainer.event_count || 0);
// Update training details
$trainerModal.find('.hvac-training-formats').text(trainer.training_formats || 'Various');
$trainerModal.find('.hvac-training-locations').text(trainer.training_locations || 'On-site');
// Show loading state for events
$trainerModal.find('.hvac-events-list').html('<li>Loading upcoming events...</li>');
// Set hidden fields for contact form
$contactForm.find('input[name="trainer_id"]').val(trainer.user_id || '');
$contactForm.find('input[name="trainer_profile_id"]').val(trainer.profile_id);
// Reset contact form
$contactForm[0].reset();
$('.hvac-form-message').hide();
// Show modal
$trainerModal.fadeIn(300);
// Fetch upcoming events via AJAX
fetchUpcomingEvents(trainer.profile_id);
}
/**
* Fetch upcoming events for a trainer via AJAX
*/
function fetchUpcomingEvents(profileId) {
if (!profileId) {
$trainerModal.find('.hvac-events-list').html('<li>No upcoming events scheduled</li>');
return;
}
$.post(hvac_find_trainer.ajax_url, {
action: 'hvac_get_trainer_upcoming_events',
nonce: hvac_find_trainer.nonce,
profile_id: profileId
}, function(response) {
if (response.success && response.data.events) {
let eventsHtml = '';
if (response.data.events.length > 0) {
response.data.events.forEach(function(event) {
eventsHtml += `<li><a href="${event.url}" target="_blank">${event.title}</a> - ${event.date}</li>`;
});
} else {
eventsHtml = '<li>No upcoming events scheduled</li>';
}
$trainerModal.find('.hvac-events-list').html(eventsHtml);
} else {
$trainerModal.find('.hvac-events-list').html('<li>No upcoming events scheduled</li>');
}
}).fail(function() {
$trainerModal.find('.hvac-events-list').html('<li>Unable to load events</li>');
});
}
/**
* Handle contact form submission
*/
function handleContactSubmit(e) {
e.preventDefault();
const $form = $(this);
const $submitBtn = $form.find('.hvac-form-submit');
const $successMsg = $form.find('.hvac-form-success');
const $errorMsg = $form.find('.hvac-form-error');
const originalText = $submitBtn.text();
$submitBtn.text('Sending...').prop('disabled', true);
// For now, just show success message
setTimeout(function() {
$successMsg.show();
$errorMsg.hide();
$form[0].reset();
$submitBtn.text(originalText).prop('disabled', false);
// Hide success message after 5 seconds
setTimeout(function() {
$successMsg.fadeOut();
}, 5000);
}, 1000);
}
/**
* Handle search input
*/
function handleSearch() {
const searchTerm = $('#hvac-trainer-search').val();
if (isLoading) return;
updateClearButtonVisibility();
currentPage = 1;
loadFilteredTrainers();
}
/**
* Handle pagination
*/
function handlePagination(e) {
e.preventDefault();
currentPage = $(this).data('page');
loadFilteredTrainers();
// Scroll to top of trainer grid
$('html, body').animate({
scrollTop: $('.hvac-trainer-directory-container').offset().top - 100
}, 500);
}
/**
* Load filtered trainers via AJAX
*/
function loadFilteredTrainers() {
if (isLoading) return;
isLoading = true;
const $container = $('.hvac-trainer-grid');
let $pagination = $('.hvac-pagination');
// Show loading state
$container.addClass('hvac-loading');
// Prepare data
const data = {
action: 'hvac_filter_trainers',
nonce: hvac_find_trainer.nonce,
page: currentPage,
filters: {
...activeFilters,
search: $('#hvac-trainer-search').val()
}
};
// Make AJAX request
$.post(hvac_find_trainer.ajax_url, data, function(response) {
if (response.success) {
// Update trainer grid
$container.html(response.data.html);
// Update pagination
if (response.data.pagination && response.data.pagination.length > 0) {
// Pagination HTML returned - replace existing or create new
if ($pagination.length > 0) {
$pagination.replaceWith(response.data.pagination);
} else {
$('.hvac-trainer-directory-container').append(response.data.pagination);
}
} else {
// No pagination HTML - either hide existing or ensure container exists for later
if ($pagination.length > 0) {
$pagination.empty();
} else if (response.data.max_pages > 1) {
// Add empty pagination container for when pages increase later
$('.hvac-trainer-directory-container').append('<div class="hvac-pagination"></div>');
}
}
// Update pagination reference after potential DOM changes
$pagination = $('.hvac-pagination');
// Update count display if exists
if (response.data.count !== undefined) {
$('.hvac-trainer-count').text(response.data.count + ' trainers found');
}
} else {
console.error('Failed to load trainers:', response);
}
}).fail(function(xhr) {
console.error('AJAX error:', xhr);
}).always(function() {
isLoading = false;
$container.removeClass('hvac-loading');
});
}
/**
* Close all modals
*/
function closeModals() {
// Remove the modal-active class to ensure proper hiding
$filterModal.removeClass('modal-active').fadeOut(300, function() {
$(this).css('display', 'none');
});
$trainerModal.fadeOut(300);
}
/**
* Debounce helper function
*/
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
/**
* Clear all filters
*/
function clearAllFilters() {
activeFilters = {};
$('#hvac-trainer-search').val('');
updateActiveFiltersDisplay();
updateClearButtonVisibility();
currentPage = 1;
loadFilteredTrainers();
}
/**
* Update clear button visibility
*/
function updateClearButtonVisibility() {
const hasFilters = Object.keys(activeFilters).length > 0;
const hasSearch = $('#hvac-trainer-search').val().trim() !== '';
if (hasFilters || hasSearch) {
$('.hvac-clear-filters').show();
} else {
$('.hvac-clear-filters').hide();
}
}
/**
* Handle direct profile URL access
* When someone accesses /find-a-trainer/profile/{id}, show the profile and handle interactions
*/
function handleDirectProfileAccess() {
// Check if we're showing a direct profile
if (hvac_find_trainer.show_direct_profile && hvac_find_trainer.direct_profile_id) {
console.log('Direct profile access detected for profile ID:', hvac_find_trainer.direct_profile_id);
// Update page title in browser
if (document.title.includes('Find a Trainer')) {
document.title = document.title.replace('Find a Trainer', 'Trainer Profile');
}
// Bind contact trainer button
$(document).on('click', '.hvac-contact-trainer-btn', function(e) {
e.preventDefault();
const profileId = $(this).data('profile-id');
showTrainerModal(profileId);
});
// Update URL without page reload for clean sharing
const currentUrl = window.location.href;
if (currentUrl.includes('/profile/') && window.history && window.history.replaceState) {
const cleanUrl = currentUrl.split('?')[0]; // Remove any query parameters
window.history.replaceState({}, document.title, cleanUrl);
}
}
}
// Expose showTrainerModal globally for MapGeo integration
window.showTrainerModal = showTrainerModal;
})(jQuery);