'use client'; import { useEffect, useState } from 'react'; import { ShieldCheck, Trash2, UserPlus } from 'lucide-react'; import { api } from '@/lib/api'; import { useAuthStore } from '@/stores/useAuthStore'; import { useMemberStore } from '@/stores/useMemberStore'; type ProjectRole = 'owner' | 'admin' | 'member' | 'viewer'; interface ProjectMemberRow { id: string; projectId: string; userId: string; role: ProjectRole; user?: { id: string; name: string; email?: string }; } const ROLE_LABEL: Record = { owner: 'Owner', admin: 'Admin', member: 'Member', viewer: 'Viewer', }; export function ProjectMemberPanel({ projectId }: { projectId: string }) { const user = useAuthStore((s) => s.user); const { members, fetchMembers } = useMemberStore(); const [rows, setRows] = useState([]); const [selectedUserId, setSelectedUserId] = useState(''); const [selectedRole, setSelectedRole] = useState('member'); const actorId = user?.id ?? ''; const reload = async () => { if (!projectId) return; const data = await api.get(`/projects/${projectId}/members`); setRows(data); }; useEffect(() => { void fetchMembers().catch(() => {}); void reload().catch(() => {}); }, [projectId]); const add = async () => { if (!actorId || !selectedUserId) return; await api.post(`/projects/${projectId}/members`, { actorId, userId: selectedUserId, role: selectedRole }); setSelectedUserId(''); await reload(); }; const updateRole = async (member: ProjectMemberRow, role: ProjectRole) => { if (!actorId) return; await api.patch(`/projects/${projectId}/members/${member.userId}/role`, { actorId, role }); await reload(); }; const remove = async (member: ProjectMemberRow) => { if (!actorId) return; await api.deleteWithBody(`/projects/${projectId}/members/${member.userId}`, { actorId }); await reload(); }; const existingUserIds = new Set(rows.map((row) => row.userId)); const candidates = members.filter((member) => !existingUserIds.has(member.id)); return (
项目成员治理
{rows.length === 0 ? (
暂无项目成员
) : rows.map((row) => (
{row.user?.name ?? row.userId}
{row.user?.email ?? row.userId}
))}
); }