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>
138 lines
4.5 KiB
JavaScript
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);
|
|
}
|
|
})();
|