feat(chat): delivery ticks on the last message in the chat list (#3)
Conversations DTO now returns last_status (sent/delivered/read for DMs; sent for groups) for my last message. The list row shows the matching tick (single/double, blue when read) and a red 'Draft:' indicator when there's unsent text. Live 'sent' on send/receive; upgrades to delivered/read on refresh. e2e 119. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+12
-4
@@ -181,6 +181,8 @@
|
||||
.chat-bottom{display:flex;justify-content:space-between;align-items:center;gap:.5rem;margin-top:.15rem;}
|
||||
.chat-prev{color:var(--muted);font-size:.82rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto;}
|
||||
.chat-row.unread .chat-prev{color:var(--ink);font-weight:500;}
|
||||
.prev-tick{display:inline-flex;vertical-align:middle;color:var(--muted);} .prev-tick.read{color:#2563eb;} .prev-tick svg{width:14px;height:14px;}
|
||||
.draft-lbl{color:#dc2626;font-weight:600;}
|
||||
.chat-row.unread .chat-name{font-weight:700;}
|
||||
.badge{flex:0 0 auto;background:var(--brand);color:var(--blue);font-size:.7rem;font-weight:800;min-width:19px;height:19px;border-radius:99px;padding:0 .35rem;display:grid;place-items:center;}
|
||||
.no-results{padding:2rem 1rem;text-align:center;color:var(--muted);font-size:.85rem;}
|
||||
@@ -1058,11 +1060,17 @@ function rowHTML(it){
|
||||
const active=selected&&selected.kind===it.kind&&selected.id===it.id;
|
||||
const cls=['chat-row']; if(active)cls.push('active'); if(it.unread>0)cls.push('unread');
|
||||
const isG=it.kind==='group';
|
||||
const preview=it.last_body?((it.last_from_me?'You: ':'')+it.last_body):(isG?((it.members||0)+' members'):'No messages yet');
|
||||
const draft=getDraft(it.kind,it.id);
|
||||
let inner;
|
||||
if(draft && !active){ inner='<span class="draft-lbl">Draft:</span> '+pEsc(draft); } // unsent draft (#1)
|
||||
else if(it.callActive){ inner='<span class="call-on">'+ic('phone',12)+' Ongoing call</span>'; }
|
||||
else if(it.last_from_me && it.last_status && it.last_body){ // my last message → tick (#3)
|
||||
inner='<span class="prev-tick '+it.last_status+'">'+ic(it.last_status==='sent'?'check':'checkCheck',13)+'</span> '+pEsc(it.last_body); }
|
||||
else { inner=pEsc(it.last_body?((it.last_from_me?'You: ':'')+it.last_body):(isG?((it.members||0)+' members'):'No messages yet')); }
|
||||
return '<div class="'+cls.join(' ')+'" data-kind="'+it.kind+'" data-id="'+pEsc(it.id)+'">'
|
||||
+ avatarHTML(it,false)
|
||||
+ '<div class="chat-main"><div class="chat-top"><span class="chat-name">'+pEsc(it.name)+'</span><span class="chat-time">'+pEsc(fmtTime(it.last_at))+'</span></div>'
|
||||
+ '<div class="chat-bottom"><span class="chat-prev">'+(it.callActive?'<span class="call-on">'+ic('phone',12)+' Ongoing call</span>':pEsc(preview))+'</span>'+(it.unread>0?'<span class="badge">'+(it.unread>99?'99+':it.unread)+'</span>':'')+'</div></div></div>';
|
||||
+ '<div class="chat-bottom"><span class="chat-prev">'+inner+'</span>'+(it.unread>0?'<span class="badge">'+(it.unread>99?'99+':it.unread)+'</span>':'')+'</div></div></div>';
|
||||
}
|
||||
function renderChats(filter){
|
||||
const q=(filter||'').trim().toLowerCase();
|
||||
@@ -1794,7 +1802,7 @@ async function sendMessage(){
|
||||
clearReply(); pendingAttach=null; hideAttach();
|
||||
{ const ck=selected.kind+':'+selected.id; if(THREAD_CACHE.has(ck)){ const a=THREAD_CACHE.get(ck); if(!a.some(x=>x.id===m.id)) a.push(m); } }
|
||||
const it=rowFor(selected.kind,selected.id);
|
||||
if(it){ it.last_body=m.body||(m.attachment?'📎 '+(m.attachment.name||'Attachment'):''); it.last_at=m.created_at; it.last_from_me=true; it.unread=0; }
|
||||
if(it){ it.last_body=m.body||(m.attachment?'📎 '+(m.attachment.name||'Attachment'):''); it.last_at=m.created_at; it.last_from_me=true; it.last_status='sent'; it.unread=0; }
|
||||
renderChats(searchVal());
|
||||
}catch(e){ inp.value=text; toast(e.message||'Could not send'); }
|
||||
}
|
||||
@@ -2000,7 +2008,7 @@ function onChatMessage(m){
|
||||
else if(kind==='dm' && wasNew) addNotif({icon:'chat', text:'New chat from '+pEsc(m.fromName||'someone'), link:{kind:'dm', id:rid}});
|
||||
}
|
||||
if(it){
|
||||
it.last_body=isSys?m.body:(m.body||(m.attachment?'📎 '+(m.attachment.name||'Attachment'):'')); it.last_at=m.created_at; it.last_from_me=(m.from===ME.id);
|
||||
it.last_body=isSys?m.body:(m.body||(m.attachment?'📎 '+(m.attachment.name||'Attachment'):'')); it.last_at=m.created_at; it.last_from_me=(m.from===ME.id); it.last_status=(m.from===ME.id)?'sent':null;
|
||||
if(m.from!==ME.id && !isOpen && !isSys) it.unread=(it.unread||0)+1;
|
||||
}
|
||||
if(isOpen){
|
||||
|
||||
Reference in New Issue
Block a user