import { useEffect, useState } from "react"; import { useServerStore } from "../stores/server.ts"; import { useAuthStore } from "../stores/auth.ts"; import { useMemberStore, type Member } from "../stores/member.ts"; import { usePresenceStore } from "../stores/presence.ts"; import type { UserStatus } from "../stores/auth.ts"; import { MemberContextMenu } from "./MemberContextMenu.tsx"; import { useConversationStore } from "../stores/conversation.ts"; function statusIcon(status: UserStatus): string { switch (status) { case "online": return "\u25cf"; case "idle": return "\u25d0"; case "dnd": return "\u26d5"; default: return "\u25cb"; } } function statusColor(status: UserStatus): string { switch (status) { case "online": return "text-gb-green"; case "idle": return "text-gb-yellow"; case "dnd": return "text-gb-red"; default: return "text-gb-gray"; } } function usernameColor(status: UserStatus): string { switch (status) { case "online": return "text-gb-aqua"; case "idle": return "text-gb-yellow"; case "dnd": return "text-gb-red"; default: return "text-gb-fg-f"; } } function MemberRow({ member }: { member: Member }) { const presence = usePresenceStore((s) => s.presences[member.id]); const status = presence?.status ?? member.status; const [menuOpen, setMenuOpen] = useState(false); const currentUser = useAuthStore((s) => s.user); const userPerms = useServerStore((s) => s.userPermissions); const activeServerId = useServerStore((s) => s.activeServerId); const createConversation = useConversationStore((s) => s.createConversation); const canKick = userPerms?.kick_members ?? false; const canBan = userPerms?.ban_members ?? false; const canMute = userPerms?.mute_members ?? false; const isSelf = currentUser?.id === member.id; return (
{menuOpen && !isSelf && activeServerId && ( { createConversation([member.id]); setMenuOpen(false); }} onKick={(_reason) => { fetch(`/api/v1/servers/${activeServerId}/members/${member.id}`, { method: "DELETE", credentials: "include" }) .then(() => setMenuOpen(false)); }} onBan={(reason) => { fetch(`/api/v1/servers/${activeServerId}/bans`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user_id: member.id, reason }), }).then(() => setMenuOpen(false)); }} onMute={(duration, reason) => { fetch(`/api/v1/servers/${activeServerId}/mutes`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ user_id: member.id, duration, reason }), }).then(() => setMenuOpen(false)); }} onClose={() => setMenuOpen(false)} /> )}
); } export function MemberList() { const activeServerId = useServerStore((s) => s.activeServerId); const membersByServer = useMemberStore((s) => s.membersByServer); const fetchMembers = useMemberStore((s) => s.fetchMembers); const presences = usePresenceStore((s) => s.presences); const members = activeServerId ? membersByServer[activeServerId] || [] : []; useEffect(() => { if (activeServerId) { fetchMembers(activeServerId); } }, [activeServerId, fetchMembers]); const online = members.filter((m) => { const status = presences[m.id]?.status ?? m.status; return status !== "offline"; }); const offline = members.filter((m) => { const status = presences[m.id]?.status ?? m.status; return status === "offline"; }); return (
[MEMBERS]
{!activeServerId && (

[select a server]

)} {activeServerId && members.length === 0 && (

[no members]

)} {online.length > 0 && (
ONLINE
---
{online.map((m) => ( ))}
)} {offline.length > 0 && (
OFFLINE
---
{offline.map((m) => ( ))}
)}
); }