/** * Admin Panel Application * * Gestión de configuraciones de componentes del tema * * @package ROI_Theme * @since 2.0.0 */ const AdminPanel = { /** * Estado de la aplicación */ STATE: { settings: {}, hasChanges: false, isLoading: false }, /** * Inicializar aplicación */ init() { this.bindEvents(); this.loadSettings(); }, /** * Vincular eventos */ bindEvents() { // Botón guardar const saveBtn = document.getElementById('saveSettings'); if (saveBtn) { saveBtn.addEventListener('click', () => { this.saveSettings(); }); } // Detectar cambios en formularios const enableSaveButton = () => { this.STATE.hasChanges = true; const btn = document.getElementById('saveSettings'); if (btn) btn.disabled = false; }; document.querySelectorAll('input, select, textarea').forEach(input => { // Evento 'input' se dispara mientras se escribe (tiempo real) input.addEventListener('input', enableSaveButton); // Evento 'change' se dispara cuando pierde foco (para select y checkboxes) input.addEventListener('change', enableSaveButton); }); // Tabs const tabs = document.querySelectorAll('.nav-tabs .nav-link'); tabs.forEach(tab => { tab.addEventListener('click', (e) => { e.preventDefault(); this.switchTab(tab); }); }); }, /** * Cambiar tab */ switchTab(tab) { // Remover active de todos document.querySelectorAll('.nav-tabs .nav-link').forEach(t => { t.classList.remove('active'); }); document.querySelectorAll('.tab-pane').forEach(pane => { pane.classList.remove('show', 'active'); }); // Activar seleccionado tab.classList.add('active'); const targetId = tab.getAttribute('data-bs-target').substring(1); const targetPane = document.getElementById(targetId); if (targetPane) { targetPane.classList.add('show', 'active'); } }, /** * Cargar configuraciones desde servidor */ async loadSettings() { this.STATE.isLoading = true; this.showSpinner(true); try { const response = await axios({ method: 'POST', url: roiAdminData.ajaxUrl, data: new URLSearchParams({ action: 'roi_get_settings', nonce: roiAdminData.nonce }) }); if (response.data.success) { this.STATE.settings = response.data.data; this.renderAllComponents(); } else { this.showNotice('Error al cargar configuraciones', 'error'); } } catch (error) { console.error('Error loading settings:', error); this.showNotice('Error de conexión', 'error'); } finally { this.STATE.isLoading = false; this.showSpinner(false); } }, /** * Guardar configuraciones al servidor */ async saveSettings() { if (!this.STATE.hasChanges) { this.showNotice('No hay cambios para guardar', 'info'); return; } this.showSpinner(true); try { const formData = this.collectFormData(); // Crear FormData para WordPress AJAX const postData = new URLSearchParams(); postData.append('action', 'roi_save_settings'); postData.append('nonce', roiAdminData.nonce); // Agregar components como JSON string postData.append('components', JSON.stringify(formData.components)); const response = await axios({ method: 'POST', url: roiAdminData.ajaxUrl, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: postData }); if (response.data.success) { this.STATE.hasChanges = false; const btn = document.getElementById('saveSettings'); if (btn) btn.disabled = true; this.showNotice('Configuración guardada correctamente', 'success'); } else { this.showNotice(response.data.data.message || 'Error al guardar', 'error'); } } catch (error) { console.error('Error saving settings:', error); this.showNotice('Error de conexión', 'error'); } finally { this.showSpinner(false); } }, /** * Recolectar datos del formulario * Cada componente agregará su sección aquí cuando se implemente */ collectFormData() { return { components: { // Los componentes se agregarán aquí cuando se ejecute el algoritmo } }; }, /** * Renderizar todos los componentes */ renderAllComponents() { const components = this.STATE.settings.components || {}; // Los métodos render de componentes se llamarán aquí cuando se implementen }, /** * Utilidad: Mostrar spinner */ showSpinner(show) { const spinner = document.querySelector('.spinner'); if (spinner) { spinner.style.display = show ? 'inline-block' : 'none'; } }, /** * Utilidad: Mostrar notificación */ showNotice(message, type = 'info') { // WordPress admin notices const noticeDiv = document.createElement('div'); noticeDiv.className = `notice notice-${type} is-dismissible`; noticeDiv.innerHTML = `

${message}

`; const container = document.querySelector('.roi-admin-panel'); if (container) { container.insertBefore(noticeDiv, container.firstChild); // Auto-dismiss después de 5 segundos setTimeout(() => { noticeDiv.remove(); }, 5000); } } }; // Inicializar cuando el DOM esté listo document.addEventListener('DOMContentLoaded', () => { AdminPanel.init(); });