// static/js/dashboard.jsx
function UserDashboard() {
const { token, setView } = useContext(AuthContext);
const [tests, setTests] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
let isMounted = true;
async function loadTests() {
try {
setLoading(true);
setError("");
const data = await API.getAvailableTests(token);
if (isMounted) {
setTests(Array.isArray(data) ? data : []);
}
} catch (e) {
console.error(e);
if (isMounted) {
setError(e.message || "Не удалось загрузить список тестов");
setTests([]);
}
} finally {
if (isMounted) {
setLoading(false);
}
}
}
if (token) {
loadTests();
} else {
setLoading(false);
setTests([]);
}
return () => {
isMounted = false;
};
}, [token]);
if (loading) {
return (
);
}
return (
Доступные тесты
{error && (
{error}
)}
{!error && tests.length === 0 && (
Для вас пока нет доступных тестов.
)}
{tests.length > 0 && (
{tests.map(test => {
const hasDetails =
typeof test.last_percent === 'number' &&
typeof test.total_questions === 'number' &&
test.total_questions > 0 &&
typeof test.last_correct_questions === 'number';
const hasLastAttempt = test.last_score !== null && test.last_score !== undefined;
let resultBoxClasses = "p-2 rounded text-xs mt-2";
let resultTitle = "";
if (test.status === 'passed') {
resultBoxClasses += " bg-green-50 text-green-800 border border-green-200";
resultTitle = "Результат последней попытки — ТЕСТ СДАН";
} else if (test.status === 'failed') {
resultBoxClasses += " bg-red-50 text-red-800 border border-red-200";
resultTitle = "Результат последней попытки — ТЕСТ НЕ СДАН";
} else {
resultBoxClasses += " bg-gray-50 text-gray-700 border border-gray-200";
resultTitle = "Результат последней попытки";
}
return (
{test.title}
{test.description}
🕒 Время: {test.time_limit ? test.time_limit + ' мин' : 'Без ограничений'}
🎯 Проходной: {test.passing_score}%
🔄 Попыток: {test.attempts_used} / {test.attempts_allowed || '∞'}
{/* Блок с результатами последней попытки — показываем, если она вообще была */}
{hasLastAttempt && (
{resultTitle}
{hasDetails ? (
<>
Правильных ответов:{" "}
{test.last_correct_questions} из {test.total_questions}
Баллы:{" "}
{test.last_score}
{typeof test.max_score === 'number' && test.max_score > 0
? ` из ${test.max_score}`
: ''}
{typeof test.last_percent === 'number' && (
<> ({test.last_percent.toFixed(1)}%)>
)}
>
) : (
Баллы:{" "}
{test.last_score}
)}
)}
{/* Блок с кнопкой — снизу карточки */}
{test.status === 'passed' ? (
Тест уже сдан.
) : (
)}
);
})}
)}
);
}