Files
COMERCIAL-GTI/public/js/app.js
T
DESKTOP-F2O4A80\UserandClaude b8d10b210c Commit inicial: GTI Maquina Comercial
App local (Node + SQLite) para captura, tratamento e exportacao de leads
comerciais, com dashboard de gestao, login/usuarios e integracao Z-PRO.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-12 14:22:21 -03:00

138 lines
4.5 KiB
JavaScript

/* Shell do aplicativo: login + abas + configurações + usuários. */
(async function init() {
// sessao (o servidor ja bloqueia "/" sem cookie, mas precisamos dos dados do usuario)
let usuarioAtual;
try {
({ user: usuarioAtual } = await API.get('/api/auth/me'));
} catch {
window.location.href = '/login.html';
return;
}
el('usuario-logado').textContent = `${usuarioAtual.username} (${usuarioAtual.role === 'admin' ? 'admin' : 'comercial'})`;
el('btn-usuarios').classList.toggle('hidden', usuarioAtual.role !== 'admin');
el('btn-sair').addEventListener('click', async () => {
await API.post('/api/auth/logout');
window.location.href = '/login.html';
});
// usuarios (somente admin)
async function carregarListaUsuarios() {
const { users } = await API.get('/api/users');
el('lista-usuarios').replaceChildren(...users.map((u) =>
h('div', { class: 'row space-between' },
h('span', {}, u.username),
h('span', { class: 'muted' }, u.role === 'admin' ? 'Administrador' : 'Comercial'))));
}
el('btn-usuarios').addEventListener('click', async () => {
el('modal-usuarios').showModal();
try {
await carregarListaUsuarios();
} catch (error) {
toast(`Erro: ${error.message}`);
}
});
el('btn-fechar-usuarios').addEventListener('click', () => el('modal-usuarios').close());
el('form-novo-usuario').addEventListener('submit', async (event) => {
event.preventDefault();
try {
await API.post('/api/users', {
username: el('novo-usuario-username').value,
password: el('novo-usuario-password').value,
role: el('novo-usuario-role').value
});
el('novo-usuario-username').value = '';
el('novo-usuario-password').value = '';
await carregarListaUsuarios();
toast('Usuário criado');
} catch (error) {
toast(`Erro: ${error.message}`);
}
});
// abas
for (const tab of document.querySelectorAll('.tab')) {
tab.addEventListener('click', () => {
for (const t of document.querySelectorAll('.tab')) {
t.classList.toggle('active', t === tab);
t.setAttribute('aria-selected', t === tab ? 'true' : 'false');
}
for (const panel of document.querySelectorAll('.tab-panel')) {
panel.classList.toggle('active', panel.id === `tab-${tab.dataset.tab}`);
}
if (tab.dataset.tab === 'tratamento') Tratamento.ativar();
});
}
// configurações
el('btn-settings').addEventListener('click', async () => {
const { settings } = await API.get('/api/settings');
el('cfg-pipeline').value = settings['zpro.pipelineId'] || 1;
el('cfg-stage').value = settings['zpro.stageId'] || 1;
el('cfg-responsible').value = settings['zpro.responsibleId'] || 15;
el('cfg-forecast').value = settings['zpro.closingForecastDays'] || 30;
el('modal-settings').showModal();
});
el('btn-salvar-settings').addEventListener('click', async (event) => {
event.preventDefault();
try {
await API.put('/api/settings', {
'zpro.pipelineId': el('cfg-pipeline').value,
'zpro.stageId': el('cfg-stage').value,
'zpro.responsibleId': el('cfg-responsible').value,
'zpro.closingForecastDays': el('cfg-forecast').value
});
el('modal-settings').close();
toast('Configurações salvas');
} catch (error) {
toast(`Erro: ${error.message}`);
}
});
// limpar toda a base (zona de risco)
el('btn-limpar-base').addEventListener('click', () => {
el('reset-base-senha').value = '';
el('modal-settings').close();
el('modal-reset-base').showModal();
});
el('btn-cancelar-reset-base').addEventListener('click', () => {
el('modal-reset-base').close();
});
el('btn-confirmar-reset-base').addEventListener('click', async () => {
const senha = el('reset-base-senha').value;
if (!senha) {
toast('Informe a senha de segurança');
return;
}
try {
await API.post('/api/admin/reset', { senha });
el('modal-reset-base').close();
toast('Base de leads limpa com sucesso — recarregando...');
setTimeout(() => window.location.reload(), 1200);
} catch (error) {
toast(`Erro: ${error.message}`);
}
});
// fecha modais clicando fora
for (const dialog of document.querySelectorAll('dialog')) {
dialog.addEventListener('click', (event) => {
if (event.target === dialog) dialog.close();
});
}
Tratamento.bindEvents();
try {
await Captura.init();
} catch (error) {
toast(`Erro ao carregar: ${error.message}`, 8000);
}
})();