diff --git a/frontend/src/index.css b/frontend/src/index.css index 1494493..13c9c43 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -265,6 +265,11 @@ body { .spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid var(--border); border-top-color: var(--primary); border-radius: 50%; animation: spin 0.6s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } +@keyframes fadeInUp { + from { opacity: 0; transform: translateX(-50%) translateY(8px); } + to { opacity: 1; transform: translateX(-50%) translateY(0); } +} + /* ── Section items ──────────────────────────────────────────── */ .section-item { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; background: var(--card-bg); } diff --git a/frontend/src/pages/QuizPage.jsx b/frontend/src/pages/QuizPage.jsx index e97c713..48290e3 100644 --- a/frontend/src/pages/QuizPage.jsx +++ b/frontend/src/pages/QuizPage.jsx @@ -85,18 +85,6 @@ function ModeSelectScreen({ quiz, voices, onStart }) { {quiz.time_limit_minutes ? ` · ${quiz.time_limit_minutes} min limit` : ''}

- {skipped.length > 0 && ( -
-

- ⚠️ {skipped.length} question{skipped.length > 1 ? 's' : ''} skipped (no correct answer found): -

- -
- )}

Choose how to take this quiz:

@@ -147,9 +135,17 @@ export default function QuizPage() { const [attemptId, setAttemptId] = useState(null) const [timeLeft, setTimeLeft] = useState(null) const [totalTime, setTotalTime] = useState(null) + const [toast, setToast] = useState('') const timerRef = useRef(null) + const toastRef = useRef(null) const hasStarted = useRef(false) + const showToast = (msg) => { + setToast(msg) + clearTimeout(toastRef.current) + toastRef.current = setTimeout(() => setToast(''), 3000) + } + useEffect(() => { const load = async () => { try { @@ -198,21 +194,13 @@ useEffect(() => { const setAnswer = (questionId, value) => setAnswers(prev => ({ ...prev, [questionId]: value })) - // Warn before navigating away mid-quiz - const safeNavigate = (targetIdx) => { - if (Object.keys(answers).length > 0 && attemptId) { - const confirmed = window.confirm( - 'You have answered some questions.\n\n• OK — go back (progress saved so far)\n• Cancel — stay on current question' - ) - if (!confirmed) return - } - setCurrentIdx(targetIdx) - } + const safeNavigate = (targetIdx) => setCurrentIdx(targetIdx) const handleSubmit = useCallback(async (autoSubmit = false) => { if (!attemptId || submitting) return if (!autoSubmit && Object.keys(answers).length === 0) { - if (!window.confirm('You haven\'t answered any questions. Submit anyway?')) return + showToast('No answers selected — submitting with 0 answered.') + await new Promise(r => setTimeout(r, 1200)) } clearInterval(timerRef.current) setSubmitting(true) @@ -251,6 +239,17 @@ useEffect(() => { return (
+ {toast && ( +
+ {toast} +
+ )}