Coleta de Dados Planejamento

Coleta de dados

Preencha o formulário para que possamos elaborar um planejamento financeiro feito sob medida para você.

(Para voltar para o passo anterior, pressione ‘ESC’)

IMÓVEL:

`; return grupo; } // Preparar grupo inicial (#1) prepararGrupo(document.querySelector('.casa-group[data-indice="1"]'), 1); // Adicionar adicionarCasaBtn.addEventListener('click', () => { contadorCasa++; const novoGrupo = construirGrupoCasa(contadorCasa); // insere antes da barra de botões const barra = wrapperCasa.querySelector('div[style*="text-align: right"]'); wrapperCasa.insertBefore(novoGrupo, barra); prepararGrupo(novoGrupo, contadorCasa); }); // Remover removerCasaBtn.addEventListener('click', () => { const grupos = wrapperCasa.querySelectorAll('.casa-group'); if (grupos.length > 1) { grupos[grupos.length - 1].remove(); contadorCasa--; } }); });

DÍVIDA:

INVESTIMENTOS:

FILHOS:

APOSENTADORIA:

PROTEÇÃO:

FLUXO DE CAIXA:

Uso do cartão de crédito

FLUXO DE CAIXA:

Gastos fixos essenciais

FLUXO DE CAIXA:

Gastos fixos recorrentes

FLUXO DE CAIXA:

Gastos variáveis

FLUXO DE CAIXA:

Valores destinados ao futuro

Total mensal de gastos:

Total anual de gastos:

FLUXO DE CAIXA:

Renda

FLUXO DE CAIXA:

Renda Cônjuge

FLUXO DE CAIXA:

Resumo

GASTO ATUAL
GASTO IDEAL

Receita bruta anual:

Receita líquida anual:

Total anual de gastos:

Diferença:

RECOMENDAÇÃO:

proposta comercial

Receita bruta anual:

À vista

R$ 3.500,00

Parcelado

R$ 3.500,00

Valor da Parcela:

Valor

R$ 3.500,00

Parcela:

Parcela:

Parcela:

Parcela:

REVISÃO DE DADOS PESSOAIS

Revise seus dados pessoais

Formulário de Contrato

Valor: ${formatarMoeda(seg.valor)}
Participação: ${pct}%
`; tooltipGastos.style.borderColor = CATEGORIAS_CORES[seg.cat]; const offset = 14; tooltipGastos.style.left = (e.clientX + offset) + 'px'; tooltipGastos.style.top = (e.clientY + offset) + 'px'; tooltipGastos.style.display = 'block'; }); canvas.addEventListener('mouseleave', ()=> tooltipGastos.style.display='none'); } // ------- HELPERS DE LEITURA ------- function parseValorCampo(inputEl) { if (!inputEl || !inputEl.value) return 0; const val = inputEl.value.replace(/[R$\s.]/g, '').replace(',', '.'); const num = parseFloat(val); return isNaN(num) ? 0 : num; } function somarListaIdsBasica(ids) { // Soma campos que NÃO são dinâmicos (sem sufixo -N) let soma = 0; ids.forEach(id => { const isDinamico = IDS_DINAMICOS_PREFIX.some(pref => id === `form-field-${pref}`); if (isDinamico) return; // dinâmicos serão somados à parte const el = document.getElementById(id); soma += parseValorCampo(el); }); return soma; } function somarIdsDinamicosSeExistirem(ids) { let soma = 0; ids.forEach(id => { const match = id.match(/^form-field-(\d+)/); if (!match) return; const numero = match[1]; if (!IDS_DINAMICOS_PREFIX.includes(numero)) return; // pega todos que começam com esse prefixo (com e sem -N) document.querySelectorAll(`input[id^="form-field-${numero}"]`).forEach(el => { soma += parseValorCampo(el); }); }); return soma; } // ------- TOTALIZAR POR CATEGORIA ------- function totalizarCategoriasGastos() { // mantém os IDs como você já tinha const base = { essenciais: ['form-field-276','form-field-277_1','form-field-277_2','form-field-277_3','form-field-279', 'form-field-396'], recorrentes: ['form-field-280','form-field-281','form-field-282','form-field-283','form-field-284','form-field-285','form-field-391','form-field-287'], variaveis: ['form-field-288','form-field-289','form-field-290','form-field-291','form-field-292','form-field-293','form-field-294','form-field-296'], futuro: ['form-field-297','form-field-298','form-field-299','form-field-300','form-field-302'] }; const IDS_DINAMICOS_PREFIX = ['279','287','296','302']; function parseValorCampo(inputEl) { if (!inputEl || !inputEl.value) return 0; const val = inputEl.value.replace(/[R$\s.]/g, '').replace(',', '.'); const num = parseFloat(val); return isNaN(num) ? 0 : num; } function somaGrupo(ids) { let soma = 0; ids.forEach(id => { const isDinamico = IDS_DINAMICOS_PREFIX.some(pref => id === `form-field-${pref}`); if (isDinamico) return; const el = document.getElementById(id); soma += parseValorCampo(el); }); // somar clones dinâmicos (ex.: 279-1, 279-2…) ids.forEach(id => { const m = id.match(/^form-field-(\d+)/); if (!m) return; const n = m[1]; if (!IDS_DINAMICOS_PREFIX.includes(n)) return; document.querySelectorAll(`input[id^="form-field-${n}"]`).forEach(el => { soma += parseValorCampo(el); }); }); return soma; } const totaisRaw = { essenciais: somaGrupo(base.essenciais), recorrentes: somaGrupo(base.recorrentes), variaveis: somaGrupo(base.variaveis), futuro: somaGrupo(base.futuro) }; const totais = { fixo: (totaisRaw.essenciais || 0) + (totaisRaw.recorrentes || 0), variaveis: totaisRaw.variaveis || 0, futuro: totaisRaw.futuro || 0 }; const totalGeral = Object.values(totais).reduce((a, v) => a + v, 0); return { totais, totalGeral }; } function anexarTooltipDonut(canvasId){ const canvas = document.getElementById(canvasId); if (!canvas) return; // evita listeners duplicados if (canvas.dataset.tooltipReady === '1') return; canvas.dataset.tooltipReady = '1'; canvas.addEventListener('mousemove', (e) => { const segmentos = segmentosPorCanvas[canvasId] || []; if (!segmentos.length) { tooltipGastos.style.display = 'none'; return; } const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; const scaleY = canvas.height / rect.height; const x = (e.clientX - rect.left) * scaleX; const y = (e.clientY - rect.top) * scaleY; const w = canvas.width, h = canvas.height; const cx = w/2, cy = h/2; const rOuter = Math.min(w, h) * 0.45; const rInner = rOuter * 0.60; const dx = x - cx, dy = y - cy; const dist = Math.hypot(dx, dy); if (dist rOuter){ tooltipGastos.style.display='none'; return; } let ang = Math.atan2(dy, dx); if (ang ang >= s.start && ang Categoria: ${NOME_CATEGORIA[seg.cat]}
Valor: ${formatarMoeda(seg.valor)}
Participação: ${pct}%
`; tooltipGastos.style.borderColor = CATEGORIAS_CORES[seg.cat]; const offset = 14; tooltipGastos.style.left = (e.clientX + offset) + 'px'; tooltipGastos.style.top = (e.clientY + offset) + 'px'; tooltipGastos.style.display = 'block'; }); canvas.addEventListener('mouseleave', ()=> tooltipGastos.style.display='none'); } // ------- DESENHAR DONUT (CANVAS PURO) ------- function desenharDonutGenerico({ canvasId, legendaId, totais, totalGeral }){ const canvas = document.getElementById(canvasId); const legenda = document.getElementById(legendaId); if (!canvas || !canvas.getContext) return; const ctx = canvas.getContext('2d'); const w = canvas.width, h = canvas.height; const cx = w/2, cy = h/2; const rOuter = Math.min(w, h) * 0.45; const rInner = rOuter * 0.60; ctx.clearRect(0,0,w,h); segmentosPorCanvas[canvasId] = []; if (!totalGeral || totalGeral Preencha seus gastos para ver o gráfico.'; return; } let anguloAtual = -Math.PI/2; const ordem = ['fixo','variaveis','futuro']; ordem.forEach(cat=>{ const valor = totais[cat] || 0; if (valor { const valor = totais[cat] || 0; if (valor { const input = document.getElementById(id); if (!input || !input.value) return; const valor = input.value.replace(/[R$\s.]/g, '').replace(',', '.'); const numero = parseFloat(valor); if (!isNaN(numero)) { if (idsBrutosAnuais.includes(id)) { total += numero / 12; } else { total += numero; } } }); receitaBrutaAnualGlobal = total * 12; const valorFinal = `${formatarMoeda(total)}`; campoReceitaBruta.innerHTML = `Receita bruta mensal: ${valorFinal}`; // Atualiza receita bruta anual const campoReceitaBrutaAnual = document.querySelector('[data-id="71b80110"] .elementor-heading-title'); if (campoReceitaBrutaAnual) { campoReceitaBrutaAnual.innerHTML = `Receita bruta anual: ${formatarMoeda(receitaBrutaAnualGlobal)}`; } atualizarValorTresPorCento(); } function atualizarValorTresPorCento() { const campoTresPorCento = document.querySelector('[data-id="71b80111"] .elementor-heading-title'); const campoParcelado = document.querySelector('[data-id="71b80112"] .elementor-heading-title'); const campoValorParcela = document.querySelector('[data-id="71b80113"] .elementor-heading-title'); if (!campoTresPorCento || !campoParcelado || !campoValorParcela) return; const inputPrecoEditado = document.getElementById('form-field-precoEditado'); let base = receitaBrutaAnualGlobal * 0.033; if (base { const sels = Array.from(document.querySelectorAll( 'select#form-field-meioPagamentoParcelado, select[name="form_fields[meioPagamentoParcelado]"]' )); return sels.find(s => s.offsetParent !== null) || sels[0] || null; })(); const valorSelecionado = seletorParcelado?.value || ''; if (valorSelecionado) { numeroParcelas = parseInt(valorSelecionado.replace('x', ''), 10); if (!isNaN(numeroParcelas) && numeroParcelas >= 2 && numeroParcelas 0) { const valorParcela = valorFinalParcelado / numeroParcelas; campoValorParcela.innerHTML = `Valor da Parcela: ${formatarMoeda(valorParcela)}`; } else { campoValorParcela.innerHTML = `Valor da Parcela: -`; } // ✅ recalc leve (1 por frame) do multi if (typeof window.__avelRecalcMulti === 'function') { window.__avelRecalcMulti(0); } } // ====== MULTI PAGAMENTO (ÚNICO): permite editar "Valor" + BRL + validação soma vs 71b80117 ====== (function () { const PERCENTUAIS_PARCELADO = { 2: 0.0515, 3: 0.0565, 4: 0.0635, 5: 0.0696, 6: 0.0757, 7: 0.0856, 8: 0.0918, 9: 0.0981, 10: 0.1044, 11: 0.1107, 12: 0.1171 }; const brl = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', minimumFractionDigits: 2 }); function formatBRLFromCents(cents) { return brl.format((Number(cents || 0)) / 100); } function parseBRLToCents(str) { if (!str) return 0; const digits = String(str).replace(/\D/g, ''); return digits ? parseInt(digits, 10) : 0; } function getInBoxVisible(box, selector) { if (!box) return null; const list = Array.from(box.querySelectorAll(selector)); return list.find(el => el.offsetParent !== null) || list[0] || null; } function getSelectVisivel(selector) { const sels = Array.from(document.querySelectorAll(selector)); return sels.find(s => s.offsetParent !== null) || sels[0] || null; } function getMetodosAtivos() { const selQtd = getSelectVisivel('select#form-field-MaismeioPagamento, select[name="form_fields[MaismeioPagamento]"]'); const val = selQtd?.value || ''; const m = String(val).match(/\d/); const qtd = m ? parseInt(m[0], 10) : 0; if (qtd === 2) return [2, 3]; if (qtd === 3) return [2, 3, 4]; if (qtd >= 4) return [2, 3, 4, 5]; return []; } function feeCentsForMethod(baseParteCents, metodo, parcelasValue, parcelasVisivel) { const met = String(metodo || '').toUpperCase(); if (met === 'PIX') return 149; if (met === 'BOLETO') return 189; if (met === 'CREDIT_CARD') { if (parcelasVisivel) { const n = parseInt(String(parcelasValue || '').replace(/\D/g, ''), 10); if (!isNaN(n) && n >= 2 && n 0 falta | 0 ? '-' : '+'; el.style.color = '#f50062'; el.style.color = '#f50062'; el.innerHTML = `${totalFmt} ( ${sinal} ${diffAbsFmt} )`; } // ===== estado (pra não recalcular pesado ao digitar no input) ===== const STATE = (window.__avelMultiState = window.__avelMultiState || { lastTotalFinalCents: 0 }); function mascararBRLNoInput(input) { if (!input) return; const cents = parseBRLToCents(input.value); input.value = cents ? formatBRLFromCents(cents) : ''; } // Atualiza SÓ a validação (não repovoa inputs) + ✅ atualiza "Parcela:" baseado no valor digitado function validarSomente() { const ativos = getMetodosAtivos(); let somaInputsCents = 0; ativos.forEach((n) => { const box = document.querySelector(`[class~="${n}metodoPagamento"]`); if (!box) return; const inputValor = getInBoxVisible( box, `input#form-field-${n}valorPagamento, input[name="form_fields[${n}valorPagamento]"]` ); const selectMetodo = getInBoxVisible( box, `select#form-field-${n}maisPagamento, select[name="form_fields[${n}maisPagamento]"]` ); const selectParcelas = getInBoxVisible( box, `select#form-field-${n}maisPagamentoParcelas, select[name="form_fields[${n}maisPagamentoParcelas]"]` ); const valorInputCents = inputValor ? parseBRLToCents(inputValor.value) : 0; somaInputsCents += valorInputCents; // ✅ Atualiza "Parcela:" com base no VALOR DIGITADO const metUpper = String(selectMetodo?.value || '').toUpperCase(); const parcelasVisivel = !!(selectParcelas && selectParcelas.offsetParent !== null); const parcelasValue = selectParcelas?.value || ''; if (metUpper === 'CREDIT_CARD' && parcelasVisivel) { const numParc = parseInt(String(parcelasValue || '').replace(/\D/g, ''), 10); if (!isNaN(numParc) && numParc >= 2 && numParc 0) { const parcelaCents = Math.round(valorInputCents / numParc); setParcelaHeading( n, box, `Parcela: ${formatBRLFromCents(parcelaCents)}` ); } else { setParcelaHeading(n, box, `Parcela: -`); } } else { setParcelaHeading(n, box, `Parcela: -`); } }); setHeading(STATE.lastTotalFinalCents, somaInputsCents); } function atualizarParcelasSomente() { const ativos = getMetodosAtivos(); ativos.forEach((n) => { const box = document.querySelector(`[class~="${n}metodoPagamento"]`); if (!box) return; const inputValor = getInBoxVisible( box, `input#form-field-${n}valorPagamento, input[name="form_fields[${n}valorPagamento]"]` ); const selectMetodo = getInBoxVisible( box, `select#form-field-${n}maisPagamento, select[name="form_fields[${n}maisPagamento]"]` ); const selectParcelas = getInBoxVisible( box, `select#form-field-${n}maisPagamentoParcelas, select[name="form_fields[${n}maisPagamentoParcelas]"]` ); const metUpper = String(selectMetodo?.value || '').toUpperCase(); const parcelasVisivel = !!(selectParcelas && selectParcelas.offsetParent !== null); const parcelasValue = selectParcelas?.value || ''; const valorInputCents = inputValor ? parseBRLToCents(inputValor.value) : 0; if (metUpper === 'CREDIT_CARD' && parcelasVisivel) { const numParc = parseInt(String(parcelasValue || '').replace(/\D/g, ''), 10); if (!isNaN(numParc) && numParc >= 2 && numParc 0) { const parcelaCents = Math.round(valorInputCents / numParc); setParcelaHeading( n, box, `Parcela: ${formatBRLFromCents(parcelaCents)}` ); } else { setParcelaHeading(n, box, `Parcela: -`); } } else { setParcelaHeading(n, box, `Parcela: -`); } }); } const PARCELA_HEADING_DATAID = { 2: '271b80113', 3: '371b80113', 4: '471b80113', 5: '571b80113' }; function setParcelaHeading(nMetodo, box, texto) { const dataId = PARCELA_HEADING_DATAID[nMetodo]; if (!dataId) return; // tenta primeiro dentro da box (mais seguro) const el = (box && box.querySelector(`[data-id="${dataId}"] .elementor-heading-title`)) || document.querySelector(`[data-id="${dataId}"] .elementor-heading-title`); if (el) el.innerHTML = texto; } // Atualização completa (recalcula taxas e, se permitido, autopreenche) function atualizarUIValores(baseTotal) { const ativos = getMetodosAtivos(); const qtd = ativos.length; if (!qtd) return; const baseTotalCents = Math.round(Number(baseTotal || 0) * 100); if (!baseTotalCents || baseTotalCents { const box = document.querySelector(`[class~="${n}metodoPagamento"]`); if (!box) return; const baseParteCents = baseParteCentsBase + (idx = 2 && numParc ${formatBRLFromCents(parcelaCents)}` ); } else { setParcelaHeading(n, box, `Parcela: -`); } } else { setParcelaHeading(n, box, `Parcela: -`); } }); STATE.lastTotalFinalCents = totalFinalCents; setHeading(totalFinalCents, somaInputsCents); } function setHeading(totalCents, somaInputsCents) { const el = document.querySelector('[data-id="71b80117"] .elementor-heading-title'); if (!el) return; const diff = totalCents - somaInputsCents; // >0 falta | 0 ? '-' : '+'; el.style.color = '#f50062'; el.innerHTML = `${totalFmt} ( ${sinal} ${diffAbsFmt} )`; el.dataset.invalid = '1'; // ✅ if (typeof window.atualizarOpacidadeBtn === 'function') window.atualizarOpacidadeBtn(); // ✅ } // scheduler leve let raf = 0; function scheduleFullRecalc() { if (raf) cancelAnimationFrame(raf); raf = requestAnimationFrame(() => { const base = Number(window.__avelBasePrecoAtual || 0); if (!base || base recalcula completo (taxas) document.addEventListener('change', (e) => { const t = e.target; if (!t) return; if (t.matches('select#form-field-MaismeioPagamento, select[name="form_fields[MaismeioPagamento]"]')) { scheduleFullRecalc(); return; } if (t.matches('select[id^="form-field-"][id$="maisPagamento"], select[id^="form-field-"][id$="maisPagamentoParcelas"]')) { scheduleFullRecalc(); // ✅ depois do recalculo (no próximo frame), atualiza "Parcela:" com base no valor atual do input requestAnimationFrame(() => { atualizarParcelasSomente(); validarSomente(); // mantém a validação/heading total coerente }); return; } }, true); // 2) Usuário editou input "Valor" => marca manual e só valida (não sobrescreve) document.addEventListener('input', (e) => { const t = e.target; if (!t) return; if (t.matches('input[id^="form-field-"][id$="valorPagamento"], input[name^="form_fields["][name$="valorPagamento]"]')) { t.dataset.manual = '1'; // NÃO mascara aqui (pra não brigar com o cursor). Só valida. validarSomente(); } }, true); // 3) Ao sair do input, aplica máscara BRL e valida document.addEventListener('blur', (e) => { const t = e.target; if (!t) return; if (t.matches('input[id^="form-field-"][id$="valorPagamento"], input[name^="form_fields["][name$="valorPagamento]"]')) { mascararBRLNoInput(t); validarSomente(); } }, true); // bootstrap scheduleFullRecalc(); })(); // ====== Listeners dos seletores (com select visível no parcelado) ====== const seletorPagamento = document.getElementById('form-field-meioPagamentoAVista'); if (seletorPagamento) { seletorPagamento.addEventListener('change', atualizarValorTresPorCento); } const seletorParceladoVisivel = (() => { const sels = Array.from(document.querySelectorAll( 'select#form-field-meioPagamentoParcelado, select[name="form_fields[meioPagamentoParcelado]"]' )); return sels.find(s => s.offsetParent !== null) || sels[0] || null; })(); if (seletorParceladoVisivel) { seletorParceladoVisivel.addEventListener('change', atualizarValorTresPorCento); } // Executa ao carregar a página somarRendas(); const inputPrecoEditado = document.getElementById('form-field-precoEditado'); if (inputPrecoEditado) { inputPrecoEditado.addEventListener('blur', atualizarValorTresPorCento); inputPrecoEditado.addEventListener('change', atualizarValorTresPorCento); } [...idsBrutosMensais, ...idsBrutosAnuais].forEach(id => { const input = document.getElementById(id); if (input) { input.addEventListener('input', somarRendas); } }); function somarGastos() { let total = 0; coletarIdsGastos().forEach(id => { const input = document.getElementById(id); if (!input) return; const valor = input.value.replace(/[R$\s.]/g, '').replace(',', '.'); const numero = parseFloat(valor); if (!isNaN(numero)) total += numero; }); const valorMensal = `${formatarMoeda(total)}`; const valorAnual = `${formatarMoeda(total * 12)}`; campoMensal.innerHTML = `Total mensal de gastos: ${valorMensal}`; campoAnual.innerHTML = `Total anual de gastos: ${valorAnual}`; campoTotalAnualExtra.innerHTML = `Total mensal de gastos: ${valorMensal}`; ultimoTotalGastos = total; atualizarDiferencaReceitaGastos(ultimoTotalReceitaLiquida, ultimoTotalGastos); atualizarGraficoGastos(); } document.addEventListener('input', (e) => { if (e.target.matches( `input[id^="form-field-279"], input[id^="form-field-287"], input[id^="form-field-296"], input[id^="form-field-302"]` )) { somarGastos(); calcularReceitaLiquidaMensal(); atualizarGraficoGastos(); } }); function calcularReceitaLiquidaMensal() { let totalLiquido = 0; // Rendas líquidas mensais (somadas direto) idsLiquidoMultiplica12.forEach(id => { const input = document.getElementById(id); if (!input) return; const valor = input.value.replace(/[R$\s.]/g, '').replace(',', '.'); const numero = parseFloat(valor); if (!isNaN(numero)) totalLiquido += numero; }); // Rendas brutas adicionais com ou sem desconto de IR idsLiquidoDescontar.forEach(id => { const input = document.getElementById(id); if (!input) return; const valor = input.value.replace(/[R$\s.]/g, '').replace(',', '.'); const numero = parseFloat(valor); if (!isNaN(numero)) { if(id === 'form-field-308' || id === 'form-field-318') { // 308 e 318 são mensais, sem desconto de IR totalLiquido += numero; } else if(id === 'form-field-310' || id === 'form-field-320') { // 310 e 320 são anuais, sem desconto de IR -> dividir por 12 totalLiquido += numero / 12; } else if(id === 'form-field-309' || id === 'form-field-311' || id === 'form-field-319' || id === 'form-field-321') { // Estes campos são tratados como mensais brutos, aplicar IR diretamente totalLiquido += numero * 0.725; } else { // Demais continuam sendo anuais com desconto IR dividido por 12 totalLiquido += (numero * 0.725) / 12; } } }); const valorFormatado = `${formatarMoeda(totalLiquido)}`; campoReceitaLiquida.innerHTML = `Receita líquida mensal: ${valorFormatado}`; ultimoTotalReceitaLiquida = totalLiquido; atualizarDiferencaReceitaGastos(ultimoTotalReceitaLiquida, ultimoTotalGastos); } function atualizarDiferencaReceitaGastos(receitaLiquida, gastosAnuais) { const diferenca = receitaLiquida - gastosAnuais; const valorFormatado = `${formatarMoeda(diferenca)}`; campoDiferenca.innerHTML = `Diferença mensal: ${valorFormatado}`; } function precisaRecalcular(el) { if (!el || el.tagName !== 'INPUT') return false; const id = el.id || ''; // Dinâmicos: 279, 287, 296, 302 — com ou sem sufixo -N const dinamicos = /^(form-field-(279|287|296|302))(?:-\d+)?$/; return dinamicos.test(id) || baseIdsGastos.includes(id) || idsLiquidoMultiplica12.includes(id) || idsLiquidoDescontar.includes(id); } document.addEventListener('input', (e) => { if (precisaRecalcular(e.target)) { somarGastos(); calcularReceitaLiquidaMensal(); } }); // Executar ao carregar somarGastos(); calcularReceitaLiquidaMensal(); function atualizarObrigatoriedadeCampos() { Object.entries(camposObrigatoriosPorObjetivo).forEach(([checkboxValue, inputId]) => { const checkbox = document.querySelector(`input[type="checkbox"][value="${checkboxValue}"]`); const input = document.getElementById(inputId); const container = input?.closest('.elementor-field-group'); if (checkbox && input && container) { if (checkbox.checked) { input.setAttribute('required', 'required'); input.setAttribute('aria-required', 'true'); container.classList.add('elementor-field-required'); } else { input.removeAttribute('required'); input.removeAttribute('aria-required'); container.classList.remove('elementor-field-required'); } } }); } // Executa ao carregar atualizarObrigatoriedadeCampos(); // ====== BLOCO DE SELEÇÃO DE PAGAMENTO (AVista, Parcelado, MaisPagamento) ====== const conteinerAVista = document.querySelector('.conteinerAVista'); const conteinerParcelado = document.querySelector('.conteinerParcelado'); const conteinerMaisPagamento = document.querySelector('.conteinerMaisPagamento'); const formAVista = document.getElementById('formsAvista'); const formParcelado = document.getElementById('formsParcelado'); // Internos da box "Mais Pagamentos" const formMaisPagamentoInternos = [ document.getElementById('metodoMaisPagamento'), document.getElementById('2metodo'), document.getElementById('3metodo'), document.getElementById('4metodo'), document.getElementById('5metodo'), document.getElementById('2Parcelado'), document.getElementById('3Parcelado'), document.getElementById('4Parcelado'), document.getElementById('5Parcelado'), ].filter(Boolean); const btnContrato = document.getElementById('btncontrato'); // Garante transição suave no botão if (btnContrato) { btnContrato.style.transition = 'opacity 1s ease, pointer-events 1s ease'; btnContrato.style.opacity = '0'; btnContrato.style.pointerEvents = 'none'; } // Lista única de containers de pagamento const containersPagamento = [ conteinerAVista, conteinerParcelado, conteinerMaisPagamento ].filter(Boolean); // Atualiza opacidade e interatividade do botão function atualizarOpacidadeBtn() { if (!btnContrato) return; const elTotal = document.querySelector('[data-id="71b80117"] .elementor-heading-title'); const avistaAtivo = !!conteinerAVista && conteinerAVista.classList.contains('ativo'); const parceladoAtivo = !!conteinerParcelado && conteinerParcelado.classList.contains('ativo'); const maisPagAtivo = !!conteinerMaisPagamento && conteinerMaisPagamento.classList.contains('ativo'); // inválido quando multi está vermelho / com diff const totalInvalido = !!elTotal && ( elTotal.dataset.invalid === '1' || getComputedStyle(elTotal).color === 'rgb(245, 0, 98)' // #f50062 ); // ✅ regra final: // - À vista OU Parcelado: botão aparece direto // - Mais Pagamento: só aparece se NÃO estiver inválido const deveMostrar = avistaAtivo || parceladoAtivo || (maisPagAtivo && !totalInvalido); btnContrato.style.opacity = deveMostrar ? '1' : '0'; btnContrato.style.pointerEvents = deveMostrar ? 'auto' : 'none'; } // ✅ MUITO IMPORTANTE: deixa global pro setHeading conseguir esconder/mostrar ao mudar o total window.atualizarOpacidadeBtn = atualizarOpacidadeBtn; // Alterna o estado do container clicado (suporta 3 opções) function alternarAtivoPagamento(clicado) { const jaAtivo = clicado.classList.contains('ativo'); if (jaAtivo) { // Se clicar novamente no ativo, desativa todos containersPagamento.forEach(c => c.classList.remove('ativo')); } else { // Ativa apenas o clicado containersPagamento.forEach(c => c.classList.toggle('ativo', c === clicado) ); } atualizarOpacidadeBtn(); } // Helper: só alterna se o clique NÃO foi dentro de nenhum interno function bindCliqueContainer(container, internos = []) { if (!container) return; const listaInternos = Array.isArray(internos) ? internos : [internos]; container.addEventListener('click', (e) => { const clicouDentroInterno = listaInternos.some( el => el && el.contains(e.target) ); if (clicouDentroInterno) return; alternarAtivoPagamento(container); }); } // ====== TOGGLE MAIS PAGAMENTO (corrigindo display original) ====== const btnMaisPag = document.querySelector('.btnmaispag'); const containerPagamento = document.querySelector('.containerPagamento'); // ⚠️ aqui você NÃO declara conteinerMaisPagamento de novo (você já tem no script) // usa a variável existente: conteinerMaisPagamento if (btnMaisPag && conteinerMaisPagamento && containerPagamento) { const btnWrapper = btnMaisPag.closest('.btnmaispag') || btnMaisPag; // --- salva o display original do MaisPagamento (flex/grid/etc) --- if (!conteinerMaisPagamento.dataset.displayOriginal) { const displayAtual = getComputedStyle(conteinerMaisPagamento).display; // se por acaso já estiver "none" no load, usa flex como fallback conteinerMaisPagamento.dataset.displayOriginal = (displayAtual && displayAtual !== 'none') ? displayAtual : 'flex'; } function esconderContainerPagamentoSemSumirBotao() { Array.from(containerPagamento.children).forEach((child) => { if (child.contains(btnWrapper)) return; if (!child.dataset._displayOriginal) { child.dataset._displayOriginal = getComputedStyle(child).display; } child.style.pointerEvents = 'none'; child.style.display = 'none'; }); containerPagamento.style.pointerEvents = 'none'; btnWrapper.style.pointerEvents = 'auto'; } function mostrarContainerPagamentoDeNovo() { Array.from(containerPagamento.children).forEach((child) => { if (child.contains(btnWrapper)) return; const original = child.dataset._displayOriginal || 'block'; child.style.display = original; child.style.pointerEvents = 'auto'; }); containerPagamento.style.pointerEvents = 'auto'; } // Estado inicial do MaisPagamento (oculto, mas mantendo displayOriginal salvo) conteinerMaisPagamento.style.display = 'none'; conteinerMaisPagamento.style.opacity = '0'; conteinerMaisPagamento.style.pointerEvents = 'none'; conteinerMaisPagamento.style.transition = 'opacity 0.5s ease'; conteinerMaisPagamento.dataset.aberto = conteinerMaisPagamento.dataset.aberto || '0'; function abrirMaisPagamento() { esconderContainerPagamentoSemSumirBotao(); // ✅ volta com o display correto (flex/grid) conteinerMaisPagamento.style.display = conteinerMaisPagamento.dataset.displayOriginal; // reflow p/ transição void conteinerMaisPagamento.offsetHeight; conteinerMaisPagamento.style.opacity = '1'; conteinerMaisPagamento.style.pointerEvents = 'auto'; conteinerMaisPagamento.dataset.aberto = '1'; } function fecharMaisPagamento() { conteinerMaisPagamento.style.opacity = '0'; conteinerMaisPagamento.style.pointerEvents = 'none'; conteinerMaisPagamento.dataset.aberto = '0'; setTimeout(() => { if (conteinerMaisPagamento.dataset.aberto === '0') { conteinerMaisPagamento.style.display = 'none'; } }, 500); mostrarContainerPagamentoDeNovo(); } btnMaisPag.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const aberto = conteinerMaisPagamento.dataset.aberto === '1'; if (aberto) fecharMaisPagamento(); else abrirMaisPagamento(); }); } // ====== MÉTODOS DE PAGAMENTO (2/3/4) - FUNCIONA COM IDs DUPLICADOS (Elementor) ====== (function () { const SELECT_CSS = 'select#form-field-MaismeioPagamento, select[name="form_fields[MaismeioPagamento]"]'; function firstByClass(cls) { return document.getElementsByClassName(cls)[0] || null; } function saveDisplay(el) { if (!el) return; if (!el.dataset._displayOriginal) { const d = getComputedStyle(el).display; el.dataset._displayOriginal = (d && d !== 'none') ? d : 'flex'; // seus containers são e-flex } } function hide(el) { if (!el) return; saveDisplay(el); el.style.display = 'none'; el.style.pointerEvents = 'none'; } function show(el) { if (!el) return; saveDisplay(el); el.style.display = el.dataset._displayOriginal || 'flex'; el.style.pointerEvents = 'auto'; } function extrairNumero(valor) { // "2 Métodos de Pagamento" -> 2 const m = String(valor || '').match(/\d/); return m ? parseInt(m[0], 10) : null; } function aplicarPorQuantidade(qtd) { const c2 = firstByClass('2metodoPagamento'); const c3 = firstByClass('3metodoPagamento'); const c4 = firstByClass('4metodoPagamento'); const c5 = firstByClass('5metodoPagamento'); const wrap45 = document.querySelector('.metodoPagamento4e5'); // padrão: tudo oculto hide(c2); hide(c3); hide(c4); hide(c5); hide(wrap45); if (!qtd) return; // SUA LÓGICA ATUAL if (qtd === 2) { show(c2); show(c3); return; } if (qtd === 3) { show(c2); show(c3); show(wrap45); show(c4); hide(c5); return; } // qtd === 4 if (qtd >= 4) { show(c2); show(c3); show(wrap45); show(c4); show(c5); return; } } // pega o select VISÍVEL quando houver duplicados function getSelectVisivel() { const sels = Array.from(document.querySelectorAll(SELECT_CSS)); if (!sels.length) return null; // prioriza o que está visível (offsetParent != null) const visivel = sels.find(s => s.offsetParent !== null); return visivel || sels[0]; } function atualizarAPartirDoSelect(sel) { const qtd = extrairNumero(sel?.value); aplicarPorQuantidade(qtd); } // 1) EVENT DELEGATION: pega exatamente o select que o usuário mudou (mesmo com ID duplicado) document.addEventListener('change', (e) => { const t = e.target; if (t && t.matches && t.matches(SELECT_CSS)) { setTimeout(() => atualizarAPartirDoSelect(t), 0); } }, true); document.addEventListener('input', (e) => { const t = e.target; if (t && t.matches && t.matches(SELECT_CSS)) { setTimeout(() => atualizarAPartirDoSelect(t), 0); } }, true); // 2) bootstrap inicial (quando a tela abre / Elementor renderiza) function bootstrap() { const sel = getSelectVisivel(); if (sel) atualizarAPartirDoSelect(sel); } setTimeout(bootstrap, 0); // 3) fallback curto (Elementor cria/duplica elementos depois) let tent = 0; const timer = setInterval(() => { bootstrap(); tent++; if (tent >= 60) clearInterval(timer); // ~6s }, 100); })(); // ====== PARCELADO: OCULTAR POR PADRÃO + MOSTRAR SÓ SE CREDIT_CARD (fix classe numérica) ====== (function () { const REGRAS = [ { selectId: 'form-field-2maisPagamento', boxSel: '[class~="2metodoPagamento"]', parceladoFormId: '2Parcelado', headingSel: '.elementor-element-270b80113' }, { selectId: 'form-field-3maisPagamento', boxSel: '[class~="3metodoPagamento"]', parceladoFormId: '3Parcelado', headingSel: '.elementor-element-370b80113' }, { selectId: 'form-field-4maisPagamento', boxSel: '[class~="4metodoPagamento"]', parceladoFormId: '4Parcelado', headingSel: '.elementor-element-470b80113' }, { selectId: 'form-field-5maisPagamento', boxSel: '[class~="5metodoPagamento"]', parceladoFormId: '5Parcelado', headingSel: '.elementor-element-570b80113' } ]; function esconder(el) { if (!el) return; el.style.setProperty('display', 'none', 'important'); el.style.setProperty('pointer-events', 'none', 'important'); el.style.setProperty('visibility', 'hidden', 'important'); el.style.setProperty('opacity', '0', 'important'); } function mostrar(el, fallbackDisplay = 'block') { if (!el) return; if (!el.dataset._displayOriginal) { const d = getComputedStyle(el).display; el.dataset._displayOriginal = (d && d !== 'none') ? d : fallbackDisplay; } el.style.setProperty('display', el.dataset._displayOriginal, 'important'); el.style.setProperty('pointer-events', 'auto', 'important'); el.style.setProperty('visibility', 'visible', 'important'); el.style.setProperty('opacity', '1', 'important'); } function getTargets(cfg) { const box = document.querySelector(cfg.boxSel); // form Parcelado dentro da box const form = box ? box.querySelector(`#${CSS.escape(cfg.parceladoFormId)}`) : document.getElementById(cfg.parceladoFormId); const formWrap = form ? form.closest('.elementor-widget-form') : null; // heading "Parcela:" dentro da box const heading = box ? box.querySelector(cfg.headingSel) : document.querySelector(cfg.headingSel); const headingWrap = heading ? heading.closest('.elementor-element') : null; return { box, form, formWrap, heading, headingWrap }; } function esconderPadraoTudo() { REGRAS.forEach(cfg => { const { formWrap, headingWrap } = getTargets(cfg); esconder(formWrap); esconder(headingWrap); }); } function aplicar(cfg) { const select = document.getElementById(cfg.selectId); if (!select) return; const { formWrap, headingWrap } = getTargets(cfg); const isCartao = (select.value || '').toUpperCase() === 'CREDIT_CARD'; if (isCartao) { // widget-form normalmente é block (mas pode ser flex) mostrar(formWrap, 'block'); mostrar(headingWrap, 'block'); } else { esconder(formWrap); esconder(headingWrap); } } // 1) some com tudo no início (mesmo se Elementor vier setando display inline) esconderPadraoTudo(); // 2) aplica estado inicial conforme selects já setados setTimeout(() => { REGRAS.forEach(aplicar); }, 0); // 3) ao mudar o select, atualiza imediatamente document.addEventListener('change', (e) => { const t = e.target; if (!t || !t.id) return; const cfg = REGRAS.find(r => r.selectId === t.id); if (!cfg) return; aplicar(cfg); }, true); // 4) Elementor pode re-renderizar e reexibir: garante re-hide + reaplica const obs = new MutationObserver(() => { esconderPadraoTudo(); REGRAS.forEach(aplicar); }); obs.observe(document.body, { childList: true, subtree: true }); })(); // Bind dos containers (SEM duplicar listeners) bindCliqueContainer(conteinerAVista, formAVista); bindCliqueContainer(conteinerParcelado, formParcelado); bindCliqueContainer(conteinerMaisPagamento, formMaisPagamentoInternos); // ✅ Alias: sua atualizarValorTresPorCento() chama __avelRecalcMulti // e o multi que criamos expõe atualizarMultiPagamento. if (typeof window.__avelRecalcMulti !== 'function') { window.__avelRecalcMulti = function () { if (typeof window.atualizarMultiPagamento === 'function') { window.atualizarMultiPagamento(window.__avelBasePrecoAtual || 0); } }; } // ✅ sempre que trocar o ativo, se for "Mais Pagamento", recalc o multi function afterTogglePagamento() { atualizarOpacidadeBtn(); if (conteinerMaisPagamento?.classList.contains('ativo')) { // garante base atualizado e recalcula multi if (typeof atualizarValorTresPorCento === 'function') atualizarValorTresPorCento(); if (typeof window.atualizarMultiPagamento === 'function') { window.atualizarMultiPagamento(window.__avelBasePrecoAtual || 0); } } } // Hook: roda depois que o bindCliqueContainer alternar o "ativo" function hookAfterToggle(container, internos) { if (!container) return; const lista = Array.isArray(internos) ? internos : [internos]; container.addEventListener('click', (e) => { const clicouDentroInterno = lista.some(el => el && el.contains(e.target)); if (clicouDentroInterno) return; // roda depois do toggle do bindCliqueContainer setTimeout(afterTogglePagamento, 0); }); } hookAfterToggle(conteinerAVista, formAVista); hookAfterToggle(conteinerParcelado, formParcelado); hookAfterToggle(conteinerMaisPagamento, formMaisPagamentoInternos); // Estado inicial do botão atualizarOpacidadeBtn(); // ========= Ir para contrato (mantém igual) ========= const containerContrator = document.querySelector('.containercontrator'); const blocoPreco = document.querySelector('.preco'); // Estilos iniciais containerContrator.style.opacity = '0'; containerContrator.style.pointerEvents = 'none'; containerContrator.style.display = 'none'; blocoPreco.style.opacity = '1'; containerContrator.style.transition = 'opacity 0.5s ease'; blocoPreco.style.transition = 'opacity 0.5s ease'; function restaurarPagamentoAoVoltarDoContrato() { const containerPagamento = document.querySelector('.containerPagamento'); if (containerPagamento) { const original = containerPagamento.dataset._displayOriginal || 'block'; containerPagamento.style.setProperty('display', original, 'important'); containerPagamento.style.setProperty('pointer-events', 'auto', 'important'); containerPagamento.style.setProperty('visibility', 'visible', 'important'); containerPagamento.style.setProperty('opacity', '1', 'important'); } // ✅ garante que a UI “reacenda” corretamente (botão, etc.) setTimeout(() => { if (typeof atualizarOpacidadeBtn === 'function') atualizarOpacidadeBtn(); // se quiser manter o cálculo do multi consistente caso o Mais Pagamento esteja ativo if (conteinerMaisPagamento?.classList.contains('ativo')) { if (typeof atualizarValorTresPorCento === 'function') atualizarValorTresPorCento(); if (typeof window.atualizarMultiPagamento === 'function') { window.atualizarMultiPagamento(window.__avelBasePrecoAtual || 0); } } }, 0); } function restaurarMaisPagamentoSeNecessario() { if (!conteinerMaisPagamento) return; const estavaAberto = conteinerMaisPagamento.dataset._estavaAberto === '1'; if (!estavaAberto) return; // reativa estado lógico conteinerMaisPagamento.classList.add('ativo'); conteinerMaisPagamento.dataset.aberto = '1'; // restaura display original salvo no toggle const displayOriginal = conteinerMaisPagamento.dataset.displayOriginal || 'flex'; conteinerMaisPagamento.style.setProperty('display', displayOriginal, 'important'); conteinerMaisPagamento.style.setProperty('pointer-events', 'auto', 'important'); conteinerMaisPagamento.style.setProperty('visibility', 'visible', 'important'); conteinerMaisPagamento.style.setProperty('opacity', '1', 'important'); // garante recalculo correto setTimeout(() => { if (typeof atualizarValorTresPorCento === 'function') atualizarValorTresPorCento(); if (typeof window.atualizarMultiPagamento === 'function') { window.atualizarMultiPagamento(window.__avelBasePrecoAtual || 0); } if (typeof atualizarOpacidadeBtn === 'function') atualizarOpacidadeBtn(); }, 0); } // Abrir container de contrato // Abrir container de contrato ✅ (corrigido para não “vazar” dropdown do Mais Pagamento) btnContrato?.addEventListener('click', () => { // ===== PASSO 1: SALVA SE O MAIS PAGAMENTO ESTAVA ABERTO ===== if (conteinerMaisPagamento) { conteinerMaisPagamento.dataset._estavaAberto = conteinerMaisPagamento.dataset.aberto === '1' ? '1' : '0'; } // ✅ Mata a área de pagamento inteira (evita foco/click em selects invisíveis) const containerPagamento = document.querySelector('.containerPagamento'); if (containerPagamento) { if (!containerPagamento.dataset._displayOriginal) { containerPagamento.dataset._displayOriginal = getComputedStyle(containerPagamento).display || 'block'; } containerPagamento.style.setProperty('display', 'none', 'important'); containerPagamento.style.setProperty('pointer-events', 'none', 'important'); containerPagamento.style.setProperty('visibility', 'hidden', 'important'); containerPagamento.style.setProperty('opacity', '0', 'important'); } // ✅ Garantia extra: o Mais Pagamento não pode ficar “ativo” por baixo if (conteinerMaisPagamento) { conteinerMaisPagamento.classList.remove('ativo'); conteinerMaisPagamento.dataset.aberto = '0'; conteinerMaisPagamento.style.setProperty('display', 'none', 'important'); conteinerMaisPagamento.style.setProperty('pointer-events', 'none', 'important'); conteinerMaisPagamento.style.setProperty('visibility', 'hidden', 'important'); conteinerMaisPagamento.style.setProperty('opacity', '0', 'important'); } // (mantém igual) blocoPreco.style.opacity = '0'; blocoPreco.style.pointerEvents = 'none'; blocoPreco.style.display = 'none'; containerContrator.style.display = 'flex'; containerContrator.style.opacity = '1'; containerContrator.style.pointerEvents = 'auto'; }); //////////////////////////////////////////// // Armazena os últimos valores enviados por campo const valoresEnviados = new Map(); // Envia dados ao endpoint com autenticação via API Key function enviarParaWebhook(id, valor) { // Captura sempre o valor do campo form-field-168 const urlPipeInput = document.getElementById('form-field-168'); const urlPipe = urlPipeInput ? urlPipeInput.value : ''; const payload = { id, valor, urlPipe }; // Evita envio duplicado do mesmo campo e mesmo valor const chaveUnica = `${id}-${valor}-${urlPipe}`; if (valoresEnviados.get(id) === chaveUnica) return; valoresEnviados.set(id, chaveUnica); fetch("https://iah9mm1rj6.execute-api.us-east-2.amazonaws.com/financial_planning/r1", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": "II9ao2TV9i4jubEIXpcDC7Owc8ssqEVG1ERZB39Q" }, body: JSON.stringify(payload) }).catch(err => { console.error('Erro ao enviar para o endpoint:', err); }); } // Dispara ao sair de campos de texto document.addEventListener('blur', e => { const el = e.target; if ((el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') && el.type !== 'radio' && el.type !== 'checkbox') { const id = el.id || el.name; const valor = el.value.trim(); enviarParaWebhook(id, valor); } }, true); // Dispara ao alterar checkbox, radio ou select document.addEventListener('change', e => { const el = e.target; const id = el.id || el.name; if (el.tagName === 'INPUT') { if (el.type === 'radio' && el.checked) { enviarParaWebhook(id, el.value); } if (el.type === 'checkbox') { enviarParaWebhook(id, el.checked); } } if (el.tagName === 'SELECT') { enviarParaWebhook(id, el.value); } }); const btnEnv = document.getElementById('btnenv'); if (btnEnv) { btnEnv.addEventListener('click', () => { conteinerFormulario.style.opacity = '0'; conteinerFormulario.style.pointerEvents = 'none'; const preco = document.querySelector('.preco'); if (preco) { preco.style.opacity = '1'; } // Envia o valor de "Fim do forms" com ID 390 const urlPipeInput = document.getElementById('form-field-168'); const urlPipe = urlPipeInput ? urlPipeInput.value : ''; fetch("https://iah9mm1rj6.execute-api.us-east-2.amazonaws.com/financial_planning/r1", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": "II9ao2TV9i4jubEIXpcDC7Owc8ssqEVG1ERZB39Q" }, body: JSON.stringify({ id: 390, valor: "Fim do forms", urlPipe: urlPipe }) }).catch(err => { console.error('Erro ao enviar "Fim do forms":', err); }); }); } });