From 7b2e17c7405a9b0ffa1c50655fec81dd6d5f227d Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sat, 24 Jan 2026 00:36:22 -0500 Subject: [PATCH] Update conversations.php --- conversations.php | 165 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 141 insertions(+), 24 deletions(-) diff --git a/conversations.php b/conversations.php index ab2f0d5..08a25e3 100644 --- a/conversations.php +++ b/conversations.php @@ -665,14 +665,13 @@ border-radius: 4px; } - .reaction-badge { - display: inline-block; - background: rgba(0,0,0,0.06); - padding: 2px 6px; - border-radius: 12px; - font-size: 12px; - margin-top: 8px; - } + .reaction-badge { background:#fff; border:1px solid rgba(0,0,0,0.06); display:inline-flex; align-items:center; justify-content:center; padding:4px 6px; border-radius:14px; font-size:13px; margin-top:6px; } + + /* Reaction picker */ + #reaction-picker { position:fixed; display:none; z-index:2000; background:#fff; border-radius:10px; box-shadow:0 6px 24px rgba(0,0,0,0.16); padding:8px; min-width:160px; transition:transform .12s ease, opacity .12s ease; transform:scale(.96); opacity:0; } + #reaction-picker.show { transform:scale(1); opacity:1; } + #reaction-picker .emoji { font-size:18px; padding:6px; cursor:pointer; border-radius:6px; margin:4px; display:inline-flex; align-items:center; justify-content:center; } + #reaction-picker .emoji:hover { background: rgba(0,0,0,0.04); } .conversation-avatar img, .conversation-avatar-img { max-width: 44px; max-height:44px; border-radius:50%; } .conversation-avatar-wrapper { width:48px; display:flex; align-items:center; justify-content:center } @@ -755,7 +754,7 @@ - + @@ -1107,6 +1106,20 @@ this.sendMessage(); }); + // Forward handler: open preview when user chooses to forward an existing message + this.forwardMessage = function(messageId) { + try { + const input = document.getElementById('message-input'); + if (input) { + input.dataset.forwardTo = messageId; + } + this.showReplyPreview(messageId, 'forward'); + // Optionally focus the recipient selection by showing a hint or opening the sidebar + } catch (e) { + console.warn('forwardMessage failed', e); + } + }; + // Edit user name button const editUserBtn = document.getElementById('edit-user-btn'); if (editUserBtn) editUserBtn.addEventListener('click', () => this.promptEditUser()); @@ -1116,19 +1129,77 @@ const input = document.getElementById('message-input'); if (!input) return; input.dataset.replyTo = messageId; - this.showReplyPreview(messageId); + input.dataset.forwardTo = null; + this.showReplyPreview(messageId, 'reply'); input.focus(); }; - // React to message placeholder - this.reactToMessage = function(messageId) { - // simple emoji picker or quick reaction; for now show a prompt - const e = prompt('Reaccionar con emoji (ej: 👍):'); - if (!e) return; - fetch('api/react_message.php', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ message_id: messageId, emoji: e }) }) - .then(r => r.json()).then(j => { if (j && j.success) { this.loadconversations(this.currentUserId, false); } else { alert('Error reaccionando'); } }).catch(err => { console.error(err); alert('Error reaccionando'); }); + // Reaction picker: open a small emoji palette near the click + this.openReactionPicker = function(ev, messageId) { + if (ev && ev.stopPropagation) ev.stopPropagation(); + const picker = document.getElementById('reaction-picker'); + if (!picker) return; + this._pendingReactionMessage = messageId; + + // position picker near event or center + picker.style.display = 'block'; + picker.classList.remove('show'); + // compute position + let left = (window.innerWidth / 2) - (picker.offsetWidth / 2); + let top = (window.innerHeight / 2) - (picker.offsetHeight / 2); + if (ev && ev.clientX) { + left = Math.min(Math.max(8, ev.clientX - 40), window.innerWidth - picker.offsetWidth - 8); + top = Math.min(Math.max(8, ev.clientY - 24), window.innerHeight - picker.offsetHeight - 8); + } + picker.style.left = left + 'px'; + picker.style.top = top + 'px'; + + // small delay to allow CSS transition + setTimeout(() => picker.classList.add('show'), 10); }; + // Hide reaction picker on document click + document.addEventListener('click', (ev) => { + const picker = document.getElementById('reaction-picker'); + if (picker && picker.style.display === 'block' && !picker.contains(ev.target)) { + picker.classList.remove('show'); + setTimeout(()=>{ picker.style.display='none'; },160); + } + }); + + // Attach click handler for emojis (event delegation) + document.addEventListener('click', async (ev) => { + const t = ev.target; + if (t && t.dataset && t.dataset.emoji) { + ev.stopPropagation(); + const emoji = t.dataset.emoji; + const mid = this._pendingReactionMessage; + if (!mid) return; + try { + 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) { + // 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); + } else { + showAlert && showAlert('Error aplicando reacción', 'danger'); + } + } catch (err) { + console.error('Reaction error', err); + showAlert && showAlert('Error aplicando reacción', 'danger'); + } finally { + const picker = document.getElementById('reaction-picker'); + if (picker) { + picker.classList.remove('show'); + setTimeout(()=>{ picker.style.display='none'; },160); + } + this._pendingReactionMessage = null; + } + } + }); + // Message type (text/template) const typeSelect = document.getElementById('message-type'); if (typeSelect) { @@ -2047,14 +2118,15 @@ } return ` -
+
${replyHtml}
${content}
${reactionHtml}
- + +
${time} @@ -2077,6 +2149,32 @@ } } + // Update reaction badge for a single message in the DOM + updateMessageReactionInView(messageId, emoji) { + try { + const container = document.getElementById('chat-conversations'); + if (!container) return; + const el = container.querySelector(`[data-message-id="${messageId}"]`); + if (!el) return; + let badge = el.querySelector('.reaction-badge'); + if (emoji) { + if (badge) { + badge.textContent = emoji; + } else { + const div = document.createElement('div'); + div.className = 'reaction-badge'; + div.textContent = emoji; + const bubble = el.querySelector('.message-bubble'); + if (bubble) bubble.insertBefore(div, bubble.querySelector('.message-actions')); + } + } else { + if (badge && badge.parentNode) badge.parentNode.removeChild(badge); + } + } catch (e) { + console.warn('updateMessageReactionInView failed', e); + } + } + async loadQuickReplies() { const panel = document.getElementById('quick-replies-panel'); if (!panel) return; @@ -2200,15 +2298,16 @@ this.scrollToBottom(); } - showReplyPreview(messageId) { + showReplyPreview(messageId, type = 'reply') { 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); + const msg = this.conversations.find(m => m.message_id == messageId || m.id == messageId); + const text = msg ? (msg.content || msg.message_text || (msg.caption || '[Mensaje]')) : ('Mensaje ' + messageId); if (preview && previewText) { - previewText.textContent = 'En respuesta a: ' + (String(text).replace(/\n/g,' ')).substring(0,140); + if (type === 'reply') previewText.textContent = 'En respuesta a: ' + (String(text).replace(/\n/g,' ')).substring(0,140); + else if (type === 'forward') previewText.textContent = 'Reenviando: ' + (String(text).replace(/\n/g,' ')).substring(0,140); preview.style.display = 'flex'; } if (cancelBtn) { @@ -2224,7 +2323,10 @@ const preview = document.getElementById('reply-preview'); if (preview) preview.style.display = 'none'; const input = document.getElementById('message-input'); - if (input) input.dataset.replyTo = null; + if (input) { + input.dataset.replyTo = null; + input.dataset.forwardTo = null; + } } catch (e) { console.warn('hideReplyPreview failed', e); } @@ -2747,5 +2849,20 @@
+ + + \ No newline at end of file