diff --git a/conversations.php b/conversations.php index 87bdc3c..5984e77 100644 --- a/conversations.php +++ b/conversations.php @@ -474,23 +474,29 @@ .quick-replies-wrapper { position: relative; } .quick-replies-panel { display: none; - background: #fff; - border: 1px solid #e6eef5; - box-shadow: 0 8px 20px rgba(2,6,23,0.06); - padding: 8px; - border-radius: 8px; - max-height: 220px; + background: rgba(255,255,255,0.96); + border: none; + box-shadow: 0 6px 18px rgba(2,6,23,0.04); + padding: 6px; + border-radius: 6px; + max-height: 180px; overflow-y: auto; display: flex; gap: 6px; flex-wrap: wrap; + align-items: center; } - .quick-replies-panel .btn { min-width: 80px; max-width: 180px; font-size: 12px; } + .quick-replies-panel .btn { min-width: 72px; max-width: 200px; font-size: 13px; padding:6px 10px; } #quick-replies-toggle { background: transparent; border-radius: 20px; } @media (max-width: 768px) { .quick-replies-panel { left: 8px; right: 8px; bottom: 56px; min-width: auto; } } + /* Improve audio control visibility and color in supporting browsers */ + .message-media audio { background: #fff; border-radius: 8px; padding: 4px; accent-color: var(--whatsapp-green); } + /* Ensure mic icon contrast */ + #mic-btn i { color: white; font-size: 14px; } + /* Make mic button more visible */ #mic-btn { margin-left: 6px; @@ -711,7 +717,7 @@
- + @@ -880,12 +886,31 @@ // Determine an id to dedupe notifications (prefer server id) const nid = notification && notification.id ? String(notification.id) : ('msg:' + String((notification && notification.message) || '').slice(0,200)); + // If the user already dismissed/acked this notification earlier, skip it + if (this._dismissedNotifications.has(nid)) { + console.debug('Notification previously dismissed, skipping', nid); + return; + } if (this._shownNotifications.has(nid)) { - // already shown + // already shown in this session console.debug('Notification already shown, skipping', nid); return; } + + // mark as shown immediately and try to ack on server so it doesn't reappear this._shownNotifications.add(nid); + try { + const ok = await this.ackNotification(notification); + if (ok) { + this._dismissedNotifications.add(nid); + this._pendingAck.delete(nid); + } else { + // schedule for retry + this._pendingAck.set(nid, notification); + } + } catch (e) { + this._pendingAck.set(nid, notification); + } const toast = document.createElement('div'); // compact by default @@ -1882,7 +1907,8 @@ if (!r.is_active) return; const btn = document.createElement('button'); btn.className = 'btn btn-sm btn-outline-primary'; - const text = (r.response_text || '').replace(/\n/g,' '); + let text = (r.response_text || '').replace(/\n/g,' '); + text = this.stripEmoji(text); btn.textContent = text.length > 30 ? text.substring(0,30) + '...' : text; btn.title = r.response_text; btn.addEventListener('click', () => { @@ -1904,7 +1930,8 @@ resp.data.slice(0,4).forEach(t => { const btn = document.createElement('button'); btn.className = 'btn btn-sm btn-outline-secondary'; - const text = (t.body_text || t.name || t.template_name || '').replace(/\n/g,' '); + let text = (t.body_text || t.name || t.template_name || '').replace(/\n/g,' '); + text = this.stripEmoji(text); btn.textContent = text.length > 30 ? text.substring(0,30) + '...' : text; btn.title = t.name; btn.addEventListener('click', () => { this.sendTemplateQuick(t.template_name, t.language_code || 'es'); panel.style.display='none'; document.getElementById('quick-replies-toggle').setAttribute('aria-expanded','false'); }); @@ -2232,6 +2259,16 @@ const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; } + + // Remove common emoji/pictograph characters for minimal quick reply labels + stripEmoji(text) { + if (!text) return ''; + try { + return String(text).replace(/[\u{1F300}-\u{1FAFF}\u{1F600}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, '').trim(); + } catch (e) { + return String(text); + } + } async sendMediaMessage() { if (!this.selectedFile || !this.currentUserId) return;