import React, { useMemo } from 'react'; import type { MemberWithUser } from '@opencord/shared'; import { useServerStore } from '../../stores/serverStore'; import { useUIStore } from '../../stores/uiStore'; import { Avatar } from '../ui/Avatar'; const ROLE_ORDER: Record = { owner: 0, admin: 1, member: 2 }; const ROLE_LABELS: Record = { owner: 'OWNER', admin: 'ADMIN', member: 'MEMBER' }; export function MemberSidebar() { const members = useServerStore((s) => s.members); const memberListOpen = useUIStore((s) => s.memberListOpen); const openUserProfile = useUIStore((s) => s.openUserProfile); const { roleGroups, offlineMembers } = useMemo(() => { const online = members.filter(m => m.user.status !== 'offline'); const offline = members.filter(m => m.user.status === 'offline'); // Group online members by role const groups = new Map(); for (const m of online) { const role = m.role || 'member'; if (!groups.has(role)) groups.set(role, []); groups.get(role)!.push(m); } // Sort groups by role hierarchy const sorted = [...groups.entries()].sort( (a, b) => (ROLE_ORDER[a[0]] ?? 99) - (ROLE_ORDER[b[0]] ?? 99) ); return { roleGroups: sorted, offlineMembers: offline }; }, [members]); if (!memberListOpen) return null; const roleColors: Record = { owner: 'text-discord-red', admin: 'text-discord-blurple', member: 'text-discord-text-primary', }; const getMemberColor = (member: MemberWithUser) => { if (member.roles && member.roles.length > 0) { return { color: member.roles[0]!.color }; } return undefined; }; const handleMemberClick = (e: React.MouseEvent, user: any) => { e.stopPropagation(); const rect = e.currentTarget.getBoundingClientRect(); openUserProfile(user, { top: Math.min(rect.top, window.innerHeight - 450), left: rect.left - 316, }); }; const renderMember = (member: MemberWithUser, isOffline = false) => { const displayName = member.user.displayName ?? member.user.username; return (
handleMemberClick(e, member.user)} className="flex items-center gap-3 px-2 py-1.5 rounded-[4px] hover:bg-discord-modifier-hover cursor-pointer group transition-colors" >
{displayName}
{!isOffline && member.user.customStatus && (
{member.user.customStatus}
)}
); }; return (
{/* Role-based groups */} {roleGroups.map(([role, groupMembers]) => (

{ROLE_LABELS[role] ?? role.toUpperCase()} — {groupMembers.length}

{groupMembers.map((m) => renderMember(m))}
))} {/* Offline */} {offlineMembers.length > 0 && (

OFFLINE — {offlineMembers.length}

{offlineMembers.map((m) => renderMember(m, true))}
)}
); }