Files
breakpilot-lehrer/studio-v2/app/parent/quiz/[unitId]/page.tsx
Benjamin Admin 9e63b09cb7 Wire Parent Quiz to central translation system + native language audio
Uses useNativeLanguage() hook for all UI text. Shows native language
translation of vocab word + audio button for native pronunciation.
Removed inline pt translations dict (now in exerciseTranslations.ts).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 00:22:39 +02:00

169 lines
7.2 KiB
TypeScript

'use client'
import React, { useState, useEffect, useCallback } from 'react'
import { useParams, useRouter } from 'next/navigation'
import { useTheme } from '@/lib/ThemeContext'
import { useLanguage } from '@/lib/LanguageContext'
import { AudioButton } from '@/components/learn/AudioButton'
import { useNativeLanguage } from '@/lib/useNativeLanguage'
interface QAItem {
id: string; question: string; answer: string
translations?: Record<string, { text?: string }>
}
// UI translations now come from useNativeLanguage() hook + exerciseTranslations.ts
export default function ParentQuizPage() {
const { unitId } = useParams<{ unitId: string }>()
const router = useRouter()
const { isDark } = useTheme()
const { language } = useLanguage()
const { t, wordInNative, nativeLang, isThirdLanguage } = useNativeLanguage()
const [items, setItems] = useState<QAItem[]>([])
const [currentIndex, setCurrentIndex] = useState(0)
const [showAnswer, setShowAnswer] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const [stats, setStats] = useState({ correct: 0, incorrect: 0 })
const [isComplete, setIsComplete] = useState(false)
const glassCard = isDark
? 'bg-white/10 backdrop-blur-xl border border-white/10'
: 'bg-white/80 backdrop-blur-xl border border-black/5'
useEffect(() => {
fetch(`/api/learning-units/${unitId}/qa`)
.then(r => r.ok ? r.json() : { qa_items: [] })
.then(d => setItems(d.qa_items || []))
.catch(() => {})
.finally(() => setIsLoading(false))
}, [unitId])
const handleResult = useCallback((correct: boolean) => {
setStats(prev => ({
correct: prev.correct + (correct ? 1 : 0),
incorrect: prev.incorrect + (correct ? 0 : 1),
}))
setShowAnswer(false)
if (currentIndex + 1 >= items.length) { setIsComplete(true) }
else { setCurrentIndex(i => i + 1) }
}, [currentIndex, items.length])
const currentItem = items[currentIndex]
const nativeTranslation = wordInNative(currentItem?.translations)
if (isLoading) {
return (
<div className="flex items-center justify-center py-20">
<div className="w-8 h-8 border-4 border-blue-400 border-t-transparent rounded-full animate-spin" />
</div>
)
}
return (
<div dir={language === 'ar' ? 'rtl' : 'ltr'}>
{/* Header */}
<div className={`${glassCard} border-0 border-b`}>
<div className="max-w-lg mx-auto px-6 py-4 flex items-center justify-between">
<button onClick={() => router.push('/parent')} className={`text-sm ${isDark ? 'text-white/60' : 'text-slate-500'}`}>
{t('back')}
</button>
<span className={`font-bold ${isDark ? 'text-white' : 'text-slate-900'}`}>
{t('question')} {currentIndex + 1}/{items.length}
</span>
<span />
</div>
</div>
{/* Progress */}
<div className="w-full h-1.5 bg-white/10">
<div className="h-full bg-gradient-to-r from-blue-500 to-cyan-500 transition-all" style={{ width: `${(currentIndex / Math.max(items.length, 1)) * 100}%` }} />
</div>
<div className="flex-1 flex items-center justify-center px-6 py-8">
{isComplete ? (
<div className={`${glassCard} rounded-3xl p-10 text-center max-w-md w-full`}>
<div className="text-5xl mb-4">{stats.correct > stats.incorrect ? '\uD83C\uDF89' : '\uD83D\uDCAA'}</div>
<h2 className={`text-2xl font-bold mb-2 ${isDark ? 'text-white' : 'text-slate-900'}`}>{t('done')}</h2>
<p className={`text-lg mb-6 ${isDark ? 'text-white/70' : 'text-slate-600'}`}>
{stats.correct}/{items.length} {t('correct').toLowerCase()}
</p>
<div className="flex gap-3">
<button onClick={() => { setCurrentIndex(0); setStats({ correct: 0, incorrect: 0 }); setIsComplete(false) }}
className="flex-1 py-3 rounded-xl bg-gradient-to-r from-blue-500 to-cyan-500 text-white font-medium">{t('again')}</button>
<button onClick={() => router.push('/parent')}
className={`flex-1 py-3 rounded-xl border font-medium ${isDark ? 'border-white/20 text-white/80' : 'border-slate-300 text-slate-700'}`}>{t('back')}</button>
</div>
</div>
) : currentItem ? (
<div className="w-full max-w-md space-y-6">
{/* Instruction for parent */}
<p className={`text-center text-sm ${isDark ? 'text-white/50' : 'text-slate-500'}`}>
{t('ask_child')}
</p>
{/* Word to ask */}
<div className={`${glassCard} rounded-3xl p-8 text-center`}>
<span className={`text-3xl font-bold ${isDark ? 'text-white' : 'text-slate-900'}`}>
{currentItem.question}
</span>
{nativeTranslation && (
<p className={`text-lg mt-3 ${isDark ? 'text-blue-300/70' : 'text-blue-600'}`}>
({nativeTranslation})
</p>
)}
<div className="flex justify-center gap-3 mt-4">
<AudioButton text={currentItem.question} lang="en" isDark={isDark} size="md" />
{nativeTranslation && (
<AudioButton text={nativeTranslation} lang={nativeLang as 'en' | 'de'} isDark={isDark} size="md" />
)}
</div>
</div>
{/* Show/Hide Answer */}
<button
onClick={() => setShowAnswer(!showAnswer)}
className={`w-full py-3 rounded-xl border text-sm font-medium transition-all ${
isDark ? 'border-white/20 text-white/70 hover:bg-white/5' : 'border-slate-200 text-slate-600 hover:bg-slate-50'
}`}
>
{showAnswer ? t('hide_answer') : t('show_answer')}
</button>
{showAnswer && (
<div className={`${glassCard} rounded-2xl p-6 text-center`}>
<p className={`text-xs mb-2 ${isDark ? 'text-white/40' : 'text-slate-400'}`}>{t('correct_answer')}</p>
<span className={`text-2xl font-bold ${isDark ? 'text-green-300' : 'text-green-700'}`}>
{currentItem.answer}
</span>
{nativeTranslation && (
<p className={`text-sm mt-1 ${isDark ? 'text-white/50' : 'text-slate-500'}`}>
({nativeTranslation})
</p>
)}
<div className="flex justify-center mt-3">
<AudioButton text={currentItem.answer} lang="de" isDark={isDark} size="md" />
</div>
</div>
)}
{/* Right/Wrong Buttons */}
<div className="flex gap-4">
<button onClick={() => handleResult(false)}
className="flex-1 py-4 rounded-2xl font-semibold bg-gradient-to-r from-red-500 to-rose-500 text-white hover:shadow-lg transition-all">
{t('wrong')}
</button>
<button onClick={() => handleResult(true)}
className="flex-1 py-4 rounded-2xl font-semibold bg-gradient-to-r from-green-500 to-emerald-500 text-white hover:shadow-lg transition-all">
{t('correct')}
</button>
</div>
</div>
) : null}
</div>
</div>
)
}