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

91 lines
2.7 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, memo } from 'react'
import VoiceRecorder from '@/components/VoiceRecorder'
import {
SpeakingTestContainer
} from '@/components/review/shared'
import { BaseReviewProps } from '@/types/review'
interface SentenceSpeakingTestProps extends BaseReviewProps {
exampleImage?: string
onImageClick?: (image: string) => void
}
const SentenceSpeakingTestComponent: React.FC<SentenceSpeakingTestProps> = ({
cardData,
exampleImage,
onAnswer,
onReportError,
onImageClick,
disabled = false
}) => {
const [showResult, setShowResult] = useState(false)
// 判斷是否已答題(錄音提交後設定 hasAnswered = true
const hasAnswered = showResult
const handleRecordingComplete = useCallback(() => {
if (disabled || showResult) return
setShowResult(true)
onAnswer(cardData.example) // 語音測驗通常都算正確
}, [disabled, showResult, cardData.example, onAnswer])
// 提示區域
const promptArea = (
<div className="text-center">
<p className="text-lg text-gray-700 text-left mb-4">
</p>
{exampleImage && (
<div className="bg-gray-50 rounded-lg p-4">
<img
src={exampleImage}
alt="Example illustration"
className="w-full max-w-md mx-auto rounded-lg cursor-pointer"
onClick={() => onImageClick?.(exampleImage)}
/>
</div>
)}
</div>
)
// 錄音區域
const recordingArea = (
<div className="w-full">
<VoiceRecorder
targetText={cardData.example}
targetTranslation={cardData.exampleTranslation}
exampleImage={exampleImage}
instructionText="請看例句圖片並大聲說出完整的例句:"
onRecordingComplete={handleRecordingComplete}
/>
</div>
)
// 結果顯示區域
const resultArea = showResult ? (
<div className="p-6 rounded-lg bg-blue-50 border border-blue-200 w-full">
<p className="text-blue-700 text-left text-xl font-semibold mb-2">
</p>
<p className="text-gray-600 text-left">
...
</p>
</div>
) : null
return (
<SpeakingTestContainer
cardData={cardData}
testTitle="例句口說"
promptArea={promptArea}
recordingArea={recordingArea}
resultArea={resultArea}
onAnswer={onAnswer}
onReportError={onReportError}
disabled={disabled}
/>
)
}
export const SentenceSpeakingTest = memo(SentenceSpeakingTestComponent)
SentenceSpeakingTest.displayName = 'SentenceSpeakingTest'