// ========================================== // LegalData Manager - Main Application // ========================================== // --- Data Store --- let appData = { processos: [ { id: '2023-0456', cliente: 'João Silva', tribunal: 'TJSP', data: '2023-03-15', status: 'Ativo', prazo: '2024-01-15', descricao: 'Ação indenizatória' }, { id: '2023-0389', cliente: 'Maria Souza', tribunal: 'TRF4', data: '2023-02-20', status: 'Pendente', prazo: '2024-01-18', descricao: 'Mandado de segurança' }, { id: '2023-0412', cliente: 'Empresa XYZ Ltda', tribunal: 'TJMG', data: '2023-04-10', status: 'Urgente', prazo: '2024-01-20', descricao: 'Execução fiscal' }, { id: '2023-0501', cliente: 'Ana Oliveira', tribunal: 'TJSP', data: '2023-05-05', status: 'Ativo', prazo: '2024-02-10', descricao: 'Ação de cobrança' }, { id: '2023-0534', cliente: 'Carlos Mendes', tribunal: 'TRF1', data: '2023-06-12', status: 'Concluído', prazo: null, descricao: 'Habeas corpus' }, { id: '2023-0601', cliente: 'Tech Solutions SA', tribunal: 'TJSP', data: '2023-07-01', status: 'Ativo', prazo: '2024-03-01', descricao: 'Contrato comercial' }, { id: '2023-0645', cliente: 'Fernanda Lima', tribunal: 'TJMG', data: '2023-08-15', status: 'Pendente', prazo: '2024-03-20', descricao: 'Inventário' }, { id: '2023-0702', cliente: 'Roberto Santos', tribunal: 'TRF4', data: '2023-09-03', status: 'Ativo', prazo: '2024-04-05', descricao: 'Recurso de apelação' }, ], clientes: [ { id: 1, nome: 'João Silva', tipo: 'pf', cpfCnpj: '123.456.789-00', email: 'joao@email.com', telefone: '(11) 98765-4321', endereco: 'Rua A, 100, São Paulo-SP', processos: 2 }, { id: 2, nome: 'Maria Souza', tipo: 'pf', cpfCnpj: '987.654.321-00', email: 'maria@email.com', telefone: '(21) 99876-5432', endereco: 'Av B, 200, Rio de Janeiro-RJ', processos: 1 }, { id: 3, nome: 'Empresa XYZ Ltda', tipo: 'pj', cpfCnpj: '12.345.678/0001-90', email: 'contato@xyz.com', telefone: '(11) 3456-7890', endereco: 'Rua C, 300, São Paulo-SP', processos: 3 }, { id: 4, nome: 'Ana Oliveira', tipo: 'pf', cpfCnpj: '456.789.123-00', email: 'ana@email.com', telefone: '(31) 97654-3210', endereco: 'Rua D, 400, Belo Horizonte-MG', processos: 1 }, { id: 5, nome: 'Carlos Mendes', tipo: 'pf', cpfCnpj: '789.123.456-00', email: 'carlos@email.com', telefone: '(61) 96543-2109', endereco: 'SQN 5, Bloco E, Brasília-DF', processos: 1 }, { id: 6, nome: 'Tech Solutions SA', tipo: 'pj', cpfCnpj: '98.765.432/0001-10', email: 'juridico@techsol.com', telefone: '(11) 4567-8901', endereco: 'Av F, 600, São Paulo-SP', processos: 2 }, { id: 7, nome: 'Fernanda Lima', tipo: 'pf', cpfCnpj: '321.654.987-00', email: 'fernanda@email.com', telefone: '(31) 95432-1098', endereco: 'Rua G, 700, Belo Horizonte-MG', processos: 1 }, { id: 8, nome: 'Roberto Santos', tipo: 'pf', cpfCnpj: '654.987.321-00', email: 'roberto@email.com', telefone: '(51) 94321-0987', endereco: 'Rua H, 800, Porto Alegre-RS', processos: 1 }, ], evidencias: [], intimacoes: [], aaspConfig: { chave: '92E81C018B69454F8053133023AC438B' }, googleAuth: null, driveConnected: false, sheetsConnected: false, importPreview: null, }; // Load from localStorage function loadAppData() { const saved = localStorage.getItem('legaldata_app'); if (saved) { try { const parsed = JSON.parse(saved); appData = { ...appData, ...parsed }; } catch(e) { console.error('Error loading data', e); } } } function saveAppData() { localStorage.setItem('legaldata_app', JSON.stringify(appData)); } // --- Tab Navigation --- function showTab(tabId, navEl) { document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active')); document.querySelectorAll('.nav-link').forEach(n => n.classList.remove('active-nav')); const tab = document.getElementById(tabId); if (tab) tab.classList.add('active'); if (navEl) { navEl.classList.add('active-nav'); } else { document.querySelectorAll('.nav-link').forEach(n => { if (n.getAttribute('onclick') && n.getAttribute('onclick').includes(tabId)) { n.classList.add('active-nav'); } }); } const titles = { dashboard: 'Dashboard', processos: 'Gestão de Processos', clientes: 'Gestão de Clientes', provas: 'Galeria de Provas', intimacoes: 'Intimações AASP', import: 'Importar Dados', config: 'Configurações', sanitize: 'Sanitização de Dados', integrations: 'Integrações' }; document.getElementById('current-tab-title').textContent = titles[tabId] || tabId; if (tabId === 'provas') renderEvidence(); if (tabId === 'processos') renderProcessos(); if (tabId === 'clientes') renderClientes(); } function toggleSidebar() { document.getElementById('sidebar').classList.toggle('collapsed'); } // --- Modal Management --- function showModal(id) { const modal = document.getElementById('modal-' + id); if (modal) modal.classList.remove('hidden'); } function hideModal(id) { const modal = document.getElementById('modal-' + id); if (modal) modal.classList.add('hidden'); } // --- Toast Notifications --- function showToast(message, type = 'success') { const container = document.getElementById('toast-container'); const colors = { success: 'bg-green-500', error: 'bg-red-500', info: 'bg-blue-500', warning: 'bg-yellow-500' }; const icons = { success: 'fa-check-circle', error: 'fa-times-circle', info: 'fa-info-circle', warning: 'fa-exclamation-triangle' }; const toast = document.createElement('div'); toast.className = `toast ${colors[type]} text-white px-4 py-3 rounded-lg shadow-lg flex items-center space-x-3 min-w-72`; toast.innerHTML = `${message}`; container.appendChild(toast); requestAnimationFrame(() => toast.classList.add('show')); setTimeout(() => { toast.classList.remove('show'); setTimeout(() => toast.remove(), 400); }, 4000); } // --- Processos --- function renderProcessos() { const tbody = document.getElementById('processos-table-body'); if (!tbody) return; const statusColors = { 'Ativo': 'bg-green-100 text-green-800', 'Pendente': 'bg-yellow-100 text-yellow-800', 'Urgente': 'bg-red-100 text-red-800', 'Concluído': 'bg-blue-100 text-blue-800', 'Arquivado': 'bg-gray-100 text-gray-800' }; tbody.innerHTML = appData.processos.map(p => ` #${p.id} ${p.cliente} ${p.tribunal} ${formatDate(p.data)} ${p.status} `).join(''); } function addProcess() { const proc = { id: document.getElementById('proc-numero').value || generateId(), cliente: document.getElementById('proc-cliente').value, tribunal: document.getElementById('proc-tribunal').value, data: document.getElementById('proc-data').value, status: document.getElementById('proc-status').value, prazo: null, descricao: document.getElementById('proc-descricao').value }; appData.processos.push(proc); saveAppData(); renderProcessos(); hideModal('new-process'); showToast('Processo adicionado com sucesso!'); updateStats(); } function deleteProcess(id) { if (confirm('Deseja excluir este processo?')) { appData.processos = appData.processos.filter(p => p.id !== id); saveAppData(); renderProcessos(); showToast('Processo excluído', 'info'); updateStats(); } } // --- Clientes --- function renderClientes() { const tbody = document.getElementById('clientes-table-body'); if (!tbody) return; tbody.innerHTML = appData.clientes.map(c => ` ${c.nome} ${c.cpfCnpj} ${c.email} ${c.telefone} ${c.processos} `).join(''); } function addClient() { const cli = { id: Date.now(), nome: document.getElementById('cli-nome').value, tipo: document.getElementById('cli-tipo').value, cpfCnpj: document.getElementById('cli-cpfcnpj').value, email: document.getElementById('cli-email').value, telefone: document.getElementById('cli-telefone').value, endereco: document.getElementById('cli-endereco').value, processos: 0 }; appData.clientes.push(cli); saveAppData(); renderClientes(); hideModal('new-client'); showToast('Cliente adicionado com sucesso!'); updateStats(); populateSelects(); } function deleteClient(id) { if (confirm('Deseja excluir este cliente?')) { appData.clientes = appData.clientes.filter(c => c.id !== id); saveAppData(); renderClientes(); showToast('Cliente excluído', 'info'); updateStats(); } } // --- Evidence Gallery --- let selectedEvidenceFiles = []; let currentEvidenceIndex = 0; function renderEvidence() { const grid = document.getElementById('evidence-grid'); const noEv = document.getElementById('no-evidence'); if (!grid) return; const filterClient = document.getElementById('evidence-filter-client')?.value || ''; const filterType = document.getElementById('evidence-filter-type')?.value || ''; let filtered = appData.evidencias; if (filterClient) filtered = filtered.filter(e => e.clienteId == filterClient); if (filterType) filtered = filtered.filter(e => e.categoria.toLowerCase().includes(filterType)); if (filtered.length === 0) { grid.innerHTML = ''; noEv?.classList.remove('hidden'); return; } noEv?.classList.add('hidden'); grid.innerHTML = filtered.map((ev, i) => { const icon = getFileIcon(ev.tipo); const thumb = ev.thumb || `http://static.photos/${ev.categoria === 'foto' ? 'people' : 'office'}/320x240/${ev.id}`; return `
${ev.tipo && ev.tipo.startsWith('image/') ? `${ev.descricao}` : ``}

${ev.descricao || 'Sem descrição'}

${ev.clienteNome || 'N/A'} • ${formatDate(ev.data)}

${ev.categoria} ${ev.driveId ? '' : ''}
`; }).join(''); document.getElementById('stat-provas').textContent = appData.evidencias.length; } function getFileIcon(tipo) { if (!tipo) return 'fas fa-file'; if (tipo.startsWith('image/')) return 'fas fa-file-image'; if (tipo === 'application/pdf') return 'fas fa-file-pdf'; if (tipo.startsWith('video/')) return 'fas fa-file-video'; if (tipo.startsWith('audio/')) return 'fas fa-file-audio'; return 'fas fa-file'; } function handleEvidenceDrop(event) { const files = event.dataTransfer.files; processEvidenceFiles(files); } function handleEvidenceSelect(event) { const files = event.target.files; processEvidenceFiles(files); } function processEvidenceFiles(files) { selectedEvidenceFiles = Array.from(files); const preview = document.getElementById('ev-preview'); preview.innerHTML = ''; preview.classList.remove('hidden'); selectedEvidenceFiles.forEach((file, i) => { if (file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = (e) => { preview.innerHTML += `
${file.name.length > 15 ? file.name.substring(0,12)+'...' : file.name}
`; }; reader.readAsDataURL(file); } else { preview.innerHTML += `

${file.name}

`; } }); } function uploadEvidence() { const clienteId = document.getElementById('ev-cliente').value; const cliente = appData.clientes.find(c => c.id == clienteId); const processo = document.getElementById('ev-processo').value; const categoria = document.getElementById('ev-categoria').value; const descricao = document.getElementById('ev-descricao').value; const uploadToDrive = document.getElementById('ev-upload-drive').checked; if (!clienteId) { showToast('Selecione um cliente', 'error'); return; } if (selectedEvidenceFiles.length === 0) { showToast('Selecione ao menos um arquivo', 'error'); return; } selectedEvidenceFiles.forEach((file, i) => { const evId = Date.now() + i; const evidencia = { id: evId, clienteId: parseInt(clienteId), clienteNome: cliente?.nome || 'N/A', processoId: processo, categoria: categoria, descricao: descricao || file.name, tipo: file.type, nomeArquivo: file.name, data: new Date().toISOString(), thumb: null, driveId: null, localData: null }; // Create local thumbnail for images if (file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = (e) => { evidencia.thumb = e.target.result; evidencia.localData = e.target.result; appData.evidencias.push(evidencia); saveAppData(); renderEvidence(); }; reader.readAsDataURL(file); } else { // Store file reference const reader = new FileReader(); reader.onload = (e) => { evidencia.localData = e.target.result; appData.evidencias.push(evidencia); saveAppData(); renderEvidence(); }; reader.readAsDataURL(file); } // Upload to Google Drive if connected and checked if (uploadToDrive && appData.driveConnected) { uploadToGoogleDrive(file, evId); } }); selectedEvidenceFiles = []; document.getElementById('ev-preview').innerHTML = ''; document.getElementById('ev-preview').classList.add('hidden'); hideModal('upload-evidence'); showToast('Prova(s) enviada(s) com sucesso!'); updateStats(); } function viewEvidence(id) { const ev = appData.evidencias.find(e => e.id === id); if (!ev) return; currentEvidenceIndex = appData.evidencias.findIndex(e => e.id === id); const content = document.getElementById('lightbox-content'); const caption = document.getElementById('lightbox-caption'); if (ev.tipo && ev.tipo.startsWith('image/') && ev.localData) { content.innerHTML = ``; } else if (ev.tipo === 'application/pdf' && ev.localData) { content.innerHTML = ``; } else if (ev.tipo && ev.tipo.startsWith('video/') && ev.localData) { content.innerHTML = ``; } else if (ev.tipo && ev.tipo.startsWith('audio/') && ev.localData) { content.innerHTML = `
`; } else { content.innerHTML = `

${ev.nomeArquivo || 'Arquivo'}

Pré-visualização não disponível

`; } caption.textContent = `${ev.descricao} — ${ev.clienteNome} — ${formatDate(ev.data)}`; document.getElementById('lightbox').classList.add('active'); } function closeLightbox() { document.getElementById('lightbox').classList.remove('active'); } function navigateEvidence(direction) { currentEvidenceIndex += direction; if (currentEvidenceIndex < 0) currentEvidenceIndex = appData.evidencias.length - 1; if (currentEvidenceIndex >= appData.evidencias.length) currentEvidenceIndex = 0; const ev = appData.evidencias[currentEvidenceIndex]; if (ev) viewEvidence(ev.id); } function filterEvidence() { renderEvidence(); } // --- AASP Integration --- const AASP_BASE_URL = 'https://api.aasp.org.br'; async function fetchAASPIntimacoes() { const chave = document.getElementById('aasp-chave').value; const tipo = document.getElementById('aasp-tipo').value; const data = document.getElementById('aasp-data').value; const diferencial = document.getElementById('aasp-diferencial').checked; const codigo = document.getElementById('aasp-codigo').value; const btn = document.getElementById('btn-fetch-aasp'); if (!chave) { showToast('Informe a chave de acesso AASP', 'error'); return; } btn.disabled = true; btn.innerHTML = ' Buscando...'; try { const endpoint = tipo === 'empresa' ? 'Empresa' : 'Associado'; let url = `${AASP_BASE_URL}/api/${endpoint}/intimacao/json?chave=${encodeURIComponent(chave)}`; if (data) url += `&data=${encodeURIComponent(data)}`; if (diferencial) url += `&diferencial=true`; if (tipo === 'empresa' && codigo) url += `&codigoPessoaAssociado=${codigo}`; const response = await fetch(url); if (!response.ok) throw new Error(`Erro HTTP: ${response.status}`); const result = await response.json(); appData.intimacoes = Array.isArray(result) ? result : [result]; renderIntimacoes(); document.getElementById('stat-intimacoes').textContent = appData.intimacoes.length; updateNotificationBadge(); showToast(`${appData.intimacoes.length} intimação(ões) encontrada(s)!`); saveAppData(); } catch (error) { console.error('AASP API Error:', error); // Show mock data for demo showAASPMockData(); showToast('Usando dados de demonstração (API pode requerer CORS proxy)', 'warning'); } finally { btn.disabled = false; btn.innerHTML = ' Buscar Intimações'; } } function showAASPMockData() { appData.intimacoes = [ { id: 1, dataDisponibilizacao: '2024-01-10', dataPublicacao: '2024-01-09', jornal: 'DJE - TJSP', orgao: 'TJSP', vara: '5ª Vara Cível', numeroProcesso: '2023-0456', nomeParte: 'João Silva', tipoIntimacao: 'Sentença', conteudo: 'Intimação da parte ré para ciência da sentença proferida nos autos...', advogado: 'Dr. Ricardo Mendes', OAB: 'OAB/SP 123.456' }, { id: 2, dataDisponibilizacao: '2024-01-10', dataPublicacao: '2024-01-09', jornal: 'DJE - TRF3', orgao: 'TRF3', vara: '2ª Vara Federal', numeroProcesso: '2023-0389', nomeParte: 'Maria Souza', tipoIntimacao: 'Despacho', conteudo: 'Intimação para manifestação sobre despacho que deferiu liminarmente a tutela de urgência...', advogado: 'Dra. Ana Paula Torres', OAB: 'OAB/SP 234.567' }, { id: 3, dataDisponibilizacao: '2024-01-11', dataPublicacao: '2024-01-10', jornal: 'DJE - TJMG', orgao: 'TJMG', vara: '1ª Vara de Fazenda Pública', numeroProcesso: '2023-0412', nomeParte: 'Empresa XYZ Ltda', tipoIntimacao: 'Decisão', conteudo: 'Intimação da requerida para, querendo, apresentar impugnação ao cumprimento de sentença...', advogado: 'Dr. Paulo Santos', OAB: 'OAB/MG 56.789' }, { id: 4, dataDisponibilizacao: '2024-01-12', dataPublicacao: '2024-01-11', jornal: 'DJE - TJSP', orgao: 'TJSP', vara: '15ª Vara Cível', numeroProcesso: '2023-0501', nomeParte: 'Ana Oliveira', tipoIntimacao: 'Audiência', conteudo: 'Intimação para audiência de conciliação designada para o dia 25/01/2024 às 14:00...', advogado: 'Dra. Carolina Lima', OAB: 'OAB/SP 345.678' }, ]; renderIntimacoes(); document.getElementById('stat-intimacoes').textContent = appData.intimacoes.length; updateNotificationBadge(); saveAppData(); } function renderIntimacoes() { const list = document.getElementById('intimacoes-list'); const count = document.getElementById('intimacoes-count'); count.textContent = `${appData.intimacoes.length} resultado(s)`; if (appData.intimacoes.length === 0) { list.innerHTML = '

Nenhuma intimação encontrada

'; return; } list.innerHTML = appData.intimacoes.map((int, i) => { const statusColor = int.tipoIntimacao === 'Sentença' ? 'bg-red-100 text-red-800' : int.tipoIntimacao === 'Audiência' ? 'bg-yellow-100 text-yellow-800' : 'bg-blue-100 text-blue-800'; return `
${i + 1}

${int.numeroProcesso || 'N/A'} - ${int.nomeParte || 'N/A'}

${int.orgao || ''} • ${int.vara || ''}

${int.tipoIntimacao || 'N/A'} ${formatDate(int.dataDisponibilizacao)}

${(int.conteudo || '').substring(0, 200)}${(int.conteudo || '').length > 200 ? '...' : ''}

${int.jornal || 'N/A'} Publicação: ${formatDate(int.dataPublicacao)} ${int.advogado ? `${int.advogado}` : ''}
`; }).join(''); } async function fetchAASPJornais() { const chave = document.getElementById('aasp-chave').value; const tipo = document.getElementById('aasp-tipo').value; if (!chave) { showToast('Informe a chave AASP', 'error'); return; } try { const endpoint = tipo === 'empresa' ? 'Empresa' : 'Associado'; const url = `${AASP_BASE_URL}/api/${endpoint}/intimacao/GetJornaisComIntimacoes/json?chave=${encodeURIComponent(chave)}&qtdeDias=30`; const response = await fetch(url); const result = await response.json(); renderJornais(Array.isArray(result) ? result : [result]); } catch(e) { // Mock data renderJornais([ { jornal: 'DJE - TJSP', quantidade: 12, dataUltima: '2024-01-12' }, { jornal: 'DJE - TRF3', quantidade: 5, dataUltima: '2024-01-11' }, { jornal: 'DJE - TJMG', quantidade: 3, dataUltima: '2024-01-10' }, ]); showToast('Usando dados de demonstração para jornais', 'warning'); } } function renderJornais(jornais) { const container = document.getElementById('jornais-results'); const list = document.getElementById('jornais-list'); container.classList.remove('hidden'); list.innerHTML = jornais.map(j => `

${j.jornal || j.NomeJornal || 'N/A'}

Última publicação: ${formatDate(j.dataUltima || j.DataUltima)}

${j.quantidade || j.Quantidade || 0} intimação(ões)
`).join(''); } function linkIntimacaoToProcess(intId) { const int = appData.intimacoes.find(i => i.id === intId); if (!int) return; showToast(`Intimação ${int.numeroProcesso} vinculada ao processo!`, 'success'); } function togglePassword(fieldId) { const field = document.getElementById(fieldId); if (field.type === 'password') { field.type = 'text'; field.nextElementSibling.innerHTML = ''; } else { field.type = 'password'; field.nextElementSibling.innerHTML = ''; } } // --- Google Drive / Sheets Integration --- let gapiLoaded = false; let gisLoaded = false; let tokenClient = null; // Google API Configuration // NOTE: In production, replace with your own Client ID from Google Cloud Console const GOOGLE_CLIENT_ID = 'YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com'; const GOOGLE_API_KEY = 'YOUR_GOOGLE_API_KEY'; const SCOPES = 'https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/spreadsheets.readonly'; const SPREADSHEET_ID = '19EOpljeLASYLgyWhxJWtGBexELlt3GDoYBbcE5ZRExk'; function loadGoogleAPI() { const script = document.createElement('script'); script.src = 'https://apis.google.com/js/api.js'; script.onload = () => { gapi.load('client', async () => { try { await gapi.client.init({ apiKey: GOOGLE_API_KEY, discoveryDocs: ['https://www.googleapis.com/auth/drive.file', 'https://sheets.googleapis.com/$discovery/rest?version=v4'] }); gapiLoaded = true; console.log('GAPI loaded'); } catch(e) { console.error('GAPI init error', e); } }); }; document.body.appendChild(script); } function connectGoogleDrive() { if (!GOOGLE_CLIENT_ID || GOOGLE_CLIENT_ID.includes('YOUR_GOOGLE')) { showToast('Configure o Client ID do Google no app.js', 'warning'); showGoogleConfigInfo(); return; } try { tokenClient = google.accounts.oauth2.initTokenClient({ client_id: GOOGLE_CLIENT_ID, scope: SCOPES, callback: (tokenResponse) => { if (tokenResponse.error) { showToast('Erro na autenticação Google: ' + tokenResponse.error, 'error'); return; } appData.driveConnected = true; updateDriveStatus(true); showToast('Google Drive conectado com sucesso!'); saveAppData(); } }); tokenClient.requestAccessToken({ prompt: '' }); } catch(e) { console.error('Google Auth Error:', e); showToast('Erro ao conectar com Google. Verifique a configuração.', 'error'); showGoogleConfigInfo(); } } function connectGoogleSheets() { if (!appData.driveConnected && (!GOOGLE_CLIENT_ID || GOOGLE_CLIENT_ID.includes('YOUR_GOOGLE'))) { showToast('Configure o Google Client ID primeiro', 'warning'); showGoogleConfigInfo(); return; } if (!appData.driveConnected) { connectGoogleDrive(); return; } fetchSpreadsheetData(); } async function fetchSpreadsheetData() { try { const response = await gapi.client.sheets.spreadsheets.values.get({ spreadsheetId: SPREADSHEET_ID, range: 'A:Z' }); const rows = response.result.values; if (rows && rows.length > 0) { appData.importPreview = rows; renderImportPreview(rows); updateSheetsStatus(true); showToast(`${rows.length - 1} registros importados da planilha!`); } } catch(e) { console.error('Sheets API Error:', e); // Show mock data const mockRows = [ ['Nome', 'CPF/CNPJ', 'Email', 'Telefone', 'Endereço', 'Tipo Processo', 'Descrição'], ['João da Silva', '123.456.789-00', 'joao@email.com', '(11) 98765-4321', 'Rua A, 100 - SP', 'Cível', 'Ação indenizatória por danos morais'], ['Maria Oliveira', '987.654.321-00', 'maria@email.com', '(21) 99876-5432', 'Av B, 200 - RJ', 'Trabalhista', 'Reclamação trabalhista - horas extras'], ['Empresa ABC Ltda', '12.345.678/0001-90', 'contato@abc.com', '(11) 3456-7890', 'Rua C, 300 - SP', 'Tributário', 'Mandado de segurança - ICMS'], ]; appData.importPreview = mockRows; renderImportPreview(mockRows); updateSheetsStatus(true); showToast('Dados de demonstração carregados', 'warning'); } } function renderImportPreview(rows) { const container = document.getElementById('import-preview'); const table = document.getElementById('import-preview-table'); container.classList.remove('hidden'); if (!rows || rows.length === 0) return; const headers = rows[0]; let html = ''; headers.forEach(h => html += `${h}`); html += ''; rows.slice(1).forEach(row => { html += ''; row.forEach(cell => html += `${cell || ''}`); html += ''; }); html += ''; table.innerHTML = html; } function confirmImport() { if (!appData.importPreview) return; const rows = appData.importPreview; const headers = rows[0]; // Find column indices const nomeIdx = headers.findIndex(h => /nome/i.test(h)); const cpfIdx = headers.findIndex(h => /cpf|cnpj/i.test(h)); const emailIdx = headers.findIndex(h => /email|e-mail/i.test(h)); const telIdx = headers.findIndex(h => /telef/i.test(h)); const endIdx = headers.findIndex(h => /endere/i.test(h)); rows.slice(1).forEach(row => { const exists = appData.clientes.find(c => c.cpfCnpj === (row[cpfIdx] || '')); if (!exists && row[nomeIdx]) { appData.clientes.push({ id: Date.now() + Math.random(), nome: row[nomeIdx] || '', tipo: (row[cpfIdx] || '').length > 14 ? 'pj' : 'pf', cpfCnpj: row[cpfIdx] || '', email: row[emailIdx] || '', telefone: row[telIdx] || '', endereco: row[endIdx] || '', processos: 0 }); } }); saveAppData(); updateStats(); showToast('Dados importados com sucesso!'); } async function uploadToGoogleDrive(file, evidenceId) { if (!appData.driveConnected) return; try { const metadata = { name: `[LegalData] ${file.name}`, parents: [], description: `Prova enviada via LegalData Manager - ID: ${evidenceId}` }; const form = new FormData(); form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' })); form.append('file', file); const response = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', { method: 'POST', headers: new Headers({ 'Authorization': 'Bearer ' + gapi.auth.getToken().access_token }), body: form }); const result = await response.json(); const ev = appData.evidencias.find(e => e.id === evidenceId); if (ev) { ev.driveId = result.id; saveAppData(); showToast('Arquivo salvo no Google Drive!', 'info'); } } catch(e) { console.error('Drive upload error:', e); showToast('Erro ao salvar no Drive', 'error'); } } function updateDriveStatus(connected) { appData.driveConnected = connected; const icon = document.getElementById('drive-icon'); const text = document.getElementById('drive-status-text'); const sub = document.getElementById('drive-status-sub'); const btn = document.getElementById('drive-connect-btn'); const dot = document.getElementById('drive-conn-dot'); const label = document.getElementById('drive-conn-label'); const intBtn = document.getElementById('drive-integration-btn'); if (connected) { if (icon) icon.className = 'w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center text-green-600'; if (icon) icon.innerHTML = ''; if (text) text.textContent = 'Google Drive conectado'; if (sub) sub.textContent = 'Arquivos serão sincronizados automaticamente'; if (btn) { btn.textContent = 'Desconectar'; btn.className = 'bg-red-100 text-red-600 px-4 py-2 rounded-lg hover:bg-red-200 transition'; btn.onclick = disconnectGoogleDrive; } if (dot) { dot.className = 'w-3 h-3 rounded-full bg-green-500'; } if (label) { label.textContent = 'Conectado'; label.className = 'text-sm text-green-600 font-medium'; } if (intBtn) { intBtn.textContent = 'Desconectar'; intBtn.className = 'w-full bg-red-100 text-red-600 py-2 rounded-lg hover:bg-red-200 transition'; } } else { if (icon) icon.className = 'w-10 h-10 rounded-lg bg-gray-100 flex items-center justify-center text-gray-400'; if (icon) icon.innerHTML = ''; if (text) text.textContent = 'Google Drive desconectado'; if (sub) sub.textContent = 'Conecte para sincronizar provas na nuvem'; if (btn) { btn.innerHTML = ' Conectar Google Drive'; btn.className = 'bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition'; btn.onclick = connectGoogleDrive; } if (dot) { dot.className = 'w-3 h-3 rounded-full bg-gray-400'; } if (label) { label.textContent = 'Desconectado'; label.className = 'text-sm text-gray-500 font-medium'; } } } function updateSheetsStatus(connected) { appData.sheetsConnected = connected; const dot = document.getElementById('sheets-conn-dot'); const label = document.getElementById('sheets-conn-label'); const btn = document.getElementById('sheets-integration-btn'); if (connected) { if (dot) dot.className = 'w-3 h-3 rounded-full bg-green-500'; if (label) { label.textContent = 'Conectado'; label.className = 'text-sm text-green-600 font-medium'; } if (btn) { btn.textContent = 'Sincronizar Dados'; btn.className = 'w-full bg-green-100 text-green-700 py-2 rounded-lg hover:bg-green-200 transition'; } } } function disconnectGoogleDrive() { if (tokenClient) { const token = gapi?.auth?.getToken(); if (token) google.accounts.oauth2.revoke(token.access_token); } updateDriveStatus(false); updateSheetsStatus(false); showToast('Google Drive desconectado', 'info'); } function showGoogleConfigInfo() { const info = `

Configuração do Google OAuth

Para usar as integrações Google, você precisa:

  1. Acessar Google Cloud Console
  2. Criar um projeto e ativar as APIs: Google Drive API e Google Sheets API
  3. Criar credenciais OAuth 2.0
  4. Adicionar http://localhost como origem autorizada
  5. Copiar o Client ID e atualizar no arquivo app.js

Enquanto isso, o sistema funciona com dados locais e de demonstração.

`; const list = document.getElementById('intimacoes-list'); if (list) list.innerHTML = info + list.innerHTML; } // --- File Import --- function handleFileImport(event) { const file = event.target.files[0]; if (!file) return; if (file.name.endsWith('.csv')) { Papa.parse(file, { header: true, complete: (results) => { appData.importPreview = [results.meta.fields, ...results.data.map(r => results.meta.fields.map(f => r[f]))]; renderImportPreview(appData.importPreview); showToast(`${results.data.length} registros importados do CSV`); } }); } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) { const reader = new FileReader(); reader.onload = (e) => { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName]; const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 }); appData.importPreview = jsonData; renderImportPreview(jsonData); showToast(`${jsonData.length - 1} registros importados do Excel`); }; reader.readAsArrayBuffer(file); } } // --- Sanitization --- function sanitizeData(type) { let count = 0; switch(type) { case 'cpfcnpj': appData.clientes.forEach(c => { c.cpfCnpj = c.cpfCnpj.replace(/[^\d./-]/g, ''); count++; }); showToast(`${count} CPFs/CNPJs padronizados`); break; case 'phone': appData.clientes.forEach(c => { c.telefone = c.telefone.replace(/[^\d() -]/g, ''); count++; }); showToast(`${count} telefones padronizados`); break; case 'email': const invalid = appData.clientes.filter(c => !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(c.email)); showToast(`${invalid.length} e-mails inválidos encontrados`, invalid.length > 0 ? 'warning' : 'success'); break; case 'duplicates': const seen = new Set(); const before = appData.clientes.length; appData.clientes = appData.clientes.filter(c => { const key = c.cpfCnpj || c.email; if (seen.has(key)) return false; seen.add(key); return true; }); count = before - appData.clientes.length; showToast(`${count} duplicatas removidas`, count > 0 ? 'info' : 'success'); break; } saveAppData(); renderClientes(); } // --- Utility Functions --- function formatDate(dateStr) { if (!dateStr) return 'N/A'; try { const d = new Date(dateStr); return d.toLocaleDateString('pt-BR'); } catch(e) { return dateStr; } } function generateId() { return '2024-' + String(Math.floor(Math.random() * 9000) + 1000); } function updateStats() { document.getElementById('stat-processos').textContent = appData.processos.length; document.getElementById('stat-clientes').textContent = appData.clientes.length; document.getElementById('stat-provas').textContent = appData.evidencias.length; } function updateNotificationBadge() { const badge = document.getElementById('notification-badge'); const count = appData.intimacoes.length; if (count > 0) { badge.textContent = count; badge.classList.remove('hidden'); } else { badge.classList.add('hidden'); } } function populateSelects() { // Populate client selects const clientSelects = ['proc-cliente', 'ev-cliente']; clientSelects.forEach(id => { const el = document.getElementById(id); if (el) { el.innerHTML = '' + appData.clientes.map(c => ``).join(''); } }); // Populate process selects const procSelects = ['ev-processo']; procSelects.forEach(id => { const el = document.getElementById(id); if (el) { el.innerHTML = '' + appData.processos.map(p => ``).join(''); } }); // Evidence filter const filterClient = document.getElementById('evidence-filter-client'); if (filterClient) { filterClient.innerHTML = '' + appData.clientes.map(c => ``).join(''); } } // --- Deadline Table --- function renderDeadlineTable() { const tbody = document.getElementById('deadline-table-body'); if (!tbody) return; const urgent = appData.processos .filter(p => p.prazo && p.status !== 'Concluído') .sort((a, b) => new Date(a.prazo) - new Date(b.prazo)) .slice(0, 5); const statusColors = { 'Ativo': 'bg-green-100 text-green-800', 'Pendente': 'bg-yellow-100 text-yellow-800', 'Urgente': 'bg-red-100 text-red-800', }; tbody.innerHTML = urgent.map(p => ` #${p.id} ${p.cliente} ${p.tribunal} ${formatDate(p.prazo)} ${p.status} `).join(''); } // --- Chart --- function initChart() { const ctx = document.getElementById('processChart'); if (!ctx) return; new Chart(ctx, { type: 'doughnut', data: { labels: ['TJSP', 'TJMG', 'TRF1', 'TRF4', 'Outros'], datasets: [{ data: [45, 20, 15, 12, 8], backgroundColor: ['#4F46E5', '#10B981', '#F59E0B', '#EF4444', '#6B7280'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } } }); } // --- Auto-refresh AASP --- let aaspInterval = null; function startAASPRefresh() { if (aaspInterval) clearInterval(aaspInterval); aaspInterval = setInterval(() => { if (document.getElementById('aasp-auto-refresh')?.checked) { fetchAASPIntimacoes(); } }, 30 * 60 * 1000); // 30 minutes } // --- Keyboard Shortcuts --- document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { document.querySelectorAll('[id^="modal-"]').forEach(m => m.classList.add('hidden')); closeLightbox(); } }); // --- Initialize --- document.addEventListener('DOMContentLoaded', () => { loadAppData(); populateSelects(); renderProcessos(); renderClientes(); renderDeadlineTable(); initChart(); updateStats(); updateNotificationBadge(); if (appData.driveConnected) updateDriveStatus(true); if (appData.sheetsConnected) updateSheetsStatus(true); startAASPRefresh(); // Set today's date for AASP query const today = new Date().toISOString().split('T')[0]; const dataField = document.getElementById('aasp-data'); if (dataField) dataField.value = today; });