You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.9 KiB
112 lines
3.9 KiB
import { Link } from 'react-router-dom'; |
|
|
|
/** |
|
* @param {{ review: { |
|
* testTitle?: string, |
|
* attempterName?: string, |
|
* attempterLogin?: string, |
|
* startedAt?: string, |
|
* completedAt?: string, |
|
* correctCount: number, |
|
* totalQuestions: number, |
|
* percent: number, |
|
* passed: boolean, |
|
* passingThreshold: number, |
|
* questions: Array<{ |
|
* id: string, |
|
* text: string, |
|
* isUserCorrect: boolean, |
|
* options: Array<{ id: string, text: string, isCorrect: boolean, selected: boolean }> |
|
* }> |
|
* }, showAttempter?: boolean, backLink: { to: string, label: string } }} p |
|
*/ |
|
export default function AttemptReviewBlock({ review, showAttempter, backLink }) { |
|
if (!review?.questions?.length) { |
|
return null; |
|
} |
|
return ( |
|
<div className="attempt-review" style={{ maxWidth: 640 }}> |
|
{showAttempter && (review.attempterName || review.attempterLogin) && ( |
|
<p className="text-muted" style={{ marginTop: 0, fontSize: 14 }}> |
|
Участник: {review.attempterName || '—'}{' '} |
|
{review.attempterLogin && ( |
|
<span className="code-inline" style={{ fontSize: 12 }}> |
|
{review.attempterLogin} |
|
</span> |
|
)} |
|
</p> |
|
)} |
|
{review.completedAt && ( |
|
<p className="text-muted" style={{ marginTop: 0, fontSize: 13 }}> |
|
Завершено: {new Date(review.completedAt).toLocaleString('ru-RU')} |
|
</p> |
|
)} |
|
<ol style={{ paddingLeft: '1.1rem', marginTop: '0.75rem' }}> |
|
{review.questions.map((q, i) => ( |
|
<li |
|
key={q.id} |
|
style={{ |
|
marginBottom: '1.1rem', |
|
borderLeft: '3px solid', |
|
borderColor: q.isUserCorrect |
|
? 'color-mix(in srgb, var(--primary) 50%, var(--outline-variant))' |
|
: 'color-mix(in srgb, var(--error, #c00) 45%, var(--outline-variant))', |
|
paddingLeft: 10, |
|
}} |
|
> |
|
<p style={{ marginTop: 0, marginBottom: 8, fontWeight: 600 }}>{i + 1}. {q.text}</p> |
|
<p |
|
className={q.isUserCorrect ? 'text-muted' : 'error-text'} |
|
style={{ margin: '0 0 6px', fontSize: 13 }} |
|
> |
|
{q.isUserCorrect ? 'Верно' : 'Ошибка'} |
|
</p> |
|
<ul style={{ listStyle: 'none', padding: 0, margin: 0, fontSize: 14 }}> |
|
{q.options.map((o) => { |
|
const mark = |
|
o.selected && o.isCorrect |
|
? '✓ верно' |
|
: o.selected && !o.isCorrect |
|
? '✗ выбрано' |
|
: !o.selected && o.isCorrect |
|
? '— правильный вариант' |
|
: ''; |
|
return ( |
|
<li |
|
key={o.id} |
|
style={{ |
|
marginBottom: 4, |
|
opacity: o.selected || o.isCorrect ? 1 : 0.7, |
|
}} |
|
> |
|
<span |
|
style={ |
|
o.isCorrect |
|
? { fontWeight: 600, color: 'var(--primary, #007168)' } |
|
: o.selected |
|
? {} |
|
: { color: 'var(--secondary)' } |
|
} |
|
> |
|
{o.text} |
|
</span> |
|
{mark && ( |
|
<span className="text-muted" style={{ marginLeft: 8, fontSize: 12 }}> |
|
{mark} |
|
</span> |
|
)} |
|
</li> |
|
); |
|
})} |
|
</ul> |
|
</li> |
|
))} |
|
</ol> |
|
{backLink && ( |
|
<p className="link-back" style={{ marginTop: '1rem' }}> |
|
<Link to={backLink.to}>{backLink.label}</Link> |
|
</p> |
|
)} |
|
</div> |
|
); |
|
}
|
|
|