feat: 建立Review Tests組件展示頁面
- 新增/review-tests測試頁面專門展示review-tests組件 - 導航欄添加🧪測試項目方便快速進入 - 實現Tab切換界面,每個測驗組件獨立展示 - 包含操作日誌系統追蹤組件互動行為 - 修正SentenceSpeakingTest組件props類型錯誤 - 提供完整模擬資料用於組件測試 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
74932e58ff
commit
f494331bdb
|
|
@ -0,0 +1,220 @@
|
|||
'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-gray-50">
|
||||
<Navigation />
|
||||
|
||||
<div className="max-w-7xl mx-auto px-4 py-8">
|
||||
{/* 頁面標題 */}
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold text-gray-900 mb-2">Review Tests 組件展示</h1>
|
||||
</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="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div className={`px-6 py-4 border-b ${testComponents.find(c => c.id === activeTab)?.color}`}>
|
||||
<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 className="p-8">
|
||||
{/* 條件渲染當前選中的測驗組件 */}
|
||||
{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>
|
||||
)
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat
|
|||
{ href: '/dashboard', label: '儀表板' },
|
||||
{ href: '/flashcards', label: '詞卡' },
|
||||
{ href: '/review', label: '複習' },
|
||||
{ href: '/review-tests', label: '🧪 測試' },
|
||||
{ href: '/generate', label: 'AI 生成' },
|
||||
{ href: '/settings', label: '⚙️ 設定' }
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue