- Changed headquarters country and state fields from text inputs to dropdown selections - Added dynamic state/province loading based on selected country (US/Canada) - Added 'Other' option for non-US/Canada countries with text input fallback - Properly handle org_headquarters_state_other field in backend processing - JavaScript handlers for dynamic country/state interaction - Consistent with Training Venue Information dropdown behavior Co-Authored-By: Ben Reed <ben@tealmaker.com>
432 lines
No EOL
17 KiB
JavaScript
432 lines
No EOL
17 KiB
JavaScript
jQuery(document).ready(function($) {
|
|
const $countrySelect = $('#user_country');
|
|
const $stateSelect = $('#user_state');
|
|
const $stateOtherInput = $('#user_state_other');
|
|
const $registrationForm = $('#hvac-registration-form');
|
|
|
|
// Headquarters fields
|
|
const $hqCountrySelect = $('#org_headquarters_country');
|
|
const $hqStateSelect = $('#org_headquarters_state');
|
|
const $hqStateOtherInput = $('#org_headquarters_state_other');
|
|
|
|
// Venue fields
|
|
const $createVenue = $('input[name="create_venue"]');
|
|
const $venueDetails = $('#venue-details');
|
|
const $venueName = $('#venue_name');
|
|
const $businessName = $('#business_name');
|
|
const $userCity = $('#user_city');
|
|
const $venuePhone = $('#venue_phone');
|
|
const $venueWebsite = $('#venue_website');
|
|
const $businessPhone = $('#business_phone');
|
|
const $businessWebsite = $('#business_website');
|
|
|
|
// Form validation helpers
|
|
function showFieldError(fieldId, message) {
|
|
const $field = $('#' + fieldId);
|
|
const $existingError = $field.siblings('.error-message');
|
|
|
|
if ($existingError.length) {
|
|
$existingError.text(message);
|
|
} else {
|
|
$field.after('<p class="error-message" id="' + fieldId + '_error">' + message + '</p>');
|
|
}
|
|
|
|
$field.addClass('error');
|
|
}
|
|
|
|
function clearFieldError(fieldId) {
|
|
const $field = $('#' + fieldId);
|
|
$field.siblings('.error-message').remove();
|
|
$field.removeClass('error');
|
|
}
|
|
|
|
// Real-time email validation
|
|
$('#user_email').on('blur', function() {
|
|
const email = $(this).val();
|
|
if (email && !isValidEmail(email)) {
|
|
showFieldError('user_email', 'Please enter a valid email address.');
|
|
} else {
|
|
clearFieldError('user_email');
|
|
}
|
|
});
|
|
|
|
$('#business_email').on('blur', function() {
|
|
const email = $(this).val();
|
|
if (email && !isValidEmail(email)) {
|
|
showFieldError('business_email', 'Please enter a valid business email address.');
|
|
} else {
|
|
clearFieldError('business_email');
|
|
}
|
|
});
|
|
|
|
function isValidEmail(email) {
|
|
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return re.test(email);
|
|
}
|
|
|
|
// Real-time password validation
|
|
$('#user_pass').on('input blur', function() {
|
|
const password = $(this).val();
|
|
if (password) {
|
|
const errors = [];
|
|
if (password.length < 8) {
|
|
errors.push('at least 8 characters');
|
|
}
|
|
if (!/[A-Z]/.test(password)) {
|
|
errors.push('one uppercase letter');
|
|
}
|
|
if (!/[a-z]/.test(password)) {
|
|
errors.push('one lowercase letter');
|
|
}
|
|
if (!/[0-9]/.test(password)) {
|
|
errors.push('one number');
|
|
}
|
|
|
|
if (errors.length > 0) {
|
|
showFieldError('user_pass', 'Password must contain ' + errors.join(', ') + '.');
|
|
} else {
|
|
clearFieldError('user_pass');
|
|
// Check confirm password if it has a value
|
|
const confirmPass = $('#confirm_password').val();
|
|
if (confirmPass) {
|
|
$('#confirm_password').trigger('blur');
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Confirm password validation
|
|
$('#confirm_password').on('blur', function() {
|
|
const password = $('#user_pass').val();
|
|
const confirmPassword = $(this).val();
|
|
|
|
if (confirmPassword && password !== confirmPassword) {
|
|
showFieldError('confirm_password', 'Passwords do not match.');
|
|
} else {
|
|
clearFieldError('confirm_password');
|
|
}
|
|
});
|
|
|
|
// URL validation for optional fields
|
|
function isValidURL(url) {
|
|
try {
|
|
new URL(url);
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$('#user_url, #user_linkedin, #business_website, #venue_website').on('blur', function() {
|
|
const url = $(this).val();
|
|
const fieldId = $(this).attr('id');
|
|
|
|
if (url && !isValidURL(url)) {
|
|
const fieldName = fieldId === 'user_url' ? 'personal website' :
|
|
fieldId === 'user_linkedin' ? 'LinkedIn profile' :
|
|
fieldId === 'business_website' ? 'organization website' :
|
|
'venue website';
|
|
showFieldError(fieldId, 'Please enter a valid URL for your ' + fieldName + '.');
|
|
} else {
|
|
clearFieldError(fieldId);
|
|
}
|
|
});
|
|
|
|
// Handle venue creation toggle
|
|
$createVenue.on('change', function() {
|
|
if ($(this).val() === 'Yes') {
|
|
$venueDetails.slideDown();
|
|
// Auto-populate venue name if empty
|
|
updateVenueName();
|
|
// Auto-populate venue phone and website
|
|
if (!$venuePhone.val() && $businessPhone.val()) {
|
|
$venuePhone.val($businessPhone.val());
|
|
}
|
|
if (!$venueWebsite.val() && $businessWebsite.val()) {
|
|
$venueWebsite.val($businessWebsite.val());
|
|
}
|
|
} else {
|
|
$venueDetails.slideUp();
|
|
}
|
|
});
|
|
|
|
// Auto-populate venue name
|
|
function updateVenueName() {
|
|
if (!$venueName.val()) {
|
|
const businessName = $businessName.val();
|
|
const city = $userCity.val();
|
|
if (businessName && city) {
|
|
$venueName.val(businessName + ' of ' + city);
|
|
} else if (businessName) {
|
|
$venueName.val(businessName + ' Training Venue');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update venue name when business name or city changes
|
|
$businessName.on('blur', updateVenueName);
|
|
$userCity.on('blur', updateVenueName);
|
|
|
|
// Copy organization info to venue fields
|
|
$businessPhone.on('blur', function() {
|
|
if (!$venuePhone.val() && $(this).val()) {
|
|
$venuePhone.val($(this).val());
|
|
}
|
|
});
|
|
|
|
$businessWebsite.on('blur', function() {
|
|
if (!$venueWebsite.val() && $(this).val()) {
|
|
$venueWebsite.val($(this).val());
|
|
}
|
|
});
|
|
|
|
// Form submission validation
|
|
$registrationForm.on('submit', function(e) {
|
|
let hasErrors = false;
|
|
const errors = [];
|
|
|
|
// Check required fields
|
|
const requiredFields = [
|
|
{ id: 'user_email', name: 'Email' },
|
|
{ id: 'user_pass', name: 'Password' },
|
|
{ id: 'confirm_password', name: 'Confirm Password' },
|
|
{ id: 'first_name', name: 'First Name' },
|
|
{ id: 'last_name', name: 'Last Name' },
|
|
{ id: 'display_name', name: 'Display Name' },
|
|
{ id: 'description', name: 'Biographical Info' },
|
|
{ id: 'business_name', name: 'Organization Name' },
|
|
{ id: 'business_phone', name: 'Organization Phone' },
|
|
{ id: 'business_email', name: 'Organization Email' },
|
|
{ id: 'business_description', name: 'Organization Description' },
|
|
{ id: 'application_details', name: 'Application Details' }
|
|
];
|
|
|
|
// Check venue fields if creating venue
|
|
if ($('input[name="create_venue"]:checked').val() === 'Yes') {
|
|
requiredFields.push(
|
|
{ id: 'venue_name', name: 'Venue Name' },
|
|
{ id: 'venue_address', name: 'Street Address' },
|
|
{ id: 'user_country', name: 'Country' },
|
|
{ id: 'user_city', name: 'City' },
|
|
{ id: 'user_zip', name: 'Zip/Postal Code' }
|
|
);
|
|
}
|
|
|
|
requiredFields.forEach(field => {
|
|
const $field = $('#' + field.id);
|
|
if (!$field.val() || $field.val().trim() === '') {
|
|
hasErrors = true;
|
|
errors.push(field.name + ' is required.');
|
|
showFieldError(field.id, field.name + ' is required.');
|
|
}
|
|
});
|
|
|
|
// Check org logo
|
|
const $orgLogo = $('#org_logo');
|
|
if ($orgLogo.length && !$orgLogo[0].files.length) {
|
|
hasErrors = true;
|
|
errors.push('Organization Logo is required.');
|
|
showFieldError('org_logo', 'Organization Logo is required.');
|
|
}
|
|
|
|
// Check state/province for venue
|
|
if ($('input[name="create_venue"]:checked').val() === 'Yes') {
|
|
const country = $('#user_country').val();
|
|
if (country) {
|
|
if (country === 'United States' || country === 'Canada') {
|
|
const state = $('#user_state').val();
|
|
if (!state || state === '') {
|
|
hasErrors = true;
|
|
errors.push('State/Province is required.');
|
|
showFieldError('user_state', 'State/Province is required.');
|
|
}
|
|
} else {
|
|
const otherState = $('#user_state_other').val();
|
|
if (!otherState || otherState.trim() === '') {
|
|
hasErrors = true;
|
|
errors.push('State/Province is required.');
|
|
showFieldError('user_state_other', 'State/Province is required.');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check radio buttons
|
|
if (!$('input[name="create_venue"]:checked').length) {
|
|
hasErrors = true;
|
|
errors.push('Please select whether to create a training venue profile.');
|
|
}
|
|
|
|
// Check business type dropdown
|
|
const businessType = $('#business_type').val();
|
|
if (!businessType || businessType === '') {
|
|
hasErrors = true;
|
|
errors.push('Business Type is required.');
|
|
showFieldError('business_type', 'Business Type is required.');
|
|
}
|
|
|
|
// Check checkbox groups
|
|
const checkboxGroups = [
|
|
{ name: 'training_audience[]', label: 'Training Audience' },
|
|
{ name: 'training_formats[]', label: 'Training Formats' },
|
|
{ name: 'training_locations[]', label: 'Training Locations' },
|
|
{ name: 'training_resources[]', label: 'Training Resources' }
|
|
];
|
|
|
|
checkboxGroups.forEach(group => {
|
|
if (!$('input[name="' + group.name + '"]:checked').length) {
|
|
hasErrors = true;
|
|
errors.push('Please select at least one option for ' + group.label + '.');
|
|
}
|
|
});
|
|
|
|
if (hasErrors) {
|
|
e.preventDefault();
|
|
|
|
// Show error summary at the top
|
|
let $errorSummary = $('.hvac-form-errors');
|
|
if (!$errorSummary.length) {
|
|
$errorSummary = $('<div class="hvac-form-errors" role="alert"><h3>Please correct the following errors:</h3><ul></ul></div>');
|
|
$registrationForm.prepend($errorSummary);
|
|
}
|
|
|
|
const $errorList = $errorSummary.find('ul');
|
|
$errorList.empty();
|
|
errors.forEach(error => {
|
|
$errorList.append('<li>' + error + '</li>');
|
|
});
|
|
|
|
// Scroll to top of form
|
|
$('html, body').animate({
|
|
scrollTop: $('.hvac-registration-form').offset().top - 100
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
// Function to populate states/provinces
|
|
function loadStates(country) {
|
|
console.log(`Loading states/provinces for ${country}`); // Keep log for debugging
|
|
$stateSelect.find('option').not('[value=""],[value="Other"]').remove(); // Clear existing options except defaults
|
|
|
|
let options = {};
|
|
if (country === 'United States' && typeof hvacRegistrationData !== 'undefined' && hvacRegistrationData.states) {
|
|
options = hvacRegistrationData.states;
|
|
} else if (country === 'Canada' && typeof hvacRegistrationData !== 'undefined' && hvacRegistrationData.provinces) {
|
|
options = hvacRegistrationData.provinces;
|
|
} else {
|
|
// If country is not US/CA or data is missing, ensure 'Other' is selected and input shown
|
|
$stateSelect.val('Other').trigger('change'); // Trigger change to show 'Other' input if needed
|
|
return;
|
|
}
|
|
|
|
// Append new options
|
|
$.each(options, function(value, label) {
|
|
// Append before the 'Other' option if it exists, otherwise just append
|
|
const $otherOption = $stateSelect.find('option[value="Other"]');
|
|
const $newOption = $('<option></option>').val(value).text(label);
|
|
if ($otherOption.length > 0) {
|
|
$newOption.insertBefore($otherOption);
|
|
} else {
|
|
$stateSelect.append($newOption);
|
|
}
|
|
});
|
|
|
|
// Ensure the 'Other' input is hidden initially when states/provinces are loaded
|
|
$stateOtherInput.hide().val('');
|
|
// Reset state selection to default prompt
|
|
$stateSelect.val('');
|
|
}
|
|
|
|
// Handle state/province field visibility based on 'Other' selection
|
|
$stateSelect.change(function() {
|
|
if ($(this).val() === 'Other') {
|
|
$stateOtherInput.show().prop('required', true); // Make required if Other is selected
|
|
} else {
|
|
$stateOtherInput.hide().val('').prop('required', false); // Hide and make not required
|
|
}
|
|
}).trigger('change'); // Trigger on load to set initial visibility
|
|
|
|
// Handle country change to show/hide/populate state field
|
|
$countrySelect.change(function() {
|
|
const country = $(this).val();
|
|
|
|
if (country === 'United States' || country === 'Canada') {
|
|
loadStates(country);
|
|
$stateSelect.show().prop('required', true); // Show and require state select
|
|
$stateOtherInput.prop('required', false); // Ensure 'Other' input is not required initially
|
|
} else if (country) {
|
|
// For other countries, hide state select, select 'Other', show/require 'Other' input
|
|
$stateSelect.hide().val('Other').prop('required', false); // Hide and make not required
|
|
$stateOtherInput.show().prop('required', true); // Show and require 'Other' input
|
|
} else {
|
|
// No country selected
|
|
$stateSelect.hide().val('').prop('required', false); // Hide and make not required
|
|
$stateOtherInput.hide().val('').prop('required', false); // Hide and make not required
|
|
}
|
|
}).trigger('change'); // Trigger on load to set initial state based on pre-selected country (if any)
|
|
|
|
// Function to populate headquarters states/provinces
|
|
function loadHqStates(country) {
|
|
console.log(`Loading HQ states/provinces for ${country}`);
|
|
$hqStateSelect.find('option').not('[value=""],[value="Other"]').remove();
|
|
|
|
let options = {};
|
|
if (country === 'United States' && typeof hvacRegistrationData !== 'undefined' && hvacRegistrationData.states) {
|
|
options = hvacRegistrationData.states;
|
|
} else if (country === 'Canada' && typeof hvacRegistrationData !== 'undefined' && hvacRegistrationData.provinces) {
|
|
options = hvacRegistrationData.provinces;
|
|
} else {
|
|
// For other countries, just select 'Other' without triggering
|
|
$hqStateSelect.val('Other');
|
|
$hqStateOtherInput.show().prop('required', false);
|
|
return;
|
|
}
|
|
|
|
// Append new options
|
|
$.each(options, function(value, label) {
|
|
const $otherOption = $hqStateSelect.find('option[value="Other"]');
|
|
const $newOption = $('<option></option>').val(value).text(label);
|
|
if ($otherOption.length > 0) {
|
|
$newOption.insertBefore($otherOption);
|
|
} else {
|
|
$hqStateSelect.append($newOption);
|
|
}
|
|
});
|
|
|
|
// Hide the 'Other' input and reset state selection
|
|
$hqStateOtherInput.hide().val('');
|
|
$hqStateSelect.val('');
|
|
}
|
|
|
|
// Handle headquarters state/province field visibility based on 'Other' selection
|
|
$hqStateSelect.change(function() {
|
|
if ($(this).val() === 'Other') {
|
|
$hqStateOtherInput.show().prop('required', false);
|
|
} else {
|
|
$hqStateOtherInput.hide().val('').prop('required', false);
|
|
}
|
|
}).trigger('change');
|
|
|
|
// Handle headquarters country change to show/hide/populate state field
|
|
$hqCountrySelect.change(function() {
|
|
const country = $(this).val();
|
|
|
|
if (country === 'United States' || country === 'Canada') {
|
|
loadHqStates(country);
|
|
$hqStateSelect.show().prop('required', false);
|
|
$hqStateOtherInput.prop('required', false);
|
|
} else if (country) {
|
|
// For other countries, hide state select, select 'Other', show 'Other' input
|
|
$hqStateSelect.hide().val('Other').prop('required', false);
|
|
$hqStateOtherInput.show().prop('required', false);
|
|
} else {
|
|
// No country selected
|
|
$hqStateSelect.hide().val('').prop('required', false);
|
|
$hqStateOtherInput.hide().val('').prop('required', false);
|
|
}
|
|
}).trigger('change');
|
|
|
|
// Initialize venue visibility on load
|
|
$createVenue.filter(':checked').trigger('change');
|
|
|
|
}); |