Spaces:
Sleeping
Sleeping
File size: 4,498 Bytes
1bb18a0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | import React from 'react';
const PRIORITY_CONFIG = {
5: { color: '#ef4444', label: 'CRITICAL' },
4: { color: '#f59e0b', label: 'HIGH' },
3: { color: '#eab308', label: 'MEDIUM' },
2: { color: '#22c55e', label: 'LOW' },
1: { color: '#94a3b8', label: 'MINIMAL' },
};
function ScoreGauge({ score }) {
const pct = Math.max(0, Math.min(1, score));
const color = pct >= 0.75 ? '#22c55e' : pct >= 0.5 ? '#f59e0b' : pct >= 0.25 ? '#f97316' : '#ef4444';
const size = 100;
const stroke = 8;
const r = (size - stroke * 2) / 2;
const circ = 2 * Math.PI * r;
const dash = circ * pct;
return (
<div className="score-gauge">
<svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="rgba(255,255,255,0.07)" strokeWidth={stroke} />
<circle
cx={size / 2} cy={size / 2} r={r}
fill="none"
stroke={color}
strokeWidth={stroke}
strokeDasharray={`${dash} ${circ}`}
strokeLinecap="round"
style={{ transition: 'stroke-dasharray 0.8s ease' }}
/>
</svg>
<div className="score-gauge-text">
<span className="score-value" style={{ color }}>{(score * 100).toFixed(0)}</span>
<span className="score-pct-label">/ 100</span>
</div>
</div>
);
}
export default function ScorePanel({ goals, score, done, totalReward, currentStep, maxSteps }) {
const completedGoals = goals.filter(g => g.completed);
const completionPct = goals.length > 0 ? (completedGoals.length / goals.length) * 100 : 0;
return (
<div className="panel score-panel">
<div className="panel-header">
<span className="panel-title">🎯 Goals & Score</span>
</div>
{/* Score gauge */}
<div className="score-section">
<ScoreGauge score={score} />
<div className="score-meta">
<div className="score-label-main">{done ? 'FINAL SCORE' : 'LIVE SCORE'}</div>
<div className="score-completion">
{completedGoals.length}/{goals.length} goals done
</div>
<div className="completion-bar-wrapper">
<div className="completion-bar">
<div
className="completion-bar-fill"
style={{
width: `${completionPct}%`,
background: completionPct >= 75 ? '#22c55e' : completionPct >= 50 ? '#f59e0b' : '#ef4444'
}}
/>
</div>
<span className="completion-pct">{completionPct.toFixed(0)}%</span>
</div>
</div>
</div>
{/* Goal checklist */}
<div className="goals-list">
<div className="goals-header">OBJECTIVES</div>
{goals.map(goal => {
const cfg = PRIORITY_CONFIG[goal.priority] || PRIORITY_CONFIG[1];
return (
<div key={goal.id} className={`goal-item ${goal.completed ? 'goal-done' : ''}`}>
<div
className="goal-checkbox"
style={{
borderColor: goal.completed ? cfg.color : 'rgba(148,163,184,0.3)',
background: goal.completed ? cfg.color : 'transparent',
}}
>
{goal.completed && <span className="goal-check">✓</span>}
</div>
<div className="goal-text">
<span className="goal-desc" style={{ color: goal.completed ? '#64748b' : '#e2e8f0' }}>
{goal.description}
</span>
<span className="goal-priority-tag" style={{ color: cfg.color }}>
P{goal.priority} • {cfg.label}
</span>
</div>
</div>
);
})}
</div>
{done && (
<div className="final-score-banner" style={{
background: score >= 0.7 ? 'rgba(34,197,94,0.1)' : score >= 0.4 ? 'rgba(245,158,11,0.1)' : 'rgba(239,68,68,0.1)',
borderColor: score >= 0.7 ? '#22c55e' : score >= 0.4 ? '#f59e0b' : '#ef4444',
}}>
<div className="final-score-title">
{score >= 0.8 ? '🏆 Excellent' : score >= 0.6 ? '✅ Good' : score >= 0.4 ? '⚠️ Adequate' : '❌ Poor'}
</div>
<div className="final-score-num" style={{ color: score >= 0.7 ? '#22c55e' : score >= 0.4 ? '#f59e0b' : '#ef4444' }}>
{score.toFixed(4)}
</div>
</div>
)}
</div>
);
}
|