From 18edc5dbfbb699a3d3d533615911d340d1667c8e Mon Sep 17 00:00:00 2001 From: sravan Date: Thu, 20 Aug 2026 22:39:13 +0530 Subject: [PATCH] Moderation UX: Block on DM contact info + visible report-resolved notice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tester feedback: 1. "Block contact not on the contact info." The earlier Block button was only on the group-sender mini-profile, which a 1:1 chat never opens. A DM's info panel is openSharedItems('dm',…) (tap the conversation header). Added a full-width "Block contact / Unblock contact" button there. 2. "Reporter gets no notification on resolution." Delivery was actually working (verified: the reporter receives the 'report-resolved' event over the chat WS), but the client only added a silent bell entry — easy to miss — and a self- resolve (same admin reported + resolved) is intentionally skipped. Made it a visible toast + ping for an online reporter (report-new likewise toasts admins). Co-Authored-By: Claude Opus 4.8 --- server/public/home.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/public/home.html b/server/public/home.html index 416ecdf..bd9dc6e 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -1932,10 +1932,13 @@ async function openSharedItems(kind,id,name){ const r0=rowFor(kind,id); const fav=!!(r0&&r0.favorite); const online=!!(r0&&r0.online); const ov=document.createElement('div'); ov.className='modal-ov'; ov.id='sharedModal'; ov.innerHTML=''; + +mediaRowHTML() + +((kind==='dm' && id!==(ME&&ME.id))?'':'') + +''; document.body.appendChild(ov); ov.onclick=e=>{ if(e.target===ov) ov.remove(); }; ov.querySelector('#shClose').onclick=()=>ov.remove(); + const bb=ov.querySelector('#shBlock'); if(bb) bb.onclick=()=>{ ov.remove(); toggleBlock(id, name); }; // block/unblock this contact from their info panel const sp=ov.querySelector('#shPhoto'); if(sp) sp.onclick=()=>{ const r=rowFor(kind,id)||r0; if(r&&r.avatar) openLightbox(r.avatar); else toast('No profile photo'); }; // #5: click the DP in the info view to preview it const fb=ov.querySelector('#shFav'); if(fb) fb.onclick=async()=>{ const r=rowFor(kind,id); const on=!(r&&r.favorite); if(r) r.favorite=on; fb.classList.toggle('on',on); fb.title=on?'Remove from favourites':'Add to favourites'; try{ await postJSON('/api/favorites',{kind,id,on}); }catch(_){} renderChats(searchVal()); }; wireMediaEntry(ov, kind, id, name); @@ -4754,7 +4757,7 @@ function connectChatWs(){ if(_chatReconnectT){ clearTimeout(_chatReconnectT); _chatReconnectT=null; } chatWs=new WebSocket((location.protocol==='https:'?'wss://':'ws://')+location.host+'/ws'); chatWs.onopen=()=>{ try{ chatWs.send(JSON.stringify({type:'chat-hello'})); }catch(_){} if(_chatConnectedOnce) resyncChat(); _chatConnectedOnce=true; }; - chatWs.onmessage=(e)=>{ let d; try{ d=JSON.parse(e.data); }catch(_){ return; } if(d.type==='chat-message' && d.message) onChatMessage(d.message); else if(d.type==='chat-deleted') onChatDeleted(d); else if(d.type==='chat-hidden') onChatHidden(d); else if(d.type==='chat-pinned') onChatPinned(d); else if(d.type==='chat-edited') onChatEdited(d); else if(d.type==='chat-reaction') onChatReaction(d); else if(d.type==='poll-update' && d.poll) onPollUpdate(d); else if(d.type==='chat-read') onChatRead(d); else if(d.type==='chat-delivered') onChatDelivered(d); else if(d.type==='group-read') onGroupRead(d); else if(d.type==='group-call') onGroupCall(d); else if(d.type==='dm-call') onDmCall(d); else if(d.type==='call-taken') onCallTaken(d); else if(d.type==='call-answered') onCallAnswered(d); else if(d.type==='presence') onPresence(d); else if(d.type==='chat-typing') onTyping(d); else if(d.type==='notif-clear') onNotifClear(d); else if(d.type==='group-update') onGroupUpdate(d); else if(d.type==='call-invite') showCallInvite(d.room, d.byName); else if(d.type==='meeting-invite') showMeetingInvite(d.meeting); else if(d.type==='meeting-reminder') showMeetingReminder(d.meeting); else if(d.type==='meeting-cancelled') showMeetingCancelled(d.meeting); else if(d.type==='group-role') onGroupRole(d); else if(d.type==='report-resolved') addNotif({icon:'flag', text:'An admin reviewed a message you reported.'}); else if(d.type==='report-new') addNotif({icon:'flag', text:'A message was reported — open “Reported messages” to review.'}); }; + chatWs.onmessage=(e)=>{ let d; try{ d=JSON.parse(e.data); }catch(_){ return; } if(d.type==='chat-message' && d.message) onChatMessage(d.message); else if(d.type==='chat-deleted') onChatDeleted(d); else if(d.type==='chat-hidden') onChatHidden(d); else if(d.type==='chat-pinned') onChatPinned(d); else if(d.type==='chat-edited') onChatEdited(d); else if(d.type==='chat-reaction') onChatReaction(d); else if(d.type==='poll-update' && d.poll) onPollUpdate(d); else if(d.type==='chat-read') onChatRead(d); else if(d.type==='chat-delivered') onChatDelivered(d); else if(d.type==='group-read') onGroupRead(d); else if(d.type==='group-call') onGroupCall(d); else if(d.type==='dm-call') onDmCall(d); else if(d.type==='call-taken') onCallTaken(d); else if(d.type==='call-answered') onCallAnswered(d); else if(d.type==='presence') onPresence(d); else if(d.type==='chat-typing') onTyping(d); else if(d.type==='notif-clear') onNotifClear(d); else if(d.type==='group-update') onGroupUpdate(d); else if(d.type==='call-invite') showCallInvite(d.room, d.byName); else if(d.type==='meeting-invite') showMeetingInvite(d.meeting); else if(d.type==='meeting-reminder') showMeetingReminder(d.meeting); else if(d.type==='meeting-cancelled') showMeetingCancelled(d.meeting); else if(d.type==='group-role') onGroupRole(d); else if(d.type==='report-resolved'){ addNotif({icon:'flag', text:'An admin reviewed a message you reported.'}); try{ playPing(); }catch(_){} try{ if(window.BZToast) BZToast.info('An admin reviewed a message you reported.'); else toast('An admin reviewed a message you reported.'); }catch(_){} } else if(d.type==='report-new'){ addNotif({icon:'flag', text:'A message was reported — open “Reported messages” to review.'}); try{ if(window.BZToast) BZToast.info('A message was reported — review it in Reported messages.'); }catch(_){} } }; chatWs.onclose=()=>{ if(_chatReconnectT) clearTimeout(_chatReconnectT); _chatReconnectT=setTimeout(connectChatWs, 3000); }; // auto-reconnect (single pending timer) }catch(_){} }