diff --git a/public/index.html b/public/index.html index 79568da..3b423fa 100644 --- a/public/index.html +++ b/public/index.html @@ -16,6 +16,7 @@ @@ -226,6 +227,48 @@
+ + +
+
+

Campanhas de outreach

+ +
+
+ + +
+

Nova campanha

+
+ + +
+
+ + +
+
+ +
+
+
+ +
+ +
+
+ + +
+

+
+ + +
+
+
+
+ @@ -480,6 +523,7 @@ + diff --git a/public/js/app.js b/public/js/app.js index 65c035d..b915b6f 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -64,6 +64,7 @@ panel.classList.toggle('active', panel.id === `tab-${tab.dataset.tab}`); } if (tab.dataset.tab === 'tratamento') Tratamento.ativar(); + if (tab.dataset.tab === 'campanhas') Campanhas.ativar(); }); } diff --git a/public/js/campanhas.js b/public/js/campanhas.js new file mode 100644 index 0000000..ebc67fa --- /dev/null +++ b/public/js/campanhas.js @@ -0,0 +1,111 @@ +/* Aba Campanhas: criacao, fila de aprovacao, saude/variantes, estagio/agendamento. */ +const Campanhas = (() => { + let carregado = false; + let variantesCount = 0; + + const STATUS_LABELS = { rascunho: 'Rascunho', rodando: 'Rodando', pausado: 'Pausado', concluido: 'Concluido' }; + + function addVarianteRow(codigoSugerido) { + const codigo = codigoSugerido || String.fromCharCode(65 + variantesCount); + variantesCount += 1; + el('campanha-variantes').append( + h('div', { class: 'row', 'data-variante-code': codigo }, + h('span', { class: 'chip' }, codigo), + h('textarea', { class: 'campanha-variante-mensagem', rows: 2, placeholder: 'Ola {empresa}, ...' })) + ); + } + + async function carregarProdutos() { + const { produtos } = await API.get('/api/campaigns/produtos'); + el('campanha-produto').replaceChildren( + ...produtos.map((p) => h('option', { value: p.value }, `${p.value} (${fmt.format(p.total)} leads)`)) + ); + } + + async function carregarSegmentos(produto) { + const container = el('campanha-segmentos'); + if (!produto) { container.replaceChildren(); return; } + const { segmentos } = await API.get(`/api/campaigns/segmentos?produto=${encodeURIComponent(produto)}`); + container.replaceChildren(...segmentos.map((s) => + h('label', { class: 'chip' }, + h('input', { type: 'checkbox', value: s.value, class: 'campanha-segmento-check' }), + ` ${s.value} (${fmt.format(s.total)})`) + )); + } + + function segmentosSelecionados() { + return Array.from(document.querySelectorAll('.campanha-segmento-check:checked')).map((i) => i.value); + } + + function variantesPreenchidas() { + return Array.from(el('campanha-variantes').children).map((row) => ({ + code: row.dataset.varianteCode, + mensagem: row.querySelector('.campanha-variante-mensagem').value.trim() + })).filter((v) => v.mensagem); + } + + async function abrirModalNovaCampanha() { + el('campanha-nome').value = ''; + el('campanha-limite-inicial').value = 10; + el('campanha-limite-teto').value = 80; + el('campanha-erro').textContent = ''; + el('campanha-variantes').replaceChildren(); + variantesCount = 0; + addVarianteRow('A'); + await carregarProdutos(); + await carregarSegmentos(el('campanha-produto').value); + el('modal-nova-campanha').showModal(); + } + + function renderCampanhaCard(campanha) { + return h('div', { class: 'item' }, + h('div', {}, + h('strong', {}, campanha.nome), + h('span', { class: 'sub' }, ` ${campanha.produto} — ${campanha.segmentos.join(', ')}`)), + h('span', { class: `chip ${campanha.status === 'rodando' ? 'ok' : campanha.status === 'pausado' ? 'warn' : ''}` }, + STATUS_LABELS[campanha.status] || campanha.status)); + } + + async function carregarLista() { + const { campanhas } = await API.get('/api/campaigns'); + el('campanhas-lista').replaceChildren( + ...(campanhas.length ? campanhas.map(renderCampanhaCard) : [h('p', { class: 'muted' }, 'Nenhuma campanha criada ainda.')]) + ); + } + + function ativar() { + if (carregado) return; + carregado = true; + + el('btn-nova-campanha').addEventListener('click', () => { + abrirModalNovaCampanha().catch((error) => toast(`Erro: ${error.message}`)); + }); + el('btn-cancelar-campanha').addEventListener('click', () => el('modal-nova-campanha').close()); + el('btn-add-variante').addEventListener('click', () => addVarianteRow()); + el('campanha-produto').addEventListener('change', (event) => { + carregarSegmentos(event.target.value).catch((error) => toast(`Erro: ${error.message}`)); + }); + + el('btn-salvar-campanha').addEventListener('click', async () => { + try { + await API.post('/api/campaigns', { + nome: el('campanha-nome').value.trim(), + produto: el('campanha-produto').value, + segmentos: segmentosSelecionados(), + variantes: variantesPreenchidas(), + limiteDiarioInicial: Number(el('campanha-limite-inicial').value) || 10, + limiteDiarioTeto: Number(el('campanha-limite-teto').value) || 80 + }); + el('modal-nova-campanha').close(); + toast('Campanha criada'); + await carregarLista(); + } catch (error) { + el('campanha-erro').textContent = error.message; + } + }); + + carregarLista().catch((error) => toast(`Erro: ${error.message}`)); + } + + return { ativar }; +})();