102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import React, { useState, useCallback, useMemo, memo } from 'react'
|
||
import AudioPlayer from '@/components/AudioPlayer'
|
||
import { ChoiceTestProps } from '@/types/review'
|
||
import {
|
||
ErrorReportButton,
|
||
TestResultDisplay,
|
||
TestHeader
|
||
} from '@/components/review/shared'
|
||
|
||
interface VocabChoiceTestProps extends ChoiceTestProps {
|
||
// VocabChoiceTest specific props (if any)
|
||
}
|
||
|
||
const VocabChoiceTestComponent: React.FC<VocabChoiceTestProps> = ({
|
||
cardData,
|
||
options,
|
||
onAnswer,
|
||
onReportError,
|
||
disabled = false
|
||
}) => {
|
||
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null)
|
||
const [showResult, setShowResult] = useState(false)
|
||
|
||
const handleAnswerSelect = useCallback((answer: string) => {
|
||
if (disabled || showResult) return
|
||
setSelectedAnswer(answer)
|
||
setShowResult(true)
|
||
onAnswer(answer)
|
||
}, [disabled, showResult, onAnswer])
|
||
|
||
const isCorrect = useMemo(() =>
|
||
selectedAnswer === cardData.word
|
||
, [selectedAnswer, cardData.word])
|
||
|
||
return (
|
||
<div className="relative">
|
||
<div className="flex justify-end mb-2">
|
||
<ErrorReportButton onClick={onReportError} />
|
||
</div>
|
||
|
||
<div className="bg-white rounded-xl shadow-lg p-8">
|
||
{/* 標題區 */}
|
||
<TestHeader
|
||
title="詞彙選擇"
|
||
difficultyLevel={cardData.difficultyLevel}
|
||
/>
|
||
|
||
{/* 指示文字 */}
|
||
<p className="text-lg text-gray-700 mb-6 text-left">
|
||
請選擇符合上述定義的英文詞彙:
|
||
</p>
|
||
|
||
{/* 定義顯示區 */}
|
||
<div className="text-center mb-8">
|
||
<div className="bg-gray-50 rounded-lg p-4 mb-6">
|
||
<h3 className="font-semibold text-gray-900 mb-2 text-left">定義</h3>
|
||
<p className="text-gray-700 text-left">{cardData.definition}</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 選項區域 - 響應式網格布局 */}
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-6">
|
||
{options.map((option, idx) => (
|
||
<button
|
||
key={idx}
|
||
onClick={() => handleAnswerSelect(option)}
|
||
disabled={disabled || showResult}
|
||
className={`p-4 text-center rounded-lg border-2 transition-all ${
|
||
showResult
|
||
? option === cardData.word
|
||
? 'border-green-500 bg-green-50 text-green-700'
|
||
: option === selectedAnswer
|
||
? 'border-red-500 bg-red-50 text-red-700'
|
||
: 'border-gray-200 bg-gray-50 text-gray-500'
|
||
: 'border-gray-200 hover:border-blue-300 hover:bg-blue-50'
|
||
}`}
|
||
>
|
||
<div className="text-lg font-medium">{option}</div>
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* 結果反饋區 */}
|
||
{showResult && (
|
||
<TestResultDisplay
|
||
isCorrect={isCorrect}
|
||
correctAnswer={cardData.word}
|
||
userAnswer={selectedAnswer || ''}
|
||
word={cardData.word}
|
||
pronunciation={cardData.pronunciation}
|
||
example={cardData.example}
|
||
exampleTranslation={cardData.exampleTranslation}
|
||
showResult={showResult}
|
||
/>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export const VocabChoiceTest = memo(VocabChoiceTestComponent)
|
||
VocabChoiceTest.displayName = 'VocabChoiceTest' |