Files
CES_SERVE_WEB/web/src/views/users.ts
Welton Moura 402ac776ac feat: sistema GastroBar PDV completo
- Backend: Fastify + Prisma/SQLite com autenticacao JWT
- CRUD completo: usuarios, categorias, produtos, comandas
- Sistema de comandas com itens, status, pagamento
- Controle de estoque (entrada/saida automatica)
- Relatorios e dashboard com KPIs
- Notificacoes sonoras na cozinha
- Frontend: SPA vanilla TS com tema dark glassmorphism
- Mobile-first com bottom-sheet e cards compactos
- Busca de comandas por periodo
- Modal de detalhes com secao editavel colapsavel
2026-07-21 12:47:15 -03:00

157 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { api } from '../api';
import { renderNavbar, toast, roleBadge } from '../utils';
const ROLE_OPTIONS = ['ADMIN', 'CAIXA', 'GARCOM', 'COZINHA', 'BARMAN'];
export async function renderUsers(container: HTMLElement) {
container.innerHTML = `
${renderNavbar('/users')}
<div class="container animate-fade-in">
<div class="page-header">
<h1>Equipe 👥</h1>
<button class="btn" id="btn-novo-usuario"> Novo Usuário</button>
</div>
<div id="users-list"><p class="card-subtitle">Carregando...</p></div>
</div>
<!-- Modal Usuário -->
<div id="modal-usuario" class="modal-overlay" style="display:none;">
<div class="modal">
<div class="modal-header">
<h3 id="modal-user-title">Novo Usuário</h3>
<button class="btn-icon" onclick="document.getElementById('modal-usuario').style.display='none'">✕</button>
</div>
<div class="modal-body">
<form id="form-usuario">
<input type="hidden" id="user-id">
<div class="form-group">
<label>Nome Completo *</label>
<input type="text" id="u-nome" class="form-control" required>
</div>
<div class="form-group">
<label>E-mail *</label>
<input type="email" id="u-email" class="form-control" required>
</div>
<div class="form-group" id="senha-group">
<label>Senha *</label>
<input type="password" id="u-senha" class="form-control" placeholder="Mínimo 6 caracteres">
</div>
<div class="form-group">
<label>Cargo (Role) *</label>
<select id="u-role" class="form-control" required>
${ROLE_OPTIONS.map(r => `<option value="${r}">${r}</option>`).join('')}
</select>
</div>
<div style="display:flex;align-items:center;gap:0.75rem;margin-bottom:1.5rem;">
<input type="checkbox" id="u-ativo" checked>
<label for="u-ativo" style="cursor:pointer;color:var(--text-primary);">Usuário Ativo</label>
</div>
<button type="submit" class="btn" style="width:100%;">Salvar</button>
</form>
</div>
</div>
</div>
`;
await loadUsers();
bindUserEvents();
}
async function loadUsers() {
const list = document.getElementById('users-list')!;
try {
const users = await api.get('/usuarios');
list.innerHTML = `
<div class="table-wrap">
<table>
<thead>
<tr><th>Nome</th><th>E-mail</th><th>Cargo</th><th>Status</th><th>Desde</th><th>Ações</th></tr>
</thead>
<tbody>
${users.map((u: any) => `
<tr>
<td data-label="Nome"><strong>${u.nome}</strong></td>
<td data-label="E-mail" style="color:var(--text-secondary)">${u.email}</td>
<td data-label="Cargo">${roleBadge(u.role)}</td>
<td data-label="Status"><span class="badge ${u.ativo ? 'badge-success' : 'badge-warning'}">${u.ativo ? 'Ativo' : 'Inativo'}</span></td>
<td data-label="Desde" style="color:var(--text-secondary)">${new Date(u.criadoEm).toLocaleDateString('pt-BR')}</td>
<td data-label="Ações" style="display:flex;gap:0.5rem;flex-wrap:wrap;">
<button class="btn btn-sm btn-secondary" onclick="window.editUser(${JSON.stringify(u).replace(/"/g, '&quot;')})">✏️ Editar</button>
<button class="btn btn-sm btn-danger" onclick="window.toggleUser('${u.id}','${u.nome}',${u.ativo})">
${u.ativo ? '🚫 Desativar' : '✅ Ativar'}
</button>
</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
`;
} catch (err: any) {
list.innerHTML = `<p style="color:var(--accent-primary)">Erro: ${err.message}</p>`;
}
}
function bindUserEvents() {
document.getElementById('btn-novo-usuario')?.addEventListener('click', () => {
clearUserForm();
(document.getElementById('modal-usuario') as HTMLElement).style.display = 'flex';
(document.getElementById('u-senha') as HTMLInputElement).required = true;
(document.getElementById('senha-group') as HTMLElement).style.display = 'block';
});
document.getElementById('form-usuario')?.addEventListener('submit', async (e) => {
e.preventDefault();
const id = (document.getElementById('user-id') as HTMLInputElement).value;
const senha = (document.getElementById('u-senha') as HTMLInputElement).value;
const payload: any = {
nome: (document.getElementById('u-nome') as HTMLInputElement).value,
email: (document.getElementById('u-email') as HTMLInputElement).value,
role: (document.getElementById('u-role') as HTMLSelectElement).value,
ativo: (document.getElementById('u-ativo') as HTMLInputElement).checked,
};
if (!id) payload.senha = senha;
try {
if (id) await api.patch(`/usuarios/${id}`, payload);
else await api.post('/usuarios', { ...payload, senha });
toast(id ? 'Usuário atualizado!' : 'Usuário cadastrado!', 'success');
(document.getElementById('modal-usuario') as HTMLElement).style.display = 'none';
await loadUsers();
} catch (err: any) { toast(err.message, 'error'); }
});
(window as any).editUser = (u: any) => {
(document.getElementById('user-id') as HTMLInputElement).value = u.id;
(document.getElementById('u-nome') as HTMLInputElement).value = u.nome;
(document.getElementById('u-email') as HTMLInputElement).value = u.email;
(document.getElementById('u-role') as HTMLSelectElement).value = u.role;
(document.getElementById('u-ativo') as HTMLInputElement).checked = u.ativo;
(document.getElementById('u-senha') as HTMLInputElement).required = false;
(document.getElementById('u-senha') as HTMLInputElement).value = '';
(document.getElementById('senha-group') as HTMLElement).style.display = 'none';
(document.getElementById('modal-user-title') as HTMLElement).textContent = 'Editar Usuário';
(document.getElementById('modal-usuario') as HTMLElement).style.display = 'flex';
};
(window as any).toggleUser = async (id: string, nome: string, ativo: boolean) => {
const action = ativo ? 'desativar' : 'ativar';
if (!confirm(`Deseja ${action} o usuário "${nome}"?`)) return;
try {
await api.patch(`/usuarios/${id}`, { ativo: !ativo });
toast(`Usuário ${ativo ? 'desativado' : 'ativado'}!`, 'success');
await loadUsers();
} catch (err: any) { toast(err.message, 'error'); }
};
}
function clearUserForm() {
(document.getElementById('user-id') as HTMLInputElement).value = '';
(document.getElementById('u-nome') as HTMLInputElement).value = '';
(document.getElementById('u-email') as HTMLInputElement).value = '';
(document.getElementById('u-senha') as HTMLInputElement).value = '';
(document.getElementById('u-role') as HTMLSelectElement).value = 'GARCOM';
(document.getElementById('u-ativo') as HTMLInputElement).checked = true;
(document.getElementById('modal-user-title') as HTMLElement).textContent = 'Novo Usuário';
}