dramaling-vocab-learning/frontend/components/review/review-tests/VocabChoiceTest.optimized.tsx

170 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react'
import { ChoiceTestProps, ReviewCardData } from '@/types/review'
import { useReviewLogic } from '@/hooks/useReviewLogic'
import {
CardHeader,
AudioSection,
ErrorReportButton
} from '@/components/review/shared'
// 優化後的 VocabChoiceTest 組件
export const VocabChoiceTest: React.FC<ChoiceTestProps> = ({
cardData,
options,
onAnswer,
onReportError,
disabled = false
}) => {
// 使用共用邏輯 Hook
const {
userAnswer,
feedback,
isSubmitted,
submitAnswer
} = useReviewLogic({
cardData,
testType: 'VocabChoiceTest'
})
const [selectedAnswer, setSelectedAnswer] = useState<string | null>(null)
// 處理選項點擊
const handleOptionClick = (option: string) => {
if (isSubmitted || disabled) return
setSelectedAnswer(option)
const result = submitAnswer(option)
onAnswer(option)
}
return (
<div className="max-w-4xl mx-auto">
{/* 音頻播放區 */}
<AudioSection
word={cardData.word}
pronunciation={cardData.pronunciation}
className="mb-6"
/>
<div className="bg-white rounded-xl shadow-lg p-8">
{/* 標題區 */}
<div className="flex justify-between items-start mb-6">
<h2 className="text-2xl font-bold text-gray-900"></h2>
</div>
{/* 指示文字 */}
<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) => {
const isSelected = selectedAnswer === option
const isCorrect = feedback && feedback.isCorrect && isSelected
const isWrong = feedback && !feedback.isCorrect && isSelected
return (
<button
key={idx}
onClick={() => handleOptionClick(option)}
disabled={disabled || isSubmitted}
className={`
p-4 rounded-lg border-2 transition-all duration-200
text-left font-medium
${!isSubmitted
? 'border-gray-200 hover:border-blue-300 hover:bg-blue-50'
: isCorrect
? 'border-green-500 bg-green-50 text-green-700'
: isWrong
? 'border-red-500 bg-red-50 text-red-700'
: option.toLowerCase() === cardData.word.toLowerCase()
? 'border-green-500 bg-green-50 text-green-700'
: 'border-gray-200 bg-gray-50 text-gray-500'
}
${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
`}
>
{option}
</button>
)
})}
</div>
{/* 結果回饋 */}
{feedback && (
<div className={`p-4 rounded-lg mb-6 ${
feedback.isCorrect ? 'bg-green-50 border border-green-200' : 'bg-red-50 border border-red-200'
}`}>
<p className={`font-medium ${
feedback.isCorrect ? 'text-green-800' : 'text-red-800'
}`}>
{feedback.explanation}
</p>
</div>
)}
{/* 例句區域 */}
<div className="bg-blue-50 rounded-lg p-4 mb-6">
<h3 className="font-semibold text-gray-900 mb-2"></h3>
<p className="text-gray-800 mb-2">{cardData.example}</p>
<p className="text-gray-600 text-sm">{cardData.exampleTranslation}</p>
</div>
{/* 底部按鈕 */}
<div className="flex justify-center">
<ErrorReportButton
onClick={onReportError}
disabled={disabled}
/>
</div>
</div>
</div>
)
}
// 向後相容包裝器
interface LegacyVocabChoiceTestProps {
word: string
definition: string
example: string
exampleTranslation: string
pronunciation?: string
difficultyLevel: string
options: string[]
onAnswer: (answer: string) => void
onReportError: () => void
disabled?: boolean
}
export const VocabChoiceTestLegacy: React.FC<LegacyVocabChoiceTestProps> = (props) => {
const cardData: ReviewCardData = {
id: `temp_${props.word}`,
word: props.word,
definition: props.definition,
example: props.example,
translation: props.exampleTranslation || '',
pronunciation: props.pronunciation,
synonyms: [], // VocabChoiceTest 原來沒有 synonyms
difficultyLevel: props.difficultyLevel,
exampleTranslation: props.exampleTranslation
}
return (
<VocabChoiceTest
cardData={cardData}
options={props.options}
onAnswer={props.onAnswer}
onReportError={props.onReportError}
disabled={props.disabled}
/>
)
}