PageSourceSearch

https://mais-saude-empresarial.pages.dev/js/views/acessos.js

js mais-saude-empresarial.pages.dev collected 2026-10-03 05:24:33 UTC 4,181 bytes, 86 lines download raw bytes

1import { api } from '../api.js';
2import { esc } from '../utils.js';
3import { modalShow, closeModal, confirmModal } from '../ui/modal.js';
4import { toast } from '../ui/toast.js';
5import { isMaster } from '../state.js';
6
7export async function viewAcessos() {
8  if (!isMaster()) return '<div class="empty">Apenas o acesso Master.</div>';
9  const res = await api.get('/usuarios');
10  const items = res.items || [];
11  setTimeout(() => bind(items), 0);
12  return `<div class="card"><div class="hd"><h3>Usuários do sistema</h3><div class="sp"></div>
13    <button class="btn pri sm" data-new-user>+ Novo</button>
14  </div>
15    <div class="bd" style="overflow:auto"><table>
16      <thead><tr><th>Nome</th><th>Login</th><th>Papel</th><th>Empresa</th><th>Ações</th></tr></thead>
17      <tbody>${items.map(u => `
18        <tr>
19          <td>${esc(u.nome)}</td>
20          <td>${esc(u.login)}</td>
21          <td>${esc(u.role)}</td>
22          <td>${u.empresa_id || '—'}</td>
23          <td>
24            <button class="btn sm" data-edit-user="${u.id}">Editar</button>
25            ${u.ativo ? `<button class="btn sm danger" data-deact="${u.id}">Desativar</button>` : '<span class="mini">inativo</span>'}
26          </td>
27        </tr>`).join('') || '<tr><td colspan=5 class=empty>Sem usuários.</td></tr>'}
28      </tbody>
29    </table></div>
30  </div>`;
31}
32
33function bind(items) {
34  const usersById = new Map(items.map(u => [u.id, u]));
35  document.querySelector('[data-new-user]')?.addEventListener('click', () => modalUser(null));
36  document.querySelectorAll('[data-edit-user]').forEach(el => {
37    el.addEventListener('click', () => modalUser(+el.dataset.editUser, usersById.get(+el.dataset.editUser)));
38  });
39  document.querySelectorAll('[data-deact]').forEach(el => {
40    el.addEventListener('click', async () => {
41      if (!(await confirmModal('Desativar este usuário?', { title: 'Desativar usuário', okText: 'Desativar' }))) return;
42      try {
43        await api.delete('/usuarios/' + el.dataset.deact);
44        toast('Usuário desativado');
45        import('../router.js').then(m => m.render());
46      } catch (e) { toast('Erro: ' + e.message); }
47    });
48  });
49}
50
51async function modalUser(id, u = null) {
52  const isNew = !id;
53  const nome = u?.nome || '';
54  modalShow(isNew ? 'Novo usuário' : 'Editar usuário', `
55    <div class="field"><label for="u_nome">Nome</label><input id="u_nome" value="${esc(nome)}"></div>
56    ${isNew ? '<div class="field"><label for="u_login">Login</label><input id="u_login"></div>' : ''}
57    <div class="field"><label for="u_senha">${isNew ? 'Senha' : 'Nova senha (em branco para manter)'}</label><input id="u_senha" type="password" autocomplete="new-password"></div>
58    ${isNew ? `<div class="field"><label for="u_role">Papel</label><select id="u_role"><option value="operador">Operador</option><option value="master">Master</option></select></div>` : ''}`,
59    [
60      { t:'Salvar', cls:'pri', fn: async () => {
61        try {
62          const nomeNovo = document.getElementById('u_nome').value.trim();
63          if (!nomeNovo) { toast('Nome não pode ficar em branco'); return; }
64          const body = {};
65          // Só envia `nome` se realmente mudou — evita sobrescrever quando o usuário
66          // só quer resetar a senha e não tocou no campo.
67          if (isNew || nomeNovo !== nome) body.nome = nomeNovo;
68          const senha = document.getElementById('u_senha').value;
69          if (senha) body.senha = senha;
70          if (isNew) {
71            body.login = document.getElementById('u_login').value.trim();
72            body.role = document.getElementById('u_role').value;
73            if (!body.login || !body.senha) { toast('Login e senha obrigatórios'); return; }
74            await api.post('/usuarios', body);
75          } else {
76            if (!Object.keys(body).length) { toast('Nada pra atualizar'); return; }
77            await api.patch('/usuarios/' + id, body);
78          }
79          closeModal();
80          toast(isNew ? 'Criado' : 'Atualizado');
81          import('../router.js').then(m => m.render());
82        } catch (e) { toast('Erro: ' + (e.body?.error || e.message)); }
83      }},
84      { t:'Cancelar', fn: closeModal },
85    ]);
86}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.