// ===== MÓDULOS PARA CLIENTES, ANÁLISES E TRANSCRIÇÕES ===== // Este arquivo contém os módulos que estendem o JaniceApp (function() { 'use strict'; // Aguardar que o JaniceApp esteja disponível if (typeof window.JaniceApp === 'undefined') { console.error('JaniceApp não encontrado! Este script deve ser carregado após script.js'); return; } // ===== MÓDULO DE CLIENTES ===== JaniceApp.modules.clients = { init: function() { console.log('🔄 Inicializando módulo de Clientes...'); // Carregar clientes this.loadClients(); // Configurar abas this.setupClientTabs(); // Configurar logos clicáveis this.setupClickableLogos(); // Configurar eventos this.setupEvents(); console.log('✅ Módulo de Clientes inicializado'); }, setupEvents: function() { // ===== EVENTOS DO PAINEL DE CLIENTES ===== // Botão para criar novo cliente if (JaniceApp.elements.newClientBtn) { JaniceApp.elements.newClientBtn.addEventListener('click', () => { this.setupClientForm('new'); }); } // Botão para cancelar formulário if (JaniceApp.elements.cancelClientBtn) { JaniceApp.elements.cancelClientBtn.addEventListener('click', () => { if (JaniceApp.state.currentClientId) { // Voltar para os detalhes do cliente atual JaniceApp.elements.clientFormContainer.style.display = 'none'; JaniceApp.elements.clientDetailsContainer.style.display = 'block'; } else { // Esconder formulário e mostrar tela de boas-vindas JaniceApp.elements.clientFormContainer.style.display = 'none'; JaniceApp.elements.welcomeContainer.style.display = 'block'; } }); } // Submissão do formulário de cliente if (JaniceApp.elements.clientForm) { JaniceApp.elements.clientForm.addEventListener('submit', (e) => this.saveClient(e)); } // Preview de logo ao selecionar arquivo if (JaniceApp.elements.clientLogoInput) { JaniceApp.elements.clientLogoInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = function(event) { JaniceApp.elements.logoPreview.innerHTML = `Logo Preview`; JaniceApp.elements.logoPreview.style.display = 'block'; }; reader.readAsDataURL(file); } else { JaniceApp.elements.logoPreview.style.display = 'none'; } }); } // Pesquisa de clientes if (JaniceApp.elements.clientSearchInput) { JaniceApp.elements.clientSearchInput.addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase().trim(); if (!searchTerm) { this.renderClientList(JaniceApp.state.currentClients); return; } const filteredClients = JaniceApp.state.currentClients.filter(client => client.nome.toLowerCase().includes(searchTerm) || client.cnpj.includes(searchTerm) ); this.renderClientList(filteredClients); }); } // Eventos do painel central if (JaniceApp.elements.editClientBtn) { JaniceApp.elements.editClientBtn.addEventListener('click', () => { const client = JaniceApp.state.currentClients.find(c => c._id === JaniceApp.state.currentClientId); if (client) { this.setupClientForm('edit', client); } }); } if (JaniceApp.elements.deleteClientBtn) { JaniceApp.elements.deleteClientBtn.addEventListener('click', () => { const client = JaniceApp.state.currentClients.find(c => c._id === JaniceApp.state.currentClientId); if (client) { this.showDeleteConfirmation(client); } }); } if (JaniceApp.elements.newAnalysisBtn) { JaniceApp.elements.newAnalysisBtn.addEventListener('click', () => { JaniceApp.modules.analysis.showAnalysisForm(); }); } // Eventos do modal de confirmação if (JaniceApp.elements.closeModalBtn) { JaniceApp.elements.closeModalBtn.addEventListener('click', () => { JaniceApp.elements.deleteConfirmModal.classList.remove('show'); }); } if (JaniceApp.elements.cancelDeleteBtn) { JaniceApp.elements.cancelDeleteBtn.addEventListener('click', () => { JaniceApp.elements.deleteConfirmModal.classList.remove('show'); }); } // Fechar modal ao clicar fora dele window.addEventListener('click', (e) => { if (e.target === JaniceApp.elements.deleteConfirmModal) { JaniceApp.elements.deleteConfirmModal.classList.remove('show'); } }); }, // Carregar lista de clientes loadClients: async function() { try { const clients = await JaniceApp.utils.safeFetch('/api/clientes'); // Se safeFetch retornou null (redirecionamento), não continuar if (clients === null) return; JaniceApp.state.currentClients = clients; this.renderClientList(clients); } catch (error) { console.error('Erro ao carregar clientes:', error); JaniceApp.elements.clientList.innerHTML = `

Erro ao carregar clientes. Tente novamente.

`; } }, // Renderizar lista de clientes renderClientList: function(clients) { if (!clients.length) { JaniceApp.elements.clientList.innerHTML = `

Nenhum cliente cadastrado

`; return; } JaniceApp.elements.clientList.innerHTML = clients.map(client => { const logoHtml = client.logo ? `Logo ${client.nome}` : ``; const corPersonalizada = client.cor || '#6a5acd'; return `

${client.nome}

CNPJ: ${JaniceApp.utils.formatCnpj(client.cnpj)}

`; }).join(''); // Adicionar eventos de clique JaniceApp.elements.clientList.querySelectorAll('.client-item').forEach(item => { item.addEventListener('click', () => { const clientId = item.dataset.id; this.loadClientDetails(clientId); }); }); }, // Carregar detalhes do cliente loadClientDetails: function(clientId) { const client = JaniceApp.state.currentClients.find(c => c._id === clientId); if (!client) return; // Armazenar ID do cliente atual JaniceApp.state.currentClientId = clientId; // Atualizar painel lateral JaniceApp.elements.detailClientName.textContent = client.nome; JaniceApp.elements.detailClientCnpj.textContent = JaniceApp.utils.formatCnpj(client.cnpj); if (client.logo) { JaniceApp.elements.detailClientLogo.innerHTML = `Logo`; } else { JaniceApp.elements.detailClientLogo.innerHTML = ''; } // Atualizar painel central JaniceApp.elements.centralClientName.textContent = client.nome; JaniceApp.elements.centralClientCnpj.textContent = JaniceApp.utils.formatCnpj(client.cnpj); if (client.logo) { JaniceApp.elements.centralClientLogo.innerHTML = ` Logo da empresa
Clique para alterar logo
`; } else { JaniceApp.elements.centralClientLogo.innerHTML = `
Clique para adicionar logo
`; } // Aplicar cor personalizada if (client.cor) { const colorWithAlpha = JaniceApp.utils.hexToRgba(client.cor, 0.1); JaniceApp.elements.clientDetailsPanel.style.backgroundColor = colorWithAlpha; JaniceApp.elements.clientDetailsPanel.style.borderColor = client.cor; } // Mostrar painéis JaniceApp.elements.clientFormContainer.style.display = 'none'; JaniceApp.elements.clientDetailsContainer.style.display = 'block'; JaniceApp.elements.welcomeContainer.style.display = 'none'; JaniceApp.elements.clientDetailsPanel.style.display = 'block'; // Carregar dados específicos das abas JaniceApp.modules.analysis.loadClientAnalyses(clientId); JaniceApp.modules.transcriptions.loadClientTranscriptions(clientId); JaniceApp.modules.actionPlans.loadClientActionPlans(clientId); // Carregar mockups e galeria if (JaniceApp.modules.mockups && JaniceApp.modules.mockups.loadClientMockups) { JaniceApp.modules.mockups.loadClientMockups(clientId); } if (JaniceApp.modules.mockups && JaniceApp.modules.mockups.loadGallery) { JaniceApp.modules.mockups.loadGallery(); } }, // Configurar abas do cliente setupClientTabs: function() { const tabButtons = document.querySelectorAll('.tab-button'); const tabContents = document.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.addEventListener('click', () => { const targetTab = button.dataset.tab; // Remover classe active de todos os botões e conteúdos tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); // Adicionar classe active ao botão clicado e conteúdo correspondente button.classList.add('active'); document.getElementById(`${targetTab}-tab`).classList.add('active'); }); }); }, // Configurar formulário de cliente (novo ou edição) setupClientForm: function(mode, clientData = null) { // Limpar formulário JaniceApp.elements.clientForm.reset(); JaniceApp.elements.logoPreview.style.display = 'none'; JaniceApp.elements.logoPreview.innerHTML = ''; if (mode === 'new') { JaniceApp.elements.clientFormTitle.textContent = 'Novo Cliente'; JaniceApp.elements.clientCnpjInput.disabled = false; JaniceApp.elements.clientForm.dataset.mode = 'new'; JaniceApp.elements.clientForm.dataset.id = ''; // Configurar cor padrão para novo cliente const colorInput = document.getElementById('client-color'); if (colorInput) { colorInput.value = '#6a5acd'; this.setupColorPicker(); // Atualizar preview } } else if (mode === 'edit') { JaniceApp.elements.clientFormTitle.textContent = 'Editar Cliente'; JaniceApp.elements.clientNameInput.value = clientData.nome; JaniceApp.elements.clientCnpjInput.value = JaniceApp.utils.formatCnpj(clientData.cnpj); JaniceApp.elements.clientCnpjInput.disabled = true; // Não permitir editar CNPJ if (clientData.logo) { JaniceApp.elements.logoPreview.innerHTML = `Logo`; JaniceApp.elements.logoPreview.style.display = 'block'; } // Carregar cor do cliente const colorInput = document.getElementById('client-color'); if (colorInput) { colorInput.value = clientData.cor || '#6a5acd'; this.setupColorPicker(); // Atualizar preview com a cor carregada } JaniceApp.elements.clientForm.dataset.mode = 'edit'; JaniceApp.elements.clientForm.dataset.id = clientData._id; } // Mostrar formulário JaniceApp.elements.clientDetailsContainer.style.display = 'none'; JaniceApp.elements.clientFormContainer.style.display = 'block'; JaniceApp.elements.welcomeContainer.style.display = 'none'; }, // Salvar cliente (novo ou edição) saveClient: async function(event) { event.preventDefault(); const mode = JaniceApp.elements.clientForm.dataset.mode; const clientId = JaniceApp.elements.clientForm.dataset.id; // Validar campos if (!JaniceApp.elements.clientNameInput.value.trim()) { alert('O nome da empresa é obrigatório'); return; } if (mode === 'new' && !JaniceApp.elements.clientCnpjInput.value.trim()) { alert('O CNPJ é obrigatório'); return; } try { // Preparar dados do cliente const formData = new FormData(); formData.append('nome', JaniceApp.elements.clientNameInput.value.trim()); if (mode === 'new') { formData.append('cnpj', JaniceApp.elements.clientCnpjInput.value.trim()); } if (JaniceApp.elements.clientLogoInput.files.length > 0) { formData.append('logo', JaniceApp.elements.clientLogoInput.files[0]); } // Incluir cor personalizada const colorInput = document.getElementById('client-color'); if (colorInput) { formData.append('cor', colorInput.value); } // Configurar requisição let url, method; if (mode === 'new') { url = '/api/clientes'; method = 'POST'; } else { url = `/api/clientes/${clientId}`; method = 'PUT'; } // Enviar requisição const response = await fetch(url, { method, body: formData }); if (!response.ok) { const errorData = await response.json(); // Tratamento específico para diferentes tipos de erros if (errorData.code === 'INVALID_CNPJ') { throw new Error(`CNPJ inválido: ${errorData.message}`); } else if (errorData.code === 'DUPLICATE_CNPJ') { throw new Error(`CNPJ duplicado: ${errorData.message}`); } else if (errorData.code === 'FILE_TOO_LARGE') { throw new Error('Imagem muito grande: A imagem do logo deve ter no máximo 5MB.'); } else if (errorData.code === 'VALIDATION_ERROR') { const details = errorData.details ? Object.values(errorData.details).join('\n- ') : ''; throw new Error(`Dados inválidos:\n- ${details || errorData.message}`); } else { // Erro genérico, usar a mensagem fornecida pelo servidor throw new Error(errorData.message || 'Erro ao salvar cliente'); } } // Processar resposta const savedClient = await response.json(); // Recarregar lista de clientes await this.loadClients(); // Mostrar detalhes do cliente salvo this.loadClientDetails(savedClient._id); } catch (error) { console.error('Erro ao salvar cliente:', error); // Usar um modal ou uma caixa de diálogo mais amigável em vez de alert // Por enquanto, vamos usar alert com formatação melhorada alert(`❌ ${error.message || 'Não foi possível salvar o cliente. Tente novamente.'}`); } }, // Mostrar confirmação de exclusão showDeleteConfirmation: function(client) { // Preencher nome do cliente no modal JaniceApp.elements.deleteClientName.textContent = client.nome; // Configurar botão de confirmação JaniceApp.elements.confirmDeleteBtn.onclick = () => { this.deleteClient(client._id); }; // Mostrar modal JaniceApp.elements.deleteConfirmModal.classList.add('show'); }, // Excluir cliente deleteClient: async function(clientId) { try { // Fazer requisição para excluir cliente const response = await fetch(`/api/clientes/${clientId}`, { method: 'DELETE' }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'Erro ao excluir cliente'); } // Fechar modal JaniceApp.elements.deleteConfirmModal.classList.remove('show'); // Recarregar lista de clientes await this.loadClients(); // Esconder detalhes do cliente e mostrar tela de boas-vindas JaniceApp.elements.clientDetailsContainer.style.display = 'none'; JaniceApp.elements.clientDetailsPanel.style.display = 'none'; JaniceApp.elements.welcomeContainer.style.display = 'block'; // Limpar ID do cliente atual JaniceApp.state.currentClientId = null; } catch (error) { console.error('Erro ao excluir cliente:', error); alert(error.message || 'Não foi possível excluir o cliente. Tente novamente.'); } }, // Configurar seletor de cores setupColorPicker: function() { const colorInput = document.getElementById('client-color'); const colorSample = document.getElementById('color-sample'); const colorValue = document.getElementById('color-value'); if (colorInput && colorSample && colorValue) { // Função para atualizar preview function updateColorPreview(color) { colorSample.style.backgroundColor = color; colorValue.textContent = color.toUpperCase(); } // Atualizar preview quando a cor mudar (input para tempo real) colorInput.addEventListener('input', (e) => { updateColorPreview(e.target.value); }); // Atualizar preview quando a cor mudar (change para compatibilidade) colorInput.addEventListener('change', (e) => { updateColorPreview(e.target.value); }); // Inicializar com cor atual updateColorPreview(colorInput.value); } }, // Configurar logos clicáveis setupClickableLogos: function() { // Logo do painel central const centralLogo = document.getElementById('central-client-logo'); const detailLogo = document.getElementById('detail-client-logo'); if (centralLogo && detailLogo) { // Tornar logos clicáveis centralLogo.classList.add('clickable'); detailLogo.classList.add('clickable'); // Eventos de clique nos logos centralLogo.addEventListener('click', () => { if (JaniceApp.state.currentClientId) { document.getElementById('central-logo-input').click(); } }); detailLogo.addEventListener('click', () => { if (JaniceApp.state.currentClientId) { document.getElementById('detail-logo-input').click(); } }); // Eventos de mudança nos inputs de arquivo const centralLogoInput = document.getElementById('central-logo-input'); const detailLogoInput = document.getElementById('detail-logo-input'); if (centralLogoInput) { centralLogoInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { this.uploadClientLogo(e.target.files[0]); } }); } if (detailLogoInput) { detailLogoInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { this.uploadClientLogo(e.target.files[0]); } }); } } }, // Função para fazer upload do logo do cliente uploadClientLogo: async function(file) { if (!JaniceApp.state.currentClientId) { alert('Nenhum cliente selecionado'); return; } // Validar tamanho do arquivo (máximo 5MB) if (file.size > 5 * 1024 * 1024) { alert('A imagem é muito grande. O tamanho máximo permitido é 5MB.'); return; } // Validar tipo de arquivo if (!file.type.startsWith('image/')) { alert('Por favor, selecione apenas arquivos de imagem.'); return; } try { // Mostrar feedback visual const centralLogo = document.getElementById('central-client-logo'); const detailLogo = document.getElementById('detail-client-logo'); // Adicionar classe de carregamento centralLogo.style.opacity = '0.5'; detailLogo.style.opacity = '0.5'; // Preparar dados do formulário const formData = new FormData(); formData.append('logo', file); // Enviar requisição const response = await fetch(`/api/clientes/${JaniceApp.state.currentClientId}`, { method: 'PUT', body: formData }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Erro ao atualizar logo'); } // Processar resposta const updatedClient = await response.json(); // Atualizar logos na interface this.updateClientLogos(updatedClient.logo); // Recarregar lista de clientes para refletir mudanças await this.loadClients(); // Feedback de sucesso console.log('✅ Logo atualizado com sucesso'); } catch (error) { console.error('Erro ao atualizar logo:', error); alert(`Não foi possível atualizar o logo: ${error.message}`); } finally { // Restaurar opacidade const centralLogo = document.getElementById('central-client-logo'); const detailLogo = document.getElementById('detail-client-logo'); centralLogo.style.opacity = '1'; detailLogo.style.opacity = '1'; // Limpar inputs const centralLogoInput = document.getElementById('central-logo-input'); const detailLogoInput = document.getElementById('detail-logo-input'); if (centralLogoInput) centralLogoInput.value = ''; if (detailLogoInput) detailLogoInput.value = ''; } }, // Função para atualizar logos na interface updateClientLogos: function(logoUrl) { const centralLogo = document.getElementById('central-client-logo'); const detailLogo = document.getElementById('detail-client-logo'); if (logoUrl) { // Atualizar logo central centralLogo.innerHTML = ` Logo da empresa
Clique para alterar logo
`; // Atualizar logo lateral detailLogo.innerHTML = ` Logo da empresa
Clique para alterar logo
`; } else { // Mostrar ícone padrão centralLogo.innerHTML = `
Clique para adicionar logo
`; detailLogo.innerHTML = `
Clique para adicionar logo
`; } } }; // ===== MÓDULO DE ANÁLISES ===== JaniceApp.modules.analysis = { init: function() { console.log('🔄 Inicializando módulo de Análises...'); // Configurar eventos this.setupEvents(); console.log('✅ Módulo de Análises inicializado'); }, setupEvents: function() { // Cancelar análise if (JaniceApp.elements.cancelAnalysisBtn) { JaniceApp.elements.cancelAnalysisBtn.addEventListener('click', () => { JaniceApp.elements.analysisContainer.style.display = 'none'; // Voltar para os detalhes do cliente if (JaniceApp.state.currentClientId) { JaniceApp.elements.clientDetailsPanel.style.display = 'block'; } else { JaniceApp.elements.welcomeContainer.style.display = 'block'; } }); } // Iniciar análise if (JaniceApp.elements.startAnalysisBtn) { JaniceApp.elements.startAnalysisBtn.addEventListener('click', () => { if (JaniceApp.state.currentClientId) { JaniceApp.elements.analysisContainer.style.display = 'none'; this.createNewAnalysis(JaniceApp.state.currentClientId); } }); } // Copiar relatório if (JaniceApp.elements.copyReportButton) { JaniceApp.elements.copyReportButton.addEventListener('click', () => { this.copyReport(); }); } // Exportar PDF if (JaniceApp.elements.exportPdfButton) { JaniceApp.elements.exportPdfButton.addEventListener('click', () => { this.exportPdf(); }); } }, // Mostrar formulário de nova análise showAnalysisForm: function() { // Mostrar apenas o formulário de análise (estado exclusivo) JaniceApp.utils.showOnlySection('analysis-container'); // Scroll automático para o formulário de análise JaniceApp.utils.scrollToElement('analysis-container'); }, // Criar nova análise createNewAnalysis: async function(clientId) { try { // Registrar processo no painel de processos ativos const client = JaniceApp.state.currentClients.find(c => c._id === clientId); const processId = JaniceApp.state.activeProcessesManager.registerProcess( 'analise', clientId, `Análise de ${client ? client.nome : 'Cliente'}` ); // Mostrar tela de carregamento JaniceApp.elements.welcomeContainer.style.display = 'none'; JaniceApp.elements.errorContainer.style.display = 'none'; JaniceApp.elements.resultContainer.style.display = 'none'; JaniceApp.elements.loadingContainer.style.display = 'block'; // Inicializar barra de progresso this.resetProgress(); // Armazenar o ID do cliente para uso futuro window.currentAnalysisClientId = clientId; // Enviar solicitação para criar análise const response = await fetch(`/api/analises/cliente/${clientId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); // Verificar se a resposta foi bem-sucedida if (!response.ok) { // Fechar conexão SSE se estiver aberta if (window.progressEventSource) { window.progressEventSource.close(); window.progressEventSource = null; } const errorData = await response.json(); throw new Error(errorData.message || 'Erro ao criar análise'); } // Processar resposta - apenas armazenar o ID da análise const analysis = await response.json(); window.currentAnalysisId = analysis._id; // Recarregar histórico de análises em segundo plano this.loadClientAnalyses(clientId); // Iniciar atualizações de progresso via SSE // A visualização da análise só acontecerá quando o processo estiver concluído this.startProgressUpdates(clientId); } catch (error) { console.error('Erro:', error); this.showError(error.message || 'Ocorreu um erro ao criar a análise.'); } }, // Carregar análises do cliente loadClientAnalyses: async function(clientId) { try { const analyses = await JaniceApp.utils.safeFetch(`/api/analises/cliente/${clientId}`); // Se safeFetch retornou null (redirecionamento), não continuar if (analyses === null) return; if (!analyses.length) { JaniceApp.elements.analysisList.innerHTML = `

Nenhuma análise realizada

`; return; } // Ordenar análises por data (mais recente primeiro) analyses.sort((a, b) => new Date(b.dataCriacao) - new Date(a.dataCriacao)); // Renderizar lista de análises JaniceApp.elements.analysisList.innerHTML = analyses.map(analysis => { let statusClass = 'completed'; let statusText = 'Concluído'; if (analysis.emProgresso) { statusClass = 'in-progress'; statusText = 'Em progresso'; } else if (analysis.erro) { statusClass = 'error'; statusText = 'Erro'; } return `
${new Date(analysis.dataCriacao).toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit', year: 'numeric' })}
Análise de Mercado e Estratégia
${statusText}
`; }).join(''); // Adicionar evento de clique para cada análise JaniceApp.elements.analysisList.querySelectorAll('.analysis-item').forEach(item => { const content = item.querySelector('.analysis-item-content'); content.addEventListener('click', () => { const analysisId = item.dataset.id; this.viewAnalysis(analysisId); }); }); // Adicionar eventos para botões de delete JaniceApp.elements.analysisList.querySelectorAll('.delete-analysis-btn').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); // Evitar que o clique propague para o item const analysisId = btn.dataset.id; this.deleteAnalysis(analysisId); }); }); } catch (error) { console.error('Erro ao carregar análises:', error); JaniceApp.elements.analysisList.innerHTML = `

Erro ao carregar análises. Tente novamente.

`; } }, // Visualizar análise específica viewAnalysis: async function(analysisId) { try { const response = await fetch(`/api/analises/${analysisId}`, { credentials: 'include', headers: { 'Accept': 'application/json' } }); if (!response.ok) { console.error(`❌ [FETCH-ERROR] Status: ${response.status} ${response.statusText}`); console.error(`❌ [FETCH-ERROR] URL: ${response.url}`); if (response.status === 502) { throw new Error('Erro 502: Servidor temporariamente indisponível. Tente novamente em alguns segundos.'); } else if (response.status === 401) { throw new Error('Erro de autenticação. Faça login novamente.'); } else { throw new Error(`Erro ${response.status}: ${response.statusText}`); } } const analysis = await response.json(); JaniceApp.state.currentAnalysisData = analysis; // Preencher dados da análise JaniceApp.elements.companyNameEl.textContent = analysis.cliente.nome; JaniceApp.elements.resultCnpjEl.textContent = JaniceApp.utils.formatCnpj(analysis.cliente.cnpj); JaniceApp.elements.resultDateEl.textContent = new Date(analysis.dataCriacao).toLocaleString('pt-BR'); // Limpar conteúdo anterior se existir const existingContent = document.querySelector('.analysis-content-container'); if (existingContent) { existingContent.remove(); } // Criar container para o conteúdo da análise const analysisContentContainer = document.createElement('div'); analysisContentContainer.className = 'analysis-content-container'; analysisContentContainer.innerHTML = `
${this.formatMarkdownForAnalysis(analysis.conteudo)}
`; // Inserir o conteúdo da análise no container de resultado let inserted = false; // Opção 1: Tentar inserir no resultContentContainer const resultContentContainer = document.querySelector('.result-content'); if (resultContentContainer) { resultContentContainer.prepend(analysisContentContainer); inserted = true; } // Opção 2: Tentar inserir usando pdfViewer como referência if (!inserted && JaniceApp.elements.pdfViewer && JaniceApp.elements.pdfViewer.parentNode) { JaniceApp.elements.pdfViewer.parentNode.insertBefore(analysisContentContainer, JaniceApp.elements.pdfViewer); inserted = true; } // Opção 3: Tentar inserir diretamente no resultContainer if (!inserted) { const resultContainer = document.getElementById('result-container'); if (resultContainer) { resultContainer.prepend(analysisContentContainer); inserted = true; } } // Se nenhuma das opções funcionou, registrar erro if (!inserted) { console.error('Não foi possível encontrar um container para inserir o conteúdo da análise'); throw new Error('Não foi possível exibir a análise. Container não encontrado.'); } // Configurar PDF com verificação de nulos if (analysis.pdfUrl) { // Verificar se pdfViewer existe antes de tentar definir seu innerHTML if (JaniceApp.elements.pdfViewer) { JaniceApp.elements.pdfViewer.innerHTML = `

Relatório PDF Pronto

Seu relatório estratégico foi gerado com sucesso e está pronto para visualização.

O PDF será aberto em uma nova aba do navegador
`; } // Verificar se exportPdfButton existe antes de modificá-lo if (JaniceApp.elements.exportPdfButton) { JaniceApp.elements.exportPdfButton.disabled = false; JaniceApp.elements.exportPdfButton.innerHTML = ' Abrir Relatório PDF'; } } else { // Verificar se pdfViewer existe antes de tentar definir seu innerHTML if (JaniceApp.elements.pdfViewer) { JaniceApp.elements.pdfViewer.innerHTML = `

PDF não disponível. Você ainda pode copiar o relatório usando o botão abaixo.

`; } // Verificar se exportPdfButton existe antes de modificá-lo if (JaniceApp.elements.exportPdfButton) { JaniceApp.elements.exportPdfButton.disabled = true; JaniceApp.elements.exportPdfButton.innerHTML = ' PDF Indisponível'; } } // Mostrar apenas a seção de resultados (estado exclusivo) JaniceApp.utils.showOnlySection('result-container'); // Scroll automático para a seção de resultados JaniceApp.utils.scrollToElement('result-container'); } catch (error) { console.error('Erro ao visualizar análise:', error); alert('Não foi possível carregar a análise. Tente novamente.'); } }, // Deletar análise deleteAnalysis: async function(analysisId) { if (!confirm('Tem certeza que deseja excluir esta análise? Esta ação não pode ser desfeita.')) { return; } try { const response = await fetch(`/api/analises/${analysisId}`, { method: 'DELETE' }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Erro ao excluir análise'); } // Recarregar lista de análises if (JaniceApp.state.currentClientId) { this.loadClientAnalyses(JaniceApp.state.currentClientId); } console.log('✅ Análise excluída com sucesso'); } catch (error) { console.error('Erro ao excluir análise:', error); alert('Não foi possível excluir a análise. Tente novamente.'); } }, // Formatar markdown específico para análises formatMarkdownForAnalysis: function(text) { if (!text) return ''; let formatted = text; // Converter títulos formatted = formatted.replace(/^# (.+)$/gm, '

$1

'); formatted = formatted.replace(/^## (.+)$/gm, '

$1

'); formatted = formatted.replace(/^### (.+)$/gm, '

$1

'); formatted = formatted.replace(/^#### (.+)$/gm, '

$1

'); // Converter negrito e itálico formatted = formatted.replace(/\*\*([^*]+)\*\*/g, '$1'); formatted = formatted.replace(/\*([^*]+)\*/g, '$1'); // Converter listas formatted = formatted.replace(/^- (.+)$/gm, '
  • $1
  • '); formatted = formatted.replace(/^(\d+)\. (.+)$/gm, '
  • $2
  • '); // Agrupar listas formatted = formatted.replace(/((
  • .*<\/li>\s*)+)/g, ''); // Converter tabelas simples const tableRegex = /\|(.+)\|\n\|[-\s|]+\|\n((\|.+\|\n?)+)/g; formatted = formatted.replace(tableRegex, (match, header, separator, rows) => { const headerCells = header.split('|').map(cell => cell.trim()).filter(cell => cell); const rowsArray = rows.trim().split('\n').map(row => row.split('|').map(cell => cell.trim()).filter(cell => cell) ); let table = ''; headerCells.forEach(cell => { table += ``; }); table += ''; rowsArray.forEach(row => { table += ''; row.forEach(cell => { table += ``; }); table += ''; }); table += '
    ${cell}
    ${cell}
    '; return table; }); // Converter parágrafos formatted = formatted.replace(/\n\n/g, '

    '); formatted = `

    ${formatted}

    `; // Limpar tags vazias formatted = formatted.replace(/

    <\/p>/g, ''); formatted = formatted.replace(/

    ()/g, '$1'); formatted = formatted.replace(/(<\/h[1-6]>)<\/p>/g, '$1'); formatted = formatted.replace(/

    (