| import { useEffect, useRef } from 'react'; |
|
|
| const scoreMessage = (pct) => { |
| if (pct === 100) return 'Perfect score — absolutely outstanding! 🎉'; |
| if (pct >= 80) return 'Excellent command of the material.'; |
| if (pct >= 60) return 'Good effort — room to grow.'; |
| if (pct >= 40) return 'Keep studying — you\'ll get there.'; |
| return 'Review the material and try again.'; |
| }; |
|
|
| function ResultCard({ r, index }) { |
| const correct = r.correct; |
| return ( |
| <div |
| className={`r-card ${correct ? 'r-correct' : 'r-incorrect'}`} |
| style={{ animationDelay: `${index * 0.07}s` }} |
| > |
| <div className={`r-badge ${correct ? 'badge-ok' : 'badge-no'}`}> |
| {correct ? '✓ Correct' : '✗ Incorrect'} |
| </div> |
| <div className="r-question">Q{index + 1}. {r.question}</div> |
| |
| {!correct && ( |
| <> |
| <div className="answer-grid"> |
| <div> |
| <div className="a-label">Your Answer</div> |
| <div className="a-val-wrong">{r.user_answer || '—'}</div> |
| </div> |
| <div> |
| <div className="a-label">Correct Answer</div> |
| <div className="a-val-right">{r.correct_answer}</div> |
| </div> |
| </div> |
| {r.explanation && ( |
| <div className="expl-box"> |
| <div className="expl-label">Explanation</div> |
| <div className="expl-text">{r.explanation}</div> |
| </div> |
| )} |
| {r.concept && ( |
| <div className="concept-pill">✦ {r.concept}</div> |
| )} |
| </> |
| )} |
| </div> |
| ); |
| } |
|
|
| export default function ResultsView({ result, onReset }) { |
| const { score, total, results } = result; |
| const pct = total ? (score / total) * 100 : 0; |
| const barRef = useRef(null); |
|
|
| useEffect(() => { |
| |
| const t = setTimeout(() => { |
| if (barRef.current) barRef.current.style.width = `${pct.toFixed(1)}%`; |
| }, 150); |
| return () => clearTimeout(t); |
| }, [pct]); |
|
|
| return ( |
| <div> |
| {/* Score Hero */} |
| <div className="score-wrap"> |
| <div className="score-num"> |
| {score}<span className="score-denom">/{total}</span> |
| </div> |
| <div className="score-label-text">Final Score</div> |
| <div className="score-bar-bg"> |
| <div className="score-bar-fill" ref={barRef} /> |
| </div> |
| <div className="score-msg">{scoreMessage(pct)}</div> |
| </div> |
| |
| {/* Detailed Review */} |
| <div className="step-header" style={{ marginTop: '1.5rem' }}> |
| <div className="step-badge">✦</div> |
| <div className="step-title">Detailed Review</div> |
| </div> |
| |
| {results.map((r, i) => ( |
| <ResultCard key={i} r={r} index={i} /> |
| ))} |
| |
| <div className="spacer" /> |
| <button className="btn btn-ghost" onClick={onReset} id="btn-try-again"> |
| ↺ Try Again |
| </button> |
| </div> |
| ); |
| } |
|
|