diff --git a/backend/src/infrastructure/repositories/consultor_repository_impl.py b/backend/src/infrastructure/repositories/consultor_repository_impl.py index 1292db5..da6d3cf 100644 --- a/backend/src/infrastructure/repositories/consultor_repository_impl.py +++ b/backend/src/infrastructure/repositories/consultor_repository_impl.py @@ -169,17 +169,21 @@ class ConsultorRepositoryImpl(ConsultorRepository): situacoes.append(situacao) inicio = ( - self._parse_date(dc.get("inicioVinculacao")) + self._parse_date(c.get("inicio")) + or self._parse_date(dc.get("inicioVinculacao")) or self._parse_date(dc.get("inicioSituacao")) - or self._parse_date(c.get("inicio")) ) + if inicio and inicio.year < 1950: + inicio = None situacao_texto = (dc.get("situacaoConsultoria") or "").lower() is_situacao_ativa = "atividade" in situacao_texto or "ativo" in situacao_texto fim = ( - self._parse_date(dc.get("fimVinculacao")) + self._parse_date(c.get("fim")) + or self._parse_date(dc.get("fimVinculacao")) or (self._parse_date(dc.get("inativacaoSituacao")) if not is_situacao_ativa else None) - or self._parse_date(c.get("fim")) ) + if fim and fim.year < 1950: + fim = None if inicio and fim and fim < inicio: fim = None diff --git a/frontend/src/components/BlocoCriteriosModal.css b/frontend/src/components/BlocoCriteriosModal.css index 7db65c8..aee4871 100644 --- a/frontend/src/components/BlocoCriteriosModal.css +++ b/frontend/src/components/BlocoCriteriosModal.css @@ -250,6 +250,16 @@ border-bottom: 1px solid rgba(255, 255, 255, 0.1); } +.bloco-tabela th:nth-child(3), +.bloco-tabela th:nth-child(4) { + text-align: center; +} + +.bloco-tabela.bonus-valores th:nth-child(2), +.bloco-tabela.bonus-valores th:nth-child(3) { + text-align: center; +} + .bloco-tabela td { padding: 0.5rem 0.75rem; border-bottom: 1px solid rgba(255, 255, 255, 0.05); diff --git a/frontend/src/components/ConsultorCard.css b/frontend/src/components/ConsultorCard.css index 2eb5e11..10a19a4 100644 --- a/frontend/src/components/ConsultorCard.css +++ b/frontend/src/components/ConsultorCard.css @@ -175,6 +175,22 @@ gap: 0.65rem; } +.consultant-selos-row { + display: flex; + flex-wrap: wrap; + gap: 0.35rem; + margin-top: 0.5rem; + justify-content: flex-start; + width: 100%; +} + +.consultant-selos-row .selos-container.selos-compacto { + display: flex; + gap: 0.35rem; + justify-content: flex-start; + margin-left: 0 !important; +} + .consultant-area { color: var(--muted); font-size: 0.95rem; @@ -914,6 +930,36 @@ color: #e2e8f0; } +.selo-banca { + background: linear-gradient(135deg, rgba(167, 139, 250, 0.2), rgba(167, 139, 250, 0.08)); + border-color: rgba(167, 139, 250, 0.35); + color: #c4b5fd; +} + +.selo-evento { + background: linear-gradient(135deg, rgba(251, 146, 60, 0.2), rgba(251, 146, 60, 0.08)); + border-color: rgba(251, 146, 60, 0.35); + color: #fdba74; +} + +.selo-proj { + background: linear-gradient(135deg, rgba(16, 185, 129, 0.2), rgba(16, 185, 129, 0.08)); + border-color: rgba(16, 185, 129, 0.35); + color: #6ee7b7; +} + +.selo-idioma { + background: linear-gradient(135deg, rgba(56, 189, 248, 0.2), rgba(56, 189, 248, 0.08)); + border-color: rgba(56, 189, 248, 0.35); + color: #7dd3fc; +} + +.selo-titulacao { + background: linear-gradient(135deg, rgba(192, 132, 252, 0.2), rgba(192, 132, 252, 0.08)); + border-color: rgba(192, 132, 252, 0.35); + color: #d8b4fe; +} + .tipos-section { grid-column: 1 / -1; margin-top: 1rem; diff --git a/frontend/src/components/ConsultorCard.jsx b/frontend/src/components/ConsultorCard.jsx index f88534c..6be4dc5 100644 --- a/frontend/src/components/ConsultorCard.jsx +++ b/frontend/src/components/ConsultorCard.jsx @@ -23,6 +23,16 @@ const SELOS = { CO_ORIENT_TESE: { codigo: 'CO_ORIENT_TESE', label: 'Coorient. Tese', cor: 'selo-coorient', icone: 'š' }, CO_ORIENT_DISS: { codigo: 'CO_ORIENT_DISS', label: 'Coorient. Diss.', cor: 'selo-coorient', icone: 'š' }, CO_ORIENT_POS_DOC: { codigo: 'CO_ORIENT_POS_DOC', label: 'Coorient. Pos-Doc', cor: 'selo-coorient', icone: 'š¬' }, + MB_BANCA_POS_DOC: { codigo: 'MB_BANCA_POS_DOC', label: 'Banca Pos-Doc', cor: 'selo-banca', icone: 'š¬' }, + MB_BANCA_TESE: { codigo: 'MB_BANCA_TESE', label: 'Banca Tese', cor: 'selo-banca', icone: 'š' }, + 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: 'š' }, + TITULACAO_POS_DOUTOR: { codigo: 'TITULACAO_POS_DOUTOR', label: 'Pos-Doutor', cor: 'selo-titulacao', icone: 'š' }, }; const TIPOS_ATUACAO_CONFIG = { @@ -98,6 +108,30 @@ const gerarSelos = (consultor) => { gerarSelosOrientacaoContagem('CO_ORIENT_TESE', true, SELOS.CO_ORIENT_TESE); gerarSelosOrientacaoContagem('CO_ORIENT_DISS', true, SELOS.CO_ORIENT_DISS); + const membrosBanca = Array.isArray(consultor.membros_banca) ? consultor.membros_banca : []; + const bancaPosDoc = membrosBanca.filter((m) => m.codigo === 'MB_BANCA_POS_DOC'); + const bancaTese = membrosBanca.filter((m) => m.codigo === 'MB_BANCA_TESE'); + const bancaDiss = membrosBanca.filter((m) => m.codigo === 'MB_BANCA_DISS'); + if (bancaPosDoc.length > 0) { + selos.push({ ...SELOS.MB_BANCA_POS_DOC, qtd: bancaPosDoc.length, hint: `Banca Pos-Doc (${bancaPosDoc.length}x)` }); + } + if (bancaTese.length > 0) { + selos.push({ ...SELOS.MB_BANCA_TESE, qtd: bancaTese.length, hint: `Banca Tese (${bancaTese.length}x)` }); + } + if (bancaDiss.length > 0) { + selos.push({ ...SELOS.MB_BANCA_DISS, qtd: bancaDiss.length, hint: `Banca Dissertacao (${bancaDiss.length}x)` }); + } + + const participacoes = Array.isArray(consultor.participacoes) ? consultor.participacoes : []; + const eventos = participacoes.filter((p) => p.codigo === 'EVENTO'); + const projetos = participacoes.filter((p) => p.codigo === 'PROJ'); + if (eventos.length > 0) { + selos.push({ ...SELOS.EVENTO, qtd: eventos.length, hint: `Eventos (${eventos.length}x)` }); + } + if (projetos.length > 0) { + selos.push({ ...SELOS.PROJ, qtd: projetos.length, hint: `Projetos (${projetos.length}x)` }); + } + return selos; }; @@ -107,15 +141,14 @@ const SELOS_COM_DADOS = [ 'ORIENT_GP', 'ORIENT_PREMIO', 'ORIENT_MENCAO', 'COORIENT_GP', 'COORIENT_PREMIO', 'COORIENT_MENCAO', 'ORIENT_TESE', 'ORIENT_DISS', 'ORIENT_POS_DOC', - 'CO_ORIENT_TESE', 'CO_ORIENT_DISS', 'CO_ORIENT_POS_DOC' + 'CO_ORIENT_TESE', 'CO_ORIENT_DISS', 'CO_ORIENT_POS_DOC', + 'MB_BANCA_POS_DOC', 'MB_BANCA_TESE', 'MB_BANCA_DISS', + 'EVENTO', 'PROJ', ]; const SelosBadges = ({ selos, compacto = false, onSeloClick }) => { if (!selos || selos.length === 0) return null; - const selosExibidos = compacto ? selos.slice(0, 4) : selos; - const selosOcultos = compacto && selos.length > 4 ? selos.length - 4 : 0; - const handleClick = (e, selo) => { if (onSeloClick && SELOS_COM_DADOS.includes(selo.codigo)) { e.preventDefault(); @@ -126,7 +159,7 @@ const SelosBadges = ({ selos, compacto = false, onSeloClick }) => { return (
Sem dados de bancas
; + return ( +Sem eventos
; + return ( +Sem projetos
; + return ( +Sem dados detalhados para este selo
; } @@ -1009,18 +1103,25 @@ const InsightsModal = ({ consultor, totalConsultores, onClose }) => { }; const TETOS = { - INSC_AUTOR: { teto: 20, doc: '3.3 Inscrições', bonus: '+2/participação (max 10)' }, - INSC_INST_AUTOR: { teto: 50, doc: '3.3 Inscrições', bonus: '+5/participação (max 10)' }, - AVAL_COMIS_PREMIO: { teto: 60, doc: '3.4 Avaliação/Comissão', bonus: '+2/ano (max 15)' }, - AVAL_COMIS_GP: { teto: 80, doc: '3.4 Avaliação/Comissão', bonus: '+3/ano (max 20)' }, - COORD_COMIS_PREMIO: { teto: 100, doc: '3.4 Avaliação/Comissão', bonus: '+4/ano (max 20)' }, - COORD_COMIS_GP: { teto: 120, doc: '3.4 Avaliação/Comissão', bonus: '+6/ano (max 20)' }, - PREMIACAO_GP_AUTOR: { teto: 300, doc: '3.4 Premiações e Bolsas' }, - PREMIACAO_AUTOR: { teto: 150, doc: '3.4 Premiações e Bolsas' }, - MENCAO_AUTOR: { teto: 90, doc: '3.4 Premiações e Bolsas' }, - EVENTO: { teto: 5, doc: '3.5 Participações Acadêmicas', bonus: '+1/participação (max 10)' }, - PROJ: { teto: 30, doc: '3.5 Participações Acadêmicas', bonus: '+2/participação (max 10)' }, - BOL_BPQ_NIVEL: { teto: 60, doc: '3.4 Premiações e Bolsas' }, + CA: { teto: 450, doc: 'Bloco A - Coordenação CAPES', bonus: 'Tempo: 10pts/ano (max 100) | Atualidade: +30 | Retorno: +20' }, + CAJ: { teto: 370, doc: 'Bloco A - Coordenação CAPES', bonus: 'Tempo: 8pts/ano (max 80) | Atualidade: +20 | Retorno: +15' }, + CAJ_MP: { teto: 315, doc: 'Bloco A - Coordenação CAPES', bonus: 'Tempo: 6pts/ano (max 60) | Atualidade: +15 | Retorno: +10' }, + CAM: { teto: 280, doc: 'Bloco A - Coordenação CAPES', bonus: 'Tempo: 5pts/ano (max 50) | Atualidade: +20 | Retorno: +10' }, + CONS_ATIVO: { teto: 230, doc: 'Bloco B - Consultoria', bonus: 'Tempo: 5pts/ano (max 50) | Atualidade: +20 | Continuidade 8a+: +20 | Retorno: +15' }, + CONS_HIST: { teto: 230, doc: 'Bloco B - Consultoria', bonus: 'Tempo: 5pts/ano (max 50) | Continuidade 8a+: +20 | Retorno: +20' }, + CONS_FALECIDO: { teto: 230, doc: 'Bloco B - Consultoria', bonus: 'Tempo: 5pts/ano (max 50) | Continuidade 8a+: +20' }, + INSC_AUTOR: { teto: 20, doc: 'Bloco C - Inscrições', bonus: '+2/participação (max 10)' }, + INSC_INST_AUTOR: { teto: 50, doc: 'Bloco C - Inscrições', bonus: '+5/participação (max 10)' }, + AVAL_COMIS_PREMIO: { teto: 60, doc: 'Bloco C - Avaliação/Comissão', bonus: '+2/ano (max 15)' }, + AVAL_COMIS_GP: { teto: 80, doc: 'Bloco C - Avaliação/Comissão', bonus: '+3/ano (max 20)' }, + COORD_COMIS_PREMIO: { teto: 100, doc: 'Bloco C - Avaliação/Comissão', bonus: '+4/ano (max 20)' }, + COORD_COMIS_GP: { teto: 120, doc: 'Bloco C - Avaliação/Comissão', bonus: '+6/ano (max 20)' }, + PREMIACAO_GP_AUTOR: { teto: 300, doc: 'Bloco C - Premiações' }, + PREMIACAO_AUTOR: { teto: 150, doc: 'Bloco C - Premiações' }, + MENCAO_AUTOR: { teto: 90, doc: 'Bloco C - Premiações' }, + EVENTO: { teto: 5, doc: 'Bloco D - Participações', bonus: '+1/participação (max 10)' }, + PROJ: { teto: 30, doc: 'Bloco D - Participações', bonus: '+2/participação (max 10)' }, + BOL_BPQ_NIVEL: { teto: 60, doc: 'Bloco D - Bolsas CNPq' }, }; const PontuacaoModal = ({ dados, onClose }) => { @@ -1308,12 +1409,16 @@ const ConsultorCard = memo(({ consultor, highlight, selecionado, onToggleSelecio {consultor.ativo && ATIVO} {!consultor.ativo && HISTORICO} {consultor.veterano && VETERANO} -