'use client' import { useState, useEffect } from 'react' import { Button, Input, Select, toast, Spinner } from '@ciphera-net/ui' import { Plus, Trash, EnvelopeSimple, Crown, UserCircle } from '@phosphor-icons/react' import { useAuth } from '@/lib/auth/context' import { getOrganizationMembers, removeOrganizationMember, sendInvitation, getInvitations, revokeInvitation, type OrganizationMember, type OrganizationInvitation } from '@/lib/api/organization' import { getAuthErrorMessage } from '@ciphera-net/ui' const ROLE_OPTIONS = [ { value: 'admin', label: 'Admin' }, { value: 'member', label: 'Member' }, ] function RoleBadge({ role }: { role: string }) { if (role === 'owner') return ( Owner ) if (role === 'admin') return ( Admin ) return ( Member ) } export default function WorkspaceMembersTab() { const { user } = useAuth() const [members, setMembers] = useState([]) const [invitations, setInvitations] = useState([]) const [loading, setLoading] = useState(true) const [inviteEmail, setInviteEmail] = useState('') const [inviteRole, setInviteRole] = useState('member') const [inviting, setInviting] = useState(false) const [showInvite, setShowInvite] = useState(false) const canManage = user?.role === 'owner' || user?.role === 'admin' const loadMembers = async () => { if (!user?.org_id) return try { const [membersData, invitationsData] = await Promise.all([ getOrganizationMembers(user.org_id), getInvitations(user.org_id).catch(() => [] as OrganizationInvitation[]), ]) setMembers(membersData) setInvitations(invitationsData) } catch { } finally { setLoading(false) } } useEffect(() => { loadMembers() }, [user?.org_id]) const handleInvite = async () => { if (!user?.org_id || !inviteEmail.trim()) return setInviting(true) try { await sendInvitation(user.org_id, inviteEmail.trim(), inviteRole) toast.success(`Invitation sent to ${inviteEmail}`) setInviteEmail('') setShowInvite(false) loadMembers() } catch (err) { toast.error(getAuthErrorMessage(err as Error) || 'Failed to invite member') } finally { setInviting(false) } } const handleRemove = async (memberId: string, email: string) => { if (!user?.org_id) return if (!confirm(`Remove ${email} from the organization?`)) return try { await removeOrganizationMember(user.org_id, memberId) toast.success(`${email} has been removed`) loadMembers() } catch (err) { toast.error(getAuthErrorMessage(err as Error) || 'Failed to remove member') } } const handleRevokeInvitation = async (inviteId: string) => { if (!user?.org_id) return if (!confirm('Revoke this invitation?')) return try { await revokeInvitation(user.org_id, inviteId) toast.success('Invitation revoked') loadMembers() } catch (err) { toast.error(getAuthErrorMessage(err as Error) || 'Failed to revoke invitation') } } if (loading) return
return (

Members

{members.length} member{members.length !== 1 ? 's' : ''} in your organization.

{canManage && !showInvite && ( )}
{/* Invite form */} {showInvite && (
setInviteEmail(e.target.value)} placeholder="email@example.com" type="email" />