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

212 lines
6.7 KiB
TypeScript

import { useState, useRef, useEffect } from 'react'
import { ConfidenceTestProps, ReviewCardData } from '@/types/review'
import { useReviewLogic } from '@/hooks/useReviewLogic'
import {
CardHeader,
AudioSection,
ConfidenceButtons,
ErrorReportButton
} from '@/components/review/shared'
// 優化後的 FlipMemoryTest 組件
export const FlipMemoryTestNew: React.FC<ConfidenceTestProps> = ({
cardData,
onAnswer,
onConfidenceSubmit,
onReportError,
disabled = false
}) => {
// 使用共用邏輯 Hook
const {
confidence,
submitConfidence,
generateResult
} = useReviewLogic({
cardData,
testType: 'FlipMemoryTest'
})
// 翻卡特定狀態
const [isFlipped, setIsFlipped] = useState(false)
const [cardHeight, setCardHeight] = useState<number>(400)
const frontRef = useRef<HTMLDivElement>(null)
const backRef = useRef<HTMLDivElement>(null)
// 動態計算卡片高度
useEffect(() => {
const updateCardHeight = () => {
if (backRef.current) {
const backHeight = backRef.current.scrollHeight
const minHeightByScreen = window.innerWidth <= 480 ? 300 :
window.innerWidth <= 768 ? 350 : 400
const finalHeight = Math.max(minHeightByScreen, backHeight)
setCardHeight(finalHeight)
}
}
setTimeout(updateCardHeight, 100)
window.addEventListener('resize', updateCardHeight)
return () => window.removeEventListener('resize', updateCardHeight)
}, [cardData])
// 處理信心度提交
const handleConfidenceSubmit = (level: number) => {
submitConfidence(level as any)
onConfidenceSubmit(level)
// 生成並傳遞答案結果
const result = generateResult()
onAnswer(`confidence_${level}`)
}
return (
<div className="max-w-4xl mx-auto">
{/* 翻卡區域 */}
<div className="relative mb-8">
<div
className="relative w-full mx-auto perspective-1000"
style={{ height: `${cardHeight}px` }}
>
<div
className={`relative w-full h-full transition-transform duration-700 transform-style-preserve-3d cursor-pointer ${
isFlipped ? 'rotate-y-180' : ''
}`}
onClick={() => setIsFlipped(!isFlipped)}
>
{/* 正面 - 單字 */}
<div
ref={frontRef}
className={`absolute inset-0 w-full h-full backface-hidden ${
isFlipped ? 'pointer-events-none' : ''
}`}
>
<div className="bg-gradient-to-br from-blue-500 to-purple-600 rounded-2xl shadow-2xl h-full flex flex-col justify-center items-center text-white p-8">
<div className="text-center space-y-6">
<h1 className="text-4xl md:text-6xl font-bold mb-4">
{cardData.word}
</h1>
<AudioSection
word={cardData.word}
pronunciation={cardData.pronunciation}
className="text-white"
/>
<p className="text-xl opacity-90">
</p>
</div>
</div>
</div>
{/* 背面 - 詳細資訊 */}
<div
ref={backRef}
className={`absolute inset-0 w-full h-full backface-hidden rotate-y-180 ${
!isFlipped ? 'pointer-events-none' : ''
}`}
>
<div className="bg-white rounded-2xl shadow-2xl h-full border border-gray-200 overflow-y-auto">
<div className="p-8 space-y-6">
<CardHeader
cardData={cardData}
showTranslation={true}
className="mb-6"
/>
{/* 例句區域 */}
<div className="bg-gray-50 rounded-xl p-6">
<h3 className="font-semibold text-gray-900 mb-3"></h3>
<p className="text-gray-800 leading-relaxed mb-2">
{cardData.example}
</p>
<p className="text-gray-600 text-sm">
{cardData.exampleTranslation}
</p>
</div>
{/* 音頻播放 */}
<AudioSection
word={cardData.word}
pronunciation={cardData.pronunciation}
className="justify-center"
/>
<p className="text-center text-gray-500 text-sm">
</p>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 信心度評估 */}
{isFlipped && (
<div className="space-y-6">
<ConfidenceButtons
selectedLevel={confidence}
onSelect={handleConfidenceSubmit}
disabled={disabled}
/>
<div className="flex justify-center">
<ErrorReportButton
onClick={onReportError}
disabled={disabled}
/>
</div>
</div>
)}
{/* 翻卡提示 */}
{!isFlipped && (
<div className="text-center">
<p className="text-gray-600 text-sm">
💡
</p>
</div>
)}
</div>
)
}
// 用於向後相容的包裝器 (暫時保留舊介面)
interface LegacyFlipMemoryTestProps {
word: string
definition: string
example: string
exampleTranslation: string
pronunciation?: string
synonyms?: string[]
difficultyLevel: string
onConfidenceSubmit: (level: number) => void
onReportError: () => void
disabled?: boolean
}
// 預設匯出使用 Legacy 包裝器以保持向後相容
export const FlipMemoryTest: React.FC<LegacyFlipMemoryTestProps> = (props) => {
const cardData: ReviewCardData = {
id: `temp_${props.word}`,
word: props.word,
definition: props.definition,
example: props.example,
translation: props.exampleTranslation || '', // 使用 exampleTranslation 作為 translation
pronunciation: props.pronunciation,
synonyms: props.synonyms || [],
difficultyLevel: props.difficultyLevel,
exampleTranslation: props.exampleTranslation
}
return (
<FlipMemoryTestNew
cardData={cardData}
onAnswer={() => {}}
onConfidenceSubmit={props.onConfidenceSubmit}
onReportError={props.onReportError}
disabled={props.disabled}
/>
)
}