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>
428 lines
No EOL
17 KiB
JavaScript
428 lines
No EOL
17 KiB
JavaScript
/**
|
|
* HVAC Master Pending Approvals JavaScript
|
|
*
|
|
* Handles interactive functionality for the pending approvals interface
|
|
*/
|
|
|
|
(function($) {
|
|
'use strict';
|
|
|
|
window.HVAC_PendingApprovals = {
|
|
|
|
init: function() {
|
|
this.bindEvents();
|
|
this.initializeSelectors();
|
|
},
|
|
|
|
bindEvents: function() {
|
|
// Individual approve/reject buttons
|
|
$(document).on('click', '.hvac-approve-btn', this.handleIndividualApprove);
|
|
$(document).on('click', '.hvac-reject-btn', this.handleIndividualReject);
|
|
|
|
// Trainer name buttons (show details modal)
|
|
$(document).on('click', '.hvac-trainer-name-btn', this.handleShowDetails);
|
|
|
|
// Select all checkboxes
|
|
$(document).on('change', '#hvac-select-all, #hvac-header-select-all', this.handleSelectAll);
|
|
|
|
// Individual trainer checkboxes
|
|
$(document).on('change', '.hvac-trainer-select', this.handleTrainerSelect);
|
|
|
|
// Bulk action buttons
|
|
$(document).on('click', '#hvac-bulk-approve', this.handleBulkApprove);
|
|
$(document).on('click', '#hvac-bulk-reject', this.handleBulkReject);
|
|
|
|
// Modal controls
|
|
$(document).on('click', '.hvac-modal-close', this.hideModal);
|
|
$(document).on('click', '.hvac-modal', this.handleModalBackdropClick);
|
|
|
|
// Reason modal confirm button
|
|
$(document).on('click', '#hvac-confirm-reason-action', this.handleConfirmReasonAction);
|
|
|
|
// Bulk action modal confirm button
|
|
$(document).on('click', '#hvac-confirm-bulk-action', this.handleConfirmBulkAction);
|
|
|
|
// Filter form auto-submit on select changes
|
|
$(document).on('change', '#status_filter, #region_filter', function() {
|
|
$(this).closest('form').submit();
|
|
});
|
|
|
|
// ESC key to close modals
|
|
$(document).on('keydown', this.handleKeydown);
|
|
},
|
|
|
|
initializeSelectors: function() {
|
|
this.updateBulkActionButtons();
|
|
},
|
|
|
|
handleIndividualApprove: function(e) {
|
|
e.preventDefault();
|
|
const userId = $(this).data('user-id');
|
|
const trainerName = $(this).closest('tr').find('.hvac-trainer-name-btn').text();
|
|
|
|
HVAC_PendingApprovals.showReasonModal(userId, 'approve', 'Approve ' + trainerName);
|
|
},
|
|
|
|
handleIndividualReject: function(e) {
|
|
e.preventDefault();
|
|
const userId = $(this).data('user-id');
|
|
const trainerName = $(this).closest('tr').find('.hvac-trainer-name-btn').text();
|
|
|
|
HVAC_PendingApprovals.showReasonModal(userId, 'reject', 'Reject ' + trainerName);
|
|
},
|
|
|
|
handleShowDetails: function(e) {
|
|
e.preventDefault();
|
|
const userId = $(this).data('user-id');
|
|
|
|
HVAC_PendingApprovals.showTrainerDetails(userId);
|
|
},
|
|
|
|
handleSelectAll: function(e) {
|
|
const isChecked = $(this).is(':checked');
|
|
$('.hvac-trainer-select').prop('checked', isChecked);
|
|
|
|
// Sync both select-all checkboxes
|
|
$('#hvac-select-all, #hvac-header-select-all').prop('checked', isChecked);
|
|
|
|
HVAC_PendingApprovals.updateBulkActionButtons();
|
|
},
|
|
|
|
handleTrainerSelect: function(e) {
|
|
HVAC_PendingApprovals.updateBulkActionButtons();
|
|
|
|
// Update select-all checkboxes
|
|
const totalCheckboxes = $('.hvac-trainer-select').length;
|
|
const checkedCheckboxes = $('.hvac-trainer-select:checked').length;
|
|
|
|
$('#hvac-select-all, #hvac-header-select-all').prop('checked', totalCheckboxes === checkedCheckboxes);
|
|
},
|
|
|
|
handleBulkApprove: function(e) {
|
|
e.preventDefault();
|
|
const selectedIds = HVAC_PendingApprovals.getSelectedTrainerIds();
|
|
|
|
if (selectedIds.length === 0) {
|
|
alert('Please select trainers to approve.');
|
|
return;
|
|
}
|
|
|
|
HVAC_PendingApprovals.showBulkActionModal(selectedIds, 'approve');
|
|
},
|
|
|
|
handleBulkReject: function(e) {
|
|
e.preventDefault();
|
|
const selectedIds = HVAC_PendingApprovals.getSelectedTrainerIds();
|
|
|
|
if (selectedIds.length === 0) {
|
|
alert('Please select trainers to reject.');
|
|
return;
|
|
}
|
|
|
|
HVAC_PendingApprovals.showBulkActionModal(selectedIds, 'reject');
|
|
},
|
|
|
|
handleModalBackdropClick: function(e) {
|
|
if (e.target === this) {
|
|
HVAC_PendingApprovals.hideModal();
|
|
}
|
|
},
|
|
|
|
handleKeydown: function(e) {
|
|
if (e.key === 'Escape') {
|
|
HVAC_PendingApprovals.hideModal();
|
|
}
|
|
},
|
|
|
|
handleConfirmReasonAction: function(e) {
|
|
e.preventDefault();
|
|
|
|
const userId = $('#hvac-reason-user-id').val();
|
|
const action = $('#hvac-reason-action').val();
|
|
const reason = $('#hvac-approval-reason').val();
|
|
|
|
if (action === 'approve') {
|
|
HVAC_PendingApprovals.approveTrainer(userId, reason);
|
|
} else if (action === 'reject') {
|
|
HVAC_PendingApprovals.rejectTrainer(userId, reason);
|
|
}
|
|
|
|
HVAC_PendingApprovals.hideModal();
|
|
},
|
|
|
|
handleConfirmBulkAction: function(e) {
|
|
e.preventDefault();
|
|
|
|
const action = $('#hvac-bulk-action-type').val();
|
|
const reason = $('#hvac-bulk-reason').val();
|
|
const selectedIds = HVAC_PendingApprovals.getSelectedTrainerIds();
|
|
|
|
HVAC_PendingApprovals.performBulkAction(selectedIds, action, reason);
|
|
HVAC_PendingApprovals.hideModal();
|
|
},
|
|
|
|
showReasonModal: function(userId, action, title) {
|
|
$('#hvac-reason-modal-title').text(title);
|
|
$('#hvac-reason-user-id').val(userId);
|
|
$('#hvac-reason-action').val(action);
|
|
$('#hvac-approval-reason').val('');
|
|
|
|
// Update button text and color
|
|
const confirmBtn = $('#hvac-confirm-reason-action');
|
|
if (action === 'approve') {
|
|
confirmBtn.text('Approve').removeClass('hvac-btn-danger').addClass('hvac-btn-success');
|
|
} else {
|
|
confirmBtn.text('Reject').removeClass('hvac-btn-success').addClass('hvac-btn-danger');
|
|
}
|
|
|
|
this.showModal('#hvac-approval-reason-modal');
|
|
},
|
|
|
|
showBulkActionModal: function(userIds, action) {
|
|
const actionText = action === 'approve' ? 'approve' : 'reject';
|
|
const count = userIds.length;
|
|
|
|
$('#hvac-bulk-modal-title').text('Bulk ' + actionText.charAt(0).toUpperCase() + actionText.slice(1));
|
|
$('#hvac-bulk-action-type').val(action);
|
|
$('#hvac-bulk-reason').val('');
|
|
$('#hvac-bulk-action-message').text(`Are you sure you want to ${actionText} ${count} trainer(s)?`);
|
|
|
|
// Update button text and color
|
|
const confirmBtn = $('#hvac-confirm-bulk-action');
|
|
if (action === 'approve') {
|
|
confirmBtn.text('Approve All').removeClass('hvac-btn-danger').addClass('hvac-btn-success');
|
|
} else {
|
|
confirmBtn.text('Reject All').removeClass('hvac-btn-success').addClass('hvac-btn-danger');
|
|
}
|
|
|
|
this.showModal('#hvac-bulk-action-modal');
|
|
},
|
|
|
|
showTrainerDetails: function(userId) {
|
|
$('#hvac-trainer-details-content').html('Loading...');
|
|
this.showModal('#hvac-trainer-details-modal');
|
|
|
|
$.ajax({
|
|
url: hvac_ajax.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'hvac_get_trainer_details',
|
|
user_id: userId,
|
|
nonce: hvac_ajax.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#hvac-trainer-details-content').html(response.data.html);
|
|
} else {
|
|
$('#hvac-trainer-details-content').html('<p class="error">Failed to load trainer details: ' + response.data.message + '</p>');
|
|
}
|
|
},
|
|
error: function() {
|
|
$('#hvac-trainer-details-content').html('<p class="error">Failed to load trainer details. Please try again.</p>');
|
|
}
|
|
});
|
|
},
|
|
|
|
approveTrainer: function(userId, reason) {
|
|
this.showLoading();
|
|
|
|
$.ajax({
|
|
url: hvac_ajax.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'hvac_approve_trainer',
|
|
user_id: userId,
|
|
reason: reason,
|
|
nonce: hvac_ajax.nonce
|
|
},
|
|
success: function(response) {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
|
|
if (response.success) {
|
|
HVAC_PendingApprovals.showSuccessMessage(response.data.message);
|
|
HVAC_PendingApprovals.updateTrainerRow(userId, 'approved');
|
|
} else {
|
|
HVAC_PendingApprovals.showErrorMessage(response.data.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
HVAC_PendingApprovals.showErrorMessage('Failed to approve trainer. Please try again.');
|
|
}
|
|
});
|
|
},
|
|
|
|
rejectTrainer: function(userId, reason) {
|
|
this.showLoading();
|
|
|
|
$.ajax({
|
|
url: hvac_ajax.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'hvac_reject_trainer',
|
|
user_id: userId,
|
|
reason: reason,
|
|
nonce: hvac_ajax.nonce
|
|
},
|
|
success: function(response) {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
|
|
if (response.success) {
|
|
HVAC_PendingApprovals.showSuccessMessage(response.data.message);
|
|
HVAC_PendingApprovals.updateTrainerRow(userId, 'rejected');
|
|
} else {
|
|
HVAC_PendingApprovals.showErrorMessage(response.data.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
HVAC_PendingApprovals.showErrorMessage('Failed to reject trainer. Please try again.');
|
|
}
|
|
});
|
|
},
|
|
|
|
performBulkAction: function(userIds, action, reason) {
|
|
this.showLoading();
|
|
|
|
$.ajax({
|
|
url: hvac_ajax.ajax_url,
|
|
type: 'POST',
|
|
data: {
|
|
action: 'hvac_bulk_trainer_action',
|
|
user_ids: userIds,
|
|
action: action,
|
|
reason: reason,
|
|
nonce: hvac_ajax.nonce
|
|
},
|
|
success: function(response) {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
|
|
if (response.success) {
|
|
HVAC_PendingApprovals.showSuccessMessage(response.data.message);
|
|
|
|
// Update each trainer row
|
|
const newStatus = action === 'approve' ? 'approved' : 'rejected';
|
|
userIds.forEach(function(userId) {
|
|
if (response.data.results[userId] === 'success') {
|
|
HVAC_PendingApprovals.updateTrainerRow(userId, newStatus);
|
|
}
|
|
});
|
|
|
|
// Clear selections
|
|
$('.hvac-trainer-select, #hvac-select-all, #hvac-header-select-all').prop('checked', false);
|
|
HVAC_PendingApprovals.updateBulkActionButtons();
|
|
|
|
} else {
|
|
HVAC_PendingApprovals.showErrorMessage(response.data.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
HVAC_PendingApprovals.hideLoading();
|
|
HVAC_PendingApprovals.showErrorMessage('Failed to perform bulk action. Please try again.');
|
|
}
|
|
});
|
|
},
|
|
|
|
updateTrainerRow: function(userId, newStatus) {
|
|
const row = $('tr[data-user-id="' + userId + '"]');
|
|
|
|
if (row.length) {
|
|
// Update status badge
|
|
const statusCell = row.find('.hvac-col-status');
|
|
const statusBadges = {
|
|
'approved': '<span class="hvac-status-badge hvac-status-approved">Approved</span>',
|
|
'rejected': '<span class="hvac-status-badge hvac-status-rejected">Rejected</span>'
|
|
};
|
|
statusCell.html(statusBadges[newStatus] || newStatus);
|
|
|
|
// Update actions cell
|
|
const actionsCell = row.find('.hvac-col-actions');
|
|
actionsCell.html('<span class="hvac-status-text">' + newStatus.charAt(0).toUpperCase() + newStatus.slice(1) + '</span>');
|
|
|
|
// Remove checkbox column if it exists
|
|
row.find('.hvac-col-select').remove();
|
|
|
|
// Add visual feedback
|
|
row.addClass('hvac-row-updated').delay(3000).queue(function() {
|
|
$(this).removeClass('hvac-row-updated').dequeue();
|
|
});
|
|
}
|
|
},
|
|
|
|
getSelectedTrainerIds: function() {
|
|
const ids = [];
|
|
$('.hvac-trainer-select:checked').each(function() {
|
|
ids.push($(this).val());
|
|
});
|
|
return ids;
|
|
},
|
|
|
|
updateBulkActionButtons: function() {
|
|
const selectedCount = $('.hvac-trainer-select:checked').length;
|
|
const bulkButtons = $('#hvac-bulk-approve, #hvac-bulk-reject');
|
|
|
|
if (selectedCount > 0) {
|
|
bulkButtons.prop('disabled', false);
|
|
} else {
|
|
bulkButtons.prop('disabled', true);
|
|
}
|
|
},
|
|
|
|
showModal: function(modalSelector) {
|
|
$(modalSelector).fadeIn(300);
|
|
$('body').addClass('hvac-modal-open');
|
|
},
|
|
|
|
hideModal: function() {
|
|
$('.hvac-modal').fadeOut(300);
|
|
$('body').removeClass('hvac-modal-open');
|
|
},
|
|
|
|
showLoading: function() {
|
|
if ($('#hvac-loading-overlay').length === 0) {
|
|
$('body').append('<div id="hvac-loading-overlay"><div class="hvac-loading-spinner"></div></div>');
|
|
}
|
|
$('#hvac-loading-overlay').show();
|
|
},
|
|
|
|
hideLoading: function() {
|
|
$('#hvac-loading-overlay').hide();
|
|
},
|
|
|
|
showSuccessMessage: function(message) {
|
|
this.showMessage(message, 'success');
|
|
},
|
|
|
|
showErrorMessage: function(message) {
|
|
this.showMessage(message, 'error');
|
|
},
|
|
|
|
showMessage: function(message, type) {
|
|
// Remove existing messages
|
|
$('.hvac-flash-message').remove();
|
|
|
|
// Add new message
|
|
const messageHtml = '<div class="hvac-flash-message hvac-flash-' + type + '">' + message + '</div>';
|
|
$('.hvac-pending-approvals-wrapper').prepend(messageHtml);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(function() {
|
|
$('.hvac-flash-message').fadeOut(300, function() {
|
|
$(this).remove();
|
|
});
|
|
}, 5000);
|
|
|
|
// Scroll to top to show message
|
|
$('html, body').animate({ scrollTop: 0 }, 300);
|
|
}
|
|
};
|
|
|
|
// Initialize when document is ready
|
|
$(document).ready(function() {
|
|
// Only initialize if we're on the pending approvals page
|
|
if ($('.hvac-pending-approvals-wrapper').length > 0) {
|
|
HVAC_PendingApprovals.init();
|
|
}
|
|
});
|
|
|
|
})(jQuery); |