197 lines
5.1 KiB
TypeScript
197 lines
5.1 KiB
TypeScript
import { useEffect } from 'react'
|
|
import { useLearnStore } from '@/store/useLearnStore'
|
|
import { useUIStore } from '@/store/useUIStore'
|
|
import {
|
|
FlipMemoryTest,
|
|
VocabChoiceTest,
|
|
SentenceFillTest,
|
|
SentenceReorderTest,
|
|
VocabListeningTest,
|
|
SentenceListeningTest,
|
|
SentenceSpeakingTest
|
|
} from './tests'
|
|
|
|
interface TestRunnerProps {
|
|
className?: string
|
|
}
|
|
|
|
export const TestRunner: React.FC<TestRunnerProps> = ({ className }) => {
|
|
const {
|
|
currentCard,
|
|
currentMode,
|
|
updateScore,
|
|
recordTestResult,
|
|
error
|
|
} = useLearnStore()
|
|
|
|
const {
|
|
openReportModal,
|
|
openImageModal
|
|
} = useUIStore()
|
|
|
|
// 處理答題
|
|
const handleAnswer = async (answer: string, confidenceLevel?: number) => {
|
|
if (!currentCard) return
|
|
|
|
// 檢查答案正確性
|
|
const isCorrect = checkAnswer(answer, currentCard, currentMode)
|
|
|
|
// 更新分數
|
|
updateScore(isCorrect)
|
|
|
|
// 記錄到後端
|
|
await recordTestResult(isCorrect, answer, confidenceLevel)
|
|
}
|
|
|
|
// 檢查答案正確性
|
|
const checkAnswer = (answer: string, card: any, mode: string): boolean => {
|
|
switch (mode) {
|
|
case 'flip-memory':
|
|
return true // 翻卡記憶沒有對錯,只有信心等級
|
|
|
|
case 'vocab-choice':
|
|
case 'vocab-listening':
|
|
return answer === card.word
|
|
|
|
case 'sentence-fill':
|
|
return answer.toLowerCase().trim() === card.word.toLowerCase()
|
|
|
|
case 'sentence-reorder':
|
|
case 'sentence-listening':
|
|
return answer.toLowerCase().trim() === card.example.toLowerCase().trim()
|
|
|
|
case 'sentence-speaking':
|
|
return true // 口說測驗通常算正確
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// 生成測驗選項
|
|
const generateOptions = (card: any, mode: string): string[] => {
|
|
// 這裡應該根據測驗類型生成對應的選項
|
|
// 暫時返回簡單的佔位符
|
|
switch (mode) {
|
|
case 'vocab-choice':
|
|
case 'vocab-listening':
|
|
return [card.word, '其他選項1', '其他選項2', '其他選項3'].sort(() => Math.random() - 0.5)
|
|
|
|
case 'sentence-listening':
|
|
return [
|
|
card.example,
|
|
'其他例句選項1',
|
|
'其他例句選項2',
|
|
'其他例句選項3'
|
|
].sort(() => Math.random() - 0.5)
|
|
|
|
default:
|
|
return []
|
|
}
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="text-center py-8">
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-6">
|
|
<h3 className="text-lg font-semibold text-red-700 mb-2">發生錯誤</h3>
|
|
<p className="text-red-600">{error}</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!currentCard) {
|
|
return (
|
|
<div className="text-center py-8">
|
|
<div className="text-gray-500">載入測驗中...</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// 共同的 props
|
|
const commonProps = {
|
|
word: currentCard.word,
|
|
definition: currentCard.definition,
|
|
example: currentCard.example,
|
|
exampleTranslation: currentCard.translation || '',
|
|
pronunciation: currentCard.pronunciation,
|
|
difficultyLevel: currentCard.difficultyLevel || 'A2',
|
|
onReportError: () => openReportModal(currentCard),
|
|
onImageClick: openImageModal,
|
|
exampleImage: currentCard.exampleImage
|
|
}
|
|
|
|
// 渲染對應的測驗組件
|
|
switch (currentMode) {
|
|
case 'flip-memory':
|
|
return (
|
|
<FlipMemoryTest
|
|
{...commonProps}
|
|
synonyms={currentCard.synonyms}
|
|
onConfidenceSubmit={(level) => handleAnswer('', level)}
|
|
/>
|
|
)
|
|
|
|
case 'vocab-choice':
|
|
return (
|
|
<VocabChoiceTest
|
|
{...commonProps}
|
|
options={generateOptions(currentCard, currentMode)}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
case 'sentence-fill':
|
|
return (
|
|
<SentenceFillTest
|
|
{...commonProps}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
case 'sentence-reorder':
|
|
return (
|
|
<SentenceReorderTest
|
|
{...commonProps}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
case 'vocab-listening':
|
|
return (
|
|
<VocabListeningTest
|
|
{...commonProps}
|
|
options={generateOptions(currentCard, currentMode)}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
case 'sentence-listening':
|
|
return (
|
|
<SentenceListeningTest
|
|
{...commonProps}
|
|
options={generateOptions(currentCard, currentMode)}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
case 'sentence-speaking':
|
|
return (
|
|
<SentenceSpeakingTest
|
|
{...commonProps}
|
|
onAnswer={handleAnswer}
|
|
/>
|
|
)
|
|
|
|
default:
|
|
return (
|
|
<div className="text-center py-8">
|
|
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-6">
|
|
<h3 className="text-lg font-semibold text-yellow-700 mb-2">未實現的測驗類型</h3>
|
|
<p className="text-yellow-600">測驗類型 "{currentMode}" 尚未實現</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
} |