- Refactored registration form:
  * Moved Application Details to Personal Information section
  * Renamed Business Information to Training Organization Information
  * Added required Organization Logo upload with media library integration
  * Added Headquarters location fields (City, State/Province, Country)
  * Moved training-related fields into Organization section
  * Created conditional Training Venue Information section with auto-population
- Created comprehensive venue management system:
  * Training Venues List page (/trainer/venue/list) with filtering and pagination
  * Manage Venue page (/trainer/venue/manage) for create/edit operations
  * Full integration with The Events Calendar venue post type
  * AJAX-powered forms with real-time validation
- Created trainer profile system:
  * Trainer Profile view page (/trainer/profile) with stats and certifications
  * Profile Edit page (/trainer/profile/edit) with photo upload
  * Years of experience tracking and professional information
  * Integration with user meta and custom fields
- Created training organizers management:
  * Organizers List page (/trainer/organizer/list) with search functionality
  * Manage Organizer page (/trainer/organizer/manage) for CRUD operations
  * Organization logo upload and headquarters tracking
  * Full integration with The Events Calendar organizer post type
- Technical improvements:
  * Modular PHP class architecture for each feature
  * Comprehensive AJAX handlers with security nonces
  * Responsive CSS design for all new pages
  * JavaScript form validation and dynamic behavior
  * Proper WordPress and TEC API integration
All new features follow hierarchical URL structure and include breadcrumb navigation.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
		
	
			
		
			
				
	
	
		
			364 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			No EOL
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * HVAC Organizers JavaScript
 | |
|  *
 | |
|  * @package HVAC_Community_Events
 | |
|  * @version 2.0.0
 | |
|  */
 | |
| 
 | |
| jQuery(document).ready(function($) {
 | |
|     // Cache DOM elements
 | |
|     const $organizerForm = $('#hvac-organizer-form');
 | |
|     const $uploadButton = $('#hvac-upload-logo');
 | |
|     const $removeButton = $('#hvac-remove-logo');
 | |
|     const $logoIdField = $('#org_logo_id');
 | |
|     const $currentLogo = $('.hvac-current-logo');
 | |
|     const $deleteButton = $('#hvac-delete-organizer');
 | |
|     
 | |
|     // Form validation
 | |
|     function validateOrganizerForm() {
 | |
|         let isValid = true;
 | |
|         const errors = [];
 | |
|         
 | |
|         // Clear previous errors
 | |
|         $('.hvac-form-error').removeClass('hvac-form-error');
 | |
|         $('.hvac-error-message').remove();
 | |
|         
 | |
|         // Required fields
 | |
|         const requiredFields = [
 | |
|             { id: 'org_name', label: 'Organization Name' },
 | |
|             { id: 'hq_city', label: 'Headquarters City' },
 | |
|             { id: 'hq_state', label: 'Headquarters State/Province' },
 | |
|             { id: 'hq_country', label: 'Headquarters Country' }
 | |
|         ];
 | |
|         
 | |
|         requiredFields.forEach(field => {
 | |
|             const $field = $('#' + field.id);
 | |
|             const value = $field.val();
 | |
|             
 | |
|             if (!value || value.trim() === '') {
 | |
|                 isValid = false;
 | |
|                 errors.push(field.label + ' is required');
 | |
|                 $field.addClass('hvac-form-error');
 | |
|                 $field.after('<span class="hvac-error-message">' + field.label + ' is required</span>');
 | |
|             }
 | |
|         });
 | |
|         
 | |
|         // Validate email if provided
 | |
|         const email = $('#org_email').val();
 | |
|         if (email && !isValidEmail(email)) {
 | |
|             isValid = false;
 | |
|             errors.push('Please enter a valid email address');
 | |
|             $('#org_email').addClass('hvac-form-error');
 | |
|             $('#org_email').after('<span class="hvac-error-message">Please enter a valid email address</span>');
 | |
|         }
 | |
|         
 | |
|         // Validate phone format if provided
 | |
|         const phone = $('#org_phone').val();
 | |
|         if (phone && !isValidPhone(phone)) {
 | |
|             isValid = false;
 | |
|             errors.push('Please enter a valid phone number');
 | |
|             $('#org_phone').addClass('hvac-form-error');
 | |
|             $('#org_phone').after('<span class="hvac-error-message">Please enter a valid phone number</span>');
 | |
|         }
 | |
|         
 | |
|         // Validate website URL if provided
 | |
|         const website = $('#org_website').val();
 | |
|         if (website && !isValidURL(website)) {
 | |
|             isValid = false;
 | |
|             errors.push('Please enter a valid website URL');
 | |
|             $('#org_website').addClass('hvac-form-error');
 | |
|             $('#org_website').after('<span class="hvac-error-message">Please enter a valid website URL</span>');
 | |
|         }
 | |
|         
 | |
|         return isValid;
 | |
|     }
 | |
|     
 | |
|     // Email validation
 | |
|     function isValidEmail(email) {
 | |
|         const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
 | |
|         return re.test(email);
 | |
|     }
 | |
|     
 | |
|     // Phone validation
 | |
|     function isValidPhone(phone) {
 | |
|         const digits = phone.replace(/\D/g, '');
 | |
|         return digits.length >= 10 && digits.length <= 15;
 | |
|     }
 | |
|     
 | |
|     // URL validation
 | |
|     function isValidURL(url) {
 | |
|         try {
 | |
|             new URL(url);
 | |
|             return true;
 | |
|         } catch (_) {
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     // Show message
 | |
|     function showMessage(message, type = 'success') {
 | |
|         const messageClass = type === 'success' ? 'hvac-message-success' : 'hvac-message-error';
 | |
|         const $message = $('<div class="hvac-message ' + messageClass + '">' + message + '</div>');
 | |
|         
 | |
|         // Remove any existing messages
 | |
|         $('.hvac-message').remove();
 | |
|         
 | |
|         // Add new message
 | |
|         $('.hvac-page-header').after($message);
 | |
|         
 | |
|         // Auto-hide success messages after 5 seconds
 | |
|         if (type === 'success') {
 | |
|             setTimeout(function() {
 | |
|                 $message.fadeOut(function() {
 | |
|                     $(this).remove();
 | |
|                 });
 | |
|             }, 5000);
 | |
|         }
 | |
|         
 | |
|         // Scroll to top
 | |
|         $('html, body').animate({
 | |
|             scrollTop: $('.hvac-page-header').offset().top - 100
 | |
|         }, 300);
 | |
|     }
 | |
|     
 | |
|     // Handle organizer form submission
 | |
|     if ($organizerForm.length) {
 | |
|         $organizerForm.on('submit', function(e) {
 | |
|             e.preventDefault();
 | |
|             
 | |
|             // Validate form
 | |
|             if (!validateOrganizerForm()) {
 | |
|                 return false;
 | |
|             }
 | |
|             
 | |
|             // Disable submit button
 | |
|             const $submitButton = $organizerForm.find('button[type="submit"]');
 | |
|             const originalText = $submitButton.text();
 | |
|             $submitButton.prop('disabled', true).text('Saving...');
 | |
|             
 | |
|             // Gather form data
 | |
|             const formData = {
 | |
|                 action: 'hvac_save_organizer',
 | |
|                 nonce: hvacOrganizers.nonce,
 | |
|                 organizer_id: $('input[name="organizer_id"]').val(),
 | |
|                 org_name: $('#org_name').val(),
 | |
|                 org_description: $('#org_description').val(),
 | |
|                 hq_city: $('#hq_city').val(),
 | |
|                 hq_state: $('#hq_state').val(),
 | |
|                 hq_country: $('#hq_country').val(),
 | |
|                 org_phone: $('#org_phone').val(),
 | |
|                 org_email: $('#org_email').val(),
 | |
|                 org_website: $('#org_website').val(),
 | |
|                 org_logo_id: $('#org_logo_id').val()
 | |
|             };
 | |
|             
 | |
|             // Send AJAX request
 | |
|             $.ajax({
 | |
|                 url: hvacOrganizers.ajax_url,
 | |
|                 type: 'POST',
 | |
|                 data: formData,
 | |
|                 success: function(response) {
 | |
|                     if (response.success) {
 | |
|                         showMessage(response.data.message, 'success');
 | |
|                         
 | |
|                         // If creating new organizer, update form to edit mode
 | |
|                         if (!formData.organizer_id && response.data.organizer_id) {
 | |
|                             $('input[name="organizer_id"]').val(response.data.organizer_id);
 | |
|                             $('.hvac-page-header h1').text('Edit Organizer');
 | |
|                             $('.hvac-breadcrumb').html('<a href="/trainer/dashboard/">Trainer</a> > <a href="/trainer/organizer/list/">Organizers</a> > Edit');
 | |
|                             
 | |
|                             // Add delete button if not present
 | |
|                             if (!$('#hvac-delete-organizer').length) {
 | |
|                                 const deleteButton = '<button type="button" id="hvac-delete-organizer" class="hvac-button hvac-button-danger" data-organizer-id="' + response.data.organizer_id + '">Delete Organizer</button>';
 | |
|                                 $('.hvac-form-actions').append(deleteButton);
 | |
|                             }
 | |
|                         }
 | |
|                         
 | |
|                         // Update button text
 | |
|                         $submitButton.text('Update Organizer');
 | |
|                     } else {
 | |
|                         showMessage(response.data || 'An error occurred while saving the organizer.', 'error');
 | |
|                     }
 | |
|                 },
 | |
|                 error: function() {
 | |
|                     showMessage('An error occurred. Please try again.', 'error');
 | |
|                 },
 | |
|                 complete: function() {
 | |
|                     // Re-enable submit button
 | |
|                     $submitButton.prop('disabled', false).text(originalText);
 | |
|                 }
 | |
|             });
 | |
|         });
 | |
|     }
 | |
|     
 | |
|     // Handle logo upload
 | |
|     if ($uploadButton.length) {
 | |
|         let mediaUploader;
 | |
|         
 | |
|         $uploadButton.on('click', function(e) {
 | |
|             e.preventDefault();
 | |
|             
 | |
|             // If the media uploader already exists, open it
 | |
|             if (mediaUploader) {
 | |
|                 mediaUploader.open();
 | |
|                 return;
 | |
|             }
 | |
|             
 | |
|             // Create the media uploader
 | |
|             mediaUploader = wp.media({
 | |
|                 title: 'Choose Organization Logo',
 | |
|                 button: {
 | |
|                     text: 'Use this logo'
 | |
|                 },
 | |
|                 multiple: false,
 | |
|                 library: {
 | |
|                     type: 'image'
 | |
|                 }
 | |
|             });
 | |
|             
 | |
|             // When an image is selected, run a callback
 | |
|             mediaUploader.on('select', function() {
 | |
|                 const attachment = mediaUploader.state().get('selection').first().toJSON();
 | |
|                 
 | |
|                 // Update the logo preview
 | |
|                 $currentLogo.html('<img src="' + attachment.sizes.medium.url + '" alt="Organization logo" />');
 | |
|                 
 | |
|                 // Update the hidden field
 | |
|                 $logoIdField.val(attachment.id);
 | |
|                 
 | |
|                 // Update button text
 | |
|                 $uploadButton.text('Change Logo');
 | |
|                 
 | |
|                 // Show remove button if not already visible
 | |
|                 if (!$('#hvac-remove-logo').length) {
 | |
|                     const removeBtn = '<button type="button" id="hvac-remove-logo" class="hvac-button hvac-button-danger-outline">Remove Logo</button>';
 | |
|                     $uploadButton.after(removeBtn);
 | |
|                 }
 | |
|             });
 | |
|             
 | |
|             // Open the media uploader
 | |
|             mediaUploader.open();
 | |
|         });
 | |
|     }
 | |
|     
 | |
|     // Handle logo removal
 | |
|     $(document).on('click', '#hvac-remove-logo', function(e) {
 | |
|         e.preventDefault();
 | |
|         
 | |
|         // Clear the logo preview
 | |
|         $currentLogo.html('<div class="hvac-logo-placeholder-large"><span>No logo uploaded</span></div>');
 | |
|         
 | |
|         // Clear the hidden field
 | |
|         $logoIdField.val('');
 | |
|         
 | |
|         // Update button text
 | |
|         $uploadButton.text('Upload Logo');
 | |
|         
 | |
|         // Remove the remove button
 | |
|         $(this).remove();
 | |
|     });
 | |
|     
 | |
|     // Handle organizer deletion
 | |
|     $(document).on('click', '#hvac-delete-organizer', function(e) {
 | |
|         e.preventDefault();
 | |
|         
 | |
|         const $deleteButton = $(this);
 | |
|         const organizerId = $deleteButton.data('organizer-id');
 | |
|         
 | |
|         if (!organizerId) {
 | |
|             showMessage('Invalid organizer ID', 'error');
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         // Confirm deletion
 | |
|         if (!confirm('Are you sure you want to delete this organizer? This action cannot be undone.')) {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         // Disable button
 | |
|         $deleteButton.prop('disabled', true).text('Deleting...');
 | |
|         
 | |
|         // Send delete request
 | |
|         $.ajax({
 | |
|             url: hvacOrganizers.ajax_url,
 | |
|             type: 'POST',
 | |
|             data: {
 | |
|                 action: 'hvac_delete_organizer',
 | |
|                 nonce: hvacOrganizers.nonce,
 | |
|                 organizer_id: organizerId
 | |
|             },
 | |
|             success: function(response) {
 | |
|                 if (response.success) {
 | |
|                     showMessage(response.data || 'Organizer deleted successfully.', 'success');
 | |
|                     
 | |
|                     // Redirect to organizers list after 2 seconds
 | |
|                     setTimeout(function() {
 | |
|                         window.location.href = '/trainer/organizer/list/';
 | |
|                     }, 2000);
 | |
|                 } else {
 | |
|                     showMessage(response.data || 'Failed to delete organizer.', 'error');
 | |
|                     // Re-enable button
 | |
|                     $deleteButton.prop('disabled', false).text('Delete Organizer');
 | |
|                 }
 | |
|             },
 | |
|             error: function() {
 | |
|                 showMessage('An error occurred. Please try again.', 'error');
 | |
|                 // Re-enable button
 | |
|                 $deleteButton.prop('disabled', false).text('Delete Organizer');
 | |
|             }
 | |
|         });
 | |
|     });
 | |
|     
 | |
|     // Real-time validation
 | |
|     $('#org_email').on('blur', function() {
 | |
|         const email = $(this).val();
 | |
|         $('.hvac-error-message', $(this).parent()).remove();
 | |
|         $(this).removeClass('hvac-form-error');
 | |
|         
 | |
|         if (email && !isValidEmail(email)) {
 | |
|             $(this).addClass('hvac-form-error');
 | |
|             $(this).after('<span class="hvac-error-message">Please enter a valid email address</span>');
 | |
|         }
 | |
|     });
 | |
|     
 | |
|     $('#org_phone').on('blur', function() {
 | |
|         const phone = $(this).val();
 | |
|         $('.hvac-error-message', $(this).parent()).remove();
 | |
|         $(this).removeClass('hvac-form-error');
 | |
|         
 | |
|         if (phone && !isValidPhone(phone)) {
 | |
|             $(this).addClass('hvac-form-error');
 | |
|             $(this).after('<span class="hvac-error-message">Please enter a valid phone number</span>');
 | |
|         }
 | |
|     });
 | |
|     
 | |
|     $('#org_website').on('blur', function() {
 | |
|         const website = $(this).val();
 | |
|         $('.hvac-error-message', $(this).parent()).remove();
 | |
|         $(this).removeClass('hvac-form-error');
 | |
|         
 | |
|         if (website && !isValidURL(website)) {
 | |
|             $(this).addClass('hvac-form-error');
 | |
|             $(this).after('<span class="hvac-error-message">Please enter a valid website URL</span>');
 | |
|         }
 | |
|     });
 | |
|     
 | |
|     // Auto-format phone number
 | |
|     $('#org_phone').on('input', function() {
 | |
|         let value = $(this).val().replace(/\D/g, '');
 | |
|         
 | |
|         if (value.length > 0) {
 | |
|             if (value.length <= 3) {
 | |
|                 value = value;
 | |
|             } else if (value.length <= 6) {
 | |
|                 value = value.slice(0, 3) + '-' + value.slice(3);
 | |
|             } else if (value.length <= 10) {
 | |
|                 value = value.slice(0, 3) + '-' + value.slice(3, 6) + '-' + value.slice(6);
 | |
|             } else {
 | |
|                 value = value.slice(0, 3) + '-' + value.slice(3, 6) + '-' + value.slice(6, 10);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         $(this).val(value);
 | |
|     });
 | |
| }); |