'use client' import React, { useState, useEffect, useCallback, useMemo } from 'react' import { useParams, useRouter } from 'next/navigation' import { useTheme } from '@/lib/ThemeContext' import { useNativeLanguage } from '@/lib/useNativeLanguage' import { StarRating, accuracyToStars } from '@/components/gamification/StarRating' import { AudioButton } from '@/components/learn/AudioButton' import { ExerciseLayout } from '@/components/learn/ExerciseLayout' interface QAItem { id: string; question: string; answer: string translations?: Record } function getApiBase() { return '' } export default function MatchPage() { const { unitId } = useParams<{ unitId: string }>() const router = useRouter() const { isDark } = useTheme() const { t, wordInNative, nativeLang, isThirdLanguage } = useNativeLanguage() const [allItems, setAllItems] = useState([]) const [isLoading, setIsLoading] = useState(true) const [round, setRound] = useState(0) const [selectedLeft, setSelectedLeft] = useState(null) const [matched, setMatched] = useState>(new Set()) const [wrongPair, setWrongPair] = useState(null) const [firstTryCorrect, setFirstTryCorrect] = useState(0) const [retryCorrect, setRetryCorrect] = useState(0) const [errors, setErrors] = useState(0) const [failedIds, setFailedIds] = useState>(new Set()) 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(() => { (async () => { try { const resp = await fetch(`${getApiBase()}/api/learning-units/${unitId}/qa`) if (resp.ok) { const d = await resp.json(); setAllItems(d.qa_items || []) } } catch {} finally { setIsLoading(false) } })() }, [unitId]) const roundItems = useMemo(() => allItems.slice(round * 6, round * 6 + 6), [allItems, round]) const shuffledRight = useMemo(() => [...roundItems].sort(() => Math.random() - 0.5), [roundItems]) const handleLeftTap = useCallback((id: string) => { if (matched.has(id)) return setSelectedLeft(id === selectedLeft ? null : id) setWrongPair(null) }, [selectedLeft, matched]) const handleRightTap = useCallback((id: string) => { if (!selectedLeft || matched.has(id)) return if (selectedLeft === id) { setMatched(prev => new Set([...prev, id])) if (failedIds.has(id)) setRetryCorrect(c => c + 1) else setFirstTryCorrect(c => c + 1) setSelectedLeft(null) if (matched.size + 1 >= roundItems.length) { const nextStart = (round + 1) * 6 if (nextStart >= allItems.length) setTimeout(() => setIsComplete(true), 500) else setTimeout(() => { setRound(r => r + 1); setMatched(new Set()); setSelectedLeft(null) }, 800) } } else { setWrongPair(id) setErrors(e => e + 1) setFailedIds(prev => new Set([...prev, selectedLeft])) setTimeout(() => { setWrongPair(null); setSelectedLeft(null) }, 600) } }, [selectedLeft, matched, roundItems, round, allItems, failedIds]) const restart = () => { setRound(0); setMatched(new Set()); setFirstTryCorrect(0); setRetryCorrect(0) setErrors(0); setFailedIds(new Set()); setIsComplete(false); setSelectedLeft(null) } if (isLoading) { return
} const totalPairs = allItems.length const matchedTotal = round * 6 + matched.size const isPerfect = isComplete && errors === 0 // Native helper panel: list of words in native language const nativePanel = (

{nativeLang.toUpperCase()} · {t('english')} · {t('german')}

{roundItems.map(item => { const native = wordInNative(item.translations) const isSelected = selectedLeft === item.id const isMatched = matched.has(item.id) return (
{native || '—'} {native && !isMatched && ( )}
) })}
) return ( router.push('/learn')} progress={{ current: matchedTotal, total: totalPairs }} nativeHelper={nativePanel} score={
✓{firstTryCorrect}{' '} ↻{retryCorrect}{' '} ✗{errors}
} > {isComplete ? (

{isPerfect ? t('well_done') : t('all_matched')}

{firstTryCorrect}
{t('correct')}
{retryCorrect}
2.
{errors}
{t('errors')}
) : (
{/* Left: English */}

{t('english')} / English

{roundItems.map(item => (
{!matched.has(item.id) && }
))}
{/* Right: German */}

{t('german')} / Deutsch

{shuffledRight.map(item => (
{!matched.has(item.id) && }
))}
)}
) }