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

117 lines
4.1 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 React, { useState, useCallback, useMemo } from 'react'
import AudioPlayer from '@/components/AudioPlayer'
import { ChoiceTestProps } from '@/types/review'
import { ErrorReportButton } 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">
{/* 標題區 */}
<div className="flex justify-between items-start mb-6">
<h2 className="text-2xl font-bold text-gray-900"></h2>
<span className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full">
{cardData.difficultyLevel}
</span>
</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) => (
<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 && (
<div className={`p-6 rounded-lg w-full mb-6 ${
isCorrect
? 'bg-green-50 border border-green-200'
: 'bg-red-50 border border-red-200'
}`}>
<p className={`font-semibold text-left text-xl mb-4 ${
isCorrect ? 'text-green-700' : 'text-red-700'
}`}>
{isCorrect ? '正確!' : '錯誤!'}
</p>
{!isCorrect && (
<div className="mb-4">
<p className="text-gray-700 text-left">
<strong className="text-lg">{cardData.word}</strong>
</p>
</div>
)}
<div className="space-y-3">
<div className="text-left">
<div className="flex items-center text-gray-600">
{cardData.pronunciation && <span className="mx-2">{cardData.pronunciation}</span>}
<AudioPlayer text={cardData.word} />
</div>
</div>
</div>
</div>
)}
</div>
</div>
)
}
export const VocabChoiceTest = React.memo(VocabChoiceTestComponent)