import { useState, useEffect, useCallback } from 'react'; import { useParams, Link } from 'react-router-dom'; import { TeamDetail, TeamMember, TeamMemberCreate, TeamRole } from '../types'; import { getTeam, listTeamMembers, addTeamMember, updateTeamMember, removeTeamMember, } from '../api'; import { useAuth } from '../contexts/AuthContext'; import { Badge } from '../components/Badge'; import { Breadcrumb } from '../components/Breadcrumb'; import { DataTable } from '../components/DataTable'; import { UserAutocomplete } from '../components/UserAutocomplete'; import './TeamMembersPage.css'; function TeamMembersPage() { const { slug } = useParams<{ slug: string }>(); const { user } = useAuth(); const [team, setTeam] = useState(null); const [members, setMembers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [adding, setAdding] = useState(false); const [newMember, setNewMember] = useState({ username: '', role: 'member' }); const [editingMember, setEditingMember] = useState(null); const [removingMember, setRemovingMember] = useState(null); const loadData = useCallback(async () => { if (!slug) return; try { setLoading(true); const [teamData, membersData] = await Promise.all([ getTeam(slug), listTeamMembers(slug), ]); setTeam(teamData); setMembers(membersData); setError(null); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load team'); } finally { setLoading(false); } }, [slug]); useEffect(() => { loadData(); }, [loadData]); async function handleAddMember(e: React.FormEvent) { e.preventDefault(); if (!slug) return; try { setAdding(true); setError(null); await addTeamMember(slug, newMember); setNewMember({ username: '', role: 'member' }); setShowAddForm(false); loadData(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to add member'); } finally { setAdding(false); } } async function handleRoleChange(username: string, newRole: TeamRole) { if (!slug) return; try { setEditingMember(username); setError(null); await updateTeamMember(slug, username, { role: newRole }); loadData(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to update member'); } finally { setEditingMember(null); } } async function handleRemoveMember(username: string) { if (!slug) return; if (!confirm(`Remove ${username} from the team?`)) return; try { setRemovingMember(username); setError(null); await removeTeamMember(slug, username); loadData(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to remove member'); } finally { setRemovingMember(null); } } if (loading) { return (
Loading team members...
); } if (error && !team) { return (

Error loading team

{error}

Back to Teams
); } if (!team) return null; const isOwner = team.user_role === 'owner' || user?.is_admin; const isAdmin = team.user_role === 'admin' || isOwner; const roleVariants: Record = { owner: 'success', admin: 'info', member: 'default', }; const roles: TeamRole[] = ['owner', 'admin', 'member']; return (

Team Members

{isAdmin && ( )}
{error && (
{error}
)} {showAddForm && (
setShowAddForm(false)}>
e.stopPropagation()}>

Invite Member

setNewMember({ ...newMember, username })} placeholder="Search for a user..." autoFocus />
)} member.id} emptyMessage="No members in this team yet." columns={[ { key: 'member', header: 'Member', render: (member) => { const isCurrentUser = user?.username === member.username; return (
{member.username.charAt(0).toUpperCase()}
{member.username} {isCurrentUser && (you)} {member.email && ( {member.email} )}
); }, }, { key: 'role', header: 'Role', render: (member) => { const isCurrentUser = user?.username === member.username; const canModify = isAdmin && !isCurrentUser && (isOwner || member.role !== 'owner'); if (canModify) { return ( ); } return ( {member.role} ); }, }, { key: 'joined', header: 'Joined', render: (member) => ( {new Date(member.created_at).toLocaleDateString()} ), }, ...(isAdmin ? [{ key: 'actions', header: '', render: (member: TeamMember) => { const isCurrentUser = user?.username === member.username; const canModify = isAdmin && !isCurrentUser && (isOwner || member.role !== 'owner'); if (!canModify) return null; return ( ); }, }] : []), ]} />
); } export default TeamMembersPage;