// static/js/testReview.jsx function TestReview({ testId }) { const { token, setView } = useContext(AuthContext); const [loading, setLoading] = useState(true); const [data, setData] = useState(null); const [error, setError] = useState(""); useEffect(() => { let isMounted = true; async function loadReview() { try { setLoading(true); setError(""); const review = await API.userReviewTestAnswers(token, testId); if (isMounted) { setData(review); } } catch (e) { console.error(e); if (isMounted) { setError(e.message || "Не удалось загрузить ответы"); } } finally { if (isMounted) { setLoading(false); } } } loadReview(); return () => { isMounted = false; }; }, [token, testId]); if (loading) { return (
); } if (error) { return (
{error}
); } const result = data.result || {}; const percent = typeof result.percent === 'number' ? result.percent.toFixed(1) : '0.0'; return (

{data.test.title}

Баллы: {result.score} {typeof result.max_score === 'number' ? ` из ${result.max_score}` : ''} ({percent}%)
{(data.questions || []).map((q, idx) => { const earnedFull = Number(q.score_awarded || 0) >= Number(q.score || 0) && Number(q.score || 0) > 0; return (
{idx + 1}. {q.text}
{q.score_awarded || 0} / {q.score || 0}
{(q.options || []).length > 0 ? (
{q.options.map(opt => { let cls = "border rounded p-3 text-sm"; if (opt.is_correct) cls += " border-green-300 bg-green-50"; else if (opt.selected) cls += " border-red-300 bg-red-50"; else cls += " border-gray-200 bg-gray-50"; return (
{opt.is_correct ? "Верно" : (opt.selected ? "Ваш ответ" : "")} {opt.text}
); })}
) : (
Ваш ответ: {q.text_answer || "Нет ответа"}
{q.correct_text && (
Правильный ответ: {q.correct_text}
)}
)}
); })}
); }