diff --git a/frontend/src/components/CalculoDetalhado.css b/frontend/src/components/CalculoDetalhado.css new file mode 100644 index 0000000..75ae264 --- /dev/null +++ b/frontend/src/components/CalculoDetalhado.css @@ -0,0 +1,295 @@ +.calculo-detalhado { + margin-top: 1.5rem; + padding-top: 1.5rem; + border-top: 1px dashed var(--stroke); +} + +.calculo-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.25rem; +} + +.calculo-header h3 { + font-size: 0.9rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; + color: var(--text); + margin: 0; +} + +.calculo-total { + font-size: 0.85rem; + color: var(--muted); +} + +.calculo-total strong { + font-size: 1.2rem; + background: linear-gradient(120deg, var(--accent), var(--accent-2)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.componentes-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; +} + +.componente-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--stroke); + border-radius: 12px; + overflow: hidden; + transition: all 200ms ease; + cursor: pointer; +} + +.componente-card:hover { + border-color: rgba(255, 255, 255, 0.15); + transform: translateY(-2px); +} + +.componente-card.ativo { + border-color: rgba(79, 70, 229, 0.4); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); +} + +.componente-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + color: white; +} + +.componente-info { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.componente-letra { + width: 24px; + height: 24px; + display: grid; + place-items: center; + background: rgba(255, 255, 255, 0.2); + border-radius: 6px; + font-weight: 700; + font-size: 0.8rem; +} + +.componente-nome { + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.componente-pontos { + display: flex; + align-items: baseline; +} + +.pontos-valor { + font-size: 1.3rem; + font-weight: 800; +} + +.pontos-max { + font-size: 0.75rem; + opacity: 0.7; +} + +.componente-barra-container { + position: relative; + height: 4px; + background: rgba(255, 255, 255, 0.1); +} + +.componente-barra { + height: 100%; + transition: width 500ms ease; +} + +.teto-badge { + position: absolute; + right: 4px; + top: -18px; + font-size: 0.6rem; + font-weight: 700; + padding: 2px 6px; + background: var(--success); + color: white; + border-radius: 4px; + letter-spacing: 0.5px; +} + +.componente-desc { + padding: 0.75rem 1rem 0.5rem; + font-size: 0.75rem; + color: var(--muted); + margin: 0; + line-height: 1.4; +} + +.componente-toggle { + padding: 0.5rem 1rem 0.75rem; + font-size: 0.7rem; + color: var(--accent-2); + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 600; +} + +.componente-detalhes { + padding: 0 1rem 0.75rem; + display: flex; + flex-direction: column; + gap: 0.75rem; + animation: slideDown 200ms ease; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.detalhe-item { + background: rgba(0, 0, 0, 0.2); + border-radius: 8px; + padding: 0.65rem 0.75rem; +} + +.detalhe-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.4rem; +} + +.detalhe-label { + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + color: var(--text); +} + +.detalhe-valor { + font-size: 0.9rem; + font-weight: 700; +} + +.detalhe-barra-container { + height: 3px; + background: rgba(255, 255, 255, 0.1); + border-radius: 2px; + overflow: hidden; + margin-bottom: 0.5rem; +} + +.detalhe-barra { + height: 100%; + border-radius: 2px; + transition: width 400ms ease; +} + +.detalhe-formula { + font-size: 0.72rem; + color: var(--text); + font-family: 'SF Mono', 'Fira Code', monospace; + background: rgba(255, 255, 255, 0.05); + padding: 0.35rem 0.5rem; + border-radius: 4px; + margin-bottom: 0.35rem; +} + +.detalhe-explicacao { + font-size: 0.68rem; + color: var(--muted); + line-height: 1.4; +} + +.formula-resumo { + margin-top: 1.25rem; + padding: 1rem; + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--stroke); + border-radius: 10px; +} + +.formula-linha { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + flex-wrap: wrap; +} + +.formula-comp { + font-size: 0.85rem; + font-weight: 600; + padding: 0.35rem 0.65rem; + background: rgba(255, 255, 255, 0.05); + border-radius: 6px; +} + +.formula-op { + font-size: 1rem; + color: var(--muted); + font-weight: 300; +} + +.formula-total { + font-size: 1.4rem; + font-weight: 800; + background: linear-gradient(120deg, var(--accent), var(--accent-2)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + padding: 0.25rem 0.75rem; + border: 2px solid rgba(79, 70, 229, 0.4); + border-radius: 8px; +} + +@media (max-width: 1100px) { + .componentes-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .componentes-grid { + grid-template-columns: 1fr; + } + + .calculo-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .formula-linha { + gap: 0.5rem; + } + + .formula-comp { + font-size: 0.75rem; + padding: 0.25rem 0.5rem; + } + + .formula-total { + font-size: 1.1rem; + } +} diff --git a/frontend/src/components/CalculoDetalhado.jsx b/frontend/src/components/CalculoDetalhado.jsx new file mode 100644 index 0000000..f093cfe --- /dev/null +++ b/frontend/src/components/CalculoDetalhado.jsx @@ -0,0 +1,280 @@ +import React, { useState } from 'react'; +import './CalculoDetalhado.css'; + +const CalculoDetalhado = ({ consultor }) => { + const [componenteAtivo, setComponenteAtivo] = useState(null); + const { pontuacao } = consultor; + + const toggleComponente = (comp, e) => { + e.stopPropagation(); + setComponenteAtivo(componenteAtivo === comp ? null : comp); + }; + + const calcularProgresso = (valor, maximo) => Math.min((valor / maximo) * 100, 100); + + const componentes = [ + { + id: 'a', + nome: 'Coordenação CAPES', + dados: pontuacao.componente_a, + max: 450, + cor: 'var(--accent-2)', + corGradient: 'linear-gradient(135deg, #6366f1, #4f46e5)', + descricao: 'Funções de coordenação exercidas na CAPES', + detalhes: [ + { + label: 'Base', + valor: pontuacao.componente_a.base, + max: 200, + formula: inferirFormulaBase(pontuacao.componente_a.base), + explicacao: 'Pontuação pelo tipo de coordenação: CA=200, CAJ=150, CAJ-MP=120, CAM=100' + }, + { + label: 'Tempo', + valor: pontuacao.componente_a.tempo, + max: 100, + formula: inferirFormulaTempo(pontuacao.componente_a.tempo, pontuacao.componente_a.base), + explicacao: 'Anos completos × multiplicador (CA=10, CAJ=8, CAJ-MP=6, CAM=5)' + }, + { + label: 'Áreas', + valor: pontuacao.componente_a.extras, + max: 100, + formula: pontuacao.componente_a.extras > 0 ? `${pontuacao.componente_a.extras / 20} áreas extras × 20 pts` : 'Nenhuma área adicional', + explicacao: 'Cada área adicional coordenada vale 20 pts (máx 100)' + }, + { + label: 'Bônus Ativo', + valor: pontuacao.componente_a.bonus, + max: 30, + formula: pontuacao.componente_a.bonus > 0 ? `Coordenador ativo → +${pontuacao.componente_a.bonus} pts` : 'Não está ativo', + explicacao: 'Bônus por exercer função atualmente: CA=30, CAJ=20, CAJ-MP=15, CAM=10' + }, + { + label: 'Retorno', + valor: pontuacao.componente_a.retorno || 0, + max: 20, + formula: (pontuacao.componente_a.retorno || 0) > 0 ? 'Retornou à função → +20 pts' : 'Sem retorno registrado', + explicacao: 'Bônus único por retornar a exercer coordenação' + } + ] + }, + { + id: 'b', + nome: 'Coordenação PPG', + dados: pontuacao.componente_b, + max: 180, + cor: 'var(--success)', + corGradient: 'linear-gradient(135deg, #22c55e, #16a34a)', + descricao: 'Coordenação de programas de pós-graduação', + detalhes: [ + { + label: 'Base', + valor: pontuacao.componente_b.base, + max: 70, + formula: pontuacao.componente_b.base > 0 ? 'Coordenador de PPG → 70 pts' : 'Não é coordenador', + explicacao: 'Pontuação base por ser coordenador de programa' + }, + { + label: 'Tempo', + valor: pontuacao.componente_b.tempo, + max: 50, + formula: pontuacao.componente_b.tempo > 0 ? `${pontuacao.componente_b.tempo / 5} anos × 5 pts` : 'Sem tempo registrado', + explicacao: 'Cada ano completo de coordenação vale 5 pts (máx 50)' + }, + { + label: 'Programas', + valor: pontuacao.componente_b.extras, + max: 40, + formula: pontuacao.componente_b.extras > 0 ? `${pontuacao.componente_b.extras / 20} programas extras × 20 pts` : 'Apenas 1 programa', + explicacao: 'Cada programa adicional coordenado vale 20 pts (máx 40)' + }, + { + label: 'Nota PPG', + valor: pontuacao.componente_b.bonus, + max: 20, + formula: inferirFormulaNota(pontuacao.componente_b.bonus), + explicacao: 'Maior nota CAPES: 7=20pts, 6=15pts, 5=10pts, 4=5pts, 3=0pts' + } + ] + }, + { + id: 'c', + nome: 'Consultoria', + dados: pontuacao.componente_c, + max: 230, + cor: 'var(--gold)', + corGradient: 'linear-gradient(135deg, #fbbf24, #f59e0b)', + descricao: 'Atuação como consultor CAPES', + detalhes: [ + { + label: 'Base', + valor: pontuacao.componente_c.base, + max: 150, + formula: pontuacao.componente_c.base === 150 ? 'Consultor ativo → 150 pts' : pontuacao.componente_c.base === 100 ? 'Consultor histórico → 100 pts' : 'Não é consultor', + explicacao: 'Ativo (eventos recentes) = 150 pts, Histórico = 100 pts' + }, + { + label: 'Tempo', + valor: pontuacao.componente_c.tempo, + max: 50, + formula: pontuacao.componente_c.tempo > 0 ? `${pontuacao.componente_c.tempo / 5} anos × 5 pts` : 'Sem tempo registrado', + explicacao: 'Anos desde primeiro evento × 5 pts (máx 50)' + }, + { + label: 'Bônus', + valor: pontuacao.componente_c.bonus, + max: 30, + formula: inferirFormulaBonusConsultoria(pontuacao.componente_c.bonus), + explicacao: 'Continuidade (3a=5, 5a=10, 8a+=15) + Retorno (15 pts)' + } + ] + }, + { + id: 'd', + nome: 'Premiações', + dados: pontuacao.componente_d, + max: 180, + cor: 'var(--bronze)', + corGradient: 'linear-gradient(135deg, #fb923c, #ea580c)', + descricao: 'Premiações, avaliações e inscrições em prêmios', + detalhes: [ + { + label: 'Total', + valor: pontuacao.componente_d.base, + max: 180, + formula: inferirFormulaPremiacoes(pontuacao.componente_d.base, consultor.premiacoes), + explicacao: 'Premiação=60pts, Avaliação=40pts (máx 20), Inscrição=20pts' + } + ] + } + ]; + + return ( +
{comp.descricao}
+ + {componenteAtivo === comp.id && ( +