upskill-event-manager/assets/js/hvac-modal-forms.js
ben 00f88070b8 fix: resolve trainer event creation page issues and implement modal forms
- Fix AI Assistant timeout issue (frontend: 35s → 50s)
- Fix AJAX action name mismatch for categories (categorys → categories)
- Fix nonce mismatch (hvac_general_nonce → hvac_ajax_nonce)
- Add modal forms for creating new organizers, categories, and venues
- Add comprehensive AJAX endpoints with security validation
- Implement role-based permissions for category creation
- Fix searchable selectors action mapping

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-26 16:07:56 -03:00

303 lines
No EOL
11 KiB
JavaScript

/**
* HVAC Modal Forms
*
* Handles modal forms for creating new organizers, categories, and venues
* with role-based permissions and AJAX submission.
*/
(function($) {
'use strict';
class HVACModalForms {
constructor() {
this.init();
}
init() {
this.bindEvents();
this.createModalContainer();
}
bindEvents() {
// Listen for create new modal trigger
$(document).on('hvac:create-new-modal', (e, data) => {
this.showCreateModal(data.type, data.callback);
});
// Modal close events
$(document).on('click', '.hvac-modal-overlay, .hvac-modal-close', (e) => {
e.preventDefault();
this.closeModal();
});
// Prevent modal close when clicking inside modal content
$(document).on('click', '.hvac-modal-content', (e) => {
e.stopPropagation();
});
// Form submission
$(document).on('submit', '.hvac-modal-form', (e) => {
e.preventDefault();
this.handleFormSubmission(e.target);
});
// Escape key to close modal
$(document).on('keydown', (e) => {
if (e.keyCode === 27) { // ESC key
this.closeModal();
}
});
}
createModalContainer() {
if ($('#hvac-modal-container').length) {
return;
}
const modalHtml = `
<div id="hvac-modal-container" class="hvac-modal-overlay" style="display: none;">
<div class="hvac-modal-content">
<div class="hvac-modal-header">
<h3 class="hvac-modal-title"></h3>
<button type="button" class="hvac-modal-close">&times;</button>
</div>
<div class="hvac-modal-body">
<!-- Form content will be inserted here -->
</div>
</div>
</div>
`;
$('body').append(modalHtml);
}
showCreateModal(type, callback) {
this.currentCallback = callback;
const config = this.getModalConfig(type);
if (!config) {
console.error(`Unknown modal type: ${type}`);
return;
}
// Set modal title
$('.hvac-modal-title').text(config.title);
// Generate form HTML
const formHtml = this.generateFormHtml(type, config);
$('.hvac-modal-body').html(formHtml);
// Show modal
$('#hvac-modal-container').fadeIn(300);
// Focus first input
setTimeout(() => {
$('.hvac-modal-form input:first').focus();
}, 350);
}
getModalConfig(type) {
const configs = {
organizer: {
title: 'Add New Organizer',
fields: [
{ name: 'organizer_name', label: 'Organizer Name', type: 'text', required: true },
{ name: 'organizer_email', label: 'Email', type: 'email', required: false },
{ name: 'organizer_website', label: 'Website', type: 'url', required: false },
{ name: 'organizer_phone', label: 'Phone', type: 'tel', required: false }
],
action: 'hvac_create_organizer'
},
category: {
title: 'Add New Category',
fields: [
{ name: 'category_name', label: 'Category Name', type: 'text', required: true },
{ name: 'category_description', label: 'Description', type: 'textarea', required: false }
],
action: 'hvac_create_category',
permission_check: true
},
venue: {
title: 'Add New Venue',
fields: [
{ name: 'venue_name', label: 'Venue Name', type: 'text', required: true },
{ name: 'venue_address', label: 'Address', type: 'text', required: false },
{ name: 'venue_city', label: 'City', type: 'text', required: false },
{ name: 'venue_state', label: 'State/Province', type: 'text', required: false },
{ name: 'venue_zip', label: 'Zip/Postal Code', type: 'text', required: false },
{ name: 'venue_country', label: 'Country', type: 'text', required: false },
{ name: 'venue_website', label: 'Website', type: 'url', required: false },
{ name: 'venue_phone', label: 'Phone', type: 'tel', required: false }
],
action: 'hvac_create_venue'
}
};
return configs[type] || null;
}
generateFormHtml(type, config) {
// Check for category permission
if (config.permission_check && !hvacModalForms.canCreateCategories) {
return `
<div class="hvac-permission-error">
<p><strong>Permission Denied</strong></p>
<p>You don't have permission to create new categories. Please contact a master trainer for assistance.</p>
<div class="hvac-modal-actions">
<button type="button" class="hvac-btn hvac-btn-secondary hvac-modal-close">Close</button>
</div>
</div>
`;
}
let formHtml = `
<form class="hvac-modal-form" data-action="${config.action}">
<div class="hvac-form-fields">
`;
config.fields.forEach(field => {
formHtml += this.generateFieldHtml(field);
});
formHtml += `
</div>
<div class="hvac-modal-actions">
<button type="button" class="hvac-btn hvac-btn-secondary hvac-modal-close">Cancel</button>
<button type="submit" class="hvac-btn hvac-btn-primary">Create ${this.capitalizeFirst(type)}</button>
</div>
</form>
`;
return formHtml;
}
generateFieldHtml(field) {
const required = field.required ? 'required' : '';
const requiredMark = field.required ? '<span class="required">*</span>' : '';
if (field.type === 'textarea') {
return `
<div class="hvac-form-field">
<label for="${field.name}">${field.label}${requiredMark}</label>
<textarea id="${field.name}" name="${field.name}" ${required} rows="3"></textarea>
</div>
`;
}
return `
<div class="hvac-form-field">
<label for="${field.name}">${field.label}${requiredMark}</label>
<input type="${field.type}" id="${field.name}" name="${field.name}" ${required}>
</div>
`;
}
async handleFormSubmission(form) {
const $form = $(form);
const $submitBtn = $form.find('button[type="submit"]');
const action = $form.data('action');
// Disable submit button and show loading
$submitBtn.prop('disabled', true).text('Creating...');
try {
const formData = new FormData(form);
formData.append('action', action);
formData.append('nonce', hvacModalForms.nonce);
const response = await fetch(hvacModalForms.ajaxUrl, {
method: 'POST',
body: formData
});
const result = await response.json();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
if (!result.success) {
throw new Error(result.data || 'Request failed');
}
// Success - call callback with new item
if (this.currentCallback) {
this.currentCallback(result.data);
}
this.closeModal();
this.showSuccessMessage(`Successfully created ${result.data.title}`);
} catch (error) {
console.error('Form submission error:', error);
this.showErrorMessage(error.message || 'Failed to create item');
} finally {
// Re-enable submit button
$submitBtn.prop('disabled', false).text($submitBtn.text().replace('Creating...', 'Create'));
}
}
closeModal() {
$('#hvac-modal-container').fadeOut(300);
this.currentCallback = null;
}
showSuccessMessage(message) {
// Create temporary success notification
const $notification = $(`
<div class="hvac-notification hvac-success">
<span class="dashicons dashicons-yes-alt"></span>
${this.escapeHtml(message)}
</div>
`);
$('body').append($notification);
setTimeout(() => {
$notification.addClass('show');
}, 100);
setTimeout(() => {
$notification.removeClass('show');
setTimeout(() => $notification.remove(), 300);
}, 3000);
}
showErrorMessage(message) {
// Create temporary error notification
const $notification = $(`
<div class="hvac-notification hvac-error">
<span class="dashicons dashicons-warning"></span>
${this.escapeHtml(message)}
</div>
`);
$('body').append($notification);
setTimeout(() => {
$notification.addClass('show');
}, 100);
setTimeout(() => {
$notification.removeClass('show');
setTimeout(() => $notification.remove(), 300);
}, 5000);
}
capitalizeFirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
// Initialize modal forms when document is ready
$(document).ready(function() {
new HVACModalForms();
});
})(jQuery);