feat(chat): self-chat 'You' — note-to-self (#4)
Pinned 'You' chat at the top of the list (always available); messaging yourself works (to===me), with no self push/echo notification and a 'Message yourself' header. Self is filtered from the normal contacts and shows no status dot. build batch24. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+16
-7
@@ -733,7 +733,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="/icons.js?v=4"></script>
|
<script src="/icons.js?v=4"></script>
|
||||||
<script>window.__BUILD='2026-07-02-batch23';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);</script>
|
<script>window.__BUILD='2026-07-02-batch24';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);</script>
|
||||||
<div class="loading" id="loading">Loading…</div>
|
<div class="loading" id="loading">Loading…</div>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
@@ -1048,7 +1048,8 @@ function statusLabel(it){ const c=statusCls(it); return c==='incall'?'In a call'
|
|||||||
function avatarHTML(it, big){
|
function avatarHTML(it, big){
|
||||||
const isG=it.kind==='group';
|
const isG=it.kind==='group';
|
||||||
const sz=big?'width:38px;height:38px;flex:0 0 38px;':'';
|
const sz=big?'width:38px;height:38px;flex:0 0 38px;':'';
|
||||||
const corner=isG?(it.members?'<span class="mcount">'+(it.members>99?'99+':it.members)+'</span>':'')
|
const corner=it.self?''
|
||||||
|
:isG?(it.members?'<span class="mcount">'+(it.members>99?'99+':it.members)+'</span>':'')
|
||||||
:'<span class="dot '+statusCls(it)+'"></span>';
|
:'<span class="dot '+statusCls(it)+'"></span>';
|
||||||
const inner=isG?ic('users',big?20:18):pEsc(initials(it.name));
|
const inner=isG?ic('users',big?20:18):pEsc(initials(it.name));
|
||||||
// Photo overlay (BizGaze profile picture, or an uploaded group image). If it fails to
|
// Photo overlay (BizGaze profile picture, or an uploaded group image). If it fails to
|
||||||
@@ -1077,9 +1078,13 @@ function renderChats(filter){
|
|||||||
const rows=ROWS.filter(it=>!q||it.name.toLowerCase().includes(q)||(it.last_body||'').toLowerCase().includes(q))
|
const rows=ROWS.filter(it=>!q||it.name.toLowerCase().includes(q)||(it.last_body||'').toLowerCase().includes(q))
|
||||||
.sort((a,b)=>(b.last_at-a.last_at)||a.name.localeCompare(b.name));
|
.sort((a,b)=>(b.last_at-a.last_at)||a.name.localeCompare(b.name));
|
||||||
let html;
|
let html;
|
||||||
if(!q){ // group favourites at the top when not searching
|
if(!q){ // "You" pinned at top, then favourites, then the rest
|
||||||
const favs=rows.filter(r=>r.favorite), rest=rows.filter(r=>!r.favorite);
|
const self=rows.find(r=>r.self), others=rows.filter(r=>!r.self);
|
||||||
html = rows.length ? ((favs.length?'<div class="side-sec">'+ic('star',12)+' Favourites</div>'+favs.map(rowHTML).join('')+(rest.length?'<div class="side-sec">All chats</div>':''):'')+rest.map(rowHTML).join('')) : '<div class="no-results">No conversations yet.</div>';
|
const favs=others.filter(r=>r.favorite), rest=others.filter(r=>!r.favorite);
|
||||||
|
let h = self ? rowHTML(self) : '';
|
||||||
|
if(favs.length){ h+='<div class="side-sec">'+ic('star',12)+' Favourites</div>'+favs.map(rowHTML).join(''); if(rest.length) h+='<div class="side-sec">All chats</div>'; }
|
||||||
|
h+=rest.map(rowHTML).join('');
|
||||||
|
html = (self||others.length) ? h : '<div class="no-results">No conversations yet.</div>';
|
||||||
} else {
|
} else {
|
||||||
html = rows.length ? rows.map(rowHTML).join('') : '<div class="no-results">No chats match “'+pEsc(filter)+'”.</div>';
|
html = rows.length ? rows.map(rowHTML).join('') : '<div class="no-results">No chats match “'+pEsc(filter)+'”.</div>';
|
||||||
}
|
}
|
||||||
@@ -1137,12 +1142,16 @@ function setDesktopBadge(count){
|
|||||||
async function loadSidebar(){
|
async function loadSidebar(){
|
||||||
let convos=[], contacts=[];
|
let convos=[], contacts=[];
|
||||||
try{ [convos, contacts]=await Promise.all([ fetch('/api/messages/conversations').then(r=>r.json()), fetch('/api/messages/contacts').then(r=>r.json()) ]); }catch(_){}
|
try{ [convos, contacts]=await Promise.all([ fetch('/api/messages/conversations').then(r=>r.json()), fetch('/api/messages/contacts').then(r=>r.json()) ]); }catch(_){}
|
||||||
CONTACTS=Array.isArray(contacts)?contacts:[];
|
CONTACTS=(Array.isArray(contacts)?contacts:[]).filter(c=>c.id!==(ME&&ME.id)); // self isn't a normal contact (#4)
|
||||||
const items=Array.isArray(convos)?convos.slice():[];
|
const items=Array.isArray(convos)?convos.slice():[];
|
||||||
const dmIds=new Set(items.filter(i=>i.kind==='dm').map(i=>i.id));
|
const dmIds=new Set(items.filter(i=>i.kind==='dm').map(i=>i.id));
|
||||||
for(const c of CONTACTS){ if(!dmIds.has(c.id)) items.push({ kind:'dm', id:c.id, name:c.name, online:!!c.online, last_body:'', last_at:0, last_from_me:false, unread:0 }); }
|
for(const c of CONTACTS){ if(!dmIds.has(c.id)) items.push({ kind:'dm', id:c.id, name:c.name, online:!!c.online, last_body:'', last_at:0, last_from_me:false, unread:0 }); }
|
||||||
const onlineById={}; CONTACTS.forEach(c=>onlineById[c.id]=!!c.online);
|
const onlineById={}; CONTACTS.forEach(c=>onlineById[c.id]=!!c.online);
|
||||||
items.forEach(it=>{ if(it.kind==='dm') it.online=!!onlineById[it.id]; });
|
items.forEach(it=>{ if(it.kind==='dm') it.online=!!onlineById[it.id]; });
|
||||||
|
// Always-available "You" chat (note to self), pinned to the top (#4).
|
||||||
|
const selfRow=items.find(i=>i.kind==='dm' && i.id===(ME&&ME.id));
|
||||||
|
if(selfRow){ selfRow.self=true; selfRow.name='You'; selfRow.avatar=ME.avatarUrl||selfRow.avatar||null; }
|
||||||
|
else if(ME&&ME.id){ items.push({ kind:'dm', id:ME.id, name:'You', self:true, avatar:ME.avatarUrl||null, online:false, last_body:'', last_at:0, last_from_me:false, unread:0 }); }
|
||||||
ROWS=items;
|
ROWS=items;
|
||||||
renderChats(searchVal());
|
renderChats(searchVal());
|
||||||
updateRailUnread();
|
updateRailUnread();
|
||||||
@@ -1163,7 +1172,7 @@ function welcomeHTML(){
|
|||||||
function wireWelcome(){ document.querySelectorAll('#chatPanel .wcard').forEach(card=>{ card.onclick=()=>switchTab(card.dataset.go); }); }
|
function wireWelcome(){ document.querySelectorAll('#chatPanel .wcard').forEach(card=>{ card.onclick=()=>switchTab(card.dataset.go); }); }
|
||||||
function convoShellHTML(it){
|
function convoShellHTML(it){
|
||||||
const isG=it.kind==='group';
|
const isG=it.kind==='group';
|
||||||
const sub=isG?((it.members||0)+' members'):statusLabel(it);
|
const sub=it.self?'Message yourself':(isG?((it.members||0)+' members'):statusLabel(it));
|
||||||
return '<div class="convo">'
|
return '<div class="convo">'
|
||||||
+ '<div class="convo-head">'
|
+ '<div class="convo-head">'
|
||||||
+ '<button class="convo-back" id="convoBack" title="Back (Esc)" aria-label="Back">'+ic('arrowLeft',18)+'</button>'
|
+ '<button class="convo-back" id="convoBack" title="Back (Esc)" aria-label="Back">'+ic('arrowLeft',18)+'</button>'
|
||||||
|
|||||||
+3
-3
@@ -1234,9 +1234,9 @@ route('POST', '/api/messages', async (req, res) => {
|
|||||||
const dto = buildMsgDTO(R.messages.byId(id), namesFor(u.team_id), u.id);
|
const dto = buildMsgDTO(R.messages.byId(id), namesFor(u.team_id), u.id);
|
||||||
const push = { type: 'chat-message', message: { ...dto, fromName: u.name || u.email } };
|
const push = { type: 'chat-message', message: { ...dto, fromName: u.name || u.email } };
|
||||||
try { CHAT.pushToUser(to, push); } catch (_) {}
|
try { CHAT.pushToUser(to, push); } catch (_) {}
|
||||||
try { CHAT.pushToUser(u.id, push); } catch (_) {} // sync the sender's other devices
|
if (to !== u.id) try { CHAT.pushToUser(u.id, push); } catch (_) {} // sync the sender's other devices (skip for self-notes)
|
||||||
// Background/closed-tab push to the recipient (opens the DM with this sender).
|
// Background/closed-tab push to the recipient (opens the DM). Not for a note-to-self.
|
||||||
PUSH.sendToUser(to, { title: (u.name || u.email), body: (text ? (text.length > 80 ? text.slice(0, 80) + '…' : text) : '📎 Attachment'), kind: 'dm', id: u.id, tag: 'dm:' + u.id });
|
if (to !== u.id) PUSH.sendToUser(to, { title: (u.name || u.email), body: (text ? (text.length > 80 ? text.slice(0, 80) + '…' : text) : '📎 Attachment'), kind: 'dm', id: u.id, tag: 'dm:' + u.id });
|
||||||
json(res, 200, dto);
|
json(res, 200, dto);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user