fix(backend): corrigir exibicao de idiomas e selos multilingue
- Adicionar idiomas e formacoes ao _source das queries ES (client.py) - Corrigir type mismatch int/str no endpoint paginado (routes.py) - Adicionar campo evento nas inscricoes para nome do premio - Implementar extracao de idiomas do ES no repository - Ajustar frontend para exibir selo multilingue corretamente
This commit is contained in:
@@ -28,7 +28,6 @@ const SELOS = {
|
||||
MB_BANCA_DISS: { codigo: 'MB_BANCA_DISS', label: 'Banca Diss.', cor: 'selo-banca', icone: '📄' },
|
||||
EVENTO: { codigo: 'EVENTO', label: 'Evento', cor: 'selo-evento', icone: '📅' },
|
||||
PROJ: { codigo: 'PROJ', label: 'Projeto', cor: 'selo-proj', icone: '📁' },
|
||||
IDIOMA_BILINGUE: { codigo: 'IDIOMA_BILINGUE', label: 'Bilingue', cor: 'selo-idioma', icone: '🌍' },
|
||||
IDIOMA_MULTILINGUE: { codigo: 'IDIOMA_MULTILINGUE', label: 'Multilingue', cor: 'selo-idioma', icone: '🌐' },
|
||||
TITULACAO_MESTRE: { codigo: 'TITULACAO_MESTRE', label: 'Mestre', cor: 'selo-titulacao', icone: '🎓' },
|
||||
TITULACAO_DOUTOR: { codigo: 'TITULACAO_DOUTOR', label: 'Doutor', cor: 'selo-titulacao', icone: '🎓' },
|
||||
@@ -49,6 +48,13 @@ const TIPOS_ATUACAO_CONFIG = {
|
||||
|
||||
const gerarSelos = (consultor) => {
|
||||
const selos = [];
|
||||
const normalizarIdioma = (valor) => (valor || '')
|
||||
.toString()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.toLowerCase()
|
||||
.trim();
|
||||
const normalizarCodigoIdioma = (valor) => normalizarIdioma(valor).replace(/[^a-z0-9]/g, '');
|
||||
|
||||
const isPresidCamaraVigente = consultor.coordenacoes_capes?.some(
|
||||
(c) => c.codigo === 'CAM' && c.presidente && (c.ativo ?? !c.fim)
|
||||
@@ -132,6 +138,40 @@ const gerarSelos = (consultor) => {
|
||||
selos.push({ ...SELOS.PROJ, qtd: projetos.length, hint: `Projetos (${projetos.length}x)` });
|
||||
}
|
||||
|
||||
const idiomas = Array.isArray(consultor.idiomas) ? consultor.idiomas : [];
|
||||
const idiomasUnicosMap = new Map();
|
||||
let temPortugues = false;
|
||||
for (const idioma of idiomas) {
|
||||
const nome = idioma?.idioma || idioma?.nome || idioma?.descricao || '';
|
||||
const chave = normalizarIdioma(nome);
|
||||
if (!chave) continue;
|
||||
if (!idiomasUnicosMap.has(chave)) {
|
||||
idiomasUnicosMap.set(chave, nome);
|
||||
}
|
||||
if (chave.includes('portugues') || chave.includes('portuguese')) {
|
||||
temPortugues = true;
|
||||
}
|
||||
}
|
||||
const idiomasUnicos = Array.from(idiomasUnicosMap.values());
|
||||
const totalIdiomas = idiomasUnicos.length + (!temPortugues && idiomasUnicos.length > 0 ? 1 : 0);
|
||||
if (totalIdiomas >= 3) {
|
||||
selos.push({
|
||||
...SELOS.IDIOMA_MULTILINGUE,
|
||||
qtd: totalIdiomas,
|
||||
hint: `Multilingue: ${idiomasUnicos.join(', ')}`,
|
||||
});
|
||||
}
|
||||
|
||||
const titulacao = consultor.titulacao || '';
|
||||
const titulacaoLower = titulacao.toLowerCase();
|
||||
if (titulacaoLower.includes('pós-doutorado') || titulacaoLower.includes('pos-doutorado') || titulacaoLower.includes('posdoc') || titulacaoLower.includes('pós-doc')) {
|
||||
selos.push({ ...SELOS.TITULACAO_POS_DOUTOR, qtd: 1, hint: 'Pós-Doutorado' });
|
||||
} else if (titulacaoLower.includes('doutorado') || titulacaoLower.includes('doutor')) {
|
||||
selos.push({ ...SELOS.TITULACAO_DOUTOR, qtd: 1, hint: 'Doutorado' });
|
||||
} else if (titulacaoLower.includes('mestrado') || titulacaoLower.includes('mestre')) {
|
||||
selos.push({ ...SELOS.TITULACAO_MESTRE, qtd: 1, hint: 'Mestrado' });
|
||||
}
|
||||
|
||||
return selos;
|
||||
};
|
||||
|
||||
@@ -144,6 +184,8 @@ const SELOS_COM_DADOS = [
|
||||
'CO_ORIENT_TESE', 'CO_ORIENT_DISS', 'CO_ORIENT_POS_DOC',
|
||||
'MB_BANCA_POS_DOC', 'MB_BANCA_TESE', 'MB_BANCA_DISS',
|
||||
'EVENTO', 'PROJ',
|
||||
'IDIOMA_MULTILINGUE',
|
||||
'TITULACAO_MESTRE', 'TITULACAO_DOUTOR', 'TITULACAO_POS_DOUTOR',
|
||||
];
|
||||
|
||||
const SelosBadges = ({ selos, compacto = false, onSeloClick }) => {
|
||||
@@ -355,7 +397,7 @@ const TipoAtuacaoModal = ({ tipo, consultor, onClose }) => {
|
||||
{[...inscs].sort((a, b) => (b.ano || 0) - (a.ano || 0)).map((ins, i) => (
|
||||
<div key={i} className="modal-item">
|
||||
<span className="badge">{ins.codigo}</span>
|
||||
<span className="modal-item-main">{ins.premio || ins.descricao || '-'}</span>
|
||||
<span className="modal-item-main">{ins.evento || ins.premio || ins.descricao || '-'}</span>
|
||||
<span className="muted">{ins.ano || '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -837,6 +879,12 @@ const ItemDetalheModal = ({ item, tipo, onClose }) => {
|
||||
<span className="modal-detalhe-label">Código</span>
|
||||
<span className="badge">{item.codigo}</span>
|
||||
</div>
|
||||
{item.evento && (
|
||||
<div className="modal-detalhe-row">
|
||||
<span className="modal-detalhe-label">Evento</span>
|
||||
<span className="modal-detalhe-value">{item.evento}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="modal-detalhe-row">
|
||||
<span className="modal-detalhe-label">Prêmio</span>
|
||||
<span className="modal-detalhe-value">{item.premio || 'N/A'}</span>
|
||||
@@ -1461,7 +1509,7 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
|
||||
onClick={handleRawDataClick}
|
||||
title="Ver dados completos do ATUACAPES"
|
||||
>
|
||||
⋮
|
||||
📋
|
||||
</button>
|
||||
<div className="expand-icon">{expanded ? '▲' : '▼'}</div>
|
||||
</div>
|
||||
@@ -1687,7 +1735,7 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio
|
||||
>
|
||||
<span className="badge">{insc.codigo}</span>
|
||||
<span className="pontos">{PONTOS_BASE[insc.codigo] || 0} pts</span>
|
||||
<span>{insc.premio}</span>
|
||||
<span>{insc.evento || insc.premio}</span>
|
||||
<span className="muted">{insc.ano}</span>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user