feat(ui): BOTS section in member list

Members API appends server bots (is_bot). Sidebar groups ONLINE / OFFLINE / BOTS.
Bots get green BOT badge, no kick menu or profile. Mentions and DMs skip bots.
This commit is contained in:
2026-07-15 20:37:05 -04:00
parent 038ac1fe8e
commit a277c78e2c
5 changed files with 63 additions and 16 deletions
+7 -5
View File
@@ -326,7 +326,9 @@ export function ChatArea() {
const channels = activeServerId ? channelsByServer[activeServerId] || [] : [];
const activeChannel = channels.find((c) => c.id === activeChannelId);
const members = activeServerId ? membersByServer[activeServerId] || [] : [];
const memberUsernames = useMemo(() => new Set(members.map((m) => m.username)), [members]);
// Humans only for mentions / nickname lookup (bots live in member list separately).
const humanMembers = useMemo(() => members.filter((m) => !m.is_bot), [members]);
const memberUsernames = useMemo(() => new Set(humanMembers.map((m) => m.username)), [humanMembers]);
const markRead = useReadStatesStore((s) => s.markRead);
const readStates = useReadStatesStore((s) => s.states);
@@ -553,7 +555,7 @@ export function ChatArea() {
if (!isDropdownOpen) return;
const itemCount = mq !== null
? members.filter((m) =>
? humanMembers.filter((m) =>
m.username.toLowerCase().includes(mq.toLowerCase()) ||
m.display_name?.toLowerCase().includes(mq.toLowerCase())
).slice(0, 6).length
@@ -574,7 +576,7 @@ export function ChatArea() {
e.stopPropagation();
if (mq !== null) {
const q = mq.toLowerCase();
const filtered = members.filter((m) =>
const filtered = humanMembers.filter((m) =>
m.username.toLowerCase().includes(q) ||
m.display_name?.toLowerCase().includes(q)
).slice(0, 6);
@@ -618,7 +620,7 @@ export function ChatArea() {
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [members, currentUser, activeChannelId, sendMessage, replyToMessage, handleMentionSelect]);
}, [humanMembers, currentUser, activeChannelId, sendMessage, replyToMessage, handleMentionSelect]);
const handleSubmit = useCallback(async () => {
if (mentionQuery !== null || commandQuery !== null) return;
@@ -902,7 +904,7 @@ export function ChatArea() {
)}
<div className="p-3 relative">
{mentionQuery !== null && (
<MentionDropdown query={mentionQuery} members={members} selectedIndex={dropdownIndex} onSelect={handleMentionSelect} />
<MentionDropdown query={mentionQuery} members={humanMembers} selectedIndex={dropdownIndex} onSelect={handleMentionSelect} />
)}
{commandQuery !== null && (
<CommandDropdown