// Pro Dashboard v2 — Team Development Focus
function ProDashboard({ onNavigate, onPlayerSelect }) {
const { team, games, players, upcomingEvents } = window.TData;
const { physicalData, tasks, completions, computeDevScore } = window.TDataExt;
const lastGame = games[games.length-1];
const avgPts = (games.reduce((s,g)=>s+g.scoreUs,0)/games.length).toFixed(1);
const teamAtt = Math.round(players.reduce((s,p)=>s+p.attendancePct,0)/players.length);
const teamTaskPct = Math.round(players.reduce((s,p)=>{
const done = tasks.filter(t=>completions[p.id]?.[t.id]).length;
return s + (tasks.length ? done/tasks.length*100 : 0);
},0)/players.length);
// Dev scores
const devScores = players.map(p=>({...p, dev: computeDevScore(p.id)}));
const topDev = [...devScores].sort((a,b)=>b.dev-a.dev).slice(0,5);
const needsAtt = [...devScores].sort((a,b)=>a.dev-b.dev).filter(p=>p.dev<60).slice(0,4);
const teamDevAvg = Math.round(devScores.reduce((s,p)=>s+p.dev,0)/players.length);
// Physical team trend (sprint avg across evals)
const evalDates = window.TDataExt.evalDates;
const sprintByEval = evalDates.map((_,ei)=>
+(players.reduce((s,p)=>{
const d = physicalData[p.id];
return s + (d&&d[ei] ? d[ei].sprint : 3.35);
},0)/players.length).toFixed(2)
);
const saltoByEval = evalDates.map((_,ei)=>
+(players.reduce((s,p)=>{
const d = physicalData[p.id];
return s + (d&&d[ei] ? d[ei].salto : 38);
},0)/players.length).toFixed(1)
);
// Game score trend
const scoreTrend = games.map(g=>g.scoreUs);
const gameLabels = games.map(g=>g.rival.slice(0,4));
// Most improved (sprint delta)
const mostImproved = [...players].map(p=>{
const d = physicalData[p.id];
const sprintDelta = d ? +(d[0].sprint - d[d.length-1].sprint).toFixed(2) : 0;
return {...p, sprintDelta};
}).sort((a,b)=>b.sprintDelta-a.sprintDelta).slice(0,3);
const devColor = v => v>=80?T.green:v>=60?T.yellow:T.red;
return (
{/* Header */}
Panel de Desarrollo
Visión integral del equipo · Temporada 2025–26
Récord
{team.wins}–{team.losses}
{/* KPI row */}
{[
{l:"Índice de Desarrollo", v:`${teamDevAvg}`, c:devColor(teamDevAvg), sub:"/100 promedio"},
{l:"Asistencia a Entrenos", v:`${teamAtt}%`, c:teamAtt>=80?T.green:T.yellow, sub:"promedio equipo"},
{l:"Tareas Completadas", v:`${teamTaskPct}%`, c:teamTaskPct>=70?T.green:T.yellow, sub:"cumplimiento"},
{l:"Pts Promedio", v:avgPts, c:T.accent, sub:"por partido"},
{l:"Racha", v:team.streak, c:T.green, sub:"victorias consecutivas"},
{l:"Sprint Equipo", v:`${sprintByEval[sprintByEval.length-1]}"`, c:T.text, sub:"↓ mejorando"},
].map(s=>
)}
{/* Row 2: development chart + alerts */}
{/* Rendimiento en cancha */}
onNavigate("partidos")} />
{/* Físico: velocidad */}
onNavigate("fisico")} />
d.slice(5))} color={T.green} height={130} />
Segundos — menor es mejor
{/* Alerts */}
{needsAtt.length === 0 ? (
Todo el equipo bien
) : needsAtt.map(p=>(
{p.name}
Asist. {p.attendancePct}% · Dev. {p.dev}/100
{p.dev}
))}
{/* Row 3: dev rankings + tasks + physical + upcoming */}
{/* Top development */}
onNavigate("jugadoras")} />
{topDev.map((p,i)=>{
const dc = devColor(p.dev);
return (
onPlayerSelect(p)} style={{
display:"flex",alignItems:"center",gap:10,padding:"9px 10px",
borderRadius:6,cursor:"pointer",transition:"background 0.1s"
}}
onMouseEnter={e=>e.currentTarget.style.background=T.stripe}
onMouseLeave={e=>e.currentTarget.style.background=""}
>
{i+1}
{p.dev}/100
);
})}
{/* Most improved physically */}
onNavigate("fisico")} />
{mostImproved.map((p,i)=>(
onPlayerSelect(p)} style={{
display:"flex",alignItems:"center",gap:12,padding:"9px 10px",
borderRadius:6,cursor:"pointer",transition:"background 0.1s"
}}
onMouseEnter={e=>e.currentTarget.style.background=T.stripe}
onMouseLeave={e=>e.currentTarget.style.background=""}
>
{i+1}
−{p.sprintDelta}"
))}
Salto vertical equipo
d.slice(5))} color={T.accent} height={80} />
{/* Tasks + next event */}
onNavigate("tareas")} />
{tasks.slice(0,3).map(t=>{
const done = players.filter(p=>completions[p.id]?.[t.id]).length;
const pct = Math.round(done/players.length*100);
const catColor = {Técnica:T.accent,Físico:T.red,Táctica:"#7c3aed",Recuperación:T.green}[t.category]||T.accent;
return (
{t.title}
=75?T.green:pct>=50?T.yellow:T.red}}>{pct}%
=75?T.green:pct>=50?T.yellow:T.red} height={4} />
);
})}
onNavigate("agenda")} />
{upcomingEvents.slice(0,3).map(ev=>(
{ev.type==="partido"?`vs ${ev.rival}`:ev.title}
{ev.date} · {ev.time}
))}
);
}
window.ProDashboard = ProDashboard;