/* 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} />
{loading ? (
) : (
| Usuário | Cargo | Perfil | Status | Último acesso | |
{filtered.map(u => (
|
{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 });