Systematic audit and implementation of missing Master Trainer functionality with comprehensive WordPress best practices and security implementation. ## Features Implemented - Master Events Overview (/master-trainer/events/) - KPI dashboard with filtering - Import/Export Data Management (/master-trainer/import-export/) - CSV operations - Communication Templates (/trainer/communication-templates/) - Professional templates - Enhanced Announcements (/master-trainer/announcements/) - Dynamic shortcode integration - Pending Approvals System (/master-trainer/pending-approvals/) - Workflow management ## Navigation & UX Improvements - Removed redundant Events link from top-level navigation menu - Reorganized administrative functions under Tools dropdown - Enhanced navigation clarity and professional appearance - Full responsive design with accessibility compliance ## Architecture & Security - 5 new singleton manager classes following WordPress patterns - Comprehensive role-based access control (hvac_master_trainer) - Complete security implementation (nonces, sanitization, escaping) - Performance optimizations with transient caching and conditional loading - Professional error handling and user feedback systems ## Files Added (16 new files) - 4 manager classes: Import/Export, Events Overview, Pending Approvals, Communication Templates - 4 CSS files with responsive design and accessibility features - 4 JavaScript files with AJAX functionality and error handling - 2 new templates: Import/Export, Pending Approvals - 2 enhanced templates: Events Overview, Communication Templates ## Files Modified (14 files) - Core system integration in Plugin, Page Manager, Scripts/Styles classes - Navigation system cleanup in Master Menu System - Enhanced access control and role management - Template updates for dynamic content integration ## Testing & Deployment - Comprehensive testing with Playwright automation - Successful staging deployment and verification - All 5 missing pages now fully functional - Navigation improvements verified working Resolves master trainer area audit requirements with production-ready implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
468 lines
No EOL
17 KiB
JavaScript
468 lines
No EOL
17 KiB
JavaScript
/**
|
|
* HVAC Import/Export JavaScript
|
|
*
|
|
* Handles import/export functionality for master trainers
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
// Main import/export object
|
|
const HVACImportExport = {
|
|
|
|
/**
|
|
* Initialize the import/export functionality
|
|
*/
|
|
init: function() {
|
|
this.bindEvents();
|
|
this.initializeFileInputs();
|
|
},
|
|
|
|
/**
|
|
* Bind events
|
|
*/
|
|
bindEvents: function() {
|
|
// Export button events
|
|
$('#export-trainers').on('click', this.exportTrainers.bind(this));
|
|
$('#export-events').on('click', this.exportEvents.bind(this));
|
|
$('#export-user-profiles').on('click', this.exportUserProfiles.bind(this));
|
|
|
|
// Import form events
|
|
$('#import-trainer-profiles-form').on('submit', this.importTrainerProfiles.bind(this));
|
|
$('#import-events-form').on('submit', this.importEvents.bind(this));
|
|
$('#bulk-update-users-form').on('submit', this.bulkUpdateUsers.bind(this));
|
|
|
|
// Modal close events
|
|
$('.hvac-modal-close').on('click', this.closeModal.bind(this));
|
|
$('.hvac-modal').on('click', function(e) {
|
|
if (e.target === this) {
|
|
HVACImportExport.closeModal();
|
|
}
|
|
});
|
|
|
|
// Keyboard events
|
|
$(document).on('keydown', this.handleKeyDown.bind(this));
|
|
},
|
|
|
|
/**
|
|
* Initialize file inputs
|
|
*/
|
|
initializeFileInputs: function() {
|
|
$('input[type="file"]').on('change', function() {
|
|
const $input = $(this);
|
|
const $label = $input.siblings('.file-input-label');
|
|
const $fileName = $input.siblings('.file-name');
|
|
|
|
if (this.files && this.files.length > 0) {
|
|
const fileName = this.files[0].name;
|
|
$fileName.text(fileName);
|
|
$label.addClass('file-selected');
|
|
} else {
|
|
$fileName.text('');
|
|
$label.removeClass('file-selected');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Handle keyboard events
|
|
*/
|
|
handleKeyDown: function(e) {
|
|
// Close modal on Escape key
|
|
if (e.keyCode === 27) { // Escape key
|
|
this.closeModal();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Export trainers
|
|
*/
|
|
exportTrainers: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $button = $(e.currentTarget);
|
|
this.setButtonLoading($button, true);
|
|
|
|
this.makeAjaxRequest('hvac_export_trainers', {}, function(response) {
|
|
HVACImportExport.setButtonLoading($button, false);
|
|
|
|
if (response.success) {
|
|
HVACImportExport.downloadCSV(response.data.data, response.data.filename);
|
|
HVACImportExport.showResults('Export Complete', response.data.message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Export Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Export events
|
|
*/
|
|
exportEvents: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $button = $(e.currentTarget);
|
|
this.setButtonLoading($button, true);
|
|
|
|
this.makeAjaxRequest('hvac_export_events', {}, function(response) {
|
|
HVACImportExport.setButtonLoading($button, false);
|
|
|
|
if (response.success) {
|
|
HVACImportExport.downloadCSV(response.data.data, response.data.filename);
|
|
HVACImportExport.showResults('Export Complete', response.data.message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Export Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Export user profiles
|
|
*/
|
|
exportUserProfiles: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $button = $(e.currentTarget);
|
|
this.setButtonLoading($button, true);
|
|
|
|
this.makeAjaxRequest('hvac_export_user_profiles', {}, function(response) {
|
|
HVACImportExport.setButtonLoading($button, false);
|
|
|
|
if (response.success) {
|
|
HVACImportExport.downloadCSV(response.data.data, response.data.filename);
|
|
HVACImportExport.showResults('Export Complete', response.data.message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Export Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Import trainer profiles
|
|
*/
|
|
importTrainerProfiles: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $form = $(e.currentTarget);
|
|
const $fileInput = $form.find('input[type="file"]')[0];
|
|
|
|
if (!this.validateImportForm($fileInput)) {
|
|
return;
|
|
}
|
|
|
|
if (!confirm(hvac_import_export.strings.confirm_import)) {
|
|
return;
|
|
}
|
|
|
|
this.showProgressModal('Importing Trainer Profiles');
|
|
|
|
const formData = new FormData();
|
|
formData.append('import_file', $fileInput.files[0]);
|
|
formData.append('action', 'hvac_import_trainer_profiles');
|
|
formData.append('nonce', hvac_import_export.nonce);
|
|
|
|
this.makeFileUploadRequest(formData, function(response) {
|
|
HVACImportExport.closeModal();
|
|
|
|
if (response.success) {
|
|
const results = response.data.results;
|
|
const message = `
|
|
<div class="success">${response.data.message}</div>
|
|
<div class="details">
|
|
<strong>Details:</strong><br>
|
|
Created: ${results.created}<br>
|
|
Updated: ${results.updated}<br>
|
|
Errors: ${results.errors}
|
|
</div>
|
|
`;
|
|
HVACImportExport.showResults('Import Complete', message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Import Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Import events
|
|
*/
|
|
importEvents: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $form = $(e.currentTarget);
|
|
const $fileInput = $form.find('input[type="file"]')[0];
|
|
|
|
if (!this.validateImportForm($fileInput)) {
|
|
return;
|
|
}
|
|
|
|
if (!confirm(hvac_import_export.strings.confirm_import)) {
|
|
return;
|
|
}
|
|
|
|
this.showProgressModal('Importing Events');
|
|
|
|
const formData = new FormData();
|
|
formData.append('import_file', $fileInput.files[0]);
|
|
formData.append('action', 'hvac_import_events');
|
|
formData.append('nonce', hvac_import_export.nonce);
|
|
|
|
this.makeFileUploadRequest(formData, function(response) {
|
|
HVACImportExport.closeModal();
|
|
|
|
if (response.success) {
|
|
const results = response.data.results;
|
|
const message = `
|
|
<div class="success">${response.data.message}</div>
|
|
<div class="details">
|
|
<strong>Details:</strong><br>
|
|
Created: ${results.created}<br>
|
|
Updated: ${results.updated}<br>
|
|
Errors: ${results.errors}
|
|
</div>
|
|
`;
|
|
HVACImportExport.showResults('Import Complete', message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Import Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Bulk update users
|
|
*/
|
|
bulkUpdateUsers: function(e) {
|
|
e.preventDefault();
|
|
|
|
const $form = $(e.currentTarget);
|
|
const $fileInput = $form.find('input[type="file"]')[0];
|
|
|
|
if (!this.validateImportForm($fileInput)) {
|
|
return;
|
|
}
|
|
|
|
if (!confirm(hvac_import_export.strings.confirm_import)) {
|
|
return;
|
|
}
|
|
|
|
this.showProgressModal('Bulk Updating Users');
|
|
|
|
const formData = new FormData();
|
|
formData.append('import_file', $fileInput.files[0]);
|
|
formData.append('action', 'hvac_bulk_update_users');
|
|
formData.append('nonce', hvac_import_export.nonce);
|
|
|
|
this.makeFileUploadRequest(formData, function(response) {
|
|
HVACImportExport.closeModal();
|
|
|
|
if (response.success) {
|
|
const results = response.data.results;
|
|
const message = `
|
|
<div class="success">${response.data.message}</div>
|
|
<div class="details">
|
|
<strong>Details:</strong><br>
|
|
Updated: ${results.updated}<br>
|
|
Errors: ${results.errors}
|
|
</div>
|
|
`;
|
|
HVACImportExport.showResults('Bulk Update Complete', message, 'success');
|
|
} else {
|
|
HVACImportExport.showResults('Bulk Update Failed', response.data.message || 'Unknown error occurred', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Validate import form
|
|
*/
|
|
validateImportForm: function(fileInput) {
|
|
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
alert(hvac_import_export.strings.select_file);
|
|
return false;
|
|
}
|
|
|
|
const file = fileInput.files[0];
|
|
const fileName = file.name.toLowerCase();
|
|
|
|
if (!fileName.endsWith('.csv')) {
|
|
alert(hvac_import_export.strings.invalid_file);
|
|
return false;
|
|
}
|
|
|
|
// Check file size (max 10MB)
|
|
if (file.size > 10 * 1024 * 1024) {
|
|
alert('File size too large. Maximum allowed size is 10MB.');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Make AJAX request
|
|
*/
|
|
makeAjaxRequest: function(action, data, callback) {
|
|
const requestData = $.extend({
|
|
action: action,
|
|
nonce: hvac_import_export.nonce
|
|
}, data);
|
|
|
|
$.ajax({
|
|
url: hvac_import_export.ajax_url,
|
|
type: 'POST',
|
|
data: requestData,
|
|
dataType: 'json',
|
|
success: callback,
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX Error:', error);
|
|
callback({
|
|
success: false,
|
|
data: {
|
|
message: 'Network error occurred. Please try again.'
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Make file upload request
|
|
*/
|
|
makeFileUploadRequest: function(formData, callback) {
|
|
$.ajax({
|
|
url: hvac_import_export.ajax_url,
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
dataType: 'json',
|
|
success: callback,
|
|
error: function(xhr, status, error) {
|
|
console.error('Upload Error:', error);
|
|
HVACImportExport.closeModal();
|
|
callback({
|
|
success: false,
|
|
data: {
|
|
message: 'Upload error occurred. Please try again.'
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Download CSV file
|
|
*/
|
|
downloadCSV: function(csvData, filename) {
|
|
if (!csvData) {
|
|
alert('No data to export');
|
|
return;
|
|
}
|
|
|
|
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
|
|
const link = document.createElement('a');
|
|
|
|
if (link.download !== undefined) {
|
|
const url = URL.createObjectURL(blob);
|
|
link.setAttribute('href', url);
|
|
link.setAttribute('download', filename);
|
|
link.style.visibility = 'hidden';
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
} else {
|
|
// Fallback for older browsers
|
|
const url = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csvData);
|
|
window.open(url, '_blank');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Set button loading state
|
|
*/
|
|
setButtonLoading: function($button, loading) {
|
|
if (loading) {
|
|
$button.addClass('loading').prop('disabled', true);
|
|
const originalText = $button.text();
|
|
$button.data('original-text', originalText);
|
|
$button.text(hvac_import_export.strings.processing);
|
|
} else {
|
|
$button.removeClass('loading').prop('disabled', false);
|
|
const originalText = $button.data('original-text');
|
|
if (originalText) {
|
|
$button.text(originalText);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Show progress modal
|
|
*/
|
|
showProgressModal: function(title) {
|
|
$('#progress-title').text(title);
|
|
$('#progress-message').text('Please wait while we process your request...');
|
|
$('#hvac-progress-modal').fadeIn(300);
|
|
|
|
// Focus management
|
|
$('#hvac-progress-modal').attr('aria-hidden', 'false');
|
|
$('body').addClass('modal-open');
|
|
},
|
|
|
|
/**
|
|
* Show results modal
|
|
*/
|
|
showResults: function(title, message, type) {
|
|
$('#results-title').text(title);
|
|
$('#results-content').html(message);
|
|
$('#hvac-results-modal').fadeIn(300);
|
|
|
|
// Focus management
|
|
$('#hvac-results-modal').attr('aria-hidden', 'false');
|
|
$('#hvac-results-modal .hvac-modal-close').first().focus();
|
|
$('body').addClass('modal-open');
|
|
},
|
|
|
|
/**
|
|
* Close modal
|
|
*/
|
|
closeModal: function() {
|
|
$('.hvac-modal').fadeOut(300);
|
|
|
|
// Focus management
|
|
$('.hvac-modal').attr('aria-hidden', 'true');
|
|
$('body').removeClass('modal-open');
|
|
|
|
// Return focus to the element that opened the modal
|
|
if (this.lastFocusedElement) {
|
|
this.lastFocusedElement.focus();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Store last focused element for accessibility
|
|
*/
|
|
storeFocusedElement: function(element) {
|
|
this.lastFocusedElement = element;
|
|
}
|
|
};
|
|
|
|
// Initialize when document is ready
|
|
$(document).ready(function() {
|
|
// Only initialize on import-export page
|
|
if ($('.hvac-import-export-wrapper').length > 0) {
|
|
HVACImportExport.init();
|
|
}
|
|
});
|
|
|
|
// Store focused elements for accessibility
|
|
$('button, a').on('focus', function() {
|
|
HVACImportExport.storeFocusedElement(this);
|
|
});
|
|
|
|
// Global accessibility improvements
|
|
$('.hvac-modal').attr('role', 'dialog').attr('aria-hidden', 'true');
|
|
$('.hvac-modal-content').attr('role', 'document');
|
|
|
|
})(jQuery); |