dramaling-vocab-learning/frontend/app/review-design/page.tsx

221 lines
8.5 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.

'use client'
import { useState } from 'react'
import { Navigation } from '@/components/Navigation'
import {
FlipMemoryTest,
VocabChoiceTest,
SentenceFillTest,
SentenceReorderTest,
VocabListeningTest,
SentenceListeningTest,
SentenceSpeakingTest
} from '@/components/review/review-tests'
export default function ReviewTestsPage() {
const [logs, setLogs] = useState<string[]>([])
const [activeTab, setActiveTab] = useState('FlipMemoryTest')
// 測驗組件清單
const testComponents = [
{ id: 'FlipMemoryTest', name: '翻卡記憶測試', color: 'bg-blue-50' },
{ id: 'VocabChoiceTest', name: '詞彙選擇測試', color: 'bg-green-50' },
{ id: 'SentenceFillTest', name: '句子填空測試', color: 'bg-yellow-50' },
{ id: 'SentenceReorderTest', name: '句子重排測試', color: 'bg-purple-50' },
{ id: 'VocabListeningTest', name: '詞彙聽力測試', color: 'bg-red-50' },
{ id: 'SentenceListeningTest', name: '句子聽力測試', color: 'bg-indigo-50' },
{ id: 'SentenceSpeakingTest', name: '句子口說測試', color: 'bg-pink-50' }
]
// 添加日誌函數
const addLog = (message: string) => {
const timestamp = new Date().toLocaleTimeString()
setLogs(prev => [`[${activeTab}] [${timestamp}] ${message}`, ...prev.slice(0, 9)])
}
// 模擬資料
const mockCardData = {
word: "elaborate",
definition: "To explain something in more detail; to develop or present a theory, policy, or system in further detail",
example: "Could you elaborate on your proposal for the new marketing strategy?",
exampleTranslation: "你能詳細說明一下你對新行銷策略的提案嗎?",
pronunciation: "/ɪˈlæbərət/",
synonyms: ["explain", "detail", "expand", "clarify"],
difficultyLevel: "B2",
exampleImage: "https://via.placeholder.com/400x200?text=Marketing+Strategy"
}
// 選項題選項
const vocabChoiceOptions = ["elaborate", "celebrate", "collaborate", "deliberate"]
// 回調函數
const handleConfidenceSubmit = (level: number) => {
addLog(`FlipMemoryTest: 信心等級 ${level}`)
}
const handleAnswer = (answer: string) => {
addLog(`答案提交: ${answer}`)
}
const handleReportError = () => {
addLog('回報錯誤')
}
const handleImageClick = (image: string) => {
addLog(`圖片點擊: ${image}`)
}
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="max-w-4xl mx-auto px-4 py-8">
{/* 頁面標題 */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Review </h1>
<p className="text-gray-600"> review-tests UI </p>
</div>
{/* Tab 導航 */}
<div className="mb-8">
<div className="border-b border-gray-200">
<div className="flex space-x-8 overflow-x-auto">
{testComponents.map((component) => (
<button
key={component.id}
onClick={() => setActiveTab(component.id)}
className={`py-4 px-1 border-b-2 font-medium text-sm whitespace-nowrap transition-colors ${
activeTab === component.id
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
{component.name}
</button>
))}
</div>
</div>
</div>
{/* 當前測驗組件展示 */}
<div className="mb-8">
<div className="mb-6">
<h2 className="text-2xl font-semibold text-gray-900">{activeTab}</h2>
<p className="text-sm text-gray-600 mt-1">{testComponents.find(c => c.id === activeTab)?.name}</p>
</div>
<div>
{/* 條件渲染當前選中的測驗組件 */}
{activeTab === 'FlipMemoryTest' && (
<FlipMemoryTest
word={mockCardData.word}
definition={mockCardData.definition}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
pronunciation={mockCardData.pronunciation}
synonyms={mockCardData.synonyms}
difficultyLevel={mockCardData.difficultyLevel}
onConfidenceSubmit={handleConfidenceSubmit}
onReportError={handleReportError}
/>
)}
{activeTab === 'VocabChoiceTest' && (
<VocabChoiceTest
word={mockCardData.word}
definition={mockCardData.definition}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
pronunciation={mockCardData.pronunciation}
difficultyLevel={mockCardData.difficultyLevel}
options={vocabChoiceOptions}
onAnswer={handleAnswer}
onReportError={handleReportError}
/>
)}
{activeTab === 'SentenceFillTest' && (
<SentenceFillTest
word={mockCardData.word}
definition={mockCardData.definition}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
pronunciation={mockCardData.pronunciation}
difficultyLevel={mockCardData.difficultyLevel}
exampleImage={mockCardData.exampleImage}
onAnswer={handleAnswer}
onReportError={handleReportError}
onImageClick={handleImageClick}
/>
)}
{activeTab === 'SentenceReorderTest' && (
<SentenceReorderTest
word={mockCardData.word}
definition={mockCardData.definition}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
difficultyLevel={mockCardData.difficultyLevel}
onAnswer={handleAnswer}
onReportError={handleReportError}
/>
)}
{activeTab === 'VocabListeningTest' && (
<VocabListeningTest
word={mockCardData.word}
definition={mockCardData.definition}
pronunciation={mockCardData.pronunciation}
difficultyLevel={mockCardData.difficultyLevel}
options={vocabChoiceOptions}
onAnswer={handleAnswer}
onReportError={handleReportError}
/>
)}
{activeTab === 'SentenceListeningTest' && (
<SentenceListeningTest
word={mockCardData.word}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
difficultyLevel={mockCardData.difficultyLevel}
options={vocabChoiceOptions}
onAnswer={handleAnswer}
onReportError={handleReportError}
/>
)}
{activeTab === 'SentenceSpeakingTest' && (
<SentenceSpeakingTest
word={mockCardData.word}
example={mockCardData.example}
exampleTranslation={mockCardData.exampleTranslation}
difficultyLevel={mockCardData.difficultyLevel}
exampleImage={mockCardData.exampleImage}
onAnswer={handleAnswer}
onReportError={handleReportError}
onImageClick={handleImageClick}
/>
)}
</div>
</div>
{/* 操作日誌區域 */}
<div className="mt-8 bg-white rounded-lg shadow p-4">
<h3 className="font-semibold text-gray-900 mb-3"></h3>
<div className="space-y-1 max-h-32 overflow-y-auto">
{logs.length === 0 ? (
<p className="text-gray-500 text-sm"></p>
) : (
logs.map((log, index) => (
<div key={index} className="text-sm text-gray-600 font-mono">
{log}
</div>
))
)}
</div>
</div>
</div>
</div>
)
}