/* JRN — Admin: Usuários, cadastro/edição e permissões */ /* ---------- Modal: cadastro / edição de usuário ---------- */ function UserFormModal({ user, onClose, onSave }) { const isEdit = !!user; const [f, setF] = useState(user ? { nome: user.nome, email: user.email, cargo: user.cargo, perfil: user.perfil, status: user.status, _dbId: user._dbId } : { nome: '', email: '', cargo: '', perfil: 'comum', status: 'ativo' }); const [saving, setSaving] = useState(false); const [err, setErr] = useState(''); const set = (k, v) => setF(s => ({ ...s, [k]: v })); const valid = f.nome.trim() && /\S+@\S+\.\S+/.test(f.email); const handleSave = async () => { setSaving(true); setErr(''); try { await onSave(f); } catch (e) { setErr(e.message || 'Erro ao salvar.'); setSaving(false); } }; return ( Cancelar {saving ? : null} {isEdit ? 'Salvar alterações' : 'Cadastrar usuário'} }> {err &&
{err}
}
set('nome', e.target.value)} placeholder="Ex.: Maria Souza" /> set('email', e.target.value)} placeholder="nome@empresa.com.br" disabled={isEdit} /> set('cargo', e.target.value)} placeholder="Ex.: Controller" /> {!isEdit && ( )}
{f.perfil === 'admin' && (
Administradores acessam todas as empresas, dashboards e funções administrativas automaticamente.
)}
); } /* ---------- Modal: permissões (empresa + dashboard + funções) ---------- */ function PermissionsModal({ user, empresas, onClose, onSaved }) { const [allDashboards, setAllDashboards] = useState([]); const [emp, setEmp] = useState(new Set()); const [dash, setDash] = useState(new Set()); const [fns, setFns] = useState(new Set()); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [err, setErr] = useState(''); useEffect(() => { Promise.all([ apiDashboardsGet(), apiPermissoesGet(user.id, empresas), ]).then(([dashes, perms]) => { setAllDashboards(dashes); setEmp(new Set(perms.empresas)); setDash(new Set(perms.dashboards)); setFns(new Set(perms.funcoes)); }).catch(e => setErr(e.message || 'Erro ao carregar permissões.')) .finally(() => setLoading(false)); }, []); const dashByCompany = (companyId) => allDashboards.filter(d => d.companyId === companyId); const toggleEmp = (id) => { const ne = new Set(emp); const nd = new Set(dash); if (ne.has(id)) { ne.delete(id); dashByCompany(id).forEach(d => nd.delete(d.id)); } else { ne.add(id); } setEmp(ne); setDash(nd); }; const toggleDash = (d) => { const nd = new Set(dash); if (nd.has(d.id)) { nd.delete(d.id); } else { nd.add(d.id); } setDash(nd); if (!emp.has(d.companyId) && nd.has(d.id)) setEmp(new Set(emp).add(d.companyId)); }; const toggleFn = (id) => { const n = new Set(fns); n.has(id) ? n.delete(id) : n.add(id); setFns(n); }; const save = async () => { setSaving(true); setErr(''); try { await apiPermissoesSet(user.id, [...emp], [...dash], [...fns], empresas, allDashboards); onSaved(); } catch (e) { setErr(e.message || 'Erro ao salvar permissões.'); setSaving(false); } }; return ( {emp.size} empresas · {dash.size} painéis · {fns.size} funções Cancelar {saving ? : null} Salvar permissões }> {err &&
{err}
} {loading ? (
) : (
Empresas e painéis
{(empresas || []).map(c => { const ds = dashByCompany(c.id); const on = emp.has(c.id); return (
toggleEmp(c.id)} accent={c.cor} />
{c.nome}
{c.tipo} · {ds.length} painéis
{on && (
{ds.map(d => ( ))} {ds.length === 0 && Nenhum dashboard cadastrado.}
)}
); })}
Funções administrativas
{FUNCOES_ADMIN.map(fn => ( ))}
)}
); } /* ---------- Página: lista de usuários ---------- */ function UsersAdmin({ empresas, toast }) { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [q, setQ] = useState(''); const [perfil, setPerfil] = useState('todos'); const [modal, setModal] = useState(null); // {type:'form'|'perm', user} const loadUsers = () => { setLoading(true); apiUsuariosGet().then(setUsers).catch(() => toast('Erro ao carregar usuários.', 'danger')).finally(() => setLoading(false)); }; useEffect(loadUsers, []); const filtered = users.filter(u => (perfil === 'todos' || u.perfil === perfil) && (u.nome.toLowerCase().includes(q.toLowerCase()) || u.email.toLowerCase().includes(q.toLowerCase())) ); const saveUser = async (f) => { if (f._dbId) { await apiUsuariosUpdate(f); toast('Usuário atualizado com sucesso.'); } else { await apiUsuariosCreate(f); toast('Usuário cadastrado com sucesso.'); } setModal(null); loadUsers(); }; const savePerm = () => { setModal(null); toast('Permissões atualizadas.'); }; const removeUser = async (u) => { if (!confirm(`Remover ${u.nome}?`)) return; try { await apiUsuariosDelete(u); toast('Usuário removido.', 'danger'); loadUsers(); } catch (e) { toast(e.message || 'Erro ao remover.', 'danger'); } }; return (
setModal({ type: 'form' })}>Novo usuário} />
setQ(e.target.value)} />
{loading ? (
) : ( {filtered.map(u => ( ))}
UsuárioCargoPerfilStatusÚltimo acesso
{u.avatar} {u.nome} {u.email}
{u.cargo} {u.perfil === 'admin' ? Admin : Comum} {u.ultimoAcesso}
{u.perfil !== 'admin' && ( )}
{filtered.length === 0 && }
)}
{modal?.type === 'form' && ( setModal(null)} onSave={saveUser} /> )} {modal?.type === 'perm' && ( setModal(null)} onSaved={savePerm} /> )}
); } Object.assign(window, { UsersAdmin, UserFormModal, PermissionsModal });