Update conversations.php
This commit is contained in:
+100
-73
@@ -2143,6 +2143,8 @@
|
|||||||
// no reemplazar ni limpiar la conversación actual; solo indicar que no hay más.
|
// no reemplazar ni limpiar la conversación actual; solo indicar que no hay más.
|
||||||
if (!initial && Array.isArray(messages) && messages.length === 0) {
|
if (!initial && Array.isArray(messages) && messages.length === 0) {
|
||||||
try { if (topLoader && topLoader.parentNode) topLoader.remove(); } catch(e) {}
|
try { if (topLoader && topLoader.parentNode) topLoader.remove(); } catch(e) {}
|
||||||
|
// Asegurar que no quedemos en estado de loading
|
||||||
|
this.loadingMessages = false;
|
||||||
this.hasMoreMessages = false;
|
this.hasMoreMessages = false;
|
||||||
// show hint and preserve current view
|
// show hint and preserve current view
|
||||||
this.showNoMoreMessagesHint();
|
this.showNoMoreMessagesHint();
|
||||||
@@ -2150,30 +2152,45 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si es carga inicial y el servidor devolvió vacío, pero ya teníamos mensajes, preservarlos.
|
||||||
|
if (initial && Array.isArray(messages) && messages.length === 0 && Array.isArray(this.conversations) && this.conversations.length > 0) {
|
||||||
|
try { if (topLoader && topLoader.parentNode) topLoader.remove(); } catch(e) {}
|
||||||
|
this.loadingMessages = false;
|
||||||
|
if (typeof showAlert === 'function') showAlert('No se pudieron recargar mensajes; manteniendo historial actual', 'warning');
|
||||||
|
console.warn('Initial load returned empty but existing view contains messages - preserving current conversation');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (initial) {
|
if (initial) {
|
||||||
|
// Reemplazar sólo en carga inicial válida (puede estar vacía si no hay nada en DB)
|
||||||
this.conversations = messages;
|
this.conversations = messages;
|
||||||
} else {
|
} else {
|
||||||
// Evitar introducir duplicados que ya existen en la vista actual
|
// Prepend sólo si hay mensajes nuevos
|
||||||
try {
|
if (Array.isArray(messages) && messages.length > 0) {
|
||||||
const existingKeys = new Set(this.conversations.map(m => this.messageKey(m)));
|
// Evitar introducir duplicados que ya existen en la vista actual
|
||||||
const beforeLen = messages.length;
|
try {
|
||||||
messages = messages.filter(m => {
|
const existingKeys = new Set((this.conversations || []).map(m => this.messageKey(m)));
|
||||||
const k = this.messageKey(m);
|
const beforeLen = messages.length;
|
||||||
const seen = existingKeys.has(k);
|
messages = messages.filter(m => {
|
||||||
if (!seen) existingKeys.add(k); // mark as seen to avoid duplicates within the batch
|
const k = this.messageKey(m);
|
||||||
else {
|
const seen = existingKeys.has(k);
|
||||||
if (console && console.debug) console.debug('Skipping duplicate message from server (already in view)', m && (m.id || m.message_id), m && m.created_at);
|
if (!seen) existingKeys.add(k); // mark as seen to avoid duplicates within the batch
|
||||||
|
else {
|
||||||
|
if (console && console.debug) console.debug('Skipping duplicate message from server (already in view)', m && (m.id || m.message_id), m && m.created_at);
|
||||||
|
}
|
||||||
|
return !seen;
|
||||||
|
});
|
||||||
|
const dropped = beforeLen - messages.length;
|
||||||
|
if (dropped > 0) {
|
||||||
|
if (console && console.info) console.info(`Omitted ${dropped} messages because they already exist in view`);
|
||||||
}
|
}
|
||||||
return !seen;
|
} catch (e) { console.warn('duplicate filtering failed', e); }
|
||||||
});
|
|
||||||
const dropped = beforeLen - messages.length;
|
|
||||||
if (dropped > 0) {
|
|
||||||
if (console && console.info) console.info(`Omitted ${dropped} messages because they already exist in view`);
|
|
||||||
}
|
|
||||||
} catch (e) { console.warn('duplicate filtering failed', e); }
|
|
||||||
|
|
||||||
// Prepend mensajes antiguos
|
// Prepend mensajes antiguos
|
||||||
this.conversations = messages.concat(this.conversations);
|
this.conversations = messages.concat(this.conversations || []);
|
||||||
|
} else {
|
||||||
|
// No hay mensajes nuevos para añadir; nada que hacer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizar paginación (earliest timestamp y id)
|
// Actualizar paginación (earliest timestamp y id)
|
||||||
@@ -2182,68 +2199,72 @@
|
|||||||
|
|
||||||
// Improved dedupe: pick the most "readable" message when duplicates exist
|
// Improved dedupe: pick the most "readable" message when duplicates exist
|
||||||
try {
|
try {
|
||||||
const best = new Map(); // key => { index, score }
|
if (!this.conversations || this.conversations.length === 0) {
|
||||||
const toRemove = [];
|
// Nothing to dedupe
|
||||||
|
} else {
|
||||||
|
const best = new Map(); // key => { index, score }
|
||||||
|
const toRemove = [];
|
||||||
|
|
||||||
const scoreFor = (m) => {
|
const scoreFor = (m) => {
|
||||||
let s = 0;
|
let s = 0;
|
||||||
if (!m) return s;
|
if (!m) return s;
|
||||||
// Prefer explicit media type messages
|
// Prefer explicit media type messages
|
||||||
if (m.message_type && m.message_type !== 'text') s += 50;
|
if (m.message_type && m.message_type !== 'text') s += 50;
|
||||||
// Prefer messages with thumbnails or local files
|
// Prefer messages with thumbnails or local files
|
||||||
if (m.local_thumb || m.local_file || m.media_url_external || m.media_url) s += 30;
|
if (m.local_thumb || m.local_file || m.media_url_external || m.media_url) s += 30;
|
||||||
// Prefer human text content (avoid raw JSON blobs)
|
// Prefer human text content (avoid raw JSON blobs)
|
||||||
if (m.content) {
|
if (m.content) {
|
||||||
const c = String(m.content).trim();
|
const c = String(m.content).trim();
|
||||||
const looksJson = c.startsWith('{') && c.endsWith('}');
|
const looksJson = c.startsWith('{') && c.endsWith('}');
|
||||||
if (looksJson) {
|
if (looksJson) {
|
||||||
s -= 20; // penalize raw JSON-looking content
|
s -= 20; // penalize raw JSON-looking content
|
||||||
} else {
|
} else {
|
||||||
s += 10;
|
s += 10;
|
||||||
if (c.length < 200) s += 5;
|
if (c.length < 200) s += 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (m.message_id) s += 3;
|
||||||
if (m.message_id) s += 3;
|
if (m.reply_to_message_id) s += 2;
|
||||||
if (m.reply_to_message_id) s += 2;
|
return s;
|
||||||
return s;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = this.conversations.length - 1; i >= 0; i--) {
|
for (let i = this.conversations.length - 1; i >= 0; i--) {
|
||||||
const m = this.conversations[i];
|
const m = this.conversations[i];
|
||||||
if (!m) continue;
|
if (!m) continue;
|
||||||
const mid = m.message_id || m.id || null;
|
const mid = m.message_id || m.id || null;
|
||||||
let key = null;
|
let key = null;
|
||||||
if (mid) key = String(mid);
|
if (mid) key = String(mid);
|
||||||
else {
|
else {
|
||||||
const partMedia = m.media_url || m.media_url_external || m.local_file || m.local_thumb || m.content || '';
|
const partMedia = m.media_url || m.media_url_external || m.local_file || m.local_thumb || m.content || '';
|
||||||
const ts = m.created_at ? String(Math.floor(new Date(m.created_at).getTime() / 1000)) : '';
|
const ts = m.created_at ? String(Math.floor(new Date(m.created_at).getTime() / 1000)) : '';
|
||||||
key = `${m.direction||'?'}|${m.message_type||m.media_type||'text'}|${partMedia}|${ts}`;
|
key = `${m.direction||'?'}|${m.message_type||m.media_type||'text'}|${partMedia}|${ts}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const s = scoreFor(m);
|
const s = scoreFor(m);
|
||||||
if (!best.has(key)) {
|
if (!best.has(key)) {
|
||||||
best.set(key, { index: i, score: s });
|
|
||||||
} else {
|
|
||||||
const prev = best.get(key);
|
|
||||||
if (s > prev.score) {
|
|
||||||
// keep current, remove previous
|
|
||||||
toRemove.push(prev.index);
|
|
||||||
best.set(key, { index: i, score: s });
|
best.set(key, { index: i, score: s });
|
||||||
} else {
|
} else {
|
||||||
// remove current
|
const prev = best.get(key);
|
||||||
toRemove.push(i);
|
if (s > prev.score) {
|
||||||
|
// keep current, remove previous
|
||||||
|
toRemove.push(prev.index);
|
||||||
|
best.set(key, { index: i, score: s });
|
||||||
|
} else {
|
||||||
|
// remove current
|
||||||
|
toRemove.push(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (toRemove.length) {
|
if (toRemove.length) {
|
||||||
// dedupe unique indices
|
// dedupe unique indices
|
||||||
const uniq = Array.from(new Set(toRemove)).sort((a,b) => a - b);
|
const uniq = Array.from(new Set(toRemove)).sort((a,b) => a - b);
|
||||||
// remove from highest index down
|
// remove from highest index down
|
||||||
for (let j = uniq.length - 1; j >= 0; j--) {
|
for (let j = uniq.length - 1; j >= 0; j--) {
|
||||||
const idx = uniq[j];
|
const idx = uniq[j];
|
||||||
const removed = this.conversations.splice(idx, 1)[0];
|
const removed = this.conversations.splice(idx, 1)[0];
|
||||||
console.debug('Dedupe removed message at index', idx, 'removed=', removed && (removed.message_id || removed.id || removed.content || removed.media_url) );
|
console.debug('Dedupe removed message at index', idx, 'removed=', removed && (removed.message_id || removed.id || removed.content || removed.media_url) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -2263,7 +2284,13 @@
|
|||||||
// Renderizar incrementalmente para evitar parpadeos y preservar reproducción de media
|
// Renderizar incrementalmente para evitar parpadeos y preservar reproducción de media
|
||||||
// Si cargamos paginación (initial=false), pasar la cantidad de mensajes recién obtenidos para insertarlos al inicio
|
// Si cargamos paginación (initial=false), pasar la cantidad de mensajes recién obtenidos para insertarlos al inicio
|
||||||
const newlyFetched = (!initial && Array.isArray(messages)) ? messages.length : 0;
|
const newlyFetched = (!initial && Array.isArray(messages)) ? messages.length : 0;
|
||||||
this.renderMessagesIncremental(initial, newlyFetched);
|
if (this.conversations && this.conversations.length > 0) {
|
||||||
|
this.renderMessagesIncremental(initial, newlyFetched);
|
||||||
|
} else if (initial) {
|
||||||
|
// Si es carga inicial y no tenemos mensajes, mostrar una vista vacía
|
||||||
|
const container = document.getElementById('chat-conversations');
|
||||||
|
if (container) container.innerHTML = `<div class="no-conversation"><i class="fab fa-whatsapp"></i><h4>No hay mensajes</h4><p>Envía un mensaje para iniciar la conversación.</p></div>`;
|
||||||
|
}
|
||||||
|
|
||||||
// Replace media rendering uses window.renderMediaMessage inside element creation/update
|
// Replace media rendering uses window.renderMediaMessage inside element creation/update
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user