From f8874c86efa94152cdf17989f4455d83a93bf97a Mon Sep 17 00:00:00 2001 From: rajchales-monito Date: Thu, 23 Jul 2026 23:23:32 +0200 Subject: [PATCH] Add unread chat indicator --- public/admin.css | 33 +++++++++++++++++++++++++++++++++ public/admin.js | 13 ++++++++++--- server.js | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/public/admin.css b/public/admin.css index 4a0146a..d33eacb 100644 --- a/public/admin.css +++ b/public/admin.css @@ -95,6 +95,8 @@ label { display: grid; gap: 6px; color: var(--muted); font-size: 13px; } } .conversation-item.active { background: #eaf6f1; } .conversation-item.fresh { animation: pulse 1.2s ease-in-out 4; } +.conversation-item.unread { background: #fffdf4; } +.conversation-item.unread.active { background: #eaf6f1; } .conversation-open { min-width: 0; text-align: left; @@ -108,6 +110,31 @@ label { display: grid; gap: 6px; color: var(--muted); font-size: 13px; } } .conversation-open:hover { filter: none; background: #f3f7f4; } .row { display: flex; justify-content: space-between; gap: 10px; align-items: center; } +.visitor-row { min-width: 0; } +.visitor-name-wrap { + min-width: 0; + display: inline-flex; + align-items: center; + gap: 7px; +} +.visitor-name-wrap strong { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.unread-dot { + width: 9px; + height: 9px; + flex: 0 0 auto; + border-radius: 50%; + background: #c9d4ce; +} +.conversation-item.unread .unread-dot { + background: #ff3b30; + box-shadow: 0 0 0 0 rgb(255 59 48 / 55%); + animation: unreadPulse 1.25s ease-out infinite; +} .status { font-size: 12px; color: white; @@ -492,6 +519,12 @@ pre { 50% { background: #dff7eb; } } +@keyframes unreadPulse { + 0% { box-shadow: 0 0 0 0 rgb(255 59 48 / 55%); } + 70% { box-shadow: 0 0 0 8px rgb(255 59 48 / 0%); } + 100% { box-shadow: 0 0 0 0 rgb(255 59 48 / 0%); } +} + @media (max-width: 820px) { body { overflow: auto; } .app { height: auto; min-height: 100vh; grid-template-columns: 1fr; overflow: visible; } diff --git a/public/admin.js b/public/admin.js index 438ee88..4e229d0 100644 --- a/public/admin.js +++ b/public/admin.js @@ -199,6 +199,8 @@ async function openConversation(id) { state.activeId = id; const data = await api(`/api/admin/conversations/${id}`); state.active = data; + const index = state.conversations.findIndex((item) => item.id === id); + if (index >= 0) state.conversations[index] = { ...state.conversations[index], ...data.conversation }; renderConversations(); renderActive(); } @@ -246,10 +248,15 @@ function renderSite() { function renderConversations() { const conversations = filteredConversations(); $("#conversationList").innerHTML = conversations.length ? conversations.map((item) => ` -
+