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.03;
if (base = 2 && numeroParcelas 0) {
const valorParcela = valorFinalParcelado / numeroParcelas;
campoValorParcela.innerHTML = `Valor da Parcela:
${formatarMoeda(valorParcela)}`;
} else {
campoValorParcela.innerHTML = `Valor da Parcela: -`;
}
}
// Listeners dos seletores
const seletorPagamento = document.getElementById('form-field-meioPagamentoAVista');
if (seletorPagamento) {
seletorPagamento.addEventListener('change', atualizarValorTresPorCento);
}
const seletorParcelado = document.getElementById('form-field-meioPagamentoParcelado');
if (seletorParcelado) {
seletorParcelado.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();
const conteinerAVista = document.querySelector('.conteinerAVista');
const conteinerParcelado = document.querySelector('.conteinerParcelado');
const formAVista = document.getElementById('formsAvista');
const formParcelado = document.getElementById('formsParcelado');
const btnContrato = document.getElementById('btncontrato');
// Garante transição suave no botão
btnContrato.style.transition = 'opacity 1s ease, pointer-events 1s ease';
btnContrato.style.opacity = '0';
btnContrato.style.pointerEvents = 'none';
// Função para atualizar a opacidade e interatividade do botão
function atualizarOpacidadeBtn() {
const temAtivo =
conteinerAVista.classList.contains('ativo') ||
conteinerParcelado.classList.contains('ativo');
btnContrato.style.opacity = temAtivo ? '1' : '0';
btnContrato.style.pointerEvents = temAtivo ? 'auto' : 'none';
}
// Alterna o estado do container clicado
function alternarAtivo(clicado, outro) {
const jaAtivo = clicado.classList.contains('ativo');
// Se já estiver ativo e for clicado novamente, desativa ambos
if (jaAtivo) {
clicado.classList.remove('ativo');
outro.classList.remove('ativo');
} else {
clicado.classList.add('ativo');
outro.classList.remove('ativo');
}
atualizarOpacidadeBtn();
}
// Eventos para clique no container AVista
conteinerAVista?.addEventListener('click', (e) => {
if (!formAVista.contains(e.target)) {
alternarAtivo(conteinerAVista, conteinerParcelado);
}
});
// Eventos para clique no container Parcelado
conteinerParcelado?.addEventListener('click', (e) => {
if (!formParcelado.contains(e.target)) {
alternarAtivo(conteinerParcelado, conteinerAVista);
}
});
// Ir para contrato
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';
// Abrir container de contrato
btnContrato?.addEventListener('click', () => {
// Oculta .preco
blocoPreco.style.opacity = '0';
blocoPreco.style.pointerEvents = 'none';
blocoPreco.style.display = 'none';
// Exibe .containercontrator
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', () => {
const conteinerFormulario = document.querySelector('.conteinerformulario');
const preco = document.querySelector('.preco');
// Esconde formulário e mostra tela de preço
if (conteinerFormulario) {
conteinerFormulario.style.opacity = '0';
conteinerFormulario.style.pointerEvents = 'none';
}
if (preco) {
preco.style.opacity = '1';
preco.style.pointerEvents = 'auto';
}
// === CORREÇÃO: garantir leitura segura do urlPipe ===
let urlPipe = '';
const urlPipeInput = document.getElementById('form-field-168');
// Se o campo existe e tem valor, usa ele
if (urlPipeInput && urlPipeInput.value.trim() !== '') {
urlPipe = urlPipeInput.value.trim();
}
// Se ainda está vazio, tenta extrair direto da URL (?utm=XXXX)
if (!urlPipe) {
const match = window.location.href.match(/[?&]utm=(\d+)/);
if (match && match[1]) {
urlPipe = `https://guiainvest-270444.pipedrive.com/deal/${match[1]}`;
}
}
// Se ainda assim não tiver valor, não envia nada
if (!urlPipe) {
console.warn('⚠️ Nenhum urlPipe encontrado, envio cancelado.');
return;
}
// Envia o valor de "Fim do forms" com ID 390
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);
});
});
}
});