import React, { useState, useEffect, useCallback, useRef } from 'react'; import ReactDOM from 'react-dom'; import { rankingService } from '../services/api'; import './RawDataModal.css'; const decodeHtmlEntities = (str) => { if (typeof str !== 'string') return str; const textarea = document.createElement('textarea'); textarea.innerHTML = str; return textarea.value; }; const formatDate = (dateStr) => { if (!dateStr) return null; try { if (dateStr.includes('/')) { return dateStr.split(' ')[0]; } const date = new Date(dateStr); return date.toLocaleDateString('pt-BR'); } catch { return dateStr; } }; const formatValue = (value) => { if (value === null || value === undefined || value === '') return null; if (typeof value === 'boolean') return value ? 'Sim' : 'Não'; if (typeof value === 'number') return String(value); if (typeof value === 'string') return decodeHtmlEntities(value); if (Array.isArray(value)) { if (value.length === 0) return null; return value.map(item => { if (typeof item === 'object' && item !== null) { const val = item.nome || item.descricao || item.sigla || item.tipo || JSON.stringify(item); return decodeHtmlEntities(val); } return decodeHtmlEntities(String(item)); }).join(', '); } if (typeof value === 'object') { if (value.nome) return decodeHtmlEntities(value.nome); if (value.descricao) return decodeHtmlEntities(value.descricao); if (value.sigla) return decodeHtmlEntities(value.sigla); return null; } return decodeHtmlEntities(String(value)); }; const LABEL_MAP = { tipo: 'Tipo', nome: 'Nome', sigla: 'Sigla', codigo: 'Código', situacao: 'Situação', situacaoConsultoria: 'Situação', areaAvaliacao: 'Área de Avaliação', areaConhecimento: 'Área de Conhecimento', areaConhecimentoPos: 'Área de Conhecimento Pós', areaPesquisa: 'Área de Pesquisa', colegio: 'Colégio', ies: 'IES', programa: 'Programa', nomeEmpregador: 'Empregador', emprego: 'Vínculo', atividade: 'Atividade', dtAdmissao: 'Admissão', dtDesligamento: 'Desligamento', cnpjEmpregador: 'CNPJ Empregador', profissao: 'Profissão', matricula: 'Matrícula', vinculo: 'Vínculo', historico: 'Histórico', inicioRelacionamento: 'Início Relacionamento', fimRelacionamento: 'Fim Relacionamento', categoria: 'Categoria', tipoVinculo: 'Tipo de Vínculo', vinculoTrabalho: 'Vínculo de Trabalho', regimeTrabalho: 'Regime de Trabalho', cargaHoraria: 'Carga Horária', linhaPesquisa: 'Linha de Pesquisa', areaConcentracao: 'Área de Concentração', areaPesquisa: 'Área de Pesquisa', consultorResponsavel: 'Consultor Responsável', unidadeOrganizacional: 'Unidade Organizacional', localEvento: 'Local do Evento', nrProcesso: 'Número do Processo', idProcesso: 'ID do Processo', anoInicio: 'Ano de Início', tipoTrabalho: 'Tipo de Trabalho', inicioVinculacao: 'Início Vinculação', fimVinculacao: 'Fim Vinculação', inicioSituacao: 'Início Situação', inativacaoSituacao: 'Inativação', portaria: 'Portaria', dataPortaria: 'Data Portaria', premio: 'Prêmio', evento: 'Evento', premiacao: 'Premiação', ano: 'Ano', edicao: 'Edição', papelPessoa: 'Papel', comissao: 'Comissão', produto: 'Produto', nivel: 'Nível', modalidade: 'Modalidade', camaraTematica: 'Câmara Temática', totalOrientacaoFinalizadaMestrado: 'Orientações Finalizadas (Mestrado)', totalOrientacaoFinalizadaDoutorado: 'Orientações Finalizadas (Doutorado)', totalOrientacaoAndamentoMestrado: 'Orientações em Andamento (Mestrado)', totalOrientacaoAndamentoDoutorado: 'Orientações em Andamento (Doutorado)', totalAcompanhamentoPosDoutorado: 'Acompanhamentos Pós-Doutorado', }; const formatLabel = (key) => LABEL_MAP[key] || key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase()); const parseDate = (dateStr) => { if (!dateStr) return null; try { if (dateStr.includes('/')) { const parts = dateStr.split('/'); if (parts.length === 3) { const [day, month, year] = parts; return new Date(year, month - 1, day); } } const date = new Date(dateStr); return isNaN(date.getTime()) ? null : date; } catch { return null; } }; const getAtuacaoDate = (atuacao) => { const candidateDates = [ atuacao.inicio, atuacao.fim, atuacao.dadosEmprego?.dtAdmissao, atuacao.dadosEmprego?.dtDesligamento, atuacao.dadosDocencia?.inicioVinculacao, atuacao.dadosDocencia?.fimVinculacao, atuacao.dadosCoordenacaoArea?.inicioVinculacao, atuacao.dadosCoordenacaoArea?.fimVinculacao, atuacao.dadosHistoricoCoordenacaoArea?.inicioVinculacao, atuacao.dadosHistoricoCoordenacaoArea?.fimVinculacao, atuacao.dadosConsultoria?.inicioVinculacao, atuacao.dadosConsultoria?.fimVinculacao, atuacao.dadosConsultoria?.inicioSituacao, atuacao.dadosConsultoria?.inativacaoSituacao, atuacao.dadosEvento?.inicio, atuacao.dadosEvento?.fim, atuacao.dadosParticipacaoEvento?.inicio, atuacao.dadosParticipacaoEvento?.fim, atuacao.dadosPremiacaoPremio?.ano ? `01/01/${atuacao.dadosPremiacaoPremio.ano}` : null, atuacao.dadosParticipacaoPremio?.ano ? `01/01/${atuacao.dadosParticipacaoPremio.ano}` : null, atuacao.dadosParticipacaoInscricaoPremio?.ano ? `01/01/${atuacao.dadosParticipacaoInscricaoPremio.ano}` : null, atuacao.dadosProjeto?.anoInicio ? `01/01/${atuacao.dadosProjeto.anoInicio}` : null, ]; for (const dateStr of candidateDates) { const date = parseDate(dateStr); if (date) return date; } return null; }; const sortAtuacoesByDate = (atuacoes) => { return [...atuacoes].sort((a, b) => { const dateA = getAtuacaoDate(a); const dateB = getAtuacaoDate(b); if (!dateA && !dateB) return 0; if (!dateA) return 1; if (!dateB) return -1; return dateB.getTime() - dateA.getTime(); }); }; const DataField = ({ label, value, className = '' }) => { const formattedValue = formatValue(value); if (formattedValue === null) return null; return (
{formatLabel(label)} {formattedValue}
); }; const NestedObjectDisplay = ({ data, depth = 0 }) => { if (!data || typeof data !== 'object') return null; const entries = Object.entries(data).filter(([key, value]) => { if (value === null || value === undefined || value === '') return false; if (Array.isArray(value) && value.length === 0) return false; return true; }); if (entries.length === 0) return null; return (
{entries.map(([key, value]) => { if (typeof value === 'object' && !Array.isArray(value) && value !== null) { const simpleValue = value.nome || value.descricao || value.sigla; if (simpleValue) { return ; } return (
{formatLabel(key)}
); } if (Array.isArray(value)) { const formatted = value.map(item => { if (typeof item === 'object' && item !== null) { return item.nome || item.descricao || item.sigla || item.tipo || Object.values(item).filter(v => typeof v === 'string')[0] || ''; } return String(item); }).filter(Boolean).join(', '); if (!formatted) return null; return ; } return ; })}
); }; const Section = ({ title, icon, children, defaultOpen = true, count }) => { const [isOpen, setIsOpen] = useState(defaultOpen); return (
setIsOpen(!isOpen)}> {icon}

{title}

{count !== undefined && {count}} {isOpen ? '▼' : '▶'}
{isOpen &&
{children}
}
); }; const AtuacaoCard = ({ atuacao, index }) => { const [expanded, setExpanded] = useState(false); const tipo = atuacao.tipo || 'Tipo não informado'; const getNestedValue = (obj, path) => { if (!obj || !path) return undefined; return path.split('.').reduce((acc, key) => (acc ? acc[key] : undefined), obj); }; const joinParts = (parts) => parts.filter(Boolean).join(' · '); const buildSummary = () => { const tipoLower = tipo.toLowerCase(); const dadosDocencia = atuacao.dadosDocencia || {}; const dadosEmprego = atuacao.dadosEmprego || {}; const dadosEvento = atuacao.dadosEvento || atuacao.dadosParticipacaoEvento || {}; const dadosProjeto = atuacao.dadosProjeto || {}; const dadosProcesso = atuacao.dadosProcesso || {}; const dadosOrientacaoDiscente = atuacao.dadosOrientacaoDiscente || {}; if (tipoLower.includes('docência') || tipoLower.includes('docencia')) { const ies = dadosDocencia.ies?.sigla ? `${dadosDocencia.ies.sigla} — ${dadosDocencia.ies.nome}` : dadosDocencia.ies?.nome; const primary = joinParts([ dadosDocencia.programa?.nome || dadosDocencia.areaConhecimento?.nome || atuacao.descricao, ies, dadosDocencia.categoria, ]); const secondary = joinParts([ dadosDocencia.tipoVinculo, dadosDocencia.regimeTrabalho, dadosDocencia.cargaHoraria ? `${dadosDocencia.cargaHoraria}h` : null, ]); return { primary, secondary }; } if (tipoLower.includes('emprego')) { const primary = joinParts([ dadosEmprego.nomeEmpregador || atuacao.descricao, dadosEmprego.emprego || dadosEmprego.vinculo, dadosEmprego.atividade, ]); const secondary = joinParts([ dadosEmprego.dtAdmissao, dadosEmprego.dtDesligamento ? `até ${dadosEmprego.dtDesligamento}` : null, dadosEmprego.profissao, ]); return { primary, secondary }; } if (tipoLower.includes('evento')) { const primary = joinParts([ dadosEvento.nome || atuacao.descricao, dadosEvento.unidadeOrganizacional, dadosEvento.localEvento, ]); const secondary = joinParts([ dadosEvento.atividade, dadosEvento.tipo, dadosEvento.codigo ? `Código ${dadosEvento.codigo}` : null, ]); return { primary, secondary }; } if (tipoLower.includes('projeto')) { const primary = joinParts([ dadosProjeto.nome || atuacao.descricao, dadosProjeto.programa?.nome, dadosProjeto.ies?.sigla || dadosProjeto.ies?.nome, ]); const secondary = joinParts([ dadosProjeto.situacao, dadosProjeto.linhaPesquisa, dadosProjeto.anoInicio ? `Início ${dadosProjeto.anoInicio}` : null, ]); return { primary, secondary }; } if (tipoLower.includes('orientação de discentes') || tipoLower.includes('orientacao de discentes')) { const mestradoParts = []; if (dadosOrientacaoDiscente.totalOrientacaoFinalizadaMestrado) { mestradoParts.push(`Finalizadas ${dadosOrientacaoDiscente.totalOrientacaoFinalizadaMestrado}`); } if (dadosOrientacaoDiscente.totalOrientacaoAndamentoMestrado) { mestradoParts.push(`Andamento ${dadosOrientacaoDiscente.totalOrientacaoAndamentoMestrado}`); } const doutoradoParts = []; if (dadosOrientacaoDiscente.totalOrientacaoFinalizadaDoutorado) { doutoradoParts.push(`Finalizadas ${dadosOrientacaoDiscente.totalOrientacaoFinalizadaDoutorado}`); } if (dadosOrientacaoDiscente.totalOrientacaoAndamentoDoutorado) { doutoradoParts.push(`Andamento ${dadosOrientacaoDiscente.totalOrientacaoAndamentoDoutorado}`); } const primary = joinParts([ mestradoParts.length ? `Mestrado ${mestradoParts.join(' / ')}` : null, doutoradoParts.length ? `Doutorado ${doutoradoParts.join(' / ')}` : null, ]); const secondary = dadosOrientacaoDiscente.totalAcompanhamentoPosDoutorado ? `Pós-doc ${dadosOrientacaoDiscente.totalAcompanhamentoPosDoutorado}` : null; return { primary, secondary }; } if (tipoLower.includes('processo')) { const iesLabel = dadosProcesso.ies?.sigla || dadosProcesso.ies?.nome; const primary = joinParts([dadosProcesso.nrProcesso || atuacao.descricao, iesLabel]); const secondary = dadosProcesso.ies?.statusJuridico ? `IES ${dadosProcesso.ies.statusJuridico.trim()}` : null; return { primary, secondary }; } const fallbackPrimary = joinParts([ atuacao.descricao, getNestedValue(atuacao, 'procedencia.origem'), ]); return { primary: fallbackPrimary, secondary: null }; }; const getAtuacaoColor = (tipo) => { if (tipo.includes('Coordenação')) return 'atuacao-coordenacao'; if (tipo.includes('Consultor')) return 'atuacao-consultoria'; if (tipo.includes('Premiação')) return 'atuacao-premiacao'; if (tipo.includes('Avaliação')) return 'atuacao-avaliacao'; if (tipo.includes('Inscrição')) return 'atuacao-inscricao'; if (tipo.includes('Bolsista')) return 'atuacao-bolsa'; if (tipo.includes('Orientação')) return 'atuacao-orientacao'; return 'atuacao-outros'; }; const getAllDados = () => { const allData = {}; const dataKeys = [ 'dadosCoordenacaoArea', 'dadosHistoricoCoordenacaoArea', 'dadosConsultoria', 'dadosPremiacaoPremio', 'dadosParticipacaoPremio', 'dadosParticipacaoInscricaoPremio', 'dadosBolsistaCNPq', 'dadosOrientacao', 'dadosOrientacaoDiscente', 'dadosParticipacao', 'dadosParticipacaoEvento', 'dadosGestaoPrograma', 'dadosDocencia', 'dadosEmprego', 'dadosEvento', 'dadosProjeto', 'dadosProcesso', 'dadosAnaliseProcesso', 'dadosPapelPessoa', ]; const dateKeys = ['inicio', 'fim', 'inicioVinculacao', 'fimVinculacao', 'inicioSituacao', 'inativacaoSituacao']; const dateData = {}; dataKeys.forEach(key => { if (atuacao[key]) { Object.entries(atuacao[key]).forEach(([k, v]) => { if (dateKeys.includes(k)) { dateData[k] = v; } else { allData[k] = v; } }); } }); const baseKeys = ['descricao', 'quantidade', 'id', 'procedencia']; baseKeys.forEach((key) => { if (atuacao[key] !== null && atuacao[key] !== undefined && allData[key] === undefined) { allData[key] = atuacao[key]; } }); if (Object.keys(allData).length === 0) { if (atuacao.inicio) allData.inicio = atuacao.inicio; if (atuacao.fim) allData.fim = atuacao.fim; Object.assign(allData, dateData); } return allData; }; const dados = getAllDados(); const hasData = Object.keys(dados).length > 0; const summary = buildSummary(); return (
setExpanded(!expanded)}> #{index + 1}
{tipo} {summary.primary && {summary.primary}}
{atuacao.inicio && {formatDate(atuacao.inicio)}} {atuacao.inicio && atuacao.fim && - } {atuacao.fim ? {formatDate(atuacao.fim)} : atuacao.inicio && Atual}
{summary.secondary &&
{summary.secondary}
}
{expanded ? '−' : '+'}
{expanded && (
{hasData ? ( ) : (

Sem dados adicionais

)}
)}
); }; const RawDataModal = ({ idPessoa, nome, onClose }) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [viewMode, setViewMode] = useState('formatted'); const [filterType, setFilterType] = useState('all'); const [copyFeedback, setCopyFeedback] = useState(false); const [downloadingPDF, setDownloadingPDF] = useState(false); const fetchedRef = useRef(null); useEffect(() => { if (fetchedRef.current === idPessoa) { return; } fetchedRef.current = idPessoa; const fetchData = async () => { try { setLoading(true); setError(null); const result = await rankingService.getConsultorRaw(idPessoa); setData(result); } catch (err) { setError(err.response?.data?.detail || err.message || 'Erro ao carregar dados'); } finally { setLoading(false); } }; fetchData(); }, [idPessoa]); const handleKeyDown = useCallback((e) => { if (e.key === 'Escape') onClose(); }, [onClose]); useEffect(() => { document.addEventListener('keydown', handleKeyDown); document.body.style.overflow = 'hidden'; return () => { document.removeEventListener('keydown', handleKeyDown); document.body.style.overflow = ''; }; }, [handleKeyDown]); const copyToClipboard = async () => { try { await navigator.clipboard.writeText(JSON.stringify(data, null, 2)); setCopyFeedback(true); setTimeout(() => setCopyFeedback(false), 2000); } catch (err) { console.error('Erro ao copiar:', err); } }; const handleDownloadPDF = async () => { if (downloadingPDF) return; setDownloadingPDF(true); try { await rankingService.downloadFichaPDF(idPessoa, nome); } catch (err) { console.error('Erro ao baixar PDF:', err); alert('Erro ao gerar PDF. Tente novamente.'); } finally { setDownloadingPDF(false); } }; const source = data?._source || {}; const dadosPessoais = source.dadosPessoais || {}; const atuacoes = source.atuacoes || []; const tiposAtuacao = [...new Set(atuacoes.map(a => a.tipo))].sort(); const atuacoesFiltradas = sortAtuacoesByDate( filterType === 'all' ? atuacoes : atuacoes.filter(a => a.tipo === filterType) ); const atuacoesPorTipo = tiposAtuacao.reduce((acc, tipo) => { acc[tipo] = atuacoes.filter(a => a.tipo === tipo).length; return acc; }, {}); const modalContent = (
e.target.classList.contains('raw-modal-overlay') && onClose()}>

Dados Completos ATUACAPES

{nome} (ID: {idPessoa})
{loading && (
Carregando dados do Elasticsearch...
)} {error && (
{error}
)} {!loading && !error && data && viewMode === 'formatted' && (
{atuacoes.length > 0 && ( <>
{tiposAtuacao.map(tipo => ( setFilterType(filterType === tipo ? 'all' : tipo)} > {tipo.replace('Histórico de ', '').substring(0, 25)} {atuacoesPorTipo[tipo]} ))}
{atuacoesFiltradas.map((atuacao, idx) => ( ))}
)} {atuacoes.length === 0 && (

Nenhuma atuação registrada

)}
)} {!loading && !error && data && viewMode === 'json' && (
{JSON.stringify(data, null, 2)}
)}
Fonte: Elasticsearch ATUACAPES | Index: {data?._index || 'atuacapes'} | {atuacoes.length} atuações
); return ReactDOM.createPortal(modalContent, document.body); }; export default RawDataModal;