Update conversations.php
This commit is contained in:
+100
-5
@@ -772,6 +772,10 @@
|
||||
this.conversations = [];
|
||||
// Track shown notifications to avoid duplicates from polling
|
||||
this._shownNotifications = new Set();
|
||||
// Track notifications the user dismissed/read locally so they don't reappear
|
||||
this._dismissedNotifications = new Set();
|
||||
// Map of pending ack notifications to retry marking as read (nid => notification)
|
||||
this._pendingAck = new Map();
|
||||
// Message pagination / loading state
|
||||
this.messageLimit = 50;
|
||||
this.loadingMessages = false;
|
||||
@@ -793,6 +797,8 @@
|
||||
this.setupEventListeners();
|
||||
this.setupAutoRefresh();
|
||||
this.setupNotificationPolling();
|
||||
// start background retry loop to ack dismissed notifications on server
|
||||
this.setupNotificationAckRetry && this.setupNotificationAckRetry();
|
||||
}
|
||||
|
||||
setupNotificationPolling() {
|
||||
@@ -820,6 +826,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Try to mark a notification as read on the server. Returns true on success.
|
||||
async ackNotification(notification) {
|
||||
if (!notification || !notification.id) return true; // nothing to ack on server
|
||||
try {
|
||||
const resp = await fetch('api/mark_notification_read.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ id: notification.id })
|
||||
});
|
||||
if (!resp.ok) {
|
||||
console.warn('ackNotification: server responded with', resp.status);
|
||||
return false;
|
||||
}
|
||||
const j = await resp.json().catch(() => null);
|
||||
return !!(j && j.success) || resp.ok;
|
||||
} catch (e) {
|
||||
console.warn('ackNotification failed', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
setupNotificationAckRetry() {
|
||||
if (this._ackInterval) return;
|
||||
this._ackInterval = setInterval(async () => {
|
||||
if (this._pendingAck.size === 0) return;
|
||||
for (const [nid, notification] of Array.from(this._pendingAck.entries())) {
|
||||
try {
|
||||
const ok = await this.ackNotification(notification);
|
||||
if (ok) {
|
||||
this._pendingAck.delete(nid);
|
||||
this._dismissedNotifications.add(nid);
|
||||
console.debug('Ack retry succeeded for', nid);
|
||||
} else {
|
||||
console.debug('Ack retry still failing for', nid);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Ack retry error for', nid, e);
|
||||
}
|
||||
}
|
||||
}, 30000); // every 30s
|
||||
}
|
||||
|
||||
async showNotificationToast(notification) {
|
||||
// Create or reuse container
|
||||
const containerId = 'notification-toasts';
|
||||
@@ -860,7 +908,7 @@
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'nt-actions';
|
||||
|
||||
const removeToast = () => {
|
||||
const removeToastLocal = () => {
|
||||
if (toast.parentNode) toast.remove();
|
||||
if (this._shownNotifications.has(nid)) this._shownNotifications.delete(nid);
|
||||
};
|
||||
@@ -868,6 +916,33 @@
|
||||
const openBtn = document.createElement('button');
|
||||
openBtn.className = notification.cool ? 'btn btn-sm btn-light' : 'btn btn-sm btn-primary';
|
||||
openBtn.textContent = 'Abrir';
|
||||
openBtn.onclick = async () => {
|
||||
// Try ack on server; if fails, schedule retry. Always mark as dismissed locally so it won't reappear.
|
||||
try {
|
||||
const ok = await this.ackNotification(notification);
|
||||
if (ok) {
|
||||
this._dismissedNotifications.add(nid);
|
||||
this._pendingAck.delete(nid);
|
||||
} else {
|
||||
this._pendingAck.set(nid, notification);
|
||||
}
|
||||
} catch (e) { this._pendingAck.set(nid, notification); }
|
||||
removeToastLocal();
|
||||
// navigate to conv if present
|
||||
let data = {};
|
||||
try { data = notification.data ? JSON.parse(notification.data) : {}; } catch(e) {}
|
||||
const userId = data.user_id || notification.user_id;
|
||||
if (userId) {
|
||||
const conv = this.conversations.find(c => c.user_id == userId);
|
||||
if (conv) {
|
||||
this.openConversation(conv.user_id, conv.name, conv.phone_number);
|
||||
} else {
|
||||
this.openConversation(userId, 'Usuario', '');
|
||||
}
|
||||
}
|
||||
};
|
||||
openBtn.className = notification.cool ? 'btn btn-sm btn-light' : 'btn btn-sm btn-primary';
|
||||
openBtn.textContent = 'Abrir';
|
||||
openBtn.onclick = async () => {
|
||||
try {
|
||||
await fetch('api/mark_notification_read.php', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({id: notification.id})});
|
||||
@@ -892,9 +967,15 @@
|
||||
dismiss.title = 'Descartar';
|
||||
dismiss.onclick = async () => {
|
||||
try {
|
||||
await fetch('api/mark_notification_read.php', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({id: notification.id})});
|
||||
} catch(e) { console.warn('mark_notification_read failed', e); }
|
||||
removeToast();
|
||||
const ok = await this.ackNotification(notification);
|
||||
if (ok) {
|
||||
this._dismissedNotifications.add(nid);
|
||||
this._pendingAck.delete(nid);
|
||||
} else {
|
||||
this._pendingAck.set(nid, notification);
|
||||
}
|
||||
} catch(e) { this._pendingAck.set(nid, notification); }
|
||||
removeToastLocal();
|
||||
};
|
||||
|
||||
actions.appendChild(openBtn);
|
||||
@@ -908,7 +989,21 @@
|
||||
let timeout = notification.duration ? Number(notification.duration) : (notification.cool ? 15000 : 8000);
|
||||
if (!isFinite(timeout) || timeout <= 0) timeout = (notification.cool ? 15000 : 8000);
|
||||
timeout = Math.max(timeout, _minToastDuration);
|
||||
setTimeout(removeToast, timeout);
|
||||
setTimeout(() => {
|
||||
// on automatic timeout, attempt ack and schedule retry if needed
|
||||
(async () => {
|
||||
try {
|
||||
const ok = await this.ackNotification(notification);
|
||||
if (ok) {
|
||||
this._dismissedNotifications.add(nid);
|
||||
this._pendingAck.delete(nid);
|
||||
} else {
|
||||
this._pendingAck.set(nid, notification);
|
||||
}
|
||||
} catch (e) { this._pendingAck.set(nid, notification); }
|
||||
removeToastLocal();
|
||||
})();
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
|
||||
Reference in New Issue
Block a user