// ===== MÓDULOS PARA PLANOS DE AÇÃO, GALERIA E MOCKUPS ===== // 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 PLANOS DE AÇÃO ===== JaniceApp.modules.actionPlans = { // Elementos específicos para planos de ação elements: { newActionPlanBtn: null, cancelActionPlanBtn: null, startActionPlanBtn: null, actionPlanForm: null, actionPlanTitleInput: null, availableTranscriptions: null, availableAnalyses: null, selectedDocumentsList: null, actionPlansList: null, actionPlanTitleDisplay: null, actionPlanDate: null, actionPlanDocumentsCount: null, actionPlanText: null, exportActionPlanPdfBtn: null, copyActionPlanBtn: null, backToClientFromPlanBtn: null }, // Estado dos documentos selecionados selectedDocuments: [], init: function() { console.log('🔄 Inicializando módulo de Planos de Ação...'); // Inicializar elementos this.initElements(); // Configurar eventos this.setupEvents(); console.log('✅ Módulo de Planos de Ação inicializado'); }, initElements: function() { this.elements.newActionPlanBtn = document.getElementById('new-action-plan-btn'); this.elements.cancelActionPlanBtn = document.getElementById('cancel-action-plan-btn'); this.elements.startActionPlanBtn = document.getElementById('start-action-plan-btn'); this.elements.actionPlanForm = document.getElementById('action-plan-form'); this.elements.actionPlanTitleInput = document.getElementById('action-plan-title'); this.elements.availableTranscriptions = document.getElementById('available-transcriptions'); this.elements.availableAnalyses = document.getElementById('available-analyses'); this.elements.selectedDocumentsList = document.getElementById('selected-documents-list'); this.elements.actionPlansList = document.getElementById('action-plans-list'); this.elements.actionPlanTitleDisplay = document.getElementById('action-plan-title-display'); this.elements.actionPlanDate = document.getElementById('action-plan-date'); this.elements.actionPlanDocumentsCount = document.getElementById('action-plan-documents-count'); this.elements.actionPlanText = document.getElementById('action-plan-text'); this.elements.exportActionPlanPdfBtn = document.getElementById('export-action-plan-pdf'); this.elements.copyActionPlanBtn = document.getElementById('copy-action-plan'); this.elements.backToClientFromPlanBtn = document.getElementById('back-to-client-from-plan'); }, setupEvents: function() { // Botão de novo plano de ação if (this.elements.newActionPlanBtn) { this.elements.newActionPlanBtn.addEventListener('click', () => this.showActionPlanForm()); } // Cancelar plano de ação if (this.elements.cancelActionPlanBtn) { this.elements.cancelActionPlanBtn.addEventListener('click', () => { JaniceApp.elements.actionPlanContainer.style.display = 'none'; if (JaniceApp.state.currentClientId) { JaniceApp.elements.clientDetailsPanel.style.display = 'block'; } else { JaniceApp.elements.welcomeContainer.style.display = 'block'; } }); } // Submeter formulário if (this.elements.actionPlanForm) { this.elements.actionPlanForm.addEventListener('submit', (e) => this.submitActionPlanForm(e)); } // Monitorar mudanças no título if (this.elements.actionPlanTitleInput) { this.elements.actionPlanTitleInput.addEventListener('input', () => this.updateSubmitButtonState()); } // Voltar do resultado para detalhes do cliente if (this.elements.backToClientFromPlanBtn) { this.elements.backToClientFromPlanBtn.addEventListener('click', () => { JaniceApp.elements.actionPlanResultContainer.style.display = 'none'; JaniceApp.elements.clientDetailsPanel.style.display = 'block'; }); } // Copiar plano de ação if (this.elements.copyActionPlanBtn) { this.elements.copyActionPlanBtn.addEventListener('click', () => this.copyActionPlan()); } // Exportar PDF do plano de ação if (this.elements.exportActionPlanPdfBtn) { this.elements.exportActionPlanPdfBtn.addEventListener('click', () => this.exportActionPlanPdf()); } }, // Mostrar formulário de novo plano de ação showActionPlanForm: function() { // Limpar formulário this.elements.actionPlanForm.reset(); this.selectedDocuments = []; this.updateSelectedDocumentsList(); // Carregar documentos disponíveis this.loadAvailableDocuments(); // Mostrar apenas o formulário de plano de ação (estado exclusivo) JaniceApp.utils.showOnlySection('action-plan-container'); // Scroll automático para o formulário JaniceApp.utils.scrollToElement('action-plan-container'); }, // Carregar documentos disponíveis (transcrições e análises) loadAvailableDocuments: async function() { if (!JaniceApp.state.currentClientId) return; try { // Carregar transcrições usando safeFetch const transcriptions = await JaniceApp.utils.safeFetch(`/api/transcricoes/cliente/${JaniceApp.state.currentClientId}`); if (transcriptions !== null) { // Extrair dados do wrapper da API se presente const transcriptionsArray = Array.isArray(transcriptions) ? transcriptions : (transcriptions?.data || []); this.renderAvailableTranscriptions(transcriptionsArray); } // Carregar análises usando safeFetch const analyses = await JaniceApp.utils.safeFetch(`/api/analises/cliente/${JaniceApp.state.currentClientId}`); if (analyses !== null) { // Extrair dados do wrapper da API se presente const analysesArray = Array.isArray(analyses) ? analyses : (analyses?.data || []); this.renderAvailableAnalyses(analysesArray); } } catch (error) { console.error('Erro ao carregar documentos:', error); } }, // Renderizar transcrições disponíveis renderAvailableTranscriptions: function(transcriptions) { if (!transcriptions.length) { this.elements.availableTranscriptions.innerHTML = `

Nenhuma transcrição disponível

`; return; } // Filtrar apenas transcrições concluídas const completedTranscriptions = transcriptions.filter(t => !t.emProgresso && !t.erro); if (!completedTranscriptions.length) { this.elements.availableTranscriptions.innerHTML = `

Nenhuma transcrição concluída disponível

`; return; } this.elements.availableTranscriptions.innerHTML = completedTranscriptions.map(transcription => `
${transcription.titulo}
${new Date(transcription.dataCriacao).toLocaleDateString('pt-BR')} ${this.formatDuration(transcription.duracao)}
`).join(''); // Adicionar eventos de clique this.elements.availableTranscriptions.querySelectorAll('.document-item').forEach(item => { item.addEventListener('click', () => this.toggleDocumentSelection(item)); }); }, // Renderizar análises disponíveis renderAvailableAnalyses: function(analyses) { if (!analyses.length) { this.elements.availableAnalyses.innerHTML = `

Nenhuma análise disponível

`; return; } this.elements.availableAnalyses.innerHTML = analyses.map(analysis => `
Análise de Mercado e Estratégia
${new Date(analysis.dataCriacao).toLocaleDateString('pt-BR')}
`).join(''); // Adicionar eventos de clique this.elements.availableAnalyses.querySelectorAll('.document-item').forEach(item => { item.addEventListener('click', () => this.toggleDocumentSelection(item)); }); }, // Alternar seleção de documento toggleDocumentSelection: function(item) { const id = item.dataset.id; const type = item.dataset.type; const title = item.querySelector('.document-item-title').textContent; // Verificar se já está selecionado const existingIndex = this.selectedDocuments.findIndex(doc => doc.id === id); if (existingIndex >= 0) { // Remover da seleção this.selectedDocuments.splice(existingIndex, 1); item.classList.remove('selected'); } else { // Adicionar à seleção this.selectedDocuments.push({ id, type, title }); item.classList.add('selected'); } // Atualizar lista de documentos selecionados this.updateSelectedDocumentsList(); // Atualizar estado do botão de envio this.updateSubmitButtonState(); }, // Atualizar lista de documentos selecionados updateSelectedDocumentsList: function() { if (!this.selectedDocuments.length) { this.elements.selectedDocumentsList.innerHTML = `

Selecione pelo menos um documento acima

`; return; } this.elements.selectedDocumentsList.innerHTML = this.selectedDocuments.map(doc => `
${doc.title}
${doc.type === 'transcription' ? 'Transcrição' : 'Análise'}
`).join(''); // Adicionar eventos para remover documentos this.elements.selectedDocumentsList.querySelectorAll('.remove-selected-btn').forEach(btn => { btn.addEventListener('click', () => { const id = btn.dataset.id; this.removeDocumentFromSelection(id); }); }); }, // Remover documento da seleção removeDocumentFromSelection: function(id) { // Remover da lista de selecionados this.selectedDocuments = this.selectedDocuments.filter(doc => doc.id !== id); // Remover classe selected do item na lista de disponíveis const item = document.querySelector(`[data-id="${id}"]`); if (item) { item.classList.remove('selected'); } // Atualizar listas this.updateSelectedDocumentsList(); this.updateSubmitButtonState(); }, // Atualizar estado do botão de envio updateSubmitButtonState: function() { const hasTitle = this.elements.actionPlanTitleInput.value.trim().length > 0; const hasDocuments = this.selectedDocuments.length > 0; this.elements.startActionPlanBtn.disabled = !(hasTitle && hasDocuments); }, // Submeter formulário de plano de ação submitActionPlanForm: async function(event) { event.preventDefault(); if (!this.elements.actionPlanTitleInput.value.trim()) { alert('O título do plano de ação é obrigatório'); return; } if (!this.selectedDocuments.length) { alert('Selecione pelo menos um documento'); return; } try { // Registrar processo no painel de processos ativos const client = JaniceApp.state.currentClients.find(c => c._id === JaniceApp.state.currentClientId); const processId = JaniceApp.state.activeProcessesManager.registerProcess( 'plano-acao', JaniceApp.state.currentClientId, `Plano de Ação: ${this.elements.actionPlanTitleInput.value.trim()}` ); // Mostrar tela de carregamento IMEDIATAMENTE JaniceApp.utils.showOnlySection('loading-container'); // Adaptar interface para plano de ação document.querySelector('.loading-text').textContent = 'Gerando plano de ação estratégico...'; JaniceApp.elements.loadingStatus.textContent = 'Preparando análise dos documentos selecionados...'; // Resetar e configurar progresso específico para planos de ação this.resetProgress(); this.setupActionPlanProgressSteps(); // Iniciar simulação de progresso imediatamente this.startActionPlanProgressSimulation(); // Preparar dados - separar por tipo conforme esperado pelo backend const transcricaoIds = this.selectedDocuments .filter(doc => doc.type === 'transcription') .map(doc => doc.id); const analiseIds = this.selectedDocuments .filter(doc => doc.type === 'analysis') .map(doc => doc.id); const requestData = { titulo: this.elements.actionPlanTitleInput.value.trim(), transcricaoIds, analiseIds }; // Debug: verificar dados sendo enviados console.log('🔄 [DEBUG-PLANO-ACAO] Dados enviados:', requestData); // Enviar requisição const response = await fetch(`/api/planos-acao/${JaniceApp.state.currentClientId}/gerar`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Erro ao criar plano de ação'); } const plan = await response.json(); // Armazenar ID do plano para monitoramento window.currentActionPlanId = plan.planoId; // Iniciar monitoramento do progresso real this.startActionPlanMonitoring(plan.planoId); } catch (error) { console.error('Erro ao criar plano de ação:', error); this.showError(error.message || 'Ocorreu um erro ao criar o plano de ação.'); } }, // Configurar etapas específicas para planos de ação setupActionPlanProgressSteps: function() { document.getElementById('step-1').querySelector('.step-text').textContent = 'Análise de Documentos'; document.getElementById('step-2').querySelector('.step-text').textContent = 'Processamento IA'; document.getElementById('step-3').querySelector('.step-text').textContent = 'Geração de Estratégias'; document.getElementById('step-4').querySelector('.step-text').textContent = 'Finalização'; }, // Iniciar simulação de progresso para planos de ação startActionPlanProgressSimulation: function() { // Adicionar informações específicas sobre o processo const infoElement = document.createElement('div'); infoElement.className = 'action-plan-progress-info'; infoElement.style.cssText = ` margin: 20px 0; padding: 15px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 8px; border-left: 4px solid #28a745; font-size: 14px; line-height: 1.5; `; infoElement.innerHTML = `
Processamento Inteligente em Andamento

Nossa IA está analisando os documentos selecionados para criar um plano de ação estratégico personalizado. Este processo pode levar alguns minutos para garantir a máxima qualidade e relevância.

Tempo estimado: 2-5 minutos dependendo da quantidade de conteúdo a ser analisado.
`; // Inserir após a barra de progresso const progressContainer = document.querySelector('.progress-container'); if (progressContainer && !progressContainer.querySelector('.action-plan-progress-info')) { progressContainer.appendChild(infoElement); } // Simular progresso inicial mais lento e realista const progressSteps = [ { percentage: 15, message: 'Carregando documentos selecionados...', step: 1, stepStatus: 'active', delay: 1000 }, { percentage: 35, message: 'Analisando conteúdo com IA...', step: 2, stepStatus: 'active', delay: 2000 }, { percentage: 60, message: 'Gerando estratégias personalizadas...', step: 3, stepStatus: 'active', delay: 3000 }, { percentage: 85, message: 'Finalizando plano de ação...', step: 4, stepStatus: 'active', delay: 2000 } ]; let currentStep = 0; const executeNextStep = () => { if (currentStep < progressSteps.length) { const step = progressSteps[currentStep]; this.updateProgress(step); currentStep++; setTimeout(executeNextStep, step.delay); } // Não completar automaticamente - aguardar resposta real do servidor }; // Iniciar após pequeno delay para dar sensação de início setTimeout(executeNextStep, 500); }, // Monitorar progresso real do plano de ação startActionPlanMonitoring: function(planId) { // Verificar status a cada 5 segundos const checkInterval = setInterval(async () => { try { const response = await fetch(`/api/planos-acao/plano/${planId}`); if (!response.ok) { console.error('Erro ao verificar status do plano de ação'); return; } const plan = await response.json(); // Se não está mais em progresso if (!plan.emProgresso) { clearInterval(checkInterval); if (plan.erro) { // Mostrar erro this.showError(plan.mensagemErro || 'Erro ao gerar plano de ação'); } else { // Completar progresso e mostrar resultado this.updateProgress({ percentage: 100, message: 'Plano de ação concluído com sucesso!', step: 4, stepStatus: 'completed' }); // Aguardar 2 segundos antes de mostrar resultado setTimeout(() => { // Recarregar lista de planos de ação this.loadClientActionPlans(JaniceApp.state.currentClientId); // 🔧 CORREÇÃO: Usar showOnlySection para garantir transição correta // Mostrar o plano criado automaticamente this.viewActionPlan(planId); }, 2000); } } } catch (error) { console.error('Erro ao monitorar plano de ação:', error); } }, 5000); // Verificar a cada 5 segundos // Timeout de segurança (10 minutos) setTimeout(() => { clearInterval(checkInterval); if (document.getElementById('loading-container').style.display !== 'none') { this.showError('Timeout: O plano de ação está demorando mais que o esperado. Verifique a lista de planos de ação em alguns minutos.'); } }, 600000); // 10 minutos }, // Carregar planos de ação do cliente loadClientActionPlans: async function(clientId) { try { const actionPlans = await JaniceApp.utils.safeFetch(`/api/planos-acao/${clientId}`); // Se safeFetch retornou null (redirecionamento), não continuar if (actionPlans === null) return; if (!actionPlans.length) { this.elements.actionPlansList.innerHTML = `

Nenhum plano de ação criado

`; return; } // Ordenar por data (mais recente primeiro) actionPlans.sort((a, b) => new Date(b.dataCriacao) - new Date(a.dataCriacao)); // Renderizar lista this.elements.actionPlansList.innerHTML = actionPlans.map(plan => { let statusClass = 'completed'; let statusText = 'Concluído'; if (plan.emProgresso) { statusClass = 'in-progress'; statusText = 'Em progresso'; } else if (plan.erro) { statusClass = 'error'; statusText = 'Erro'; } // Calcular total de documentos de forma segura const documentosBase = plan.documentosBase || { transcricoes: [], analises: [] }; const totalDocumentos = (documentosBase.transcricoes?.length || 0) + (documentosBase.analises?.length || 0); return `
${new Date(plan.dataCriacao).toLocaleDateString('pt-BR')}
${plan.titulo}
${totalDocumentos} documento(s) ${statusText}
`; }).join(''); // Adicionar eventos de clique this.elements.actionPlansList.querySelectorAll('.action-plan-item').forEach(item => { const content = item.querySelector('.action-plan-item-content'); content.addEventListener('click', () => { const planId = item.dataset.id; this.viewActionPlan(planId); }); }); // Adicionar eventos para botões de delete this.elements.actionPlansList.querySelectorAll('.delete-action-plan-btn').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const planId = btn.dataset.id; this.deleteActionPlan(planId); }); }); } catch (error) { console.error('Erro ao carregar planos de ação:', error); this.elements.actionPlansList.innerHTML = `

Erro ao carregar planos de ação. Tente novamente.

`; } }, // Visualizar plano de ação viewActionPlan: async function(planId) { try { const response = await fetch(`/api/planos-acao/plano/${planId}`); if (!response.ok) { throw new Error('Erro ao carregar plano de ação'); } const plan = await response.json(); JaniceApp.state.currentActionPlanData = plan; // Preencher dados do plano this.elements.actionPlanTitleDisplay.textContent = plan.titulo; this.elements.actionPlanDate.textContent = new Date(plan.dataCriacao).toLocaleString('pt-BR'); // Calcular total de documentos de forma segura const documentosBase = plan.documentosBase || { transcricoes: [], analises: [] }; const totalDocumentos = (documentosBase.transcricoes?.length || 0) + (documentosBase.analises?.length || 0); this.elements.actionPlanDocumentsCount.textContent = `${totalDocumentos} documento(s)`; // Exibir conteúdo do plano this.elements.actionPlanText.innerHTML = `
${this.formatMarkdownForActionPlan(plan.conteudo)}
`; // Configurar botões baseado na disponibilidade do PDF if (plan.pdfUrl) { this.elements.exportActionPlanPdfBtn.disabled = false; this.elements.exportActionPlanPdfBtn.innerHTML = ' Abrir Relatório PDF'; // Criar preview do PDF similar às análises const pdfPreview = document.createElement('div'); pdfPreview.className = 'pdf-preview-section'; pdfPreview.innerHTML = `

Relatório PDF Pronto

Seu plano de ação estratégico foi gerado com sucesso e está pronto para visualização.

O PDF será aberto em uma nova aba do navegador
`; // Inserir preview após o conteúdo do plano this.elements.actionPlanText.parentNode.insertBefore(pdfPreview, this.elements.actionPlanText.nextSibling); } else { this.elements.exportActionPlanPdfBtn.disabled = true; this.elements.exportActionPlanPdfBtn.innerHTML = ' PDF Indisponível'; // Remover preview anterior se existir const existingPreview = document.querySelector('.pdf-preview-section'); if (existingPreview) { existingPreview.remove(); } } // Mostrar apenas a seção de resultado do plano de ação JaniceApp.utils.showOnlySection('action-plan-result-container'); // Scroll automático JaniceApp.utils.scrollToElement('action-plan-result-container'); } catch (error) { console.error('Erro ao visualizar plano de ação:', error); alert('Não foi possível carregar o plano de ação. Tente novamente.'); } }, // Deletar plano de ação deleteActionPlan: async function(planId) { if (!confirm('Tem certeza que deseja excluir este plano de ação? Esta ação não pode ser desfeita.')) { return; } try { const response = await fetch(`/api/planos-acao/plano/${planId}`, { method: 'DELETE' }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Erro ao excluir plano de ação'); } // Recarregar lista de planos de ação if (JaniceApp.state.currentClientId) { this.loadClientActionPlans(JaniceApp.state.currentClientId); } console.log('✅ Plano de ação excluído com sucesso'); } catch (error) { console.error('Erro ao excluir plano de ação:', error); alert('Não foi possível excluir o plano de ação. Tente novamente.'); } }, // Copiar plano de ação copyActionPlan: function() { if (!JaniceApp.state.currentActionPlanData) return; const planContent = JaniceApp.state.currentActionPlanData.conteudo; navigator.clipboard.writeText(planContent) .then(() => { const originalText = this.elements.copyActionPlanBtn.innerHTML; this.elements.copyActionPlanBtn.innerHTML = ' Copiado!'; setTimeout(() => { this.elements.copyActionPlanBtn.innerHTML = originalText; }, 2000); }) .catch(err => { console.error('Erro ao copiar: ', err); }); }, // Exportar PDF do plano de ação exportActionPlanPdf: function() { if (!JaniceApp.state.currentActionPlanData) return; if (JaniceApp.state.currentActionPlanData.pdfUrl) { window.open(`/api/planos-acao/pdf/${JaniceApp.state.currentActionPlanData._id}`, '_blank'); } else { alert('PDF não disponível para este plano de ação.'); } }, // Formatar markdown específico para planos de ação formatMarkdownForActionPlan: 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 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(/

    (