This commit is contained in:
Lizandro Guarnizo
2026-01-25 21:08:09 -05:00
parent efd711b1dc
commit eca0c919a4
3 changed files with 69 additions and 4 deletions
+33 -1
View File
@@ -10,9 +10,41 @@ $input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$message_id = $input['message_id'] ?? null;
$emoji = $input['emoji'] ?? null;
// Normalize emoji aliases and decode any HTML entities
function normalize_emoji($s) {
if (!$s) return $s;
$orig = $s;
$s = html_entity_decode($s, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$s_trim = trim(mb_strtolower($s, 'UTF-8'));
$map = [
'corazon' => '❤️', 'heart' => '❤️', '<3' => '❤️',
'like' => '👍', 'thumbsup' => '👍', 'thumbs_up' => '👍',
'laugh' => '😂', 'risa' => '😂', 'joy' => '😂',
'wow' => '😮', 'surprised' => '😮',
'sad' => '😢', 'triste' => '😢',
'clap' => '👏', 'applause' => '👏',
'party' => '🎉', 'celebrate' => '🎉',
'fire' => '🔥', 'pray' => '🙏'
];
$key = preg_replace('/[^a-z0-9_\-]/u', '', $s_trim);
if (isset($map[$key])) return $map[$key];
// If it already contains an emoji, extract the first emoji char
if (preg_match('/[\x{1F300}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}]/u', $s, $m)) {
return $m[0];
}
return trim($orig);
}
$rawEmoji = $input['emoji'] ?? null;
$emoji = normalize_emoji($emoji);
error_log('react_message: received raw=' . ($rawEmoji ?? 'NULL') . ' normalized=' . ($emoji ?? 'NULL') . ' message_id=' . ($message_id ?? 'NULL'));
if (!$message_id || !$emoji) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Parámetros faltantes: message_id, emoji']);
echo json_encode(['success' => false, 'error' => 'Parámetros faltantes: message_id, emoji (después de normalizar)']);
exit;
}
+4 -2
View File
@@ -1247,10 +1247,12 @@
const resp = await fetch('api/react_message.php', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ message_id: mid, emoji: emoji }) });
const j = await resp.json();
if (j && j.success) {
// Prefer the server-side normalized emoji when available (handles alias -> emoji mapping)
const serverEmoji = (j.updated && j.updated.reaction_emoji) ? j.updated.reaction_emoji : emoji;
// update local model and UI
const m = this.conversations.find(x => x.message_id == mid || x.id == mid);
if (m) m.reaction_emoji = emoji;
this.updateMessageReactionInView && this.updateMessageReactionInView(mid, emoji);
if (m) m.reaction_emoji = serverEmoji;
this.updateMessageReactionInView && this.updateMessageReactionInView(mid, serverEmoji);
} else {
showAlert && showAlert('Error aplicando reacción', 'danger');
}
+32 -1
View File
@@ -602,7 +602,38 @@ class WhatsAppService
$messageData['reaction_emoji'] = $data['reaction']['emoji'] ?? null;
}
$this->db->insert('conversations', $messageData);
// Special handling for reactions: update the referenced message instead of creating a separate outgoing message
if ($data['type'] === 'reaction' && !empty($messageData['reaction_to_message_id'])) {
try {
$targetMid = $messageData['reaction_to_message_id'];
$update = [
'reaction_emoji' => $messageData['reaction_emoji'],
'reaction_to_message_id' => $targetMid,
'updated_at' => date('Y-m-d H:i:s')
];
$this->db->update('conversations', $update, 'message_id = :mid OR id = :mid', ['mid' => $targetMid]);
// Optionally create a small notification for the operator UI
try {
$this->db->insert('notifications', [
'user_id' => $user['id'],
'type' => 'reaction',
'message' => 'Reacción: ' . ($messageData['reaction_emoji'] ?? ''),
'data' => json_encode(['message_id' => $targetMid, 'emoji' => $messageData['reaction_emoji'] ?? '']),
'is_read' => 0,
'created_at' => date('Y-m-d H:i:s')
]);
} catch (Exception $ne) {
error_log('Failed to create reaction notification: ' . $ne->getMessage());
}
} catch (Exception $e) {
// Fallback: if update fails, insert as outgoing message
error_log('Failed to apply reaction via update, inserting outgoing as fallback: ' . $e->getMessage());
$this->db->insert('conversations', $messageData);
}
} else {
$this->db->insert('conversations', $messageData);
}
// Solo limpiar advisor_requested si el mensaje fue enviado por un asesor (operator)
try {