/* global React */
const { useState: useS, useMemo: useM } = React;
const { Icon, Avatar, Selo, ClassifPill, Sparkline, Radar, Trail, BarRow, shade } = window;
// ============ Network Graph ============
function NetworkGraph({focusedId, onSelect}) {
const W = 980, H = 600;
const data = useM(() => buildGraph(focusedId), [focusedId]);
return (
Tipos de nó
Talento
Projeto / Startup
Mentor
Empresa / Demanda
Rede ativa
{data.nodes.length} nós · {data.edges.length} conexões
Clique em um nó para ver suas conexões. Linhas mais grossas = mais interações.
);
}
function buildGraph(focusedId) {
const W = 980, H = 600, cx = W/2, cy = H/2;
// Project hubs in inner orbit
const projetos = window.PROJETOS_INOV.slice(0, 10);
const mentores = window.MENTORES.slice(0, 6);
const empresas = window.EMPRESAS.slice(0, 6);
const talentos = window.TALENTOS;
const nodes = [];
// Place projects in inner orbit
projetos.forEach((p, i) => {
const a = (i / projetos.length) * Math.PI * 2 - Math.PI/2;
const r = 130;
nodes.push({
id: p.id, type:'projeto', x: cx + r*Math.cos(a), y: cy + r*Math.sin(a),
r: 22, color:'#7C3AED', label: p.nome.split(' ')[0].slice(0,4).toUpperCase(),
outLabel: p.nome.length < 18 ? p.nome : p.nome.split(' ')[0]
});
});
// Place mentors in mid orbit
mentores.forEach((m, i) => {
const a = (i / mentores.length) * Math.PI * 2;
const r = 230;
nodes.push({
id: m.id, type:'mentor', x: cx + r*Math.cos(a), y: cy + r*Math.sin(a),
r: 18, color:'#F59E0B', label: m.avatar
});
});
// Place companies in outer orbit (right side)
empresas.forEach((e, i) => {
const a = -Math.PI/2 + Math.PI/3 + (i/empresas.length) * Math.PI * 1.4;
const r = 285;
nodes.push({
id: e.id, type:'empresa', x: cx + r*Math.cos(a), y: cy + r*Math.sin(a),
r: 16, color:'#10B981', label: e.nome.slice(0,3).toUpperCase()
});
});
// Place talents in outer orbit
talentos.slice(0, 18).forEach((t, i) => {
const a = -Math.PI/2 + (i / 18) * Math.PI * 2;
const r = 270 + (i % 3) * 14;
nodes.push({
id: t.id, type:'talento', x: cx + r*Math.cos(a), y: cy + r*Math.sin(a),
r: 14, color:'#0B5FBE', label: t.avatar
});
});
// Build edges from CONEXOES
const nodeMap = {};
nodes.forEach(n => nodeMap[n.id] = n);
const edges = [];
window.CONEXOES.forEach(c => {
const a = nodeMap[c.a], b = nodeMap[c.b];
if (!a || !b) return;
edges.push({
x1:a.x, y1:a.y, x2:b.x, y2:b.y,
color: c.tipo==='mentora' ? '#F59E0B' : c.tipo==='demanda' ? '#10B981' : '#0B5FBE',
weight: 1.5
});
});
// Highlight focused
if (focusedId && nodeMap[focusedId]) {
nodeMap[focusedId].glow = true;
nodeMap[focusedId].r += 4;
}
return {nodes, edges};
}
window.NetworkGraph = NetworkGraph;
// ============ Talent card ============
function TalentCard({t, onClick}) {
const setor = window.SETORES_INOV.find(s => s.id === t.interesses[0]);
return (
{t.nome}
{t.cidade} · {t.curso}
{t.mr}
{t.resumo}
{t.selos.slice(0,4).map(id => )}
{t.selos.length > 4 && +{t.selos.length-4}}
{t.pontos} pts
);
}
window.TalentCard = TalentCard;
// ============ Talent detail panel ============
function TalentDetail({talentId, onClose, onOpenProjeto}) {
const t = window.findTalento(talentId);
if (!t) return null;
const projeto = t.projetoAtivo ? window.findProjeto(t.projetoAtivo) : null;
const setor = window.SETORES_INOV.find(s => s.id === t.interesses[0]);
const color = setor ? setor.cor : '#0B5FBE';
return <>
{t.mr} · {t.cidade}
{t.nome}
{t.curso} · {t.instituicao} · {t.idade} anos
Trilha de evolução · {t.pontos} pontos
5 dimensões do talento
Selos conquistados ({t.selos.length})
{t.selos.map(id => )}
Habilidades
{t.habilidades.map(h => {h})}
{(() => {
const cv = window.getCV ? window.getCV(t) : null;
if (!cv) return null;
return <>
Formação acadêmica
{cv.formacao.map((f, i) => (
{f.curso}
{f.instituicao} · {f.cidade}
{f.detalhe &&
{f.detalhe}
}
{f.inicio} – {f.fim || 'atual'}
{f.status}
))}
Experiência profissional ({cv.experiencia.length})
{cv.experiencia.length === 0
?
Sem experiência profissional registrada — talento em formação inicial.
:
{cv.experiencia.map((e, i) => (
{e.cargo}
{e.empresa} · {e.cidade}
{e.descricao}
{e.inicio} – {e.atual ? 'atual' : e.fim}
{e.tipo}
))}
}
Cursos & certificações
{cv.cursos.map((c, i) => (
{c.nome}
{c.horas}h
{c.ano}
))}
Idiomas
{cv.idiomas.map((id, i) => (
{id.nome}{id.nivel}
))}
>;
})()}
Histórico de inovação
{t.historico.map((h, i) => (
{h.tipo}
{h.titulo}
{h.resultado}
{h.ano} · +{h.pontos}
))}
{projeto && (
Projeto ativo
onOpenProjeto(projeto.id)}>
{projeto.nome.slice(0,2).toUpperCase()}
{projeto.nome}
{projeto.fase} · {projeto.cidade}
)}
{t.necessidades.length > 0 && (
O que está buscando
{t.necessidades.map(n => (
◆{n}
))}
)}
>;
}
window.TalentDetail = TalentDetail;
// ============ Project card ============
function ProjectCard({p, onClick}) {
const setor = window.SETORES_INOV.find(s => s.id === p.setor);
return (
{p.nome.slice(0,2).toUpperCase()}
{p.nome}
{setor.nome} · {p.cidade}
{p.problema}
{p.fase}
{p.equipe.slice(0,3).map((tid, i) => {
const t = window.findTalento(tid);
if (!t) return null;
return
;
})}
);
}
window.ProjectCard = ProjectCard;
// ============ Opportunity card ============
function OpCard({o, onClick}) {
const pct = o.vagas > 0 ? Math.min(100, (o.inscritos/o.vagas)*100) : 0;
return (
{o.tipo}
{o.nome}
{o.data}
{o.cidade}
{o.descricao}
{o.premio}
{o.vagas > 0 && <>
{o.inscritos} inscritos · {o.vagas} vagas
{o.dias_restantes} dias
>}
);
}
window.OpCard = OpCard;
// ============ Match feed card ============
function MatchCard({m, onSelect}) {
const tipoLabel = {
'projeto-talento':'Projeto ↔ Talento',
'projeto-mentor':'Projeto ↔ Mentor',
'empresa-talento':'Empresa ↔ Talento',
'oportunidade-talento':'Oportunidade ↔ Talento',
'oportunidade-projeto':'Oportunidade ↔ Projeto',
};
const resolveA = (id) => {
if (id.startsWith('p')) return window.findProjeto(id);
if (id.startsWith('t')) return window.findTalento(id);
if (id.startsWith('m')) return window.findMentor(id);
if (id.startsWith('e')) return window.findEmpresa(id);
if (id.startsWith('o')) return window.findOpor(id);
};
const a = resolveA(m.a), b = resolveA(m.b);
if (!a || !b) return null;
const aLabel = a.nome, bLabel = b.nome;
const aMeta = a.cidade + (a.fase ? ' · ' + a.fase : (a.curso ? ' · ' + a.curso : ''));
const bMeta = b.cidade + (b.fase ? ' · ' + b.fase : (b.curso ? ' · ' + b.curso : ''));
return (
onSelect && onSelect(m)}>
{tipoLabel[m.tipo]}
{m.razao}
);
}
window.MatchCard = MatchCard;