Crie uma carteira personalizada para seu cliente em minutos. Basta selecionar o perfil do cliente, preencher o capital aportado e nome e gerar a carteira. A recomendação do comitê de alocação será sugerida automaticamente, mas você pode ajustá-la conforme as necessidades do cliente.
Carteira
`;
assetList.appendChild(assetItem);
const detailsContainer = assetItem.querySelector('.asset-details-container');
// Adicionar os containers pré-preenchidos
for (let i = 1; i
`;
detailsContainer.appendChild(newDetails);
applyAporteFormatting();
// Função para remover containers e recalcular os valores
const closeBtn = newDetails.querySelector('.close-btn');
closeBtn.addEventListener('click', () => {
const nomeAtivo = newDetails.querySelector('input[placeholder=""]').value.trim();
const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.'));
// Se for "Debênture Vero" ou "CRI MRV", mantém o valor fixo de 5%
if (nomeAtivo === 'Debênture Vero' || nomeAtivo === 'CRI MRV') {
newDetails.remove();
updateAporteValues(detailsContainer, valorClasse); // Atualiza outros valores sem recalcular esses ativos
return; // Sai da função sem recalcular os valores para esses ativos
}
newDetails.remove();
updateAporteValues(detailsContainer, valorClasse); // Recalcula os valores para os outros ativos
updateTitleColor(detailsContainer);
});
}
// Função para adicionar novos containers ao clicar no botão + Adicionar
const addBtn = assetItem.querySelector('.add-btn');
addBtn.addEventListener('click', () => {
const newDetails = document.createElement('div');
newDetails.classList.add('asset-details');
newDetails.innerHTML = `
`;
detailsContainer.appendChild(newDetails);
applyAporteFormatting();
updateAporteValues(detailsContainer, valorClasse);
updateTitleColor(detailsContainer);
newDetails.querySelector('.close-btn').addEventListener('click', () => {
newDetails.remove();
updateAporteValues(detailsContainer, valorClasse);
updateTitleColor(detailsContainer);
});
});
document.querySelectorAll('.asset-details').forEach(function(details) {
const nomeInput = details.querySelector('input[placeholder=""]'); // Seleciona o input de nome
if (nomeInput) {
const nomeAtivo = nomeInput.value.trim(); // Obtém o valor do input de nome
// Verifica se o nome é "Debênture Vero" ou "CRI MRV"
if (nomeAtivo === 'CRA Seara (JBS)' || nomeAtivo === 'CRI Uberlândia Refrescos' || nomeAtivo === 'CRA Rede Sim') {
const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); // Obtém o capital aportado
const valorAporte = (capitalAportado * 0.03).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); // Calcula 5% do capital aportado
// Atualiza o valor do input de aporte para 5% do capital
const aporteInput = details.querySelector('.aporte-input');
if (aporteInput) {
aporteInput.value = valorAporte; // Preenche o input de aporte
}
}
}
});
// Atualizar os valores de aporte
updateAporteValues(detailsContainer, valorClasse);
updateTitleColor(detailsContainer);
}
}
}
}
function getPreFilledLabel(segment, field, index) {
const prefilledData = {
"Pós-fixado": [
{ Nome: "XP Referenciado FIF RF", Ticker: "", Retorno: "11,18% em 2024", Liquidez: "Diária", Vencimento: "", Dividendo: "", Upside: "", Características: "O objetivo do fundo é obter retornos superiores aos dos Certificados de Depositos interfinanceiro (CDI)." },
{ Nome: "XP Liquidez FIC RF REF DI CP RL", Ticker: "", Retorno: "Target de 12% ao ano", Liquidez: "Diária", Vencimento: "", Dividendo: "", Upside: "", Características: "A Classe tem por objetivo obter ganhos, mediante a aplicação de recursos, preponderantemente, em cotas de emissão de outras classes de fundos de investimento de renda fixa." },
{ Nome: "XP Crédito Estruturado 120 FIC FIM CP", Ticker: "", Retorno: "15,47% em 2024", Liquidez: "Mercado Secundário", Vencimento: "2028", Dividendo: "", Upside: "", Características: "A São Martinho é uma empresa sucroenergética brasileira que produz açúcar, etanol e energia elétrica. É uma das maiores produtoras de cana-de-açúcar do país." },
],
"Prefixado": [
{ Nome: "CRA Ubyfol", Ticker: "", Retorno: "18% a.a.", Liquidez: "Mercado Secundário", Vencimento: "2028", Dividendo: "", Upside: "", Características: "A Ubyfol é uma multinacional brasileira especialista em nutrição vegetal." },
{ Nome: "LTN - JAN/2026", Ticker: "", Retorno: "14,33% a.a.", Liquidez: "Mercado Secundário", Vencimento: "2026", Dividendo: "", Upside: "", Características: "Título de renda fixa prefixada emitido pelo governo federal. Também é conhecido como Tesouro Prefixado." },
],
"Inflação": [
{ Nome: "Deb. Petrobrás", Ticker: "", Retorno: "IPCA + 6,85% a.a", Liquidez: "Mercado secundário", Vencimento: "10 anos", Dividendo: "", Upside: "", Características: "Uma das maiores empresas brasileiras, a petrolífera Petrobrás vem a mercado para captar R$3 bilhões por meio de uma debênture incentivada, disponível para público geral." },
{ Nome: "NTN-B - AGO/2030", Ticker: "", Retorno: "IPC-A + 7,360% a.a", Liquidez: "Mercado secundário", Vencimento: "15/08/2030", Dividendo: "", Upside: "", Características: "A NTN-B 2030 é um título público de renda fixa emitido pelo Tesouro Nacional, que se destina a proteger o investidor contra a inflação" },
],
"Fundos": [
{ Nome: "TG Core", Ticker: "TGRU ", Retorno: "Retorno-alvo de 9,5% a.a. + IPCA", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O fundo investe em um portfólio de centros de conveniência e lojas comprados com um valor descontado, que contam com 232 contratos de alugueis vigentes." },
{ Nome: "RZDS11 (secundário)", Ticker: "RZDS11", Retorno: "Total Return de 133% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O Riza Domus seleciona ativos no setorimobiliário, visando um portfólio que melhor se adeque às nossas perspectivas de risco-retorno-liquide." },
{ Nome: "AZQI11 (secundário)", Ticker: "AZQI11", Retorno: "Total Return de 155% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O AZQI11 continua posicionado entre os melhores dividend vield (DY) da indústria de Fundos de Infraestrutura, considerando os últimos 12 meses (DY de 15,79% a.a.). Rendimento total distribuido por cota de R$ 0,375 no 49 trimestre de 2024." },
{ Nome: "VGIE11 (secundário)", Ticker: "VGIE11", Retorno: "Total Return de 131% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O Fundo encerrou o mês com todo o seu patrimônio líquido alocado em Ativos-Alvo, totalizando R$ 499,3 milhões em 18 debêntures, além de investir em instrumentos de caixa." },
],
"Global (Renda Fixa)": [
{ Nome: "Cleveland-Cliffs", Ticker: "", Retorno: "Dólar + 5,76% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "15/04/2030", Dividendo: "", Upside: "", Características: "Uma das maiores empresas siderúrgicas e de mineração dos EUA, fundada em 1847." },
{ Nome: "JP Morgan", Ticker: "", Retorno: "Dólar + 4,62% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "24/01/2031", Dividendo: "", Upside: "", Características: "um dos maiores e mais influentes bancos do mundo, atuando em banco de investimento, gestão de ativos, serviços bancários e financeiros." },
{ Nome: "Itaú", Ticker: "", Retorno: "Dólar + 5,03% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "27/02/2030", Dividendo: "", Upside: "", Características: "O maior banco privado do Brasil e um dos maiores da América Latina." },
],
"Global (Renda Variável)": [
{ Nome: "iShares U.S. Energy ETF", Ticker: "IYE", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor de energia dos EUA, incluindo petróleo, gás e serviços relacionados." },
{ Nome: "Vanguard Utilities ETF", Ticker: "VPU", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor de utilidades dos EUA, como fornecedoras de eletricidade, gás e água." },
{ Nome: "iShares U.S. Financials ETF", Ticker: "IYF", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor financeiro dos EUA, incluindo bancos, seguradoras e outras instituições financeiras." },
{ Nome: "Vanguard FTSE Europe ETF", Ticker: "VGK", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas da Europa, seguindo o índice FTSE desenvolvido para refletir o mercado de ações da região." },
{ Nome: "iShares Trust - China Large-Cap ETF", Ticker: "FXI", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em grandes empresas chinesas listadas nos EUA, focando nas maiores companhias do país." },
],
"Brasil (Renda Variável)": [
{ Nome: "Top Dividendos Plus", Ticker: "", Retorno: "7,0% nos últimos 12 meses", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "Nessa carteira, a XP recomenda todos os meses os melhores 10 nomes a partir de uma seleção de maiores pagadoras de dividendos entre os membros dos índices Ibovespa, Small Caps (SMLL) e IBrX 100." },
],
"Alternativos": [
{ Nome: "Riza Viseu", Ticker: "", Retorno: "TIR de 24,4% a.a", Liquidez: "Mercado Secundário", Vencimento: "7 anos, prorrogáveis por mais 2 anos", Dividendo: "", Upside: "", Características: "O fundo tem como estratégia a aquisição de participação na Riva Incorporadora, subsidiaria da Direcional." },
{ Nome: "HASH11", Ticker: "", Retorno: "135,75% nos últimos 12 meses", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O HASH11 é um fundo de índice listado na B3 que replica o Nasdaq Crypto Index™ (NCI™), índice que busca refletir globalmente o movimento do mercado de criptoativos." },
]
};
return prefilledData[segment][index - 1][field] || '';
}
let manualValues = {}; // Armazena os valores manualmente alterados
// Função para formatar os valores de moeda conforme o usuário digita
function formatCurrencyLive(input) {
let value = input.value.replace(/\D/g, ''); // Remove caracteres que não são números
if (value) {
value = (parseFloat(value) / 100).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
input.value = value;
} else {
input.value = 'R$ 0,00'; // Valor padrão caso o campo esteja vazio
}
}
// Função chamada quando o valor do aporte é alterado manualmente
function handleAporteChange(input, detailsContainer, valorClasse) {
const inputId = input.getAttribute('data-id');
let valorAporte = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.'));
if (isNaN(valorAporte)) valorAporte = 0;
// Se o valor é superior ao valor total do segmento, altere a cor para vermelho
if (valorAporte > valorClasse) {
input.style.color = 'rgb(229, 73, 126)';
} else {
input.style.color = '#1dc077';
}
// Armazena o valor manualmente alterado assim que o usuário faz uma mudança
manualValues[inputId] = valorAporte;
// Atualizar os valores restantes imediatamente
recalculateOtherAportes(input, detailsContainer, valorClasse);
}
// Função para recalcular os valores de aportes, preservando os valores manualmente alterados
function updateAporteValues(detailsContainer, valorClasse) {
const aporteInputs = detailsContainer.querySelectorAll('.aporte-input');
let totalManual = 0;
let manualCount = 0;
// Calcular o total dos aportes manuais
aporteInputs.forEach(input => {
const inputId = input.getAttribute('data-id');
if (manualValues[inputId] !== undefined) {
totalManual += manualValues[inputId];
manualCount++;
}
});
const remainingValue = valorClasse - totalManual;
const remainingContainers = aporteInputs.length - manualCount;
// Recalcular o valor para os inputs não alterados manualmente
aporteInputs.forEach(input => {
const inputId = input.getAttribute('data-id');
if (manualValues[inputId] === undefined && remainingContainers > 0) {
const valorPorContainer = remainingValue / remainingContainers;
input.value = valorPorContainer.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}
});
}
// Função para recalcular todos os inputs não alterados, mesmo após manual input
function recalculateOtherAportes(changedInput, detailsContainer, valorClasse) {
const allInputs = detailsContainer.querySelectorAll('.aporte-input');
let totalManual = 0;
let numOtherInputs = 0;
// Passo 1: Somar todos os valores manualmente alterados e contar os inputs que não foram manualmente alterados
allInputs.forEach(input => {
const manualValue = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.'));
// Verifica se o nome é "Debênture Vero" ou "CRI MRV" para garantir que permaneça em 5%
const nomeInput = input.closest('.asset-details').querySelector('input[placeholder=""]');
const nomeAtivo = nomeInput ? nomeInput.value.trim() : '';
if (nomeAtivo === 'Debênture Vero' || nomeAtivo === 'CRI MRV') {
const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.'));
const valorFixo = (capitalAportado * 0.05).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
input.value = valorFixo; // Mantém o valor fixo de 5%
input.dataset.manual = 'true'; // Marca como "manual" para não ser recalculado
} else if (!isNaN(manualValue) && input.dataset.manual === "true") {
totalManual += manualValue;
} else {
numOtherInputs++;
}
});
// Passo 2: Calcular o valor restante a ser distribuído, sem incluir os inputs de "Debênture Vero" e "CRI MRV"
const remainingValue = valorClasse - totalManual;
// Passo 3: Distribuir o valor restante para os inputs que não foram manualmente alterados
if (numOtherInputs > 0 && remainingValue > 0) {
const newAporteValue = remainingValue / numOtherInputs;
allInputs.forEach(input => {
const nomeInput = input.closest('.asset-details').querySelector('input[placeholder=""]');
const nomeAtivo = nomeInput ? nomeInput.value.trim() : '';
// Só recalcular se o input não for "Debênture Vero" ou "CRI MRV" e não tiver sido manualmente alterado
if (!input.dataset.manual && nomeAtivo !== 'Debênture Vero' && nomeAtivo !== 'CRI MRV') {
input.value = newAporteValue.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}
});
}
// Manter o input alterado manualmente como "manual"
changedInput.dataset.manual = "true";
}
// Função para aplicar a formatação e eventos aos campos de "aporte"
function applyAporteFormatting() {
const aporteInputs = document.querySelectorAll('.aporte-input');
aporteInputs.forEach(input => {
input.addEventListener('input', function () {
formatCurrencyLive(this); // Formata o valor enquanto o usuário digita
const detailsContainer = this.closest('.asset-details-container');
const totalSegmentValue = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.'));
handleAporteChange(this, detailsContainer, totalSegmentValue); // Garante que o valor é salvo imediatamente
});
input.addEventListener('blur', function () {
const detailsContainer = this.closest('.asset-details-container');
const totalSegmentValue = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.'));
recalculateOtherAportes(this, detailsContainer, totalSegmentValue); // Recalcula os outros valores ao perder o foco (após edição)
});
});
}
// Função para inicializar e atribuir o 'data-id' único a cada input de Aporte
function initializeAporteInputs(detailsContainer, valorClasse) {
const aporteInputs = detailsContainer.querySelectorAll('.aporte-input');
aporteInputs.forEach((input, index) => {
input.setAttribute('data-id', `aporte-${index}`);
input.dataset.originalValue = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.')) || 0; // Armazena o valor original
input.addEventListener('input', () => handleAporteChange(input, detailsContainer, valorClasse));
});
applyAporteFormatting(); // Garante que os novos inputs também tenham formatação
}
// Função para atualizar a cor do título com base na quantidade de containers
function updateTitleColor(detailsContainer) {
const titleLabel = detailsContainer.parentElement.querySelector('div > div');
const gerarPdfButton = document.getElementById('gerar-ppt');
if (detailsContainer.children.length === 0) {
titleLabel.style.color = 'rgb(229, 73, 126)';
gerarPdfButton.style.display = 'none';
} else {
titleLabel.style.color = '';
checkTitleColorsForPdfButton();
}
}
// Verificar se todos os títulos estão corretos para mostrar o botão de gerar PDF
function checkTitleColorsForPdfButton() {
const titles = document.querySelectorAll('.carteira-item label');
const gerarPdfButton = document.getElementById('gerar-ppt');
let anyTitleRed = false;
titles.forEach(title => {
if (window.getComputedStyle(title).color === 'rgb(229, 73, 126)') {
anyTitleRed = true;
}
});
if (!anyTitleRed) {
gerarPdfButton.style.display = 'inline-block';
} else {
gerarPdfButton.style.display = 'none';
}
}
// Função para redistribuir o valor do segmento ao adicionar ou remover containers
function redistributeAportes(detailsContainer, valorClasse) {
const aporteInputs = [...detailsContainer.querySelectorAll('.aporte-input')];
let totalManual = 0;
let numContainers = 0;
// Calcular o valor restante e contar containers não editados
aporteInputs.forEach(input => {
const inputId = input.getAttribute('data-id');
if (!manualValues[inputId]) {
numContainers++;
} else {
totalManual += manualValues[inputId];
}
});
const valorParaRedistribuir = valorClasse - totalManual;
if (numContainers > 0) {
const valorPorContainer = valorParaRedistribuir / numContainers;
aporteInputs.forEach(input => {
const inputId = input.getAttribute('data-id');
if (!manualValues[inputId]) {
input.value = valorPorContainer.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}
});
}
}
// Lógica ao adicionar/remover containers
document.querySelectorAll('.add-btn').forEach(button => {
button.addEventListener('click', function () {
const detailsContainer = this.closest('.asset-details-container');
const valorClasse = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.'));
// Aqui você adicionaria o novo container
initializeAporteInputs(detailsContainer, valorClasse); // Inicializa os inputs do novo container
redistributeAportes(detailsContainer, valorClasse); // Redistribui os valores após a adição
});
});
document.querySelectorAll('.remove-btn').forEach(button => {
button.addEventListener('click', function () {
const detailsContainer = this.closest('.asset-details-container');
const valorClasse = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.'));
// Aqui você removeria o container
redistributeAportes(detailsContainer, valorClasse); // Redistribui os valores após a remoção
});
});
// Outras funções existentes no código...
document.addEventListener('DOMContentLoaded', () => {
updateProfile();
document.getElementById('voltar').addEventListener('click', resetToInitialValues);
document.getElementById('capital').addEventListener('input', updateAssetValues);
const chartSegments = document.querySelectorAll('.chart-segments circle');
const chartTooltip = document.getElementById('chartTooltip');
chartSegments.forEach((segment, index) => {
segment.addEventListener('mouseenter', (event) => {
const segmentId = segment.classList[0].replace('segment-', '');
const segmentLabel = document.querySelector(`label[for=${segmentId}]`).textContent;
const segmentValue = document.getElementById(segmentId).value;
const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.'));
const valorClasse = (capitalAportado * (segmentValue / 100)).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
chartTooltip.innerHTML = `${segmentLabel}${segmentValue}% ${valorClasse}`;
chartTooltip.style.left = `${event.pageX + 1}px`;
chartTooltip.style.top = `${event.pageY + 1}px`;
chartTooltip.style.display = 'block';
chartSegments.forEach(s => {
if (s !== segment) {
s.style.opacity = '0.5';
}
});
segment.style.opacity = '1';
});
segment.addEventListener('mouseleave', () => {
chartTooltip.style.display = 'none';
chartSegments.forEach(s => s.style.opacity = '1');
});
segment.addEventListener('mousemove', (event) => {
const containerRect = document.querySelector('.chart-container').getBoundingClientRect();
chartTooltip.style.left = `${event.clientX - containerRect.left - 80}px`;
chartTooltip.style.top = `${event.clientY - containerRect.top - 80}px`;
});
});
document.getElementById('simular').addEventListener('click', () => {
document.getElementById('resultSection').style.display = 'block'; // Exibe a seção de resultados
document.getElementById('simular').style.display = 'none'; // Esconde o botão "Gerar Carteira"
updateAssetValues(); // Atualiza os valores da carteira
});
document.getElementById('voltar').addEventListener('click', () => {
resetToInitialValues(); // Restaura os valores iniciais
// Verifica se o resultSection está visível e mantém o botão "Gerar Carteira" oculto
if (document.getElementById('resultSection').style.display === 'block') {
document.getElementById('simular').style.display = 'none';
} else {
document.getElementById('simular').style.display = 'inline-block';
}
});
document.getElementById('simular').addEventListener('click', () => {
document.getElementById('resultSection').style.display = 'block';
document.getElementById('gerar-ppt').style.display = 'inline-block'; // Mostra o botão Gerar PPT
updateAssetValues();
});
document.getElementById('gerar-ppt').addEventListener('click', () => {
const pptx = new PptxGenJS();
const nomeCliente = document.getElementById('nome').value || 'Cliente';
const capitalAportado = document.getElementById('capital').value;
// Coletar os valores dos inputs com percentuais > 0
const valores = [];
const labels = [];
const cores = [];
let total = 0;
document.querySelectorAll('.carteira-item').forEach(item => {
const input = item.querySelector('input[type="range"]');
const valor = parseFloat(input.value);
if (valor > 0) {
const label = item.querySelector('label').textContent;
valores.push(valor);
labels.push(label);
// Obter a cor dos sliders para usar no gráfico
const cor = getComputedStyle(input).color;
cores.push(cor); // Adiciona a cor de cada item ao array de cores
total += valor; // Calcula o total para calcular percentuais
}
});
const labelsComPercentuais = labels.map((label, index) => {
const percentual = ((valores[index] / total) * 100).toFixed(1);
return `${label} - ${percentual}%`; // Adiciona o percentual à legenda
});
// Slide 1: Texto personalizado
let slide1 = pptx.addSlide();
slide1.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/3/31/Capa_Invest2.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide1.addText(`Material desenvolvido exclusivamente para ${nomeCliente}.`, { x: 2.05, y: 3.17, w: 3.4, h: 0.4, fontSize: 12, color: 'F1F1F1', fontFace: 'Montserrat Light' });
// Slide 2
let slide2 = pptx.addSlide();
slide2.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/0/00/2macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 3
let slide3 = pptx.addSlide();
slide3.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/d/db/3macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 4
let slide4 = pptx.addSlide();
slide4.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/6/67/4macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
})
// Slide 5
let slide5 = pptx.addSlide();
slide5.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/4/48/5macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
})
// Slide 6
let slide6 = pptx.addSlide();
slide6.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/4/4d/6macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 7
let slide7 = pptx.addSlide();
slide7.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/3/3e/7macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 8
let slide8 = pptx.addSlide();
slide8.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/7/72/8macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 9
let slide9 = pptx.addSlide();
slide9.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/9macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 10
let slide10 = pptx.addSlide();
slide10.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/1/1b/10macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 11
let slide11 = pptx.addSlide();
slide11.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/6/6e/11macromaio.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 12
let slide12 = pptx.addSlide();
slide12.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/3/3f/12macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 13
let slide13 = pptx.addSlide();
slide13.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/4/41/13macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 14
let slide14 = pptx.addSlide();
slide14.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/2/2f/14macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 15
let slide15 = pptx.addSlide();
slide15.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/5/59/15macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 16
let slide16 = pptx.addSlide();
slide16.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/d/dd/17macromaio.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 17
let slide17 = pptx.addSlide();
slide17.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/a/af/17macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 18
let slide18 = pptx.addSlide();
slide18.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/5/52/18macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 19
let slide19 = pptx.addSlide();
slide19.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/3/30/19macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 20
let slide20 = pptx.addSlide();
slide20.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/c/cc/20macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 21
let slide21 = pptx.addSlide();
slide21.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/4/43/21macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 22
let slide22 = pptx.addSlide();
slide22.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/f/f8/22macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 23
let slide23 = pptx.addSlide();
slide23.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/1/15/23macroabril.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 24
let slide24 = pptx.addSlide();
slide24.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/8/89/24macromaio.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 25
let slide25 = pptx.addSlide();
slide25.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/9/92/Temp16.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide25.addText(`ESTRATÉGIA DE ALOCAÇÃO`, {
x: 0.67, y: 0.57, w: '7.75', h: '0.56', fontSize: 30, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1'
});
slide25.addChart(pptx.ChartType.doughnut, [
{
name: 'Alocação de Ativos',
labels: labelsComPercentuais,
values: valores
}
], {
x: 1.22,
y: 1.88,
w: 6.95,
h: 3.47,
holeSize: 85,
showLegend: true, // Mostra a legenda
legendPos: 'r', // Posição da legenda à direita
legendColor: 'FFFFFF',
legendFontFace: 'Montserrat Light', // Define a fonte Montserrat Light
legendFontSize: 10, // Tamanho da fonte das legendas
legendFontItalic: false, // Não usar itálico
dataLabelColor: 'FFFFFF', // Cor do rótulo do gráfico
dataLabelFontSize: 9, // Tamanho do texto dos rótulos
dataLabelFontFace: 'Montserrat Bold',
showPercent: false,
});
slide25.addText(`100%`, {
x: 2.65, y: 3.31, w: '1.82', h: '0.56', fontSize: 40, fontFace: 'Montserrat Bold', align: 'center', color: 'F1F1F1'
});
slide25.addText(`Capital Aportado: ${capitalAportado}`, {
x: 1.37, y: 1.04, w: '7.75', h: '0.25', fontSize: 14, fontFace: 'Montserrat Light', align: 'left', color: '1dc077'
});
// Slide 26
let slide26 = pptx.addSlide();
slide26.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/d/da/Temp17.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide26.hidden = true;
// Slide 27
let slide27 = pptx.addSlide();
slide27.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/f/f2/Temp18.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide27.hidden = true;
// Slide 28
let slide28 = pptx.addSlide();
slide28.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/1/1d/Temp19.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide28.hidden = true;
// Slide 29 - Ativos
// Função para extrair o percentual da label "retorno"
function extrairPercentual(texto) {
// Primeiro, vamos procurar por "IPCA + [número]%" e adicionar o IPCA de 4,35%
let ipcaMatch = texto.match(/IPCA\s*\+\s*(\d+,\d+|\d+)%/i);
if (ipcaMatch) {
let percentual = parseFloat(ipcaMatch[1].replace(',', '.'));
return 4.35 + percentual; // Adiciona o IPCA de 4,35%
}
// Caso contrário, procuramos apenas pelo número percentual
let match = texto.match(/(\d+,\d+|\d+)%/);
if (match) {
return parseFloat(match[1].replace(',', '.'));
}
return null; // Retorna null se nenhum percentual for encontrado
}
// Função para adicionar o gráfico de rentabilidade
function adicionarGraficoRentabilidade(slide, percentual, isIPCA) {
let valoresAnuais = [];
let valoresAnuaisComPorcentagem = []; // Novo array para incluir o símbolo de porcentagem
for (let ano = 1; ano {
container.querySelectorAll('.asset-details').forEach(asset => {
const detalhesAtivo = [];
let percentualRetorno = null;
let nomeAtivo = '';
let tickerAtivo = '';
asset.querySelectorAll('input, textarea').forEach(input => {
if (input.value.trim() !== '') {
const rotulo = input.previousElementSibling.textContent.trim();
detalhesAtivo.push({ rotulo, valor: input.value.trim() });
// Extrair o percentual da label "retorno" para o gráfico
if (rotulo.toLowerCase().includes('retorno')) {
percentualRetorno = extrairPercentual(input.value);
isIPCA = input.value.includes('IPCA'); // Verifica se o retorno inclui IPCA
}
// Armazenar o valor da label "nome" se existir
if (rotulo.toLowerCase().includes('nome')) {
nomeAtivo = input.value.trim();
}
// Armazenar o valor da label "Ticker" se existir
if (rotulo.toLowerCase().includes('ticker')) {
tickerAtivo = input.value.trim();
}
}
});
if (detalhesAtivo.length > 0) {
const nomeSegmento = labels[index].toUpperCase();
let backgroundImage = '';
switch (nomeSegmento) {
case 'PÓS-FIXADO':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/1/15/Temp32_1.png';
break;
case 'PREFIXADO':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/9/9c/Temp32_2.png';
break;
case 'INFLAÇÃO':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/2/24/Temp32_3.png';
break;
case 'FUNDOS':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/7/7b/Temp32_4.png';
break;
case 'GLOBAL (RENDA FIXA)':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/1/1e/Temp32_5.png';
break;
case 'GLOBAL (RENDA VARIÁVEL)':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4d/Temp32_6.png';
break;
case 'BRASIL (RENDA VARIÁVEL)':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/a/a5/Temp32_7.png';
break;
case 'ALTERNATIVOS':
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4f/Temp32_8.png';
break;
default:
backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4f/Temp32_8.png'; // Fallback para uma imagem padrão
}
let slide = pptx.addSlide();
slide.addImage({
path: backgroundImage,
x: 0, y: 0, w: '100%', h: '100%'
});
slide.addText(nomeSegmento, {
x: 0.67, y: 0.57, w: '7.75', h: '0.56', fontSize: 30, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1'
});
const percentualSegmento = parseFloat(document.querySelectorAll('.carteira-item input[type="range"]')[index].value);
const capitalTotal = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.'));
const valorSegmento = (capitalTotal * (percentualSegmento / 100)).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
slide.addText(`Aporte: ${valorSegmento}`, {
x: 1.37, y: 1.04, w: '7.75', h: '0.25', fontSize: 14, fontFace: 'Montserrat Light', align: 'left', color: '1dc077'
});
let yPosition = 3.32;
let detalhesFormatados = [];
detalhesAtivo.forEach(detalhe => {
detalhesFormatados.push(
{ text: `• ${detalhe.rotulo} `, options: { fontFace: 'Montserrat Light', fontSize: 12, color: '1dc077' } },
{ text: `${detalhe.valor}`, options: { fontFace: 'Montserrat Light', fontSize: 12, color: 'ffffff' } },
{ text: '\n\n' }
);
});
slide.addText(detalhesFormatados, {
x: 0.67,
y: yPosition,
w: 4.15,
h: 0.47,
fontSize: 8,
fontFace: 'Montserrat Light',
align: 'left'
});
// Adicionar gráfico de rentabilidade se o segmento for Pós-fixado, Prefixado ou Inflação
if (['PÓS-FIXADO', 'PREFIXADO', 'INFLAÇÃO', 'ALTERNATIVOS', 'GLOBAL (RENDA FIXA)', 'ALTERNATIVOS'].includes(nomeSegmento) && percentualRetorno) {
adicionarGraficoRentabilidade(slide, percentualRetorno, isIPCA);
}
if (nomeSegmento === 'GLOBAL (RENDA VARIÁVEL)') {
if (nomeAtivo === 'JPM Global Select Equity') {
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/8/88/JPM-1.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
} else if (nomeAtivo === 'Schwab US Dividend Equity') {
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/7/72/Schwab-1.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
}
}
if (nomeSegmento === 'BRASIL (RENDA VARIÁVEL)') {
switch (tickerAtivo) {
case 'HASH11':
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Gr%C3%A1fico_de_hash.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
break;
case 'FLRY3':
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/7/74/Gr%C3%A1fico_de_FLRY.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
break;
case 'ELET3':
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/f/fd/ELET3.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
break;
case 'HASH11':
slide.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/b/b3/HASH11.png',
x: 5.54, y: 1.80, w: 3.93, h: 3.51
});
break;
default:
// Não adicionar imagem se não houver correspondência
break;
}
}
}
});
});
// Slide 29
let slide29 = pptx.addSlide();
slide29.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Temp33.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide29.hidden = true;
// Slide 30
let slide30 = pptx.addSlide();
slide30.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/8/8e/Temp34.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide30.addText(`Fez sentido a estratégia de alocação apresentada?`, {
x: 6.81, y: 1.07, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1'
});
slide30.addText(`Ficou claro o conceito do atendimento exclusivo?`, {
x: 6.81, y: 2.25, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1'
});
slide30.addText(`Acredita que ele agregará aos seus investimentos?`, {
x: 6.81, y: 3.43, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1'
});
// Slide 31
let slide31 = pptx.addSlide();
slide31.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/0/0c/Temp35.png',
x: 0, y: 0, w: '100%', h: '100%'
});
// Slide 32
let slide32 = pptx.addSlide();
slide32.addImage({
path: 'https://upload.wikimedia.org/wikipedia/commons/8/8b/Temp36.png',
x: 0, y: 0, w: '100%', h: '100%'
});
slide32.hidden = true;
// Função para baixar o arquivo PPT
pptx.writeFile(`Estudo_Investimento_${nomeCliente}.pptx`)
.then(() => {
console.log('PPT baixado com sucesso.');
})
.catch(err => {
console.error('Erro ao baixar o PPT:', err);
});
});
});