- 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>
303 lines
No EOL
11 KiB
JavaScript
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">×</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); |