"use client"; /** * The group profile's Members tab: who is in the group, their role, and the * admin controls for changing that. * * Which controls appear follows the same rules the BFF enforces — the server is * the authority, this just avoids offering buttons that would be refused. */ import { useState } from "react"; import { Plus, ShieldMinus, ShieldPlus, UserMinus } from "lucide-react"; import { toast } from "sonner"; import { UserAvatar } from "@/components/ui/user-avatar"; import { Button } from "@/components/ui/button"; import { AddMembersDialog } from "@/components/chat/add-members-dialog"; import { chat, isGroupAdmin, type ConversationDetail } from "@/lib/chat"; const ROLE_LABEL: Record = { owner: "Owner", admin: "Admin", member: "", }; export function GroupMembersTab({ conversationId, detail, selfId, onChanged, }: { conversationId: string; detail: ConversationDetail; selfId: string; onChanged: () => void; }) { const [busy, setBusy] = useState(null); const [adding, setAdding] = useState(false); const iAmAdmin = isGroupAdmin(detail.my_role); const iAmOwner = detail.my_role === "owner"; const act = async (handle: string, fn: () => Promise, ok: string) => { setBusy(handle); try { await fn(); toast.success(ok); onChanged(); } catch { toast.error("That didn't work"); } finally { setBusy(null); } }; return (
{iAmAdmin && ( )}
    {detail.participants.map((m) => { const isSelf = m.id === selfId; // The owner cannot be demoted or removed by anyone, and only the // owner may change roles at all. const canChangeRole = iAmOwner && !isSelf && m.role !== "owner"; // An admin may remove members; only the owner may remove an admin. const canRemove = !isSelf && m.role !== "owner" && (iAmOwner || (iAmAdmin && m.role !== "admin")); return (
  • {m.name} {isSelf && ( (you) )}

    @{m.handle}

    {m.role && ROLE_LABEL[m.role] && ( {ROLE_LABEL[m.role]} )} {canChangeRole && ( )} {canRemove && ( )}
  • ); })}
{adding && ( p.handle)} onClose={() => setAdding(false)} onAdded={onChanged} /> )}
); }