// static/js/10-reactions.js "use strict"; window.Glow = window.Glow || {}; Glow.reactions = Glow.reactions || { enabled: true, emojis: ["👍", "❤️", "🔥", "😂", "🎉", "👏", "😮", "😢", "👀", "✅", "🚀", "💡"], activeMessage: null }; Glow.submitCustomReaction = async () => { const message = Glow.reactions.activeMessage; const input = Glow.els.reactionCustomInput; if (!message || !input) return; const emoji = input.value.trim(); if (!emoji) return; try { const existing = (message.reactions || []).find(item => item.emoji === emoji); if (existing?.reacted) { await Glow.apiRemoveReaction(message.id, emoji); } else { await Glow.apiAddReaction(message.id, emoji); } const data = await Glow.apiGetMessageReactions(message.id); message.reactions = data.reactions || []; Glow.updateMessageReactionsDom?.(message.id, message.reactions); Glow.renderReactionPopupUsers(message.reactions); input.value = ""; if (Glow.state.activeView === "feed") { Glow.loadFeed?.(); } } catch (error) { Glow.showToast(error.message || "Could not update reaction.", "error"); } }; Glow.openReactionPopup = async message => { Glow.reactions.activeMessage = message; const grid = Glow.els.reactionPopupGrid; const list = Glow.els.reactionPopupList; const customInput = Glow.els.reactionCustomInput; if (!grid || !list) return; grid.replaceChildren(); list.replaceChildren(); for (const emoji of Glow.reactions.emojis) { const button = document.createElement("button"); button.className = "reaction-popup-button"; button.type = "button"; button.textContent = emoji; button.addEventListener("click", async () => { try { const existing = (message.reactions || []).find(item => item.emoji === emoji); if (existing?.reacted) { await Glow.apiRemoveReaction(message.id, emoji); } else { await Glow.apiAddReaction(message.id, emoji); } const data = await Glow.apiGetMessageReactions(message.id); message.reactions = data.reactions || []; Glow.updateMessageReactionsDom?.(message.id, message.reactions); Glow.renderReactionPopupUsers(message.reactions); if (Glow.state.activeView === "feed") { Glow.loadFeed?.(); } } catch (error) { Glow.showToast(error.message || "Could not update reaction.", "error"); } }); grid.append(button); } try { const data = await Glow.apiGetMessageReactions(message.id); message.reactions = data.reactions || []; } catch (_) { message.reactions = []; } if (customInput) { customInput.value = ""; } Glow.renderReactionPopupUsers(message.reactions || []); Glow.els.reactionPopupOverlay?.classList.remove("hidden"); setTimeout(() => { Glow.els.reactionCustomInput?.focus(); }, 0); }; Glow.renderReactionPopupUsers = reactions => { const list = Glow.els.reactionPopupList; if (!list) return; list.replaceChildren(); if (!reactions.length) { const empty = document.createElement("div"); empty.className = "reaction-popup-user"; empty.textContent = "No reactions yet."; list.append(empty); return; } for (const reaction of reactions) { const section = document.createElement("div"); section.className = "reaction-popup-section"; const title = document.createElement("div"); title.className = "reaction-popup-user"; title.innerHTML = `${reaction.emoji} ${reaction.count}`; section.append(title); for (const user of reaction.users || []) { const row = document.createElement("div"); row.className = "reaction-popup-user"; const left = document.createElement("span"); left.textContent = user.username; const right = document.createElement("span"); right.textContent = new Date(user.created_at).toLocaleString(); row.append(left, right); section.append(row); } list.append(section); } }; Glow.closeReactionPopup = () => { Glow.reactions.activeMessage = null; if (Glow.els.reactionCustomInput) { Glow.els.reactionCustomInput.value = ""; } Glow.els.reactionPopupOverlay?.classList.add("hidden"); }; Glow.els.reactionCustomButton?.addEventListener("click", () => { Glow.submitCustomReaction?.(); }); Glow.els.reactionCustomInput?.addEventListener("keydown", event => { if (event.key === "Enter") { event.preventDefault(); Glow.submitCustomReaction?.(); } });