From 1abe5bba2d9276494c5f541b9f7a44a7b6ea50ca Mon Sep 17 00:00:00 2001 From: lizandrogd <77708265+lizandrogd@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:11:44 -0500 Subject: [PATCH] up --- api/delete_menu_option.php | 78 +++ api/delete_user.php | 148 +++-- api/save_menu.php | 57 +- api/save_menu_option.php | 126 ++++ api/update_menu_option.php | 118 ++++ api/update_user.php | 115 ++++ assets/js/app_simple.js | 1232 +++++++++++++++++++++++++++++++++++- classes/Database.php | 10 +- 8 files changed, 1811 insertions(+), 73 deletions(-) create mode 100644 api/delete_menu_option.php create mode 100644 api/save_menu_option.php create mode 100644 api/update_menu_option.php create mode 100644 api/update_user.php diff --git a/api/delete_menu_option.php b/api/delete_menu_option.php new file mode 100644 index 0000000..d43cd9c --- /dev/null +++ b/api/delete_menu_option.php @@ -0,0 +1,78 @@ +fetch("SELECT * FROM menu_options WHERE id = :id", ['id' => $optionId]); + + if (!$option) { + throw new Exception('Opción no encontrada'); + } + + // Si se proporcionó menu_id, verificar que coincida + if ($menuId !== null && $option['menu_id'] != $menuId) { + throw new Exception('La opción no pertenece al menú especificado'); + } + + // Eliminar la opción + $result = $db->execute("DELETE FROM menu_options WHERE id = :id", ['id' => $optionId]); + + if ($result > 0) { + // Registrar en log + error_log("Opción de menú eliminada: ID={$optionId}, Menú={$option['menu_id']}"); + + echo json_encode([ + 'success' => true, + 'message' => 'Opción eliminada correctamente', + 'option_id' => $optionId, + 'menu_id' => $option['menu_id'] + ]); + } else { + throw new Exception('No se pudo eliminar la opción'); + } + +} catch (Exception $e) { + error_log("Error in delete_menu_option.php: " . $e->getMessage()); + http_response_code(400); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage() + ]); +} +?> \ No newline at end of file diff --git a/api/delete_user.php b/api/delete_user.php index 66757a1..772cca1 100644 --- a/api/delete_user.php +++ b/api/delete_user.php @@ -1,80 +1,130 @@ fetch("SELECT id, name, phone_number FROM users WHERE id = :user_id", ['user_id' => $user_id]); + + if (!$user_data) { + throw new Exception('Usuario no encontrado'); } - // Simular un pequeño delay para realismo - usleep(500000); // 0.5 segundos + // Iniciar transacción + $conn = $db->getConnection(); + $conn->beginTransaction(); - // Respuesta exitosa - $response = [ - 'success' => true, - 'message' => 'Usuario eliminado correctamente', - 'data' => [ - 'deleted_user_id' => $user_id, - 'timestamp' => date('Y-m-d H:i:s') - ], - 'debug' => $debug ? [ - 'timestamp' => date('Y-m-d H:i:s'), - 'simulated' => true, - 'user_id' => $user_id - ] : null - ]; + try { + // Eliminar mensajes relacionados usando PDO + $stmt = $conn->prepare("DELETE FROM messages WHERE user_id = ?"); + $stmt->bindValue(1, $user_id, PDO::PARAM_INT); + $stmt->execute(); + $deleted_messages = $stmt->rowCount(); - echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + // Eliminar el usuario + $stmt = $conn->prepare("DELETE FROM users WHERE id = ?"); + $stmt->bindValue(1, $user_id, PDO::PARAM_INT); + $stmt->execute(); + + if ($stmt->rowCount() === 0) { + throw new Exception('No se pudo eliminar el usuario'); + } + + // Confirmar transacción + $conn->commit(); + + // Respuesta exitosa + echo json_encode([ + 'success' => true, + 'message' => 'Usuario eliminado correctamente', + 'data' => [ + 'deleted_user_id' => $user_id, + 'deleted_user_name' => $user_data['name'], + 'deleted_user_phone' => $user_data['phone_number'], + 'deleted_messages_count' => $deleted_messages, + 'timestamp' => date('Y-m-d H:i:s') + ] + ]); + + } catch (Exception $e) { + // Revertir transacción + $conn->rollback(); + throw $e; + } } catch (Exception $e) { - $error_response = [ - 'success' => false, + http_response_code(400); + echo json_encode([ + 'success' => false, 'error' => $e->getMessage(), - 'debug' => $debug ? [ - 'timestamp' => date('Y-m-d H:i:s'), - 'file' => __FILE__, + 'debug_info' => [ + 'file' => basename(__FILE__), 'line' => $e->getLine(), 'trace' => $e->getTraceAsString() - ] : null - ]; - + ] + ]); +} catch (Error $e) { http_response_code(500); - echo json_encode($error_response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + echo json_encode([ + 'success' => false, + 'error' => 'Error interno del servidor: ' . $e->getMessage(), + 'debug_info' => [ + 'file' => basename(__FILE__), + 'line' => $e->getLine() + ] + ]); } ?> \ No newline at end of file diff --git a/api/save_menu.php b/api/save_menu.php index 1d23004..b060754 100644 --- a/api/save_menu.php +++ b/api/save_menu.php @@ -35,7 +35,19 @@ try { $db->beginTransaction(); try { -// Verificar estructura de tabla antes de insertar + // Verificar si es actualización o creación + $isUpdate = isset($input['id']) && !empty($input['id']); + $menuId = $isUpdate ? intval($input['id']) : null; + + if ($isUpdate) { + // Verificar que el menú existe + $existingMenu = $db->fetch("SELECT id FROM menus WHERE id = ?", [$menuId]); + if (!$existingMenu) { + throw new Exception('Menú no encontrado para actualizar'); + } + } + + // Verificar estructura de tabla antes de insertar/actualizar $tableStructure = $db->fetchAll("DESCRIBE menus"); $availableColumns = array_column($tableStructure, 'Field'); @@ -44,13 +56,14 @@ try { // Adaptar datos a la estructura real de la tabla $menuData = []; - // Campos básicos que deberían existir + // La tabla usa 'name' para la clave del menú if (in_array('name', $availableColumns)) { - $menuData['name'] = $input['menu_key'] ?? $input['name']; // Usar menu_key como name + $menuData['name'] = $input['menu_key'] ?? $input['name'] ?? 'menu_' . time(); } + // La tabla usa 'title' para el nombre visible del menú if (in_array('title', $availableColumns)) { - $menuData['title'] = $input['name'] ?? 'Nuevo Menú'; // Usar name como title + $menuData['title'] = $input['name'] ?? $input['title'] ?? 'Nuevo Menú'; } if (in_array('description', $availableColumns)) { @@ -66,28 +79,37 @@ try { } if (in_array('is_active', $availableColumns)) { - $menuData['is_active'] = ($input['status'] === 'active') ? 1 : 0; + // Mapear status a is_active: 'active' -> 1, cualquier otra cosa -> 0 + $menuData['is_active'] = (($input['status'] ?? 'active') === 'active') ? 1 : 0; } - if (in_array('order_position', $availableColumns)) { - // Obtener próxima posición + if (in_array('order_position', $availableColumns) && !$isUpdate) { + // Solo establecer order_position para menús nuevos $maxOrder = $db->fetch("SELECT COALESCE(MAX(order_position), 0) as max_order FROM menus"); $menuData['order_position'] = ($maxOrder['max_order'] ?? 0) + 1; } - if (in_array('created_at', $availableColumns)) { + if (in_array('created_at', $availableColumns) && !$isUpdate) { $menuData['created_at'] = date('Y-m-d H:i:s'); } if (in_array('updated_at', $availableColumns)) { $menuData['updated_at'] = date('Y-m-d H:i:s'); } - + + // Crear o actualizar menú + if ($isUpdate) { + $result = $db->update('menus', $menuData, 'id = :menu_id', ['menu_id' => $menuId]); + if (!$result || $result->rowCount() === 0) { + throw new Exception('No se pudo actualizar el menú'); + } + } else { $menuId = $db->insert('menus', $menuData); if (!$menuId) { throw new Exception('Error insertando menú'); } + } // Procesar opciones si las hay $optionsCount = 0; @@ -113,19 +135,22 @@ try { } } - // Actualizar contador de opciones - $db->execute("UPDATE menus SET options_count = :count WHERE id = :id", [ - 'count' => $optionsCount, - 'id' => $menuId - ]); + // Actualizar contador de opciones solo si la columna existe + if (in_array('options_count', $availableColumns)) { + $db->execute("UPDATE menus SET options_count = :count WHERE id = :id", [ + 'count' => $optionsCount, + 'id' => $menuId + ]); + } $db->commit(); echo json_encode([ 'success' => true, - 'message' => 'Menú guardado correctamente', + 'message' => $isUpdate ? 'Menú actualizado correctamente' : 'Menú guardado correctamente', 'menu_id' => $menuId, - 'options_created' => $optionsCount + 'options_created' => $optionsCount, + 'action' => $isUpdate ? 'updated' : 'created' ]); } catch (Exception $e) { diff --git a/api/save_menu_option.php b/api/save_menu_option.php new file mode 100644 index 0000000..f97caa7 --- /dev/null +++ b/api/save_menu_option.php @@ -0,0 +1,126 @@ +fetch("SELECT id FROM menus WHERE id = :id", ['id' => $input['menu_id']]); + if (!$menu) { + throw new Exception('Menú no encontrado'); + } + + // Verificar estructura de tabla menu_options + $tableStructure = $db->fetchAll("DESCRIBE menu_options"); + $availableColumns = array_column($tableStructure, 'Field'); + + // Preparar datos según estructura de tabla + $optionData = []; + + if (in_array('menu_id', $availableColumns)) { + $optionData['menu_id'] = (int)$input['menu_id']; + } + + if (in_array('option_number', $availableColumns)) { + $optionData['option_number'] = (int)$input['option_key']; + } + + if (in_array('option_key', $availableColumns)) { + $optionData['option_key'] = $input['option_key']; + } + + if (in_array('text', $availableColumns)) { + $optionData['text'] = $input['option_text']; + } + + if (in_array('option_text', $availableColumns)) { + $optionData['option_text'] = $input['option_text']; + } + + if (in_array('action_type', $availableColumns)) { + $optionData['action_type'] = $input['option_action'] ?? 'message'; + } + + if (in_array('option_action', $availableColumns)) { + $optionData['option_action'] = $input['option_action'] ?? 'message'; + } + + if (in_array('action_value', $availableColumns)) { + $optionData['action_value'] = $input['option_value'] ?? ''; + } + + if (in_array('option_value', $availableColumns)) { + $optionData['option_value'] = $input['option_value'] ?? ''; + } + + if (in_array('is_active', $availableColumns)) { + $optionData['is_active'] = ($input['is_active'] ?? true) ? 1 : 0; + } + + if (in_array('order_index', $availableColumns)) { + // Obtener el siguiente índice de orden + $maxOrder = $db->fetch( + "SELECT COALESCE(MAX(order_index), 0) as max_order FROM menu_options WHERE menu_id = :menu_id", + ['menu_id' => $input['menu_id']] + ); + $optionData['order_index'] = ($maxOrder['max_order'] ?? 0) + 1; + } + + if (in_array('created_at', $availableColumns)) { + $optionData['created_at'] = date('Y-m-d H:i:s'); + } + + // Insertar la opción + $optionId = $db->insert('menu_options', $optionData); + + if (!$optionId) { + throw new Exception('Error insertando opción de menú'); + } + + echo json_encode([ + 'success' => true, + 'message' => 'Opción de menú guardada correctamente', + 'option_id' => $optionId, + 'menu_id' => $input['menu_id'] + ]); + +} catch (Exception $e) { + error_log("Error in save_menu_option.php: " . $e->getMessage()); + http_response_code(400); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage() + ]); +} +?> \ No newline at end of file diff --git a/api/update_menu_option.php b/api/update_menu_option.php new file mode 100644 index 0000000..5f4f9f4 --- /dev/null +++ b/api/update_menu_option.php @@ -0,0 +1,118 @@ +fetch("SELECT * FROM menu_options WHERE id = :id", ['id' => $optionId]); + + if (!$option) { + throw new Exception('Opción no encontrada'); + } + + // Si se proporcionó menu_id, verificar que coincida + if ($menuId !== null && $option['menu_id'] != $menuId) { + throw new Exception('La opción no pertenece al menú especificado'); + } + + // Verificar estructura de tabla menu_options + $tableStructure = $db->fetchAll("DESCRIBE menu_options"); + $availableColumns = array_column($tableStructure, 'Field'); + + // Preparar datos según estructura de tabla + $updateData = []; + + if (in_array('option_number', $availableColumns)) { + $updateData['option_number'] = (int)$input['option_key']; + } + + if (in_array('option_key', $availableColumns)) { + $updateData['option_key'] = $input['option_key']; + } + + if (in_array('text', $availableColumns)) { + $updateData['text'] = $input['option_text']; + } + + if (in_array('option_text', $availableColumns)) { + $updateData['option_text'] = $input['option_text']; + } + + if (in_array('action_type', $availableColumns)) { + $updateData['action_type'] = $input['option_action'] ?? 'message'; + } + + if (in_array('option_action', $availableColumns)) { + $updateData['option_action'] = $input['option_action'] ?? 'message'; + } + + if (in_array('action_value', $availableColumns)) { + $updateData['action_value'] = $input['option_value'] ?? ''; + } + + if (in_array('option_value', $availableColumns)) { + $updateData['option_value'] = $input['option_value'] ?? ''; + } + + if (in_array('updated_at', $availableColumns)) { + $updateData['updated_at'] = date('Y-m-d H:i:s'); + } + + // Actualizar la opción + $result = $db->update('menu_options', $updateData, 'id = :option_id', ['option_id' => $optionId]); + + if ($result && $result->rowCount() >= 0) { + echo json_encode([ + 'success' => true, + 'message' => 'Opción de menú actualizada correctamente', + 'option_id' => $optionId, + 'menu_id' => $option['menu_id'] + ]); + } else { + throw new Exception('No se pudo actualizar la opción'); + } + +} catch (Exception $e) { + error_log("Error in update_menu_option.php: " . $e->getMessage()); + http_response_code(400); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage() + ]); +} +?> \ No newline at end of file diff --git a/api/update_user.php b/api/update_user.php new file mode 100644 index 0000000..f01ebb7 --- /dev/null +++ b/api/update_user.php @@ -0,0 +1,115 @@ +fetch("SELECT id FROM users WHERE id = :user_id", ['user_id' => $user_id]); + + if (!$checkUser) { + throw new Exception('Usuario no encontrado'); + } + + // Actualizar usuario usando el método de la clase Database + $updateData = [ + 'name' => $name, + 'status' => $status + ]; + + $result = $db->update('users', $updateData, 'id = :user_id', ['user_id' => $user_id]); + + if ($result === false) { + throw new Exception('No se pudo actualizar el usuario'); + } + + // Respuesta exitosa + echo json_encode([ + 'success' => true, + 'message' => 'Usuario actualizado correctamente', + 'user_id' => $user_id, + 'data' => [ + 'name' => $name, + 'status' => $status + ] + ]); + +} catch (Exception $e) { + http_response_code(400); + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage(), + 'debug_info' => [ + 'file' => basename(__FILE__), + 'line' => $e->getLine(), + 'trace' => $e->getTraceAsString() + ] + ]); +} catch (Error $e) { + http_response_code(500); + echo json_encode([ + 'success' => false, + 'error' => 'Error interno del servidor: ' . $e->getMessage(), + 'debug_info' => [ + 'file' => basename(__FILE__), + 'line' => $e->getLine() + ] + ]); +} +?> \ No newline at end of file diff --git a/assets/js/app_simple.js b/assets/js/app_simple.js index 3c37a57..88c650e 100644 --- a/assets/js/app_simple.js +++ b/assets/js/app_simple.js @@ -708,6 +708,16 @@ class SimpleWhatsAppManager { 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'); @@ -2107,10 +2117,28 @@ window.app = { }; // Funciones globales para gestión de menús -window.editMenu = function (menuId) { +window.editMenu = async function (menuId) { console.log('Editando menú:', menuId); - // TODO: Implementar edición de menús - alert(`Editar menú ${menuId} - Función en desarrollo`); + + 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) { @@ -2122,10 +2150,28 @@ window.deleteMenu = function (menuId) { } }; -window.viewMenuOptions = function (menuId) { +window.viewMenuOptions = async function (menuId) { console.log('Viendo opciones del menú:', menuId); - // TODO: Implementar visualización de opciones del menú - alert(`Ver opciones del menú ${menuId} - Función en desarrollo`); + + 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ú @@ -2598,4 +2644,1176 @@ document.addEventListener('DOMContentLoaded', function() { } }); } -}); \ No newline at end of file +}); + +// 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 = function() { + console.log('Limpiando logs...'); + + if (confirm('¿Estás seguro de que quieres limpiar todos los logs? Esta acción no se puede deshacer.')) { + const logsContainer = document.getElementById('logs-container'); + if (logsContainer) { + logsContainer.innerHTML = '
Logs limpiados
'; + + if (window.whatsappManager) { + window.whatsappManager.showInfo('Logs limpiados correctamente'); + } + } + } +}; \ No newline at end of file diff --git a/classes/Database.php b/classes/Database.php index 02e2f17..40f9ba5 100644 --- a/classes/Database.php +++ b/classes/Database.php @@ -110,7 +110,15 @@ class Database { } public function rollback() { - return $this->pdo->rollback(); + try { + return $this->pdo->rollback(); + } catch (PDOException $e) { + // Si no hay transacción activa, simplemente ignorar + if ($e->getCode() !== 'HY000' || strpos($e->getMessage(), 'no active transaction') === false) { + throw $e; + } + return false; + } } public function execute($sql, $params = []) {