From f975844d9d1ca356ee53cb1f7f71dc70eadb7754 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Fri, 3 Jul 2026 17:24:35 -0500 Subject: [PATCH] fix: reacciones y audio en chat turnero - chat_react: guardaba en tabla `messages` en lugar de `conversations` (tabla real del chat) - chat_react: columna era `whatsapp_message_id`; la correcta es `message_id` - chat.php: sendReactionEmoji actualiza la burbuja DOM inmediatamente sin esperar poll - chat_upload_media: mime_content_type() devuelve video/webm en Linux para audio grabado; ahora cualquier mime con "webm" se remapea a audio/ogg antes de determinar mediaType Co-Authored-By: Claude Sonnet 4.6 --- modules/turnero/api/chat_react.php | 2 +- modules/turnero/api/chat_upload_media.php | 17 ++++++++++------- modules/turnero/views/chat.php | 23 ++++++++++++++++++++--- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/modules/turnero/api/chat_react.php b/modules/turnero/api/chat_react.php index cf862cd..fcd4a4a 100644 --- a/modules/turnero/api/chat_react.php +++ b/modules/turnero/api/chat_react.php @@ -34,7 +34,7 @@ try { // Guardar reacción en el mensaje $db->query( - "UPDATE messages SET reaction_emoji = ?, reaction_to_message_id = ? WHERE whatsapp_message_id = ?", + "UPDATE conversations SET reaction_emoji = ?, reaction_to_message_id = ? WHERE message_id = ?", [$emoji, $messageId, $messageId] ); diff --git a/modules/turnero/api/chat_upload_media.php b/modules/turnero/api/chat_upload_media.php index 9bbae0a..dd53e82 100644 --- a/modules/turnero/api/chat_upload_media.php +++ b/modules/turnero/api/chat_upload_media.php @@ -22,9 +22,15 @@ if ($file['error'] !== UPLOAD_ERR_OK) tmErr('Error al subir archivo: código ' . $maxBytes = 64 * 1024 * 1024; // 64 MB if ($file['size'] > $maxBytes) tmErr('El archivo supera el límite de 64 MB'); -$mime = mime_content_type($file['tmp_name']) ?: $file['type']; -$caption = trim($_POST['caption'] ?? ''); -$isVoice = !empty($_POST['is_voice']); +$detectedMime = mime_content_type($file['tmp_name']) ?: $file['type']; +$browserMime = $file['type'] ?: ''; +$caption = trim($_POST['caption'] ?? ''); +$isVoice = !empty($_POST['is_voice']); + +// mime_content_type() returns video/webm for browser-recorded audio (same WebM container). +// WhatsApp rejects webm; map to audio/ogg (same Opus codec, accepted format). +$mime = (str_contains($detectedMime, 'webm') || str_contains($browserMime, 'webm')) + ? 'audio/ogg' : $detectedMime; // Determinar tipo de media if (str_starts_with($mime, 'image/')) $mediaType = 'image'; @@ -42,11 +48,8 @@ try { $wa = new WhatsAppService('turnero'); - // WhatsApp no acepta audio/webm — reenviar como audio/ogg (mismo codec Opus) - $uploadMime = (str_starts_with($mime, 'audio/webm')) ? 'audio/ogg' : $mime; - // Subir a WhatsApp Media API - $uploadResult = $wa->uploadMedia($file['tmp_name'], $uploadMime); + $uploadResult = $wa->uploadMedia($file['tmp_name'], $mime); if (!$uploadResult || !isset($uploadResult['id'])) { tmErr('No se pudo subir el archivo a WhatsApp', 502); } diff --git a/modules/turnero/views/chat.php b/modules/turnero/views/chat.php index 9aa0413..4f25553 100644 --- a/modules/turnero/views/chat.php +++ b/modules/turnero/views/chat.php @@ -931,13 +931,30 @@ function showReactionPicker(e, waId) { async function sendReactionEmoji(emoji) { document.getElementById('reaction-picker').classList.remove('show'); if (!_reactionTarget || !state.activeUserId) return; + const waId = _reactionTarget; try { - await fetch(BASE + API_REACT, { + const res = await fetch(BASE + API_REACT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ user_id: state.activeUserId, message_id: _reactionTarget, emoji }) + body: JSON.stringify({ user_id: state.activeUserId, message_id: waId, emoji }) }); - await pollMessages(); + const json = await res.json(); + if (json.success) { + // Actualizar burbuja en el DOM inmediatamente + const bubble = document.querySelector(`[data-wa-id="${waId}"]`); + if (bubble) { + let reEl = bubble.querySelector('.msg-reaction'); + if (!reEl) { + reEl = document.createElement('div'); + reEl.className = 'msg-reaction'; + bubble.appendChild(reEl); + } + reEl.textContent = emoji; + } + // Actualizar estado en memoria para consistencia + const m = state.messages.find(x => x.message_id === waId); + if (m) m.reaction_emoji = emoji; + } } catch(e) { console.error('reaction:', e); } }