Update conversations.php

This commit is contained in:
Lizandro Guarnizo
2026-01-23 23:24:27 -05:00
parent 8a30a08f67
commit baa776ba7a
+104 -17
View File
@@ -428,6 +428,33 @@
.notification-toast .nt-actions { margin-left: auto; display:flex; gap:6px; }
.notification-toast .btn { font-size: 12px; padding: 4px 8px; }
/* UI improvements for chat area */
.quick-replies .btn {
border-radius: 20px;
padding: 6px 10px;
font-size: 12px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chat-conversations {
background-repeat: repeat;
background-color: #e9efe9;
padding-bottom: 20px; /* space for reply preview and input */
}
.message-bubble { transition: transform 0.12s ease, box-shadow 0.12s ease; }
.message-bubble:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(0,0,0,0.06); }
#reply-preview { box-shadow: 0 1px 2px rgba(0,0,0,0.04); }
#reply-preview button { border: none; color: #888; }
#reply-preview button:hover { color: #333; }
.message.incoming .message-bubble::before,
.message.outgoing .message-bubble::after { content: ''; }
.notification-toast.urgent { border-left: 4px solid #e74c3c; }
.message-template {
@@ -593,6 +620,11 @@
<input type="text" id="media-caption" class="form-control mt-2" placeholder="Agregar un comentario (opcional)" maxlength="1024">
</div>
<div id="reply-preview" class="reply-preview" style="display:none; align-items:center; justify-content:space-between;">
<div style="flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;" id="reply-preview-text">En respuesta a: (selecciona un mensaje)</div>
<button class="btn btn-sm btn-link" id="cancel-reply-btn" title="Cancelar respuesta"></button>
</div>
<div class="chat-input">
<input type="file" id="file-input" accept="image/*,video/*,audio/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx" style="display: none;">
<button class="btn" id="attach-btn" title="Adjuntar archivo">
@@ -776,8 +808,8 @@
const input = document.getElementById('message-input');
if (!input) return;
input.dataset.replyTo = messageId;
this.showReplyPreview(messageId);
input.focus();
// Optionally show a small UI indicator (not implemented)
};
// React to message placeholder
@@ -1193,6 +1225,8 @@
console.warn('holdIndicator missing when releasing hold');
}
releaseBtn.style.display = 'none';
// show bot toggle again
if (btn) btn.style.display = 'inline-block';
await this.loadConversations();
} else {
alert('Error al liberar la espera');
@@ -1235,6 +1269,8 @@
releaseBtn.style.display = 'inline-block';
// show finish button
if (finishBtn) finishBtn.style.display = 'inline-block';
// hide bot toggle while in service
if (btn) btn.style.display = 'none';
await this.loadConversations();
} else {
alert('Error al marcar como atendida');
@@ -1269,6 +1305,8 @@
finishBtn.style.display = 'none';
releaseBtn.style.display = 'none';
attendBtn.style.display = 'none';
// show bot toggle again
if (btn) btn.style.display = 'inline-block';
await this.loadConversations();
} else {
alert('Error al finalizar la atención');
@@ -1285,6 +1323,14 @@
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);
// Hide bot toggle when advisor requested or in service or on hold (we expect attend/finish actions)
if (conv.advisor_requested || conv.in_service || conv.on_hold) {
btn.style.display = 'none';
} else {
btn.style.display = 'inline-block';
}
btn.onclick = async () => {
try {
const resp = await fetch('api/set_bot_enabled.php', {
@@ -1643,32 +1689,42 @@
}
async sendTemplateQuick(templateName, language) {
if (!this.currentUserId) return;
const conv = this.conversations.find(c => c.user_id === this.currentUserId);
const phone = conv ? (conv.phone_number || conv.phone || conv.user_phone) : (document.getElementById('chat-phone') ? document.getElementById('chat-phone').textContent.trim() : null);
// delegate to unified sendTemplateMessage helper
await this.sendTemplateMessage(templateName, language, null);
}
if (!phone) {
alert('No se pudo determinar el número de teléfono del destinatario.');
console.error('sendTemplateQuick: missing phone for user', this.currentUserId, conv);
async sendTemplateMessage(templateName, language = 'es', parameters = null) {
if (!this.currentUserId) return;
const recipient = this.getConversationPhone(this.currentUserId);
if (!recipient) {
alert('No se pudo determinar el número de destino para la plantilla');
console.error('sendTemplateMessage: missing recipient for user', this.currentUserId);
return;
}
try {
const resp = await fetch('api/send_message.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ recipient: phone, type: 'template', template_name: templateName, language })
});
const result = await resp.json();
if (result.success) {
const requestBody = {
recipient: recipient,
type: 'template',
template: templateName,
language: language || 'es',
parameters: parameters || []
};
const resp = await this.apiCall('send_message.php', { body: requestBody });
// hide reply preview if any
this.hideReplyPreview();
if (resp && resp.success) {
this.addMessageToView(`Plantilla: ${templateName}`, 'outgoing');
showAlert && showAlert('Mensaje de plantilla enviado correctamente', 'success');
await this.loadconversations(this.currentUserId, false);
await this.loadConversations();
} else {
alert('Error al enviar plantilla: ' + (result.error || JSON.stringify(result)));
throw new Error(resp && resp.error ? resp.error : 'Error enviando plantilla');
}
} catch (e) {
console.error('Error sending template quick', e);
alert('Error al enviar plantilla');
console.error('Error sending template message', e);
alert('Error enviando plantilla: ' + (e.message || e));
}
}
@@ -1699,6 +1755,36 @@
this.scrollToBottom();
}
showReplyPreview(messageId) {
try {
const preview = document.getElementById('reply-preview');
const previewText = document.getElementById('reply-preview-text');
const cancelBtn = document.getElementById('cancel-reply-btn');
const msg = this.conversations.find(m => m.message_id == messageId);
const text = msg ? (msg.content || msg.message_text || '[Mensaje]') : ('Mensaje ' + messageId);
if (preview && previewText) {
previewText.textContent = 'En respuesta a: ' + (String(text).replace(/\n/g,' ')).substring(0,140);
preview.style.display = 'flex';
}
if (cancelBtn) {
cancelBtn.onclick = () => this.hideReplyPreview();
}
} catch (e) {
console.warn('showReplyPreview failed', e);
}
}
hideReplyPreview() {
try {
const preview = document.getElementById('reply-preview');
if (preview) preview.style.display = 'none';
const input = document.getElementById('message-input');
if (input) input.dataset.replyTo = null;
} catch (e) {
console.warn('hideReplyPreview failed', e);
}
}
async sendMessage() {
const input = document.getElementById('message-input');
const message = input.value.trim();
@@ -1753,6 +1839,7 @@
const result = await this.apiCall('send_message.php', { body: requestBody });
// Clear reply data attribute
input.dataset.replyTo = null;
this.hideReplyPreview();
if (result && result.success) {
input.value = '';