diff --git a/public/js/campanhas.js b/public/js/campanhas.js index 775b6f8..e81dae7 100644 --- a/public/js/campanhas.js +++ b/public/js/campanhas.js @@ -5,7 +5,10 @@ const Campanhas = (() => { const STATUS_LABELS = { rascunho: 'Rascunho', rodando: 'Rodando', pausado: 'Pausado', concluido: 'Concluido' }; + const MAX_VARIANTES = 3; // A/B/C — mesmo limite usado na convencao do restante da UI/backend. + function addVarianteRow(codigoSugerido) { + if (variantesCount >= MAX_VARIANTES) return; const codigo = codigoSugerido || String.fromCharCode(65 + variantesCount); variantesCount += 1; el('campanha-variantes').append( @@ -13,6 +16,11 @@ const Campanhas = (() => { h('span', { class: 'chip' }, codigo), h('textarea', { class: 'campanha-variante-mensagem', rows: 2, placeholder: 'Ola {empresa}, ...' })) ); + atualizarBotaoAddVariante(); + } + + function atualizarBotaoAddVariante() { + el('btn-add-variante').disabled = variantesCount >= MAX_VARIANTES; } async function carregarProdutos() { @@ -83,7 +91,14 @@ const Campanhas = (() => { 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}`)); + // O modal de nova campanha esta aberto ( via showModal()) quando + // isto dispara — toast sozinho fica escondido atras do dialog (ver + // comentario em api.js), entao o erro tambem precisa aparecer no + // paragrafo inline #campanha-erro que ja existe pro erro de submit. + carregarSegmentos(event.target.value).catch((error) => { + toast(`Erro: ${error.message}`); + el('campanha-erro').textContent = `Erro: ${error.message}`; + }); }); el('btn-salvar-campanha').addEventListener('click', async () => { @@ -150,15 +165,19 @@ const Campanhas = (() => { const marcarBtn = h('button', { class: 'btn-ghost btn-sm', type: 'button', disabled: podeMarcarEstagio ? null : 'disabled', onclick: async () => { - if (!stageSelect.value) return; - await API.post(`/api/campaigns/leads/${linha.lead_id}/estagio`, { stage: stageSelect.value, campaignId: campanhaId }); - toast('Estagio atualizado'); - if (stageSelect.value === 'demonstracao_agendada') { - const dataAgendamento = prompt('Data/hora do agendamento (AAAA-MM-DD HH:MM):'); - if (dataAgendamento) { - await API.post(`/api/campaigns/leads/${linha.lead_id}/agendamentos`, { kind: 'demonstracao', scheduledAt: dataAgendamento }); - toast('Agendamento registrado'); + try { + if (!stageSelect.value) return; + await API.post(`/api/campaigns/leads/${linha.lead_id}/estagio`, { stage: stageSelect.value, campaignId: campanhaId }); + toast('Estagio atualizado'); + if (stageSelect.value === 'demonstracao_agendada') { + const dataAgendamento = prompt('Data/hora do agendamento (AAAA-MM-DD HH:MM):'); + if (dataAgendamento) { + await API.post(`/api/campaigns/leads/${linha.lead_id}/agendamentos`, { kind: 'demonstracao', scheduledAt: dataAgendamento }); + toast('Agendamento registrado'); + } } + } catch (error) { + toast(`Erro: ${error.message}`); } } }, 'Marcar');