- Fixed registration form not displaying due to missing HVAC_Security_Helpers dependency - Added require_once for dependencies in class-hvac-shortcodes.php render_registration() - Fixed event edit HTTP 500 error by correcting class instantiation to HVAC_Event_Manager - Created comprehensive E2E test suite with MCP Playwright integration - Achieved 70% test success rate with both issues fully resolved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
861 lines
No EOL
34 KiB
JavaScript
861 lines
No EOL
34 KiB
JavaScript
/**
|
||
* Find a Trainer Page JavaScript - Safari Compatible Version
|
||
* Handles filtering, modals, and AJAX interactions
|
||
* ES5 compatible for Safari browser support
|
||
*
|
||
* @package HVAC_Plugin
|
||
* @since 1.0.0
|
||
*/
|
||
|
||
(function($) {
|
||
'use strict';
|
||
|
||
// Cache DOM elements
|
||
var $filterModal, $trainerModal, $contactForm;
|
||
var currentFilter = '';
|
||
var activeFilters = {};
|
||
var currentPage = 1;
|
||
var 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');
|
||
}
|
||
|
||
/**
|
||
* 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
|
||
var 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
|
||
var 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)
|
||
var 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)
|
||
var $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
|
||
var 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] ? $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
|
||
var 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);
|
||
var tempDiv = document.createElement('div');
|
||
tempDiv.innerHTML = data.content;
|
||
var 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) {
|
||
var tempDiv = document.createElement('div');
|
||
tempDiv.innerHTML = data.tooltipContent;
|
||
var 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
|
||
var $matchingCard = $('.hvac-trainer-card').filter(function() {
|
||
var 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() {
|
||
var 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
|
||
var 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] ? $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:', data ? 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();
|
||
var profileId = $(this).data('profile-id');
|
||
if (profileId) {
|
||
// Find the corresponding trainer data from the cards
|
||
var $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
|
||
var 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) {
|
||
var 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) {
|
||
var $modalTitle = $filterModal.find('.hvac-filter-modal-title');
|
||
var $modalOptions = $filterModal.find('.hvac-filter-options');
|
||
|
||
// Set title
|
||
var title = currentFilter.replace(/_/g, ' ');
|
||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||
$modalTitle.text(title);
|
||
|
||
// Build options HTML
|
||
var optionsHtml = '';
|
||
var currentValues = activeFilters[currentFilter] || [];
|
||
|
||
data.options.forEach(function(option) {
|
||
var checked = currentValues.indexOf(option.value) !== -1 ? '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);
|
||
$filterModal.fadeIn(300);
|
||
}
|
||
|
||
/**
|
||
* Apply selected filters
|
||
*/
|
||
function applyFilters() {
|
||
var 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() {
|
||
var $container = $('.hvac-active-filters');
|
||
var html = '';
|
||
|
||
// Convert Object.entries to compatible approach
|
||
for (var filter in activeFilters) {
|
||
if (activeFilters.hasOwnProperty(filter)) {
|
||
var values = activeFilters[filter];
|
||
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();
|
||
var $filter = $(this).parent();
|
||
var filter = $filter.data('filter');
|
||
var value = $filter.data('value');
|
||
|
||
if (activeFilters[filter]) {
|
||
activeFilters[filter] = activeFilters[filter].filter(function(v) {
|
||
return 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();
|
||
|
||
var $card = $(this).closest('.hvac-trainer-card');
|
||
|
||
// Don't allow clicks on Champion cards
|
||
if ($card.hasClass('hvac-champion-card')) {
|
||
return false;
|
||
}
|
||
|
||
var profileId = $(this).data('profile-id');
|
||
|
||
// Get trainer data from the card
|
||
var 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] ? $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
|
||
var $imgContainer = $trainerModal.find('.hvac-modal-image');
|
||
var 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;
|
||
}
|
||
|
||
// Use SafariAjaxHandler if available for robust retry logic
|
||
if (window.SafariAjaxHandler && SafariAjaxHandler.isSafari()) {
|
||
SafariAjaxHandler.request('hvac_get_trainer_upcoming_events', {
|
||
profile_id: profileId
|
||
}, {
|
||
progressCallback: function(progress) {
|
||
if (progress.status === 'retrying') {
|
||
console.log('[Safari] Retrying event fetch, attempt ' + progress.attempt);
|
||
}
|
||
}
|
||
}).done(function(response) {
|
||
handleEventsResponse(response);
|
||
}).fail(function() {
|
||
$trainerModal.find('.hvac-events-list').html('<li>Unable to load events. Please try again.</li>');
|
||
});
|
||
} else {
|
||
// Fallback to standard jQuery AJAX
|
||
$.post(hvac_find_trainer.ajax_url, {
|
||
action: 'hvac_get_trainer_upcoming_events',
|
||
nonce: hvac_find_trainer.nonce,
|
||
profile_id: profileId
|
||
}, function(response) {
|
||
handleEventsResponse(response);
|
||
}).fail(function() {
|
||
$trainerModal.find('.hvac-events-list').html('<li>Unable to load events. Please try again.</li>');
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle events response
|
||
*/
|
||
function handleEventsResponse(response) {
|
||
if (response.success && response.data.events) {
|
||
var 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>');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle contact form submission
|
||
*/
|
||
function handleContactSubmit(e) {
|
||
e.preventDefault();
|
||
|
||
var $form = $(this);
|
||
var $submitBtn = $form.find('.hvac-form-submit');
|
||
var $successMsg = $form.find('.hvac-form-success');
|
||
var $errorMsg = $form.find('.hvac-form-error');
|
||
var 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() {
|
||
var 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;
|
||
var $container = $('.hvac-trainer-grid');
|
||
var $pagination = $('.hvac-pagination');
|
||
|
||
// Show loading state
|
||
$container.addClass('hvac-loading');
|
||
|
||
// Prepare data - ES5 compatible object merge
|
||
var searchValue = $('#hvac-trainer-search').val();
|
||
var filters = {};
|
||
|
||
// Copy activeFilters to filters
|
||
for (var key in activeFilters) {
|
||
if (activeFilters.hasOwnProperty(key)) {
|
||
filters[key] = activeFilters[key];
|
||
}
|
||
}
|
||
filters.search = searchValue;
|
||
|
||
var data = {
|
||
action: 'hvac_filter_trainers',
|
||
nonce: hvac_find_trainer.nonce,
|
||
page: currentPage,
|
||
filters: filters
|
||
};
|
||
|
||
// 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() {
|
||
$filterModal.fadeOut(300);
|
||
$trainerModal.fadeOut(300);
|
||
}
|
||
|
||
/**
|
||
* Debounce helper function
|
||
*/
|
||
function debounce(func, wait) {
|
||
var timeout;
|
||
return function executedFunction() {
|
||
var context = this;
|
||
var args = arguments;
|
||
var later = function() {
|
||
clearTimeout(timeout);
|
||
func.apply(context, 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() {
|
||
var filterCount = 0;
|
||
for (var key in activeFilters) {
|
||
if (activeFilters.hasOwnProperty(key)) {
|
||
filterCount++;
|
||
break; // At least one filter exists
|
||
}
|
||
}
|
||
var hasFilters = filterCount > 0;
|
||
var 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.indexOf('Find a Trainer') !== -1) {
|
||
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();
|
||
var profileId = $(this).data('profile-id');
|
||
showTrainerModal(profileId);
|
||
});
|
||
|
||
// Update URL without page reload for clean sharing
|
||
var currentUrl = window.location.href;
|
||
if (currentUrl.indexOf('/profile/') !== -1 && window.history && window.history.replaceState) {
|
||
var cleanUrl = currentUrl.split('?')[0]; // Remove any query parameters
|
||
window.history.replaceState({}, document.title, cleanUrl);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Expose showTrainerModal globally for MapGeo integration
|
||
window.showTrainerModal = showTrainerModal;
|
||
|
||
})(jQuery); |