upskill-event-manager/assets/js/hvac-master-events-overview.js
Ben a74c273b1d feat: complete master trainer area audit and implementation
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>
2025-08-23 09:56:42 -03:00

580 lines
No EOL
20 KiB
JavaScript

/**
* HVAC Master Events Overview JavaScript
*
* Handles filtering, view switching, and AJAX interactions for the master events overview page
*/
(function($) {
'use strict';
// Global variables
var currentView = 'table';
var currentFilters = {};
var currentPage = 1;
var loading = false;
// Initialize when document is ready
$(document).ready(function() {
initializeEventsOverview();
});
/**
* Initialize the events overview functionality
*/
function initializeEventsOverview() {
if ($('#hvac-master-events-overview').length === 0) {
return; // Not on events overview page
}
// Load initial data
loadKPIs();
loadEventsData();
// Bind event handlers
bindEventHandlers();
// Set default date filters (current month)
setDefaultDateFilters();
}
/**
* Bind all event handlers
*/
function bindEventHandlers() {
// Filter form submission
$('#hvac-events-filters').on('submit', function(e) {
e.preventDefault();
currentPage = 1; // Reset to first page
loadEventsData();
});
// Clear filters button
$('#clear-filters').on('click', function(e) {
e.preventDefault();
clearAllFilters();
});
// View toggle buttons
$('.hvac-view-btn').on('click', function(e) {
e.preventDefault();
var newView = $(this).data('view');
if (newView !== currentView) {
switchView(newView);
}
});
// Real-time search
$('#filter-search').on('input', debounce(function() {
currentPage = 1;
loadEventsData();
}, 500));
// Date filter changes
$('#filter-date-from, #filter-date-to').on('change', function() {
currentPage = 1;
loadEventsData();
});
// Other filter changes
$('#filter-trainer, #filter-status').on('change', function() {
currentPage = 1;
loadEventsData();
});
// Pagination (delegated event handling)
$(document).on('click', '.hvac-pagination-btn', function(e) {
e.preventDefault();
var page = $(this).data('page');
if (page && page !== currentPage && !loading) {
currentPage = page;
loadEventsData();
}
});
// Table sorting (delegated event handling)
$(document).on('click', '.hvac-sortable', function(e) {
e.preventDefault();
var column = $(this).data('column');
var currentOrder = $(this).data('order') || 'desc';
var newOrder = currentOrder === 'asc' ? 'desc' : 'asc';
// Update sort indicators
$('.hvac-sortable').removeClass('hvac-sort-asc hvac-sort-desc');
$(this).addClass('hvac-sort-' + newOrder).data('order', newOrder);
// Reload data with new sort
currentPage = 1;
loadEventsData(column, newOrder);
});
// KPI refresh
$(document).on('click', '#refresh-kpis', function(e) {
e.preventDefault();
loadKPIs(true);
});
}
/**
* Set default date filters to current month
*/
function setDefaultDateFilters() {
var today = new Date();
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
var lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
$('#filter-date-from').val(formatDate(firstDay));
$('#filter-date-to').val(formatDate(lastDay));
}
/**
* Format date for input field
*/
function formatDate(date) {
return date.toISOString().split('T')[0];
}
/**
* Clear all filters
*/
function clearAllFilters() {
$('#hvac-events-filters')[0].reset();
setDefaultDateFilters();
currentPage = 1;
loadEventsData();
}
/**
* Switch between table and calendar views
*/
function switchView(newView) {
if (loading) return;
currentView = newView;
// Update button states
$('.hvac-view-btn').removeClass('hvac-view-btn-active');
$('[data-view="' + newView + '"]').addClass('hvac-view-btn-active');
// Hide all views
$('.hvac-events-table-view, .hvac-events-calendar-view').hide();
// Show selected view
if (newView === 'table') {
$('.hvac-events-table-view').show();
loadEventsData();
} else if (newView === 'calendar') {
$('.hvac-events-calendar-view').show();
loadCalendarData();
}
}
/**
* Load KPI data
*/
function loadKPIs(forceRefresh) {
if (!forceRefresh) {
$('#hvac-kpi-loading').show();
$('#hvac-kpi-tiles').hide();
}
$.ajax({
url: hvac_master_events_ajax.ajax_url,
type: 'POST',
data: {
action: 'hvac_master_events_kpis',
nonce: hvac_master_events_ajax.nonce
},
success: function(response) {
if (response.success) {
renderKPIs(response.data);
$('#hvac-kpi-loading').hide();
$('#hvac-kpi-tiles').show();
} else {
showError('Failed to load KPI data: ' + (response.data.message || 'Unknown error'));
}
},
error: function(xhr, status, error) {
showError('Error loading KPI data: ' + error);
$('#hvac-kpi-loading').hide();
}
});
}
/**
* Render KPI tiles
*/
function renderKPIs(data) {
var html = '<div class="hvac-kpi-grid">';
// Total Events KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-calendar-alt"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">' + data.total_events + '</div>';
html += '<div class="hvac-kpi-label">Total Events</div>';
html += '</div></div>';
// Upcoming Events KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-clock"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">' + data.upcoming_events + '</div>';
html += '<div class="hvac-kpi-label">Upcoming Events</div>';
html += '</div></div>';
// Active Trainers KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-groups"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">' + data.active_trainers + '</div>';
html += '<div class="hvac-kpi-label">Active Trainers</div>';
html += '</div></div>';
// Total Tickets KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-tickets-alt"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">' + data.total_tickets + '</div>';
html += '<div class="hvac-kpi-label">Tickets Sold</div>';
html += '</div></div>';
// Total Revenue KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-money-alt"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">$' + formatMoney(data.total_revenue) + '</div>';
html += '<div class="hvac-kpi-label">Total Revenue</div>';
html += '</div></div>';
// Past Events KPI
html += '<div class="hvac-kpi-tile">';
html += '<div class="hvac-kpi-icon"><span class="dashicons dashicons-yes-alt"></span></div>';
html += '<div class="hvac-kpi-content">';
html += '<div class="hvac-kpi-number">' + data.past_events + '</div>';
html += '<div class="hvac-kpi-label">Past Events</div>';
html += '</div></div>';
html += '</div>';
// Add refresh button
html += '<div class="hvac-kpi-actions">';
html += '<button type="button" id="refresh-kpis" class="hvac-btn hvac-btn-secondary hvac-btn-sm">';
html += '<span class="dashicons dashicons-update"></span> Refresh';
html += '</button></div>';
$('#hvac-kpi-tiles').html(html);
}
/**
* Load events data for table view
*/
function loadEventsData(orderby, order) {
if (loading) return;
loading = true;
$('#hvac-events-loading').show();
$('#hvac-events-table-container').hide();
// Get filter values
var filterData = getFilterData();
// Add sorting parameters
if (orderby) {
filterData.orderby = orderby;
filterData.order = order;
}
$.ajax({
url: hvac_master_events_ajax.ajax_url,
type: 'POST',
data: {
action: 'hvac_master_events_filter',
nonce: hvac_master_events_ajax.nonce,
page: currentPage,
per_page: 20,
...filterData
},
success: function(response) {
loading = false;
if (response.success) {
renderEventsTable(response.data.events, response.data.pagination);
updateEventsCount(response.data.total_found);
$('#hvac-events-loading').hide();
$('#hvac-events-table-container').show();
} else {
showError('Failed to load events: ' + (response.data.message || 'Unknown error'));
$('#hvac-events-loading').hide();
}
},
error: function(xhr, status, error) {
loading = false;
showError('Error loading events: ' + error);
$('#hvac-events-loading').hide();
}
});
}
/**
* Load calendar data
*/
function loadCalendarData() {
if (loading) return;
$('.hvac-calendar-loading').show();
$('.hvac-calendar-content').hide();
var filterData = getFilterData();
$.ajax({
url: hvac_master_events_ajax.ajax_url,
type: 'POST',
data: {
action: 'hvac_master_events_calendar',
nonce: hvac_master_events_ajax.nonce,
...filterData
},
success: function(response) {
if (response.success) {
renderCalendar(response.data.events);
updateEventsCount(response.data.total_found);
$('.hvac-calendar-loading').hide();
$('.hvac-calendar-content').show();
} else {
showError('Failed to load calendar: ' + (response.data.message || 'Unknown error'));
$('.hvac-calendar-loading').hide();
}
},
error: function(xhr, status, error) {
showError('Error loading calendar: ' + error);
$('.hvac-calendar-loading').hide();
}
});
}
/**
* Get current filter data
*/
function getFilterData() {
return {
trainer_id: $('#filter-trainer').val() || '',
date_from: $('#filter-date-from').val() || '',
date_to: $('#filter-date-to').val() || '',
status: $('#filter-status').val() || 'all',
search: $('#filter-search').val() || ''
};
}
/**
* Render events table
*/
function renderEventsTable(events, pagination) {
var html = '<div class="hvac-events-table-wrapper">';
if (events.length === 0) {
html += '<div class="hvac-no-events">';
html += '<p>No events found matching your criteria.</p>';
html += '<button type="button" id="clear-filters" class="hvac-btn hvac-btn-secondary">Clear Filters</button>';
html += '</div>';
} else {
html += '<table class="hvac-events-table">';
html += '<thead><tr>';
html += '<th class="hvac-sortable" data-column="name">Event <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="trainer">Trainer <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="date">Date <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="status">Status <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="capacity">Capacity <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="sold">Sold <span class="hvac-sort-indicator"></span></th>';
html += '<th class="hvac-sortable" data-column="revenue">Revenue <span class="hvac-sort-indicator"></span></th>';
html += '<th>Actions</th>';
html += '</tr></thead><tbody>';
events.forEach(function(event) {
html += '<tr>';
html += '<td><strong><a href="' + event.link + '" target="_blank">' + event.name + '</a></strong></td>';
html += '<td>' + event.trainer_name + '<br><small>' + event.trainer_email + '</small></td>';
html += '<td>' + event.date + '<br><small>' + event.time + '</small></td>';
html += '<td><span class="hvac-status-badge ' + event.status_class + '">' + event.status + '</span></td>';
html += '<td>' + event.capacity + '</td>';
html += '<td>' + event.sold + '</td>';
html += '<td>' + event.revenue + '</td>';
html += '<td>';
html += '<a href="' + event.link + '" class="hvac-btn hvac-btn-sm" target="_blank">View</a> ';
html += '<a href="' + event.trainer_edit_link + '" class="hvac-btn hvac-btn-sm hvac-btn-secondary" target="_blank">Edit</a>';
html += '</td>';
html += '</tr>';
});
html += '</tbody></table>';
}
// Add pagination
if (pagination.total_pages > 1) {
html += renderPagination(pagination);
}
html += '</div>';
$('#hvac-events-table-container').html(html);
}
/**
* Render pagination
*/
function renderPagination(pagination) {
var html = '<div class="hvac-pagination">';
// Previous button
if (pagination.has_prev) {
html += '<button type="button" class="hvac-pagination-btn hvac-btn hvac-btn-secondary" data-page="' + (pagination.current_page - 1) + '">&laquo; Previous</button>';
}
// Page numbers (show 5 pages around current)
var startPage = Math.max(1, pagination.current_page - 2);
var endPage = Math.min(pagination.total_pages, pagination.current_page + 2);
if (startPage > 1) {
html += '<button type="button" class="hvac-pagination-btn hvac-btn hvac-btn-secondary" data-page="1">1</button>';
if (startPage > 2) {
html += '<span class="hvac-pagination-dots">...</span>';
}
}
for (var i = startPage; i <= endPage; i++) {
var activeClass = i === pagination.current_page ? ' hvac-btn-primary' : ' hvac-btn-secondary';
html += '<button type="button" class="hvac-pagination-btn hvac-btn' + activeClass + '" data-page="' + i + '">' + i + '</button>';
}
if (endPage < pagination.total_pages) {
if (endPage < pagination.total_pages - 1) {
html += '<span class="hvac-pagination-dots">...</span>';
}
html += '<button type="button" class="hvac-pagination-btn hvac-btn hvac-btn-secondary" data-page="' + pagination.total_pages + '">' + pagination.total_pages + '</button>';
}
// Next button
if (pagination.has_next) {
html += '<button type="button" class="hvac-pagination-btn hvac-btn hvac-btn-secondary" data-page="' + (pagination.current_page + 1) + '">Next &raquo;</button>';
}
html += '</div>';
return html;
}
/**
* Render simple calendar view
*/
function renderCalendar(events) {
var html = '<div class="hvac-simple-calendar">';
if (events.length === 0) {
html += '<div class="hvac-no-events">';
html += '<p>No events found for the selected date range.</p>';
html += '</div>';
} else {
// Group events by date
var eventsByDate = {};
events.forEach(function(event) {
var date = event.start;
if (!eventsByDate[date]) {
eventsByDate[date] = [];
}
eventsByDate[date].push(event);
});
// Sort dates
var sortedDates = Object.keys(eventsByDate).sort();
sortedDates.forEach(function(date) {
var dateObj = new Date(date);
var dateStr = dateObj.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
html += '<div class="hvac-calendar-date-group">';
html += '<h3 class="hvac-calendar-date-header">' + dateStr + '</h3>';
html += '<div class="hvac-calendar-events">';
eventsByDate[date].forEach(function(event) {
html += '<div class="hvac-calendar-event-item ' + event.className + '">';
html += '<div class="hvac-event-title"><a href="' + event.url + '" target="_blank">' + event.title + '</a></div>';
html += '<div class="hvac-event-trainer">Trainer: ' + event.trainer + '</div>';
html += '<div class="hvac-event-details">';
html += 'Capacity: ' + event.extendedProps.capacity + ' | ';
html += 'Sold: ' + event.extendedProps.sold + ' | ';
html += 'Revenue: $' + formatMoney(event.extendedProps.revenue);
html += '</div>';
html += '</div>';
});
html += '</div></div>';
});
}
html += '</div>';
$('#hvac-calendar-content').html(html);
}
/**
* Update events count display
*/
function updateEventsCount(count) {
var text = count + ' event' + (count !== 1 ? 's' : '') + ' found';
$('#events-count-display').text(text);
}
/**
* Show error message
*/
function showError(message) {
// Create a simple alert for now - could be enhanced with a modal
if (window.console) {
console.error('HVAC Events Overview:', message);
}
// Add error message to page
var errorHtml = '<div class="hvac-notice hvac-notice-error" style="margin: 20px 0;">';
errorHtml += '<p><strong>Error:</strong> ' + message + '</p>';
errorHtml += '</div>';
// Show at top of events content
$('.hvac-events-content').prepend(errorHtml);
// Auto-remove after 5 seconds
setTimeout(function() {
$('.hvac-notice-error').fadeOut(function() {
$(this).remove();
});
}, 5000);
}
/**
* Format money for display
*/
function formatMoney(amount) {
return parseFloat(amount).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
/**
* Debounce function to limit function calls
*/
function debounce(func, wait) {
var timeout;
return function executedFunction() {
var context = this;
var args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
})(jQuery);