diff --git a/api/get_conversations.php b/api/get_conversations.php
index 48688df..fd8365f 100644
--- a/api/get_conversations.php
+++ b/api/get_conversations.php
@@ -21,6 +21,8 @@ try {
COALESCE(u.name, u.phone_number) AS name,
u.phone_number,
u.avatar_url,
+ u.bot_enabled,
+ u.on_hold,
lm.message_id AS last_message_id,
lm.content AS last_message,
lm.direction AS direction,
@@ -48,15 +50,17 @@ try {
// Formatear datos para el frontend
$conversations = array_map(function($conv) {
return [
- 'id' => intval($conv['id']),
'user_id' => intval($conv['user_id']),
- 'content' => $conv['content'] ?? '',
+ 'name' => $conv['name'] ?? $conv['phone_number'],
+ 'phone_number' => $conv['phone_number'],
+ 'avatar_url' => $conv['avatar_url'] ?? null,
+ 'last_message' => $conv['last_message'] ?? '',
+ 'last_time' => $conv['last_time'] ?? null,
'direction' => $conv['direction'] ?? 'incoming',
'message_type' => $conv['message_type'] ?? 'text',
- 'status' => $conv['status'] ?? 'sent',
- 'created_at' => $conv['created_at'],
- 'phone_number' => $conv['phone_number'],
- 'name' => $conv['name'] ?? $conv['phone_number']
+ 'unread_count' => intval($conv['unread_count'] ?? 0),
+ 'bot_enabled' => isset($conv['bot_enabled']) ? (bool)$conv['bot_enabled'] : true,
+ 'on_hold' => isset($conv['on_hold']) ? (bool)$conv['on_hold'] : false
];
}, $conversations);
diff --git a/api/get_templates.php b/api/get_templates.php
index 62e0e11..4ba62a3 100644
--- a/api/get_templates.php
+++ b/api/get_templates.php
@@ -27,7 +27,8 @@ try {
$approvedOnly = isset($_GET['approved_only']) && $_GET['approved_only'] == '1';
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : null;
- $sql = "SELECT id, name, template_name, language_code, category, status, body_text, created_at FROM message_templates";
+ // Ajuste: some DBs may not have body_text column; omit it to avoid SQL errors
+ $sql = "SELECT id, name, template_name, language_code, category, status, created_at FROM message_templates";
$params = [];
if ($approvedOnly) {
diff --git a/api/release_hold.php b/api/release_hold.php
new file mode 100644
index 0000000..be7a4c1
--- /dev/null
+++ b/api/release_hold.php
@@ -0,0 +1,29 @@
+ false, 'error' => 'user_id required']);
+ exit;
+ }
+
+ $db = Database::getInstance();
+ $user = $db->fetch('SELECT phone_number FROM users WHERE id = :id', ['id' => $userId]);
+ if (!$user) {
+ http_response_code(404);
+ echo json_encode(['success' => false, 'error' => 'User not found']);
+ exit;
+ }
+
+ $db->update('users', ['on_hold' => 0], 'id = :id', ['id' => $userId]);
+
+ echo json_encode(['success' => true]);
+} catch (Exception $e) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'error' => $e->getMessage()]);
+}
diff --git a/api/set_bot_enabled.php b/api/set_bot_enabled.php
new file mode 100644
index 0000000..1c433ba
--- /dev/null
+++ b/api/set_bot_enabled.php
@@ -0,0 +1,24 @@
+ false, 'error' => 'user_id and enabled required']);
+ exit;
+ }
+
+ $db = Database::getInstance();
+ $db->update('users', ['bot_enabled' => $enabled], 'id = :id', ['id' => $userId]);
+
+ echo json_encode(['success' => true]);
+} catch (Exception $e) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'error' => $e->getMessage()]);
+}
diff --git a/conversations.php b/conversations.php
index 126b0de..4286425 100644
--- a/conversations.php
+++ b/conversations.php
@@ -471,10 +471,16 @@
@@ -728,6 +734,68 @@
});
document.querySelector(`[data-user-id="${userId}"]`)?.classList.add('active');
+ // Actualizar estado del toggle del bot según datos de la conversación
+ const conv = this.conversations.find(c => c.user_id === userId);
+ if (conv) {
+ const btn = document.getElementById('bot-toggle');
+ const holdIndicator = document.getElementById('hold-indicator');
+ const releaseBtn = document.getElementById('release-hold-btn');
+
+ if (holdIndicator) {
+ holdIndicator.style.display = conv.on_hold ? 'inline' : 'none';
+ }
+
+ if (releaseBtn) {
+ releaseBtn.style.display = conv.on_hold ? 'inline-block' : 'none';
+ releaseBtn.onclick = async () => {
+ try {
+ const resp = await fetch('api/release_hold.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ user_id: userId })
+ });
+ const json = await resp.json();
+ if (json && json.success) {
+ conv.on_hold = false;
+ holdIndicator.style.display = 'none';
+ releaseBtn.style.display = 'none';
+ await this.loadConversations();
+ } else {
+ alert('Error al liberar la espera');
+ }
+ } catch (e) {
+ console.error('Error releasing hold', e);
+ }
+ };
+ }
+
+ if (btn) {
+ btn.textContent = conv.bot_enabled ? 'Bot: On' : 'Bot: Off';
+ btn.classList.toggle('btn-outline-danger', !conv.bot_enabled);
+ btn.classList.toggle('btn-outline-secondary', conv.bot_enabled);
+ btn.onclick = async () => {
+ try {
+ const resp = await fetch('api/set_bot_enabled.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ user_id: userId, enabled: conv.bot_enabled ? 0 : 1 })
+ });
+ const json = await resp.json();
+ if (json && json.success) {
+ conv.bot_enabled = !conv.bot_enabled;
+ btn.textContent = conv.bot_enabled ? 'Bot: On' : 'Bot: Off';
+ btn.classList.toggle('btn-outline-danger', !conv.bot_enabled);
+ btn.classList.toggle('btn-outline-secondary', conv.bot_enabled);
+ } else {
+ alert('Error al cambiar el estado del bot');
+ }
+ } catch (e) {
+ console.error('Error toggling bot', e);
+ }
+ };
+ }
+ }
+
// Cargar mensajes
await this.loadMessages(userId);
// Cargar respuestas rápidas
diff --git a/scripts/add_user_bot_enabled.php b/scripts/add_user_bot_enabled.php
new file mode 100644
index 0000000..4aeed83
--- /dev/null
+++ b/scripts/add_user_bot_enabled.php
@@ -0,0 +1,15 @@
+fetch("SHOW COLUMNS FROM users LIKE 'bot_enabled'");
+if ($col) {
+ echo "Column bot_enabled already exists\n";
+ exit(0);
+}
+try {
+ $db->query("ALTER TABLE users ADD COLUMN bot_enabled TINYINT(1) NULL DEFAULT 1 AFTER bot_paused_until");
+ echo "Added column bot_enabled\n";
+} catch (Exception $e) {
+ echo "Failed to add bot_enabled: " . $e->getMessage() . "\n";
+ exit(1);
+}
diff --git a/scripts/describe_message_templates.php b/scripts/describe_message_templates.php
new file mode 100644
index 0000000..3d2bf65
--- /dev/null
+++ b/scripts/describe_message_templates.php
@@ -0,0 +1,9 @@
+fetchAll('DESCRIBE message_templates');
+ foreach ($cols as $c) echo $c['Field'] . ' => ' . $c['Type'] . PHP_EOL;
+} catch (Exception $e) {
+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
+}
diff --git a/scripts/test_bot_enabled.php b/scripts/test_bot_enabled.php
new file mode 100644
index 0000000..8901839
--- /dev/null
+++ b/scripts/test_bot_enabled.php
@@ -0,0 +1,31 @@
+execute('DELETE FROM users WHERE phone_number = :p', ['p' => $phone]);
+$userId = $db->insert('users', ['phone_number' => $phone, 'status' => 'active', 'bot_enabled' => 0, 'welcome_sent_at' => date('Y-m-d H:i:s'), 'created_at' => date('Y-m-d H:i:s')]);
+$user = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
+
+// Clear conversations
+$db->execute('DELETE FROM conversations WHERE user_id = :uid', ['uid' => $userId]);
+
+// Send message while bot disabled
+$bot->processMessage($user, 'hola', 'text');
+$outs = $db->fetchAll("SELECT * FROM conversations WHERE user_id = :uid AND direction = 'outgoing'", ['uid' => $userId]);
+echo "Outgoing after disabled: " . count($outs) . "\n";
+
+// Enable bot
+$db->update('users', ['bot_enabled' => 1], 'id = :id', ['id' => $userId]);
+$user2 = $db->fetch('SELECT * FROM users WHERE id = :id', ['id' => $userId]);
+$bot->processMessage($user2, 'hola', 'text');
+$outs2 = $db->fetchAll("SELECT * FROM conversations WHERE user_id = :uid AND direction = 'outgoing'", ['uid' => $userId]);
+echo "Outgoing after enabled: " . count($outs2) . "\n";
+
+// Cleanup
+$db->execute('DELETE FROM conversations WHERE user_id = :uid', ['uid' => $userId]);
+$db->execute('DELETE FROM users WHERE id = :id', ['id' => $userId]);
+
+echo "Done\n";
\ No newline at end of file
diff --git a/scripts/test_get_templates.php b/scripts/test_get_templates.php
new file mode 100644
index 0000000..d051b33
--- /dev/null
+++ b/scripts/test_get_templates.php
@@ -0,0 +1,13 @@
+getMessage() . "\n";
+ echo $t->getTraceAsString() . "\n";
+}
+$out = ob_get_clean();
+echo $out;
diff --git a/services/BotService.php b/services/BotService.php
index 45aedda..dccc271 100644
--- a/services/BotService.php
+++ b/services/BotService.php
@@ -51,6 +51,11 @@ class BotService {
return;
}
+ // Si el usuario ha desactivado el bot manualmente (toggle), no responder
+ if (isset($user['bot_enabled']) && !$user['bot_enabled']) {
+ return;
+ }
+
// Si el asesor ya respondió después del último mensaje del usuario, frenar al bot
$lastIncoming = $this->db->fetch("SELECT created_at FROM conversations WHERE user_id = :uid AND direction = 'incoming' ORDER BY created_at DESC LIMIT 1", ['uid' => $user['id']]);
$lastOutgoing = $this->db->fetch("SELECT created_at FROM conversations WHERE user_id = :uid AND direction = 'outgoing' ORDER BY created_at DESC LIMIT 1", ['uid' => $user['id']]);