/** * WhatsApp Bot Manager - JavaScript Simplificado * Versión sin librerías externas problemáticas */ class SimpleWhatsAppManager { constructor() { this.apiBaseUrl = './api/'; this.currentTab = 'dashboard'; this.init(); // Webhook polling state this._lastWebhook = null; this.setupWebhookPolling(); } init() { this.log('Iniciando sistema simplificado'); this.setupEventListeners(); this.setupCharts(); this.loadDashboard(); } log(message, type = 'info') { const timestamp = new Date().toLocaleTimeString(); console.log(`[${timestamp}] [${type.toUpperCase()}] ${message}`); } setupEventListeners() { this.log('Configurando event listeners'); // Navegación de tabs - más defensiva const navLinks = document.querySelectorAll('.nav-link[data-tab]'); if (navLinks) { navLinks.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const tabName = link.getAttribute('data-tab'); if (tabName) { this.showTab(tabName); } }); }); } // Formularios this.setupFormListeners(); } setupFormListeners() { // Formulario de configuración const system_configForm = document.getElementById('system_config-form'); if (system_configForm) { system_configForm.addEventListener('submit', (e) => { e.preventDefault(); this.savesystem_config(); }); } // Formulario de envío de mensaje const sendForm = document.getElementById('send-message-form'); if (sendForm) { sendForm.addEventListener('submit', (e) => { e.preventDefault(); this.sendMessage(); }); } } showTab(tabName) { this.log(`Cambiando a tab: ${tabName}`); // Ocultar todas las pestañas const tabs = document.querySelectorAll('.tab-content'); if (tabs) { tabs.forEach(tab => tab.classList.remove('active')); } // Remover clase active de navegación const navLinks = document.querySelectorAll('.nav-link'); if (navLinks) { navLinks.forEach(link => link.classList.remove('active')); } // Mostrar pestaña seleccionada const targetTab = document.getElementById(tabName); if (targetTab) { targetTab.classList.add('active'); } // Activar enlace de navegación const activeLink = document.querySelector(`[data-tab="${tabName}"]`); if (activeLink) { activeLink.classList.add('active'); } this.currentTab = tabName; this.loadTabData(tabName); } loadTabData(tabName) { this.log(`Cargando datos para tab: ${tabName}`); switch (tabName) { case 'dashboard': this.loadDashboard(); break; case 'conversations': this.loadConversations(); break; case 'users': this.loadUsers(); break; case 'send_message': this.loadconversations(); break; case 'templates': this.loadTemplates(); break; case 'menus': this.loadMenus(); break; case 'autoresponses': this.loadAutoResponses(); break; case 'logs': this.loadLogs(); break; case 'system_config': this.loadsystem_config(); break; default: this.log(`Tab no reconocido: ${tabName}`, 'warning'); } } async apiCall(endpoint, options = {}) { const url = `${this.apiBaseUrl}${endpoint}${endpoint.includes('?') ? '&' : '?'}debug=true`; this.log(`API Call: ${url}`, 'info'); try { const response = await fetch(url, { method: options.method || 'GET', headers: { 'Content-Type': 'application/json', ...options.headers }, body: options.body ? JSON.stringify(options.body) : undefined }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); this.log(`API Response: ${JSON.stringify(data).substring(0, 100)}...`, 'success'); return data; } catch (error) { this.log(`API Error: ${error.message}`, 'error'); this.showError('Error en petición: ' + error.message); throw error; } } // Polling ligero para detectar nuevos webhooks y refrescar UI rápidamente setupWebhookPolling() { // Ejecutar cada 5 segundos setInterval(async () => { try { const res = await fetch(this.apiBaseUrl + 'get_last_webhook_time.php'); if (!res.ok) return; const data = await res.json(); if (!data || !data.success) return; const last = data.last_webhook; if (!last) return; if (this._lastWebhook && this._lastWebhook === last) return; // Hubo un nuevo webhook this._lastWebhook = last; this.log('Nuevo webhook detectado, refrescando conversaciones', 'info'); // Refrescar lista de conversaciones await this.loadUsers(); // reload users (optional) await this.loadconversations(); // reload message-related selects if on send_message await this.loadConversations(); // Si hay un chat abierto, recargar sus mensajes if (this.currentTab === 'conversations' && this.currentUserId) { await this.loadconversations(this.currentUserId, false); } } catch (e) { this.log('Error polling webhook: ' + e.message, 'error'); } }, 5000); } async apiCallReal(endpoint, options = {}) { const url = `${this.apiBaseUrl}${endpoint}`; this.log(`API Call (REAL): ${url}`, 'info'); try { const response = await fetch(url, { method: options.method || 'GET', headers: { 'Content-Type': 'application/json', ...options.headers }, body: options.body ? JSON.stringify(options.body) : undefined }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); this.log(`API Response (REAL): ${JSON.stringify(data).substring(0, 100)}...`, 'success'); return data; } catch (error) { this.log(`API Error (REAL): ${error.message}`, 'error'); this.showError('Error en petición real: ' + error.message); throw error; } } async loadDashboard() { this.log('Cargando dashboard'); try { // Cargar estadísticas básicas const stats = await this.apiCall('get_stats.php'); this.updateStats(stats); // Cargar mensajes recientes const recentconversationsResponse = await this.apiCall('get_recent_messages.php'); if (recentconversationsResponse && recentconversationsResponse.success && Array.isArray(recentconversationsResponse.data)) { this.updateRecentconversations(recentconversationsResponse.data); } else if (recentconversationsResponse && Array.isArray(recentconversationsResponse)) { // Retrocompatibilidad por si la API devuelve directamente el array this.updateRecentconversations(recentconversationsResponse); } // Actualizar gráfico si existe this.updateChart(); } catch (error) { this.showError('Error cargando dashboard: ' + error.message); } } updateStats(stats) { this.log('Actualizando estadísticas del dashboard'); if (stats) { const elements = [ { id: 'total-users', value: stats.total_users || 0 }, { id: 'conversations-today', value: stats.conversations_today || 0 }, { id: 'active-users', value: stats.active_users || 0 }, { id: 'total-conversations', value: stats.total_conversations || 0 } ]; elements.forEach(item => { const element = document.getElementById(item.id); if (element) { element.textContent = item.value; this.log(`Estadística actualizada: ${item.id} = ${item.value}`); } }); } } updateRecentconversations(conversations) { const container = document.getElementById('recent-conversations'); if (!container) { this.log('Contenedor de mensajes recientes no encontrado', 'warning'); return; } container.innerHTML = ''; if (conversations && conversations.length > 0) { this.log(`Mostrando ${conversations.length} mensajes recientes`); conversations.forEach(message => { const messageElement = this.createRecentMessageElement(message); container.appendChild(messageElement); }); } else { container.innerHTML = '
No hay mensajes recientes
'; } } createRecentMessageElement(message) { const div = document.createElement('div'); div.className = 'recent-message mb-3 p-2 border-bottom'; const direction = message.direction === 'incoming' ? '📥' : '📤'; const time = new Date(message.created_at).toLocaleString(); div.innerHTML = `
${direction} ${message.phone_number} ${time}
${this.truncateText(message.content, 50)}
`; return div; } truncateText(text, length) { if (!text) return ''; return text.length > length ? text.substring(0, length) + '...' : text; } async updateChart() { if (!this.charts || !this.charts.conversations) { this.log('Gráfico no inicializado, omitiendo actualización', 'warning'); return; } try { const chartData = await this.apiCall('get_chart_data.php'); if (chartData && this.charts.conversations) { this.charts.conversations.data.labels = chartData.labels || []; this.charts.conversations.data.datasets[0].data = chartData.data || []; this.charts.conversations.update(); this.log('Gráfico actualizado correctamente'); } } catch (error) { this.log('Error actualizando gráfico: ' + error.message, 'warning'); } } setupCharts() { const ctx = document.getElementById('conversationsChart'); if (!ctx) { this.log('Canvas de gráfico no encontrado', 'warning'); return; } if (typeof Chart === 'undefined') { this.log('Chart.js no está cargado', 'warning'); return; } try { this.charts = this.charts || {}; this.charts.conversations = new Chart(ctx, { type: 'line', data: { labels: [], datasets: [{ label: 'Mensajes', data: [], borderColor: '#25d366', backgroundColor: 'rgba(37, 211, 102, 0.1)', borderWidth: 3, fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.1)' } }, x: { grid: { color: 'rgba(0,0,0,0.1)' } } }, plugins: { legend: { display: false } } } }); this.log('Gráfico de mensajes inicializado'); } catch (error) { this.log('Error inicializando gráfico: ' + error.message, 'error'); } } async loadUsers() { this.log('Cargando usuarios'); try { const response = await this.apiCall('get_users.php'); if (response && response.success) { this.updateUsersList(response.data || []); } else { this.showError('No se pudieron cargar los usuarios'); } } catch (error) { this.showError('Error cargando usuarios: ' + error.message); } } updateUsersList(users) { const container = document.getElementById('users-table'); if (!container) return; // Guardar datos para uso posterior this.usersData = users; if (users.length === 0) { container.innerHTML = 'No hay usuarios registrados'; return; } let html = ''; users.forEach(user => { const createdDate = new Date(user.created_at); const formatDate = createdDate.toLocaleDateString() + ' ' + createdDate.toLocaleTimeString('es', { hour: '2-digit', minute: '2-digit' }); html += ` ${user.id} ${user.phone_number} ${user.name || 'Sin nombre'} ${user.status} ${user.current_menu || 'Sin menú'} ${formatDate} `; }); container.innerHTML = html; } async loadConversations() { this.log('Cargando conversaciones'); try { const response = await this.apiCall('get_conversation_list.php'); console.log('Respuesta get_conversation_list:', response); // Debug if (response && response.success && Array.isArray(response.conversations)) { this.updateConversationsList(response.conversations); } else if (response && Array.isArray(response)) { // Retrocompatibilidad por si la API devuelve directamente el array this.updateConversationsList(response); } else { console.error('Formato de respuesta inesperado:', response); this.showError('Error: formato de datos inválido para conversaciones'); } } catch (error) { console.error('Error en loadConversations:', error); this.showError('Error cargando conversaciones: ' + error.message); } } updateConversationsList(conversations) { const container = document.getElementById('conversations-container'); if (!container) return; if (conversations.length === 0) { container.innerHTML = `
No hay conversaciones

Los chats aparecerán aquí cuando recibas o envíes mensajes

`; return; } let html = ''; conversations.forEach(conv => { const timeAgo = conv.time_ago || this.formatTimeAgo(conv.last_message_time || conv.created_at); const lastMessage = conv.last_message || conv.content || 'Sin mensajes'; const userName = conv.name || conv.phone_number; const userInitial = userName.charAt(0).toUpperCase(); const isOnline = Math.random() > 0.6; // Simulación de estado online // Unread badge const unreadBadge = (conv.unread_count && conv.unread_count > 0) ? `
${conv.unread_count}
` : ''; // Status icon const statusIcon = conv.last_direction === 'outgoing' ? '' : ''; // Message type indicator const messageTypeIcon = conv.last_message_type === 'template' ? ' ' : conv.last_message_type === 'image' ? ' ' : ''; html += `
${userInitial}
${userName} ${conv.last_message_status === 'read' ? '' : ''}
${timeAgo}
${statusIcon}
${messageTypeIcon}${lastMessage}
${unreadBadge}
`; }); container.innerHTML = html; // Agregar funcionalidad de búsqueda this.setupConversationSearch(conversations); } setupConversationSearch(conversations) { const searchInput = document.getElementById('search-conversations'); if (!searchInput) return; searchInput.addEventListener('input', (e) => { const query = e.target.value.toLowerCase().trim(); if (!query) { this.updateConversationsDisplay(conversations); return; } const filtered = conversations.filter(conv => { const name = (conv.name || '').toLowerCase(); const phone = (conv.phone_number || '').toLowerCase(); const message = (conv.last_message || conv.content || '').toLowerCase(); return name.includes(query) || phone.includes(query) || message.includes(query); }); this.updateConversationsDisplay(filtered); }); } updateConversationsDisplay(conversations) { const container = document.getElementById('conversations-container'); if (!container) return; if (conversations.length === 0) { container.innerHTML = `
No se encontraron conversaciones

Intenta con otros términos de búsqueda

`; return; } let html = ''; conversations.forEach(conv => { const timeAgo = conv.time_ago || this.formatTimeAgo(conv.last_message_time || conv.created_at); const lastMessage = conv.last_message || conv.content || 'Sin mensajes'; const userName = conv.name || conv.phone_number; const userInitial = userName.charAt(0).toUpperCase(); const isOnline = Math.random() > 0.6; const unreadBadge = (conv.unread_count && conv.unread_count > 0) ? `
${conv.unread_count}
` : ''; const statusIcon = conv.last_direction === 'outgoing' ? '' : ''; const messageTypeIcon = conv.last_message_type === 'template' ? ' ' : conv.last_message_type === 'image' ? ' ' : ''; html += `
${userInitial}
${userName} ${conv.last_message_status === 'read' ? '' : ''}
${timeAgo}
${statusIcon}
${messageTypeIcon}${lastMessage}
${unreadBadge}
`; }); container.innerHTML = html; } formatTimeAgo(datetime) { if (!datetime) return ''; const now = new Date(); const date = new Date(datetime); const diff = Math.floor((now - date) / 1000); if (diff < 60) return 'Ahora'; if (diff < 3600) return `${Math.floor(diff/60)}m`; if (diff < 86400) return `${Math.floor(diff/3600)}h`; if (diff < 2592000) return `${Math.floor(diff/86400)}d`; return date.toLocaleDateString(); } async loadsystem_config() { this.log('Cargando configuraciones'); try { const response = await this.apiCall('manage_config.php?action=whatsapp'); if (response && response.success) { this.updatesystem_configForm(response.data); } } catch (error) { this.showError('Error cargando configuraciones: ' + error.message); } } updatesystem_configForm(data) { if (!data) return; const fields = [ { id: 'whatsapp-token', value: data.whatsapp_token }, { id: 'phone-number-id', value: data.phone_number_id }, { id: 'webhook-token', value: data.webhook_verify_token }, { id: 'api-url', value: data.api_url }, { id: 'business-name', value: data.business_name }, { id: 'welcome-message', value: data.welcome_message } ]; fields.forEach(field => { const element = document.getElementById(field.id); if (element && field.value) { element.value = field.value; this.log(`Campo ${field.id} actualizado con valor: ${field.value}`); } else { this.log(`Campo ${field.id} no encontrado o sin valor`, 'warning'); } }); } async savesystem_config() { this.log('Guardando configuraciones'); const system_config = { token: document.getElementById('whatsapp-token').value, phone_number_id: document.getElementById('phone-number-id').value, webhook_verify_token: document.getElementById('webhook-token').value, api_url: document.getElementById('api-url').value, business_name: document.getElementById('business-name').value, welcome_message: document.getElementById('welcome-message').value }; try { const response = await this.apiCall('manage_config.php?action=save_whatsapp', { method: 'POST', body: { whatsapp: system_config } }); if (response && response.success) { this.showSuccess('Configuraciones guardadas exitosamente'); } else { this.showError('Error guardando configuraciones'); } } catch (error) { this.showError('Error: ' + error.message); } } showError(message) { this.log(`Error: ${message}`, 'error'); this.showAlert(message, 'danger'); } showSuccess(message) { this.log(`Success: ${message}`, 'success'); this.showAlert(message, 'success'); } showInfo(message) { this.log(`Info: ${message}`, 'info'); this.showAlert(message, 'info'); } showWarning(message) { this.log(`Warning: ${message}`, 'warning'); this.showAlert(message, 'warning'); } showAlert(message, type) { // Crear alerta temporal const alertDiv = document.createElement('div'); alertDiv.className = `alert alert-${type} alert-dismissible fade show position-fixed`; alertDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;'; alertDiv.innerHTML = ` ${message} `; document.body.appendChild(alertDiv); // Auto-remover después de 5 segundos setTimeout(() => { if (alertDiv.parentNode) { alertDiv.parentNode.removeChild(alertDiv); } }, 5000); } async loadconversations() { this.log('Cargando interfaz de mensajes'); const userSelect = document.getElementById('message-recipient'); const templateSelect = document.getElementById('message-template'); if (userSelect) userSelect.innerHTML = ''; if (templateSelect) templateSelect.innerHTML = ''; try { // Cargar usuarios para el select const usersResponse = await this.apiCall('get_users.php'); let users = []; if (usersResponse && usersResponse.success && Array.isArray(usersResponse.data)) { users = usersResponse.data; } else if (Array.isArray(usersResponse)) { users = usersResponse; } // Cargar plantillas para el select const templatesResponse = await this.apiCall('get_templates.php'); let templates = []; if (templatesResponse && templatesResponse.success && Array.isArray(templatesResponse.data)) { templates = templatesResponse.data; } else if (Array.isArray(templatesResponse)) { templates = templatesResponse; } this.log(`Usuarios cargados: ${users.length}, Plantillas cargadas: ${templates.length}`); if (users.length > 0) { this.populateUsersSelect(users); } else if (userSelect) { userSelect.innerHTML = ''; } if (templates.length > 0) { this.populateTemplatesSelect(templates); } else if (templateSelect) { templateSelect.innerHTML = ''; } } catch (error) { console.error('Error loadconversations:', error); if (userSelect) userSelect.innerHTML = ''; if (templateSelect) templateSelect.innerHTML = ''; this.showError('Error cargando datos para mensajes: ' + (error.message || error)); } } populateUsersSelect(users) { const select = document.getElementById('message-recipient'); if (!select) return; // Limpiar opciones existentes (excepto la primera) select.innerHTML = ''; // Agregar usuarios users.forEach(user => { const option = document.createElement('option'); option.value = user.id; option.textContent = `${user.name || user.phone_number} (${user.phone_number})`; select.appendChild(option); }); } populateTemplatesSelect(templates) { const select = document.getElementById('message-template'); if (!select) return; // Limpiar opciones existentes (excepto la primera) select.innerHTML = ''; // Agregar plantillas templates.forEach(template => { const option = document.createElement('option'); option.value = template.template_name; option.textContent = `${template.name} - ${template.category || 'Sin descripción'}`; select.appendChild(option); }); } async loadTemplates() { this.log('Cargando plantillas'); try { const response = await this.apiCall('get_templates.php'); if (response && response.success) { this.updateTemplatesList(response.data || []); } else { this.showError('Error cargando plantillas'); } } catch (error) { this.showError('Error cargando plantillas: ' + error.message); } } async loadMenus() { this.log('Cargando menús'); try { const response = await this.apiCall('get_menus.php'); if (response && response.success) { this.updateMenusList(response.data || []); } else if (response && Array.isArray(response)) { // Retrocompatibilidad this.updateMenusList(response); } else { this.showError('Error cargando menús'); } } catch (error) { this.showError('Error cargando menús: ' + error.message); } } updateTemplatesList(templates) { const container = document.getElementById('templates-table'); if (!container) return; // Guardar datos para uso posterior this.templatesData = templates; if (templates.length === 0) { container.innerHTML = 'No hay plantillas registradas'; return; } let html = ''; templates.forEach(template => { html += ` ${template.name} ${template.template_name} ${template.language_code || 'es'} ${template.category || 'utility'} ${template.status || 'pending'} `; }); container.innerHTML = html; } updateMenusList(menus) { const container = document.getElementById('menus-table'); if (!container) return; if (menus.length === 0) { container.innerHTML = 'No hay menús configurados'; return; } let html = ''; menus.forEach(menu => { const createdDate = new Date(menu.created_at || Date.now()); const formatDate = createdDate.toLocaleDateString() + ' ' + createdDate.toLocaleTimeString('es', { hour: '2-digit', minute: '2-digit' }); html += ` ${menu.name || menu.menu_name} ${menu.menu_key || menu.trigger} ${this.truncateText(menu.description || '', 50)} ${menu.status || 'active'} ${menu.options_count || 0} opciones ${formatDate} `; }); container.innerHTML = html; } async saveTemplate() { this.log('Guardando plantilla'); try { const templateData = { name: document.getElementById('template-name').value, whatsapp_name: document.getElementById('template-whatsapp-name').value, language: document.getElementById('template-language').value, category: document.getElementById('template-category').value }; // Validar campos requeridos if (!templateData.name || !templateData.whatsapp_name) { this.showError('Nombre descriptivo y nombre de WhatsApp son requeridos'); return; } const response = await this.apiCall('save_template.php', { method: 'POST', body: templateData }); if (response && response.success) { const status = response.status || 'pending'; if (status === 'approved') { this.showSuccess('Plantilla guardada y marcada como APROBADA.'); } else { this.showSuccess('Plantilla guardada correctamente. Estado: PENDIENTE.'); } // Cerrar modal const modal = document.getElementById('createTemplateModal'); if (modal) { const bsModal = bootstrap.Modal.getInstance(modal); if (bsModal) bsModal.hide(); } // Limpiar formulario document.getElementById('template-form').reset(); // Recargar plantillas this.loadTemplates(); } else { this.showError(`Error guardando plantilla: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error guardando plantilla: ' + error.message); } } async saveMenu() { this.log('Guardando menú'); try { const menuData = { name: document.getElementById('menu-name')?.value || '', menu_key: document.getElementById('menu-key')?.value || '', description: document.getElementById('menu-description')?.value || '', welcome_message: document.getElementById('menu-welcome-message')?.value || '', status: document.getElementById('menu-status')?.value || 'active' }; // Validar campos requeridos if (!menuData.name || !menuData.menu_key) { this.showError('Nombre del menú y clave del menú son requeridos'); return; } // Obtener opciones del menú const optionsContainer = document.getElementById('menu-options-container'); const options = []; if (optionsContainer) { const optionItems = optionsContainer.querySelectorAll('.menu-option-item'); optionItems.forEach((item, index) => { const optionKey = item.querySelector('.option-key')?.value || ''; const optionText = item.querySelector('.option-text')?.value || ''; const optionAction = item.querySelector('.option-action')?.value || 'message'; const optionValue = item.querySelector('.option-value')?.value || ''; if (optionKey && optionText) { options.push({ key: optionKey, text: optionText, action: optionAction, value: optionValue, order_index: index + 1 }); } }); } menuData.options = options; this.log(`Datos del menú a guardar: ${JSON.stringify(menuData)}`); const response = await this.apiCall('save_menu.php', { method: 'POST', body: menuData }); if (response && response.success) { this.showSuccess('Menú guardado correctamente'); // Cerrar modal const modal = document.getElementById('createMenuModal'); if (modal) { const bsModal = bootstrap.Modal.getInstance(modal); if (bsModal) bsModal.hide(); } // Limpiar formulario const form = document.getElementById('menu-form'); if (form) form.reset(); // Limpiar opciones const optionsContainer = document.getElementById('menu-options-container'); if (optionsContainer) optionsContainer.innerHTML = ''; // Recargar menús this.loadMenus(); } else { this.showError(`Error guardando menú: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error guardando menú: ' + error.message); } } async loadAutoResponses() { this.log('Cargando respuestas automáticas'); try { const response = await this.apiCall('get_autoresponses.php'); if (response && response.success) { this.updateAutoResponsesList(response.data || []); } else if (response && Array.isArray(response)) { this.updateAutoResponsesList(response); } else { this.showError('Error cargando respuestas automáticas'); } } catch (error) { this.showError('Error cargando respuestas automáticas: ' + error.message); } } updateAutoResponsesList(autoresponses) { const container = document.getElementById('autoresponses-table'); if (!container) return; // Almacenar los datos para uso posterior this.autoResponsesData = autoresponses; if (autoresponses.length === 0) { container.innerHTML = 'No hay respuestas automáticas configuradas'; return; } let html = ''; autoresponses.forEach(response => { const typeLabels = { 'keyword': '🔑 Palabra Clave', 'contains': '📝 Contiene', 'exact': '🎯 Exacta', 'welcome': '👋 Bienvenida', 'default': '🤖 Por Defecto' }; const typeLabel = typeLabels[response.trigger_type] || response.trigger_type; html += ` ${typeLabel} ${response.trigger_value || '-'} ${this.truncateText(response.response_text || '', 60)} ${response.is_active == 1 ? 'Activo' : 'Inactivo'} `; }); container.innerHTML = html; } async saveAutoResponse() { this.log('Guardando respuesta automática'); try { const autoresponseId = document.getElementById('autoresponse-id')?.value || ''; const responseData = { trigger_type: document.getElementById('autoresponse-trigger-type')?.value || 'keyword', trigger_value: document.getElementById('autoresponse-trigger-value')?.value || '', response_text: document.getElementById('autoresponse-text')?.value || '', response_type: document.getElementById('autoresponse-type')?.value || 'text', priority: document.getElementById('autoresponse-priority')?.value || 0, template_name: document.getElementById('autoresponse-template-name')?.value || '', menu_id: document.getElementById('autoresponse-menu-id')?.value || '', is_active: document.getElementById('autoresponse-active')?.value === '1' ? 1 : 0 }; // Si hay ID, es una actualización if (autoresponseId) { responseData.id = autoresponseId; } // Validar campos requeridos if (!responseData.response_text) { this.showError('El texto de respuesta es requerido'); return; } if (responseData.trigger_type !== 'welcome' && responseData.trigger_type !== 'default' && !responseData.trigger_value) { this.showError('El disparador es requerido para este tipo de respuesta'); return; } this.log(`Datos de respuesta automática a guardar: ${JSON.stringify(responseData)}`); const response = await this.apiCall('save_autoresponse.php', { method: 'POST', body: responseData }); if (response && response.success) { this.showSuccess('Respuesta automática guardada correctamente'); // Cerrar modal const modal = document.getElementById('createAutoResponseModal'); if (modal) { const bsModal = bootstrap.Modal.getInstance(modal); if (bsModal) bsModal.hide(); } // Limpiar formulario const form = document.getElementById('autoresponse-form'); if (form) form.reset(); // Recargar respuestas automáticas this.loadAutoResponses(); } else { this.showError(`Error guardando respuesta automática: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error guardando respuesta automática: ' + error.message); } } async deleteAutoResponseAction(responseId) { this.log(`Eliminando respuesta automática ID: ${responseId}`); try { const response = await this.apiCall('delete_autoresponse.php', { method: 'POST', body: { id: responseId } }); if (response && response.success) { this.showSuccess('Respuesta automática eliminada correctamente'); this.loadAutoResponses(); // Recargar la lista } else { this.showError(`Error eliminando respuesta automática: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error eliminando respuesta automática: ' + error.message); } } async deleteMenuAction(menuId) { this.log(`Eliminando menú ID: ${menuId}`); try { const response = await this.apiCall('delete_menu.php', { method: 'POST', body: { menu_id: menuId } }); if (response && response.success) { this.showSuccess('Menú eliminado correctamente'); this.loadMenus(); // Recargar la lista de menús } else { this.showError(`Error eliminando menú: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error eliminando menú: ' + error.message); } } async sendMessage() { this.log('Enviando mensaje'); try { const recipientType = document.getElementById('recipient-type').value; const messageType = document.getElementById('message-type').value; let recipient; let messageData = {}; // Obtener destinatario if (recipientType === 'existing') { const userSelect = document.getElementById('message-recipient'); if (!userSelect.value) { this.showError('Por favor selecciona un usuario'); return; } // Obtener datos del usuario seleccionado const selectedOption = userSelect.options[userSelect.selectedIndex]; const userId = userSelect.value; // Necesitamos obtener el número de teléfono del usuario const usersResponse = await this.apiCall('get_users.php'); if (usersResponse && usersResponse.success) { const user = usersResponse.data.find(u => u.id == userId); if (user) { recipient = user.phone_number; } else { this.showError('Usuario no encontrado'); return; } } else { this.showError('Error obteniendo datos del usuario'); return; } } else { recipient = document.getElementById('manual-recipient').value; if (!recipient) { this.showError('Por favor ingresa un número de teléfono'); return; } } // Preparar mensaje según el tipo if (messageType === 'text') { const messageText = document.getElementById('message-text').value; if (!messageText) { this.showError('Por favor escribe un mensaje'); return; } messageData = { recipient: recipient, type: 'text', message: messageText }; } else { const templateSelect = document.getElementById('message-template'); if (!templateSelect.value) { this.showError('Por favor selecciona una plantilla'); return; } messageData = { recipient: recipient, type: 'template', template_name: templateSelect.value }; } this.log(`Enviando mensaje a ${recipient}: ${JSON.stringify(messageData)}`); // Preguntar al usuario si quiere envío real o simulado const sendReal = confirm('¿Enviar mensaje REAL por WhatsApp?\n\nSí = Envío real\nNo = Envío simulado (debug)'); // Enviar mensaje const response = sendReal ? await this.apiCallReal('send_message.php', { method: 'POST', body: messageData }) : await this.apiCall('send_message.php', { method: 'POST', body: messageData }); if (response && response.success) { this.showSuccess(`Mensaje enviado correctamente a ${recipient}`); // Limpiar formulario document.getElementById('send-message-form').reset(); document.getElementById('message-recipient').value = ''; } else { this.showError(`Error enviando mensaje: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error enviando mensaje: ' + error.message); } } async loadLogs() { try { const response = await this.apiCall('get_logs.php'); if (response && response.success && Array.isArray(response.data)) { this.updateLogsTable(response.data); } else if (response && Array.isArray(response)) { // Retrocompatibilidad por si la API devuelve directamente el array this.updateLogsTable(response); } else { this.showError('Error: formato de datos inválido para logs'); } } catch (error) { this.showError('Error cargando logs: ' + error.message); } } updateLogsTable(logs) { const tbody = document.getElementById('logs-table'); if (!tbody) { this.log('Tabla de logs no encontrada', 'warning'); return; } tbody.innerHTML = ''; if (!logs || logs.length === 0) { tbody.innerHTML = 'No hay logs registrados'; return; } logs.forEach(log => { const row = this.createLogRow(log); if (row) { tbody.appendChild(row); } }); } createLogRow(log) { if (!log) return null; const tr = document.createElement('tr'); // Fecha y hora const tdDateTime = document.createElement('td'); tdDateTime.textContent = log.datetime || log.created_at || 'N/A'; tr.appendChild(tdDateTime); // Nivel const tdLevel = document.createElement('td'); const levelBadge = document.createElement('span'); levelBadge.className = `badge bg-${this.getLevelBadgeClass(log.level || log.tipo)}`; levelBadge.textContent = (log.level || log.tipo || 'INFO').toUpperCase(); tdLevel.appendChild(levelBadge); tr.appendChild(tdLevel); // Mensaje const tdMessage = document.createElement('td'); tdMessage.textContent = this.truncateText(log.message || log.mensaje || '', 100); tr.appendChild(tdMessage); // Origen const tdSource = document.createElement('td'); tdSource.textContent = log.source || log.origen || 'Sistema'; tr.appendChild(tdSource); // Acciones const tdActions = document.createElement('td'); const viewButton = document.createElement('button'); viewButton.className = 'btn btn-sm btn-outline-info'; viewButton.innerHTML = ''; viewButton.onclick = () => this.showLogDetails(log); tdActions.appendChild(viewButton); tr.appendChild(tdActions); return tr; } getLevelBadgeClass(level) { const levelClasses = { 'ERROR': 'danger', 'WARNING': 'warning', 'WARN': 'warning', 'INFO': 'info', 'DEBUG': 'secondary', 'SUCCESS': 'success' }; return levelClasses[level?.toUpperCase()] || 'secondary'; } showLogDetails(log) { const details = { 'Fecha/Hora': log.datetime || log.created_at || 'N/A', 'Nivel': (log.level || log.tipo || 'INFO').toUpperCase(), 'Mensaje': log.message || log.mensaje || '', 'Origen': log.source || log.origen || 'Sistema', 'Datos Adicionales': log.data ? JSON.stringify(log.data, null, 2) : 'N/A' }; let detailsHtml = '
'; for (const [key, value] of Object.entries(details)) { detailsHtml += `
${key}:
${value}
`; } detailsHtml += '
'; // Mostrar en modal o alert if (typeof bootstrap !== 'undefined') { // Si Bootstrap está disponible, crear modal this.showModalAlert('Detalles del Log', detailsHtml); } else { // Fallback a alert simple alert(`Detalles del Log:\n\n${Object.entries(details).map(([k,v]) => `${k}: ${v}`).join('\n')}`); } } showModalAlert(title, content) { // Crear modal temporal si no existe let modal = document.getElementById('tempLogModal'); if (!modal) { modal = document.createElement('div'); modal.id = 'tempLogModal'; modal.className = 'modal fade'; modal.innerHTML = ` `; document.body.appendChild(modal); } modal.querySelector('.modal-title').textContent = title; modal.querySelector('.modal-body').innerHTML = content; const bootstrapModal = new bootstrap.Modal(modal); bootstrapModal.show(); } async deleteUserAction(userId, userName, userPhone) { if (!confirm(`¿Estás seguro de que quieres eliminar este usuario?\n\nUsuario: ${userName}\nTeléfono: ${userPhone}\n\nEsta acción no se puede deshacer y eliminará:\n• Todos sus mensajes\n• Su historial de conversación\n• Sus datos personales`)) { return; } this.log(`Eliminando usuario ID: ${userId}`); try { const response = await this.apiCall('delete_user.php', { method: 'POST', body: { id: userId } }); if (response && response.success) { this.showSuccess('Usuario eliminado correctamente'); this.loadUsers(); // Recargar la lista } else { this.showError(`Error eliminando usuario: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error eliminando usuario: ' + error.message); } } async deleteTemplateAction(templateId) { this.log(`Eliminando plantilla ID: ${templateId}`); try { const response = await this.apiCall('delete_template.php', { method: 'POST', body: { id: templateId } }); if (response && response.success) { this.showSuccess('Plantilla eliminada correctamente'); this.loadTemplates(); // Recargar la lista } else { this.showError(`Error eliminando plantilla: ${response?.error || 'Error desconocido'}`); } } catch (error) { this.showError('Error eliminando plantilla: ' + error.message); } } } // Inicializar cuando el DOM esté listo document.addEventListener('DOMContentLoaded', function () { console.log('DOM cargado, inicializando WhatsApp Manager...'); try { window.whatsappManager = new SimpleWhatsAppManager(); console.log('WhatsApp Manager inicializado correctamente'); } catch (error) { console.error('Error inicializando WhatsApp Manager:', error); } }); // Funciones globales para modales (compatibilidad con el HTML existente) window.openCreateTemplateModal = function () { console.log('🔵 Abriendo modal de plantilla...'); const modalElement = document.getElementById('createTemplateModal'); if (!modalElement) { console.error('❌ Modal de plantilla no encontrado'); return; } try { const form = document.getElementById('template-form'); if (form) form.reset(); if (typeof bootstrap !== 'undefined' && bootstrap.Modal) { const modal = new bootstrap.Modal(modalElement); modal.show(); } else { modalElement.style.display = 'block'; modalElement.classList.add('show'); } console.log('✅ Modal de plantilla abierto'); } catch (error) { console.error('❌ Error abriendo modal de plantilla:', error); } }; window.openCreateMenuModal = function () { console.log('🔵 Abriendo modal de menú...'); const modalElement = document.getElementById('createMenuModal'); if (!modalElement) { console.error('❌ Modal de menú no encontrado'); return; } try { const form = document.getElementById('menu-form'); if (form) form.reset(); if (typeof bootstrap !== 'undefined' && bootstrap.Modal) { const modal = new bootstrap.Modal(modalElement); modal.show(); } else { modalElement.style.display = 'block'; modalElement.classList.add('show'); } console.log('✅ Modal de menú abierto'); } catch (error) { console.error('❌ Error abriendo modal de menú:', error); } }; // Función global para debugging window.debugAPI = async function (endpoint) { try { const manager = window.whatsappManager; if (manager) { const result = await manager.apiCall(endpoint); console.log('Debug API Result:', result); return result; } else { console.error('Manager no inicializado'); } } catch (error) { console.error('Debug API Error:', error); } }; // Función para abrir ventana de chat window.openChatWindow = function (userId) { console.log('Abriendo chat del usuario:', userId); // Abrir nueva ventana de chat const chatUrl = `chat_window.php?user_id=${userId}&debug=true`; const windowFeatures = 'width=1000,height=700,resizable=yes,scrollbars=yes,status=yes,toolbar=no,menubar=no,location=no'; const chatWindow = window.open(chatUrl, `chat_${userId}`, windowFeatures); if (chatWindow) { chatWindow.focus(); } else { alert('No se pudo abrir la ventana de chat. Verifica que tu navegador permita ventanas emergentes.'); } }; // Función para mostrar modal de chat function showChatModal(user, conversations) { // Escapar datos del usuario para evitar XSS const userName = escapeHtml(user.name || 'Usuario'); const userPhone = escapeHtml(user.phone_number || ''); const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('chatModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); // Event listener para cambio de tipo de mensaje document.getElementById('messageType').addEventListener('change', function() { const templateSelector = document.getElementById('templateSelector'); const messageInput = document.getElementById('messageInput'); if (this.value === 'template') { templateSelector.style.display = 'block'; messageInput.placeholder = 'Parámetros de la plantilla (opcional)'; } else { templateSelector.style.display = 'none'; messageInput.placeholder = 'Escribe tu mensaje...'; } }); // Mostrar modal const modal = new bootstrap.Modal(document.getElementById('chatModal')); modal.show(); // Scroll al final setTimeout(() => { const chatContainer = document.getElementById('chat-conversations'); chatContainer.scrollTop = chatContainer.scrollHeight; }, 200); } // Generar HTML de mensajes del chat function generateChatconversations(conversations) { if (!conversations || conversations.length === 0) { return '


No hay mensajes en esta conversación
'; } let html = ''; conversations.forEach(msg => { const isOutgoing = msg.direction === 'outgoing'; const messageClass = isOutgoing ? 'outgoing' : 'incoming'; const alignClass = isOutgoing ? 'justify-content-end' : 'justify-content-start'; const bgClass = isOutgoing ? 'bg-success text-white' : 'bg-white'; // Escapar el contenido del mensaje const messageContent = escapeHtml(msg.content) || 'Sin contenido'; const messageTime = escapeHtml(msg.time || ''); html += `
${messageContent}
${messageTime} ${isOutgoing ? '✓✓' : ''}
`; }); return html; } // Función para escapar HTML y prevenir XSS function escapeHtml(text) { if (!text) return ''; const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.toString().replace(/[&<>"']/g, function(m) { return map[m]; }); } // Función para enviar mensaje desde el chat window.sendChatMessage = async function (userId) { const messageType = document.getElementById('messageType').value; const messageInput = document.getElementById('messageInput'); const message = messageInput.value.trim(); if (!message && messageType === 'text') { alert('Por favor escribe un mensaje'); return; } if (messageType === 'template') { const templateSelect = document.getElementById('templateSelect'); const template = templateSelect.value; if (!template) { alert('Por favor selecciona una plantilla'); return; } await sendTemplateMessage(userId, template, message); } else { await sendTextMessage(userId, message); } messageInput.value = ''; }; // Función para enviar mensaje de texto async function sendTextMessage(userId, message) { try { const manager = window.whatsappManager; const usersResponse = await manager.apiCall('get_users.php?debug=true'); // Manejar diferentes formatos de respuesta let users = []; if (Array.isArray(usersResponse)) { users = usersResponse; } else if (usersResponse && usersResponse.data && Array.isArray(usersResponse.data)) { users = usersResponse.data; } else if (usersResponse && usersResponse.users && Array.isArray(usersResponse.users)) { users = usersResponse.users; } else { console.error('Formato de respuesta de usuarios inesperado:', usersResponse); throw new Error('Error obteniendo lista de usuarios'); } const user = users.find(u => u.id == userId); if (!user) { throw new Error('Usuario no encontrado'); } const response = await manager.apiCall('send_message.php', { method: 'POST', body: { recipient: user.phone_number, type: 'text', message: message } }); if (response && response.success) { // Refrescar chat openChatWindow(userId); showAlert('Mensaje enviado correctamente', 'success'); } else { throw new Error(response.error || 'Error enviando mensaje'); } } catch (error) { console.error('Error enviando mensaje:', error); showAlert('Error enviando mensaje: ' + error.message, 'danger'); } } // Función para enviar mensaje de plantilla async function sendTemplateMessage(userId, template, parameters) { try { const manager = window.whatsappManager; const usersResponse = await manager.apiCall('get_users.php?debug=true'); // Manejar diferentes formatos de respuesta let users = []; if (Array.isArray(usersResponse)) { users = usersResponse; } else if (usersResponse && usersResponse.data && Array.isArray(usersResponse.data)) { users = usersResponse.data; } else if (usersResponse && usersResponse.users && Array.isArray(usersResponse.users)) { users = usersResponse.users; } else { console.error('Formato de respuesta de usuarios inesperado:', usersResponse); throw new Error('Error obteniendo lista de usuarios'); } const user = users.find(u => u.id == userId); if (!user) { throw new Error('Usuario no encontrado'); } const response = await manager.apiCall('send_message.php', { method: 'POST', body: { recipient: user.phone_number, type: 'template', template: template, language: 'en_US', parameters: parameters ? parameters.split(',') : [] } }); if (response && response.success) { // Refrescar chat openChatWindow(userId); showAlert('Mensaje de plantilla enviado correctamente', 'success'); } else { throw new Error(response.error || 'Error enviando plantilla'); } } catch (error) { console.error('Error enviando plantilla:', error); showAlert('Error enviando plantilla: ' + error.message, 'danger'); } } // Función para ver detalles de conversación window.viewConversationDetails = async function (userId) { console.log('Mostrando detalles de conversación para usuario:', userId); try { // Obtener datos del usuario const usersResponse = await window.whatsappManager.apiCall('get_users.php'); let user = null; if (usersResponse && usersResponse.success && Array.isArray(usersResponse.data)) { user = usersResponse.data.find(u => u.id == userId); } if (!user) { window.whatsappManager.showError('Usuario no encontrado'); return; } // Obtener estadísticas de la conversación (simuladas por ahora) const stats = { total_conversations: Math.floor(Math.random() * 50) + 1, conversations_today: Math.floor(Math.random() * 10), last_activity: user.updated_at || user.created_at, first_contact: user.created_at, status: user.status || 'active' }; // Mostrar modal con detalles showConversationDetailsModal(user, stats); } catch (error) { console.error('Error obteniendo detalles de conversación:', error); window.whatsappManager.showError('Error obteniendo detalles: ' + error.message); } }; // Función para mostrar modal de detalles de conversación function showConversationDetailsModal(user, stats) { console.log('Mostrando modal de detalles para:', user); const userName = escapeHtml(user.name || 'Sin nombre'); const userPhone = escapeHtml(user.phone_number || ''); const userStatus = user.status || 'unknown'; const currentMenu = user.current_menu || 'Sin menú'; // Formatear fechas const firstContact = user.created_at ? new Date(user.created_at).toLocaleString('es') : 'N/A'; const lastActivity = stats.last_activity ? new Date(stats.last_activity).toLocaleString('es') : 'N/A'; const statusBadgeClass = userStatus === 'active' ? 'success' : userStatus === 'inactive' ? 'secondary' : 'warning'; const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('conversationDetailsModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); // Mostrar modal const modal = new bootstrap.Modal(document.getElementById('conversationDetailsModal')); modal.show(); } // Función auxiliar para calcular tiempo transcurrido function calculateTimeAgo(datetime) { if (!datetime) return 'N/A'; const now = new Date(); const date = new Date(datetime); const diffInSeconds = Math.floor((now - date) / 1000); if (diffInSeconds < 60) return 'Hace menos de 1 minuto'; if (diffInSeconds < 3600) return `Hace ${Math.floor(diffInSeconds / 60)} minutos`; if (diffInSeconds < 86400) return `Hace ${Math.floor(diffInSeconds / 3600)} horas`; if (diffInSeconds < 2592000) return `Hace ${Math.floor(diffInSeconds / 86400)} días`; return date.toLocaleDateString('es'); } // Función para mostrar alertas function showAlert(message, type = 'info') { const alertHtml = ` `; document.body.insertAdjacentHTML('beforeend', alertHtml); // Auto-dismiss después de 5 segundos setTimeout(() => { const alert = document.querySelector('.alert'); if (alert) { alert.remove(); } }, 5000); } // Función para ver conversación específica (mantener compatibilidad) window.viewConversation = function (userId) { openChatWindow(userId); }; // Función para editar usuario window.editUser = function (userId) { console.log('Editando usuario:', userId); // Buscar el usuario en los datos cargados if (window.whatsappManager && window.whatsappManager.usersData) { const user = window.whatsappManager.usersData.find(u => u.id == userId); if (user) { showEditUserModal(user); } else { alert('Error: Usuario no encontrado'); } } else { alert('Error: Datos no disponibles, recarga la página'); } }; // Función para ver historial de usuario window.viewUserHistory = function (userId) { console.log('Viendo historial del usuario:', userId); // Por ahora mostrar un modal simple const modalHtml = ` `; // Remover modal anterior const existing = document.getElementById('userHistoryModal'); if (existing) existing.remove(); document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('userHistoryModal')); modal.show(); }; // Función para confirmar eliminación de usuario window.confirmDeleteUser = function (userId) { if (confirm('¿Estás seguro de que deseas eliminar este usuario?\n\nEsta acción no se puede deshacer.')) { deleteUser(userId); } }; // Función para eliminar usuario window.deleteUser = async function (userId) { console.log('Eliminando usuario:', userId); try { const response = await window.whatsappManager.apiCall('delete_user.php', { method: 'POST', body: { user_id: userId } }); if (response && response.success) { window.whatsappManager.showSuccess('Usuario eliminado correctamente'); // Cerrar modal si está abierto const modal = document.getElementById('conversationDetailsModal'); if (modal) { const bsModal = bootstrap.Modal.getInstance(modal); if (bsModal) bsModal.hide(); } // Recargar datos if (window.whatsappManager.currentTab === 'users') { window.whatsappManager.loadUsers(); } else if (window.whatsappManager.currentTab === 'conversations') { window.whatsappManager.loadConversations(); } } else { window.whatsappManager.showError('Error eliminando usuario: ' + (response?.error || 'Error desconocido')); } } catch (error) { window.whatsappManager.showError('Error eliminando usuario: ' + error.message); } }; // Función para eliminar usuario window.deleteUser = function (userId) { console.log('Eliminando usuario:', userId); // Buscar el usuario para mostrar información let userName = 'Usuario ' + userId; let userPhone = ''; if (window.whatsappManager && window.whatsappManager.usersData) { const user = window.whatsappManager.usersData.find(u => u.id == userId); if (user) { userName = user.name || 'Usuario ' + userId; userPhone = user.phone_number || ''; } } if (window.whatsappManager) { window.whatsappManager.deleteUserAction(userId, userName, userPhone); } }; // Funciones para plantillas window.showCreateTemplateModal = function () { const modal = new bootstrap.Modal(document.getElementById('createTemplateModal')); modal.show(); }; window.editTemplate = function (templateId) { console.log('Editando plantilla:', templateId); // Las plantillas de WhatsApp no se pueden editar una vez creadas // Solo se pueden crear nuevas o eliminar existentes if (window.whatsappManager) { window.whatsappManager.showInfo( 'Las plantillas de WhatsApp aprobadas no se pueden editar una vez creadas. ' + 'Si necesitas cambiar el contenido, debes crear una nueva plantilla y enviarla a revisión.' ); } else { alert('Las plantillas no se pueden editar. Crea una nueva plantilla si necesitas modificar el contenido.'); } }; window.deleteTemplate = function (templateId) { console.log('Eliminando plantilla:', templateId); // Buscar la plantilla para mostrar información let templateName = 'Plantilla ' + templateId; if (window.whatsappManager && window.whatsappManager.templatesData) { const template = window.whatsappManager.templatesData.find(t => t.id == templateId); if (template) { templateName = template.name || 'Plantilla ' + templateId; } } if (confirm(`¿Está seguro que desea eliminar la plantilla "${templateName}"?\n\nEsta acción no se puede deshacer.`)) { if (window.whatsappManager) { window.whatsappManager.deleteTemplateAction(templateId); } } }; // Función para editar usuario - Modal simple window.showEditUserModal = function(user) { const modalHtml = ` `; // Eliminar modal anterior si existe const existingModal = document.getElementById('editUserModal'); if (existingModal) { existingModal.remove(); } // Agregar nuevo modal document.body.insertAdjacentHTML('beforeend', modalHtml); // Mostrar modal const modal = new bootstrap.Modal(document.getElementById('editUserModal')); modal.show(); }; // Función para guardar usuario editado window.saveEditedUser = async function() { const userId = document.getElementById('edit-user-id').value; const name = document.getElementById('edit-user-name').value; const status = document.getElementById('edit-user-status').value; if (window.whatsappManager) { try { const response = await window.whatsappManager.apiCall('update_user.php', { method: 'POST', body: { id: userId, name: name, status: status } }); if (response && response.success) { window.whatsappManager.showSuccess('Usuario actualizado correctamente'); // Cerrar modal const modal = bootstrap.Modal.getInstance(document.getElementById('editUserModal')); if (modal) modal.hide(); // Recargar lista window.whatsappManager.loadUsers(); } else { window.whatsappManager.showError(`Error: ${response?.error || 'Error desconocido'}`); } } catch (error) { window.whatsappManager.showError('Error actualizando usuario: ' + error.message); } } }; // Hacer que app.saveTemplate() y app.saveMenu() funcionen window.app = { saveTemplate: function () { if (window.whatsappManager) { window.whatsappManager.saveTemplate(); } }, saveMenu: function () { if (window.whatsappManager) { window.whatsappManager.saveMenu(); } }, saveAutoResponse: function () { if (window.whatsappManager) { window.whatsappManager.saveAutoResponse(); } } }; // Funciones globales para gestión de menús window.editMenu = async function (menuId) { console.log('Editando menú:', menuId); try { // Obtener datos del menú const response = await window.whatsappManager.apiCall('get_menus.php'); if (response && response.success) { const menu = response.data.find(m => m.id == menuId); if (menu) { showEditMenuModal(menu); } else { window.whatsappManager.showError('Menú no encontrado'); } } else { window.whatsappManager.showError('Error cargando datos del menú'); } } catch (error) { console.error('Error editando menú:', error); window.whatsappManager.showError('Error editando menú: ' + error.message); } }; window.deleteMenu = function (menuId) { console.log('Eliminando menú:', menuId); if (confirm(`¿Está seguro que desea eliminar el menú ${menuId}?`)) { if (window.whatsappManager) { window.whatsappManager.deleteMenuAction(menuId); } } }; window.viewMenuOptions = async function (menuId) { console.log('Viendo opciones del menú:', menuId); try { // Obtener datos del menú y sus opciones const response = await window.whatsappManager.apiCall('get_menus.php'); if (response && response.success) { const menu = response.data.find(m => m.id == menuId); if (menu) { showMenuOptionsModal(menu); } else { window.whatsappManager.showError('Menú no encontrado'); } } else { window.whatsappManager.showError('Error cargando opciones del menú'); } } catch (error) { console.error('Error viendo opciones:', error); window.whatsappManager.showError('Error viendo opciones: ' + error.message); } }; // Función para agregar nueva opción al menú window.addMenuOption = function () { const container = document.getElementById('menu-options-container'); if (!container) return; const optionIndex = container.children.length + 1; const optionHtml = ` `; container.insertAdjacentHTML('beforeend', optionHtml); }; // Función para remover opción del menú window.removeMenuOption = function (button) { const optionItem = button.closest('.menu-option-item'); if (optionItem) { optionItem.remove(); updateOptionNumbers(); } }; // Funciones globales para gestión de respuestas automáticas // La función real está más abajo en el archivo (línea ~2390) window.deleteAutoResponse = function (responseId) { console.log('Eliminando respuesta automática:', responseId); if (confirm(`¿Está seguro que desea eliminar la respuesta automática ${responseId}?`)) { if (window.whatsappManager) { window.whatsappManager.deleteAutoResponseAction(responseId); } } }; // Funciones para modal de autorespuestas window.showCreateAutoResponseModal = function() { document.getElementById('autoresponse-form').reset(); document.getElementById('autoresponse-id').value = ''; document.getElementById('createAutoResponseModalLabel').innerHTML = ' Crear Nueva Respuesta Automática'; // Reset campos específicos updateTriggerFields('keyword'); updateResponseTypeFields('text'); const modal = new bootstrap.Modal(document.getElementById('createAutoResponseModal')); modal.show(); }; window.showEditAutoResponseModal = function(autoresponse) { document.getElementById('autoresponse-id').value = autoresponse.id; document.getElementById('createAutoResponseModalLabel').innerHTML = ' Editar Respuesta Automática'; // Llenar campos del formulario document.getElementById('autoresponse-trigger-type').value = autoresponse.trigger_type; document.getElementById('autoresponse-trigger-value').value = autoresponse.trigger_value || ''; document.getElementById('autoresponse-text').value = autoresponse.response_text; document.getElementById('autoresponse-type').value = autoresponse.response_type; document.getElementById('autoresponse-priority').value = autoresponse.priority; document.getElementById('autoresponse-active').value = autoresponse.is_active ? '1' : '0'; document.getElementById('autoresponse-template-name').value = autoresponse.template_name || ''; document.getElementById('autoresponse-menu-id').value = autoresponse.menu_id || ''; // Actualizar campos según el tipo updateTriggerFields(autoresponse.trigger_type); updateResponseTypeFields(autoresponse.response_type); const modal = new bootstrap.Modal(document.getElementById('createAutoResponseModal')); modal.show(); }; window.updateTriggerFields = function(triggerType) { const valueGroup = document.getElementById('trigger-value-group'); const valueLabel = document.getElementById('trigger-value-label'); const valueInput = document.getElementById('autoresponse-trigger-value'); const valueHelp = document.getElementById('trigger-value-help'); if (!valueGroup || !valueLabel || !valueInput || !valueHelp) { console.warn('Elementos del modal de autorespuesta no encontrados'); return; } switch (triggerType) { case 'keyword': valueGroup.style.display = 'block'; valueLabel.textContent = 'Palabras Clave *'; valueInput.placeholder = 'hola,buenos días,hi,hello'; valueInput.required = true; valueHelp.textContent = 'Separa múltiples palabras con comas'; break; case 'contains': valueGroup.style.display = 'block'; valueLabel.textContent = 'Texto a Buscar *'; valueInput.placeholder = 'precio'; valueInput.required = true; valueHelp.textContent = 'Texto que debe contener el mensaje del usuario'; break; case 'exact': valueGroup.style.display = 'block'; valueLabel.textContent = 'Mensaje Exacto *'; valueInput.placeholder = 'quiero información'; valueInput.required = true; valueHelp.textContent = 'El mensaje debe coincidir exactamente'; break; case 'welcome': case 'default': valueGroup.style.display = 'none'; valueInput.required = false; valueInput.value = ''; break; } }; window.updateResponseTypeFields = function(responseType) { const templateFields = document.getElementById('template-fields'); const menuFields = document.getElementById('menu-fields'); if (!templateFields || !menuFields) { console.warn('Campos adicionales del modal no encontrados'); return; } // Ocultar todos los campos adicionales templateFields.style.display = 'none'; menuFields.style.display = 'none'; // Mostrar campos según el tipo switch (responseType) { case 'template': templateFields.style.display = 'block'; break; case 'menu': menuFields.style.display = 'block'; // Cargar menús disponibles si no están cargados loadMenusForSelect(); break; } }; window.loadMenusForSelect = function() { fetch('/api/get_menus.php') .then(response => response.json()) .then(data => { if (data.success) { const select = document.getElementById('autoresponse-menu-id'); if (select) { select.innerHTML = ''; data.data.forEach(menu => { const option = document.createElement('option'); option.value = menu.id; option.textContent = `${menu.name} (${menu.menu_key})`; select.appendChild(option); }); } } }) .catch(error => console.error('Error loading menus for select:', error)); }; // Actualizar función editAutoResponse para usar el modal window.editAutoResponse = function (responseId) { console.log('Editando respuesta automática:', responseId); // Buscar la respuesta en los datos cargados if (window.whatsappManager && window.whatsappManager.autoResponsesData) { const autoresponse = window.whatsappManager.autoResponsesData.find(ar => ar.id == responseId); if (autoresponse) { showEditAutoResponseModal(autoresponse); } else { console.error('Respuesta automática no encontrada:', responseId); alert('Error: No se pudo cargar la respuesta automática'); } } else { console.error('Datos de respuestas automáticas no disponibles'); alert('Error: Datos no disponibles, recarga la página'); } }; window.showCreateAutoResponseModal = function () { console.log('🔵 Abriendo modal de respuesta automática...'); const modalElement = document.getElementById('createAutoResponseModal'); if (!modalElement) { console.error('❌ Modal de respuesta automática no encontrado'); return; } try { const form = document.getElementById('autoresponse-form'); if (form) form.reset(); if (typeof bootstrap !== 'undefined' && bootstrap.Modal) { const modal = new bootstrap.Modal(modalElement); modal.show(); } else { modalElement.style.display = 'block'; modalElement.classList.add('show'); } console.log('✅ Modal de respuesta automática abierto'); } catch (error) { console.error('❌ Error abriendo modal de respuesta automática:', error); } }; // Función para cambiar tipo de disparador window.toggleTriggerType = function () { const triggerType = document.getElementById('autoresponse-type')?.value; const triggerContainer = document.getElementById('trigger-container'); if (triggerContainer) { if (triggerType === 'welcome' || triggerType === 'default') { triggerContainer.style.display = 'none'; } else { triggerContainer.style.display = 'block'; const triggerInput = document.getElementById('autoresponse-trigger'); const triggerLabel = document.querySelector('label[for="autoresponse-trigger"]'); if (triggerInput && triggerLabel) { switch (triggerType) { case 'keyword': triggerLabel.textContent = 'Palabra Clave *'; triggerInput.placeholder = 'ej: hola, info, precios'; break; case 'contains': triggerLabel.textContent = 'Texto que debe contener *'; triggerInput.placeholder = 'ej: precio, información'; break; case 'exact': triggerLabel.textContent = 'Mensaje exacto *'; triggerInput.placeholder = 'ej: ¿Cuáles son sus precios?'; break; } } } } }; // Funciones para el formulario de mensajes window.toggleRecipientType = function () { const recipientType = document.getElementById('recipient-type').value; const existingGroup = document.getElementById('existing-recipient-group'); const manualGroup = document.getElementById('manual-recipient-group'); if (recipientType === 'manual') { existingGroup.style.display = 'none'; manualGroup.style.display = 'block'; } else { existingGroup.style.display = 'block'; manualGroup.style.display = 'none'; } }; window.toggleMessageType = function () { const messageType = document.getElementById('message-type').value; const textGroup = document.getElementById('message-text-group'); const templateGroup = document.getElementById('template-group'); if (messageType === 'template') { textGroup.style.display = 'none'; templateGroup.style.display = 'block'; } else { textGroup.style.display = 'block'; templateGroup.style.display = 'none'; } }; // Función de diagnóstico window.runDiagnostic = function () { const resultsDiv = document.getElementById('diagnostic-results'); // Mostrar spinner de carga resultsDiv.innerHTML = `
Cargando...

Ejecutando diagnóstico...

`; fetch('./api/diagnose_whatsapp.php') .then(response => response.json()) .then(data => { if (data.success) { displayDiagnosticResults(data); } else { resultsDiv.innerHTML = `
Error: ${data.error || 'Error desconocido'}
`; } }) .catch(error => { console.error('Error en diagnóstico:', error); resultsDiv.innerHTML = `
Error de conexión: ${error.message}
`; }); }; function displayDiagnosticResults(data) { const resultsDiv = document.getElementById('diagnostic-results'); let html = `
Última verificación: ${data.timestamp}
Configuración
Phone Number ID ${data.config_status.phone_number_id ? '✓' : '✗'}
Access Token ${data.config_status.access_token ? '✓' : '✗'}
Webhook Token ${data.config_status.webhook_verify_token ? '✓' : '✗'}
Plantillas
${data.template_status.approved || 0}
Aprobadas
${data.template_status.pending || 0}
Pendientes
${data.template_status.rejected || 0}
Rechazadas
API WhatsApp
${data.api_status.reachable ? `✓ Conectado - ${data.api_status.phone_number || 'N/A'}` : `✗ ${data.api_status.error || 'No conectado'}` }
`; // Recomendaciones if (data.recommendations && data.recommendations.length > 0) { html += `
Recomendaciones
`; } html += '
'; resultsDiv.innerHTML = html; } // ============================================== // EVENT LISTENERS PARA MODALES DE AUTORESPUESTAS // ============================================== // Agregar event listeners cuando el DOM esté listo document.addEventListener('DOMContentLoaded', function() { // Event listener para cambio de tipo de trigger const triggerTypeSelect = document.getElementById('autoresponse-trigger-type'); if (triggerTypeSelect) { triggerTypeSelect.addEventListener('change', function() { updateTriggerFields(this.value); }); } // Event listener para cambio de tipo de respuesta const responseTypeSelect = document.getElementById('autoresponse-type'); if (responseTypeSelect) { responseTypeSelect.addEventListener('change', function() { updateResponseTypeFields(this.value); }); } // Event listener para el modal cuando se muestre const autoResponseModal = document.getElementById('createAutoResponseModal'); if (autoResponseModal) { autoResponseModal.addEventListener('shown.bs.modal', function () { // Enfocar el primer campo cuando se abra el modal const firstInput = autoResponseModal.querySelector('input, select, textarea'); if (firstInput) { firstInput.focus(); } }); } }); // Funciones globales para gestión de usuarios // Función para editar usuario window.editUser = function(userId) { console.log('Editando usuario:', userId); // Buscar los datos del usuario actual en la tabla const userRow = document.querySelector(`button[onclick="editUser(${userId})"]`).closest('tr'); const cells = userRow.querySelectorAll('td'); const currentData = { id: userId, phone: cells[1].textContent, name: cells[2].textContent === 'Sin nombre' ? '' : cells[2].textContent, status: cells[3].querySelector('.badge').textContent.toLowerCase() }; showEditUserModal(currentData); }; // Función para eliminar usuario window.deleteUser = function(userId) { console.log('Eliminando usuario:', userId); const userRow = document.querySelector(`button[onclick="deleteUser(${userId})"]`).closest('tr'); const userName = userRow.querySelectorAll('td')[2].textContent; const userPhone = userRow.querySelectorAll('td')[1].textContent; if (confirm(`¿Estás seguro de que quieres eliminar este usuario?\n\nUsuario: ${userName}\nTeléfono: ${userPhone}\n\nEsta acción no se puede deshacer y eliminará:\n• Todos sus mensajes\n• Su historial de conversación\n• Sus datos personales`)) { deleteUserAction(userId); } }; // Mostrar modal de edición de usuario function showEditUserModal(userData) { const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('editUserModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('editUserModal')); modal.show(); } // Guardar edición de usuario window.saveUserEdit = async function() { const userId = document.getElementById('editUserId').value; const userName = document.getElementById('editUserName').value.trim(); const userStatus = document.getElementById('editUserStatus').value; console.log('Guardando usuario:', { userId, userName, userStatus }); const userData = { user_id: userId, name: userName || null, // null si está vacío status: userStatus }; try { const response = await window.whatsappManager.apiCall('update_user.php', { method: 'POST', body: userData }); if (response && response.success) { window.whatsappManager.showSuccess('Usuario actualizado correctamente'); // Cerrar modal const modal = bootstrap.Modal.getInstance(document.getElementById('editUserModal')); if (modal) modal.hide(); // Recargar lista de usuarios setTimeout(() => { window.whatsappManager.loadUsers(); }, 500); } else { window.whatsappManager.showError(`Error actualizando usuario: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error actualizando usuario: ' + error.message); } }; // Acción de eliminar usuario async function deleteUserAction(userId) { try { console.log('Eliminando usuario con ID:', userId); const response = await window.whatsappManager.apiCall('delete_user.php', { method: 'POST', body: { user_id: userId } }); if (response && response.success) { window.whatsappManager.showSuccess('Usuario eliminado correctamente'); // Recargar lista de usuarios setTimeout(() => { window.whatsappManager.loadUsers(); }, 500); } else { window.whatsappManager.showError(`Error eliminando usuario: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error eliminando usuario: ' + error.message); } } // ========================= FUNCIONES MODALES PARA MENÚS ========================= // Modal para editar menú function showEditMenuModal(menuData) { const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('editMenuModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('editMenuModal')); modal.show(); } // Modal para ver opciones del menú function showMenuOptionsModal(menuData) { const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('viewMenuOptionsModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('viewMenuOptionsModal')); modal.show(); } // Guardar edición de menú window.saveMenuEdit = async function() { const menuId = document.getElementById('editMenuId').value; const menuName = document.getElementById('editMenuName').value.trim(); const menuKey = document.getElementById('editMenuKey').value.trim(); const menuDescription = document.getElementById('editMenuDescription').value.trim(); const menuWelcome = document.getElementById('editMenuWelcome').value.trim(); const menuStatus = document.getElementById('editMenuStatus').value; if (!menuName || !menuKey) { window.whatsappManager.showError('Nombre y clave del menú son obligatorios'); return; } console.log('Guardando menú editado:', { menuId, menuName, menuKey, menuStatus }); const menuData = { id: menuId, name: menuName, menu_key: menuKey, description: menuDescription, welcome_message: menuWelcome, status: menuStatus }; try { const response = await window.whatsappManager.apiCall('save_menu.php', { method: 'POST', body: menuData }); if (response && response.success) { window.whatsappManager.showSuccess('Menú actualizado correctamente'); // Cerrar modal const modal = bootstrap.Modal.getInstance(document.getElementById('editMenuModal')); if (modal) modal.hide(); // Recargar lista de menús setTimeout(() => { window.whatsappManager.loadMenus(); }, 500); } else { window.whatsappManager.showError(`Error actualizando menú: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error actualizando menú: ' + error.message); } }; // Funciones auxiliares para opciones window.addMenuOptionInModal = function(menuId) { console.log('Agregando opción al menú:', menuId); const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('addMenuOptionModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('addMenuOptionModal')); modal.show(); }; window.editMenuOption = async function(menuId, optionId) { console.log('Editando opción:', { menuId, optionId }); try { // Obtener datos del menú y sus opciones const response = await window.whatsappManager.apiCall('get_menus.php'); if (response && response.success) { const menu = response.data.find(m => m.id == menuId); if (menu && menu.options) { const option = menu.options.find(o => o.id == optionId); if (option) { showEditMenuOptionModal(menuId, option); } else { window.whatsappManager.showError('Opción no encontrada'); } } else { window.whatsappManager.showError('Menú no encontrado'); } } else { window.whatsappManager.showError('Error cargando datos de la opción'); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error cargando opción: ' + error.message); } }; // Modal para editar opción de menú function showEditMenuOptionModal(menuId, optionData) { const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('editMenuOptionModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('editMenuOptionModal')); modal.show(); } // Función para guardar cambios en opción editada window.saveEditedMenuOption = async function() { const optionId = document.getElementById('editOptionId').value; const menuId = document.getElementById('editOptionMenuId').value; const optionKey = document.getElementById('editOptionKey').value.trim(); const optionText = document.getElementById('editOptionText').value.trim(); const optionAction = document.getElementById('editOptionAction').value; const optionValue = document.getElementById('editOptionValue').value.trim(); if (!optionKey || !optionText) { window.whatsappManager.showError('Clave y texto de la opción son obligatorios'); return; } console.log('Actualizando opción:', { optionId, menuId, optionKey, optionText }); const optionData = { option_id: optionId, menu_id: menuId, option_key: optionKey, option_text: optionText, option_action: optionAction, option_value: optionValue }; try { const response = await window.whatsappManager.apiCall('update_menu_option.php', { method: 'POST', body: optionData }); if (response && response.success) { window.whatsappManager.showSuccess('Opción actualizada correctamente'); // Cerrar modales const editModal = bootstrap.Modal.getInstance(document.getElementById('editMenuOptionModal')); if (editModal) editModal.hide(); const viewModal = bootstrap.Modal.getInstance(document.getElementById('viewMenuOptionsModal')); if (viewModal) viewModal.hide(); // Reabrir modal actualizado setTimeout(async () => { const menusResponse = await window.whatsappManager.apiCall('get_menus.php'); if (menusResponse && menusResponse.success) { const menu = menusResponse.data.find(m => m.id == menuId); if (menu) { showMenuOptionsModal(menu); } } }, 500); } else { window.whatsappManager.showError(`Error actualizando opción: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error actualizando opción: ' + error.message); } }; window.saveNewMenuOption = async function() { const menuId = document.getElementById('addOptionMenuId').value; const optionKey = document.getElementById('addOptionKey').value.trim(); const optionText = document.getElementById('addOptionText').value.trim(); const optionAction = document.getElementById('addOptionAction').value; const optionValue = document.getElementById('addOptionValue').value.trim(); if (!optionKey || !optionText) { window.whatsappManager.showError('Clave y texto de la opción son obligatorios'); return; } console.log('Guardando nueva opción:', { menuId, optionKey, optionText, optionAction, optionValue }); const optionData = { menu_id: menuId, option_key: optionKey, option_text: optionText, option_action: optionAction, option_value: optionValue, is_active: true }; try { const response = await window.whatsappManager.apiCall('save_menu_option.php', { method: 'POST', body: optionData }); if (response && response.success) { window.whatsappManager.showSuccess('Opción agregada correctamente'); // Cerrar modal de agregar opción const addModal = bootstrap.Modal.getInstance(document.getElementById('addMenuOptionModal')); if (addModal) addModal.hide(); // Cerrar modal de ver opciones si está abierto const viewModal = bootstrap.Modal.getInstance(document.getElementById('viewMenuOptionsModal')); if (viewModal) viewModal.hide(); // Reabrir modal de ver opciones actualizado setTimeout(async () => { const menusResponse = await window.whatsappManager.apiCall('get_menus.php'); if (menusResponse && menusResponse.success) { const menu = menusResponse.data.find(m => m.id == menuId); if (menu) { showMenuOptionsModal(menu); } } }, 500); } else { window.whatsappManager.showError(`Error agregando opción: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error agregando opción: ' + error.message); } }; window.deleteMenuOption = async function(menuId, optionId) { if (!confirm('¿Estás seguro de que deseas eliminar esta opción del menú?')) { return; } console.log('Eliminando opción:', { menuId, optionId }); try { const response = await window.whatsappManager.apiCall('delete_menu_option.php', { method: 'POST', body: { menu_id: menuId, option_id: optionId } }); if (response && response.success) { window.whatsappManager.showSuccess('Opción eliminada correctamente'); // Cerrar modal actual const viewModal = bootstrap.Modal.getInstance(document.getElementById('viewMenuOptionsModal')); if (viewModal) viewModal.hide(); // Reabrir modal actualizado setTimeout(async () => { const menusResponse = await window.whatsappManager.apiCall('get_menus.php'); if (menusResponse && menusResponse.success) { const menu = menusResponse.data.find(m => m.id == menuId); if (menu) { showMenuOptionsModal(menu); } } }, 500); } else { window.whatsappManager.showError(`Error eliminando opción: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error eliminando opción: ' + error.message); } }; window.testMenuPreview = async function(menuId) { console.log('Mostrando vista previa del menú:', menuId); try { // Obtener datos del menú const response = await window.whatsappManager.apiCall('get_menus.php'); if (response && response.success) { const menu = response.data.find(m => m.id == menuId); if (menu) { showMenuPreviewModal(menu); } else { window.whatsappManager.showError('Menú no encontrado'); } } else { window.whatsappManager.showError('Error cargando datos del menú'); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error mostrando vista previa: ' + error.message); } }; // Modal de vista previa del menú estilo WhatsApp function showMenuPreviewModal(menuData) { const options = menuData.options || []; const welcomeMsg = menuData.welcome_message || `¡Hola! Bienvenido al ${menuData.title || menuData.name}`; // Construir el mensaje del menú como se vería en WhatsApp let menuMessage = `📋 *${menuData.title || menuData.name}*\n\n`; if (menuData.description) { menuMessage += `${menuData.description}\n\n`; } if (options.length > 0) { menuMessage += '*Opciones disponibles:*\n\n'; options.forEach(option => { const key = option.option_key || option.key || '?'; const text = option.option_text || option.text || 'Sin texto'; menuMessage += `${key}. ${text}\n`; }); menuMessage += '\n💬 *Responde con el número de la opción que deseas*'; } else { menuMessage += '⚠️ _Este menú no tiene opciones configuradas_'; } const modalHtml = ` `; // Remover modal anterior si existe const existingModal = document.getElementById('menuPreviewModal'); if (existingModal) { existingModal.remove(); } document.body.insertAdjacentHTML('beforeend', modalHtml); const modal = new bootstrap.Modal(document.getElementById('menuPreviewModal')); modal.show(); } // Función para copiar el mensaje de vista previa window.copyMenuPreview = function(message) { // Limpiar el mensaje de HTML const cleanMessage = message.replace(/<[^>]*>/g, ''); navigator.clipboard.writeText(cleanMessage).then(() => { window.whatsappManager.showSuccess('Mensaje copiado al portapapeles'); }).catch(err => { window.whatsappManager.showError('Error al copiar: ' + err.message); }); }; // Función para guardar nuevo menú desde el modal de index.php window.saveNewMenu = async function() { const menuName = document.getElementById('menu-name')?.value?.trim(); const menuDescription = document.getElementById('menu-description')?.value?.trim(); if (!menuName) { window.whatsappManager.showError('El nombre del menú es obligatorio'); return; } console.log('Guardando nuevo menú:', { menuName, menuDescription }); // Generar clave del menú basada en el nombre const menuKey = menuName.toLowerCase() .replace(/[^\w\s]/g, '') // Remover caracteres especiales .replace(/\s+/g, '_') // Reemplazar espacios con guiones bajos .substring(0, 20); // Limitar longitud const menuData = { name: menuName, menu_key: menuKey, description: menuDescription, welcome_message: `¡Hola! Bienvenido al ${menuName}. Por favor selecciona una opción:`, status: 'active', options: [] // Sin opciones inicialmente }; try { const response = await window.whatsappManager.apiCall('save_menu.php', { method: 'POST', body: menuData }); if (response && response.success) { window.whatsappManager.showSuccess('Menú creado correctamente'); // Limpiar formulario document.getElementById('menu-name').value = ''; document.getElementById('menu-description').value = ''; // Cerrar modal const modal = bootstrap.Modal.getInstance(document.getElementById('createMenuModal')); if (modal) modal.hide(); // Recargar lista de menús si existe la función setTimeout(() => { if (window.whatsappManager.loadMenus) { window.whatsappManager.loadMenus(); } if (typeof loadMenusTest === 'function') { loadMenusTest(); } }, 500); } else { window.whatsappManager.showError(`Error creando menú: ${response?.error || 'Error desconocido'}`); } } catch (error) { console.error('Error:', error); window.whatsappManager.showError('Error creando menú: ' + error.message); } }; // ========================= FUNCIONES GLOBALES ADICIONALES ========================= // Función para refrescar datos del dashboard window.refreshData = function() { console.log('Refrescando datos del dashboard'); if (window.whatsappManager) { window.whatsappManager.showInfo('Actualizando datos...'); // Recargar todas las secciones if (window.whatsappManager.loadUsers) { window.whatsappManager.loadUsers(); } if (window.whatsappManager.loadMenus) { window.whatsappManager.loadMenus(); } if (window.whatsappManager.loadTemplates) { window.whatsappManager.loadTemplates(); } if (window.whatsappManager.loadAutoResponses) { window.whatsappManager.loadAutoResponses(); } setTimeout(() => { window.whatsappManager.showSuccess('Datos actualizados correctamente'); }, 1000); } }; // Función para exportar usuarios window.exportUsers = function() { console.log('Exportando usuarios...'); if (window.whatsappManager) { window.whatsappManager.showInfo('Preparando exportación de usuarios...'); // Realizar llamada a API de exportación window.whatsappManager.apiCall('export_users.php') .then(response => { if (response && response.success) { // Si la API devuelve datos para descargar if (response.download_url) { window.open(response.download_url, '_blank'); } else if (response.data) { // Crear descarga directa de datos JSON const dataStr = JSON.stringify(response.data, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = `usuarios_export_${new Date().toISOString().split('T')[0]}.json`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } window.whatsappManager.showSuccess('Usuarios exportados correctamente'); } else { window.whatsappManager.showError(`Error exportando usuarios: ${response?.error || 'Error desconocido'}`); } }) .catch(error => { console.error('Error exportando usuarios:', error); window.whatsappManager.showError('Error exportando usuarios: ' + error.message); }); } }; // Función para refrescar logs window.refreshLogs = function() { console.log('Refrescando logs...'); const logsContainer = document.getElementById('logs-container'); if (logsContainer) { logsContainer.innerHTML = '
Cargando logs...
'; // Simular carga de logs (aquí se debería hacer una llamada a la API real) setTimeout(() => { logsContainer.innerHTML = `
[${new Date().toLocaleString()}] INFO: Logs actualizados correctamente
[${new Date().toLocaleString()}] SUCCESS: Sistema funcionando normalmente
`; if (window.whatsappManager) { window.whatsappManager.showSuccess('Logs actualizados'); } }, 1000); } }; // Función para limpiar logs window.clearLogs = async function() { console.log('Limpiando logs...'); if (!confirm('¿Estás seguro de que quieres limpiar todos los logs? Esta acción no se puede deshacer.')) { return; } if (window.whatsappManager) { try { const response = await window.whatsappManager.apiCall('clear_logs.php', { method: 'POST', body: { type: 'all' } }); if (response && response.success) { window.whatsappManager.showSuccess( `Logs limpiados correctamente. ${response.deleted_count} registros eliminados.` ); // Limpiar visualmente el contenedor const logsContainer = document.getElementById('logs-container'); if (logsContainer) { logsContainer.innerHTML = ' No hay logs disponibles'; } // Recargar logs window.whatsappManager.loadLogs(); } else { window.whatsappManager.showError(`Error al limpiar logs: ${response?.error || 'Error desconocido'}`); } } catch (error) { window.whatsappManager.showError('Error al limpiar logs: ' + error.message); } } else { alert('Error: Sistema no inicializado'); } };