import { useState } from 'react'; import { UserPlus, Trash2 } from 'lucide-react'; import { useUi } from '../../context/ui-context.jsx'; import { useAuth } from '../../context/auth-context.jsx'; import { useAsync, useAction } from '../../hooks/useAsync.js'; import { addProjectMember, setProjectMemberRole, removeProjectMember } from '../../services/projects.js'; import { listUsers } from '../../services/users.js'; import { Button } from '../../components/Button.jsx'; import { Field } from '../../components/Field.jsx'; import { ComboBox } from '../../components/ComboBox.jsx'; import { Badge } from '../../components/Badge.jsx'; import { DetailPopup } from '../../components/DetailPopup.jsx'; const ROLE_BADGE = { owner: { color: 'accent', key: 'project_role_owner' }, write: { color: 'success', key: 'project_role_write' }, }; export default function ProjectMembersTab({ project, onChanged }) { const { t, openDialog, pushToast } = useUi(); const { user: currentUser } = useAuth(); const runAction = useAction(); const { data: users } = useAsync(listUsers, []); const [addingMember, setAddingMember] = useState(''); const [inviteEmail, setInviteEmail] = useState(''); const [newMemberRole, setNewMemberRole] = useState('read'); const [addMemberOpen, setAddMemberOpen] = useState(false); // Compartir (agregar/quitar/cambiar permiso) es exclusivo del dueño del proyecto -- el resto // solo ve la lista de con quien esta compartido. const canManage = !!project.isOwner || currentUser?.id === project.owner_user_id; const userOptions = (users || []).filter((u) => !project.members.some((m) => m.user_id === u.id)).map((u) => ({ value: u.id, label: u.name })); const canAdd = !!addingMember || !!inviteEmail.trim(); const roleOptions = [{ value: 'read', label: t('project_role_read') }, { value: 'write', label: t('project_role_write') }]; async function addMember() { if (!canAdd) return; await runAction(async () => { const target = inviteEmail.trim() ? { email: inviteEmail.trim() } : { userId: Number(addingMember) }; const result = await addProjectMember(project.id, target, newMemberRole === 'write' ? 'write' : null); setAddingMember(''); setInviteEmail(''); setNewMemberRole('read'); setAddMemberOpen(false); onChanged(); pushToast({ tone: 'success', message: result.invited ? t('project_invite_sent') : t('common_saved') }); }); } function changeRole(member, role) { runAction(async () => { await setProjectMemberRole(project.id, member.user_id, role === 'write' ? 'write' : null); onChanged(); }); } function confirmRemoveMember(member) { openDialog({ tone: 'warning', title: t('common_confirm_delete_title'), message: t('common_confirm_delete_msg'), actions: [ { label: t('common_cancel'), variant: 'standard' }, { label: t('common_delete'), variant: 'danger', onClick: () => runAction(async () => { await removeProjectMember(project.id, member.user_id); onChanged(); }) }, ], }); } return (

{t('project_members')}

{canManage && }
{!canManage &&
{t('project_members_owner_only_hint')}
} {project.members.map((m) => { const badge = ROLE_BADGE[m.role_in_project] || { color: 'muted', key: 'project_role_read' }; return (
{m.name} · {m.email} {canManage && m.role_in_project !== 'owner' ? (
changeRole(m, v)} />
) : ( {t(badge.key)} )} {canManage && m.role_in_project !== 'owner' && ( )}
); })} {project.members.length === 0 &&
{t('common_empty')}
}
setAddMemberOpen(false)} width={420} height={420}> { setAddingMember(v); setInviteEmail(''); }} placeholder={t('project_add_member')} />
{t('common_or')}
{ setInviteEmail(e.target.value); setAddingMember(''); }} placeholder="correo@dominio.com" />
); }