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

384 lines
15 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 { Navigation } from '@/components/shared/Navigation'
import { FlipMemory } from '@/components/review/quiz/FlipMemory'
import { VocabChoiceQuiz } from '@/components/review/quiz/VocabChoiceQuiz'
import { QuizProgress } from '@/components/review/ui/QuizProgress'
import { QuizResult } from '@/components/review/quiz/QuizResult'
import { useReviewSession } from '@/hooks/review/useReviewSession'
export default function ReviewPage() {
// 使用重構後的 Hook 管理線性複習狀態
const {
quizItems,
score,
isComplete,
currentQuizItem,
currentCard,
vocabOptions,
totalQuizItems,
completedQuizItems,
handleAnswer,
handleSkip,
handleRestart,
isLoading,
error,
flashcards,
totalFlashcardsCount
} = useReviewSession()
// 除錯日誌 - 檢查狀態
console.log('🔍 Review Page 狀態檢查:', {
isLoading,
error,
flashcardsLength: flashcards.length,
totalFlashcardsCount,
currentQuizItem: currentQuizItem?.id,
currentCard: currentCard?.word,
isComplete
})
// 顯示載入狀態
if (isLoading) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-white rounded-xl shadow-lg p-8 text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<h2 className="text-xl font-semibold text-gray-700">...</h2>
<p className="text-gray-500 mt-2"></p>
</div>
</div>
</div>
</div>
)
}
// 顯示錯誤狀態
if (error) {
const isAuthError = error.includes('登入已過期') || error.includes('認證')
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-white rounded-xl shadow-lg p-8 text-center">
<div className={`text-4xl mb-4 ${isAuthError ? 'text-yellow-500' : 'text-red-500'}`}>
{isAuthError ? '🔒' : '⚠️'}
</div>
<h2 className={`text-xl font-semibold mb-2 ${isAuthError ? 'text-yellow-700' : 'text-red-700'}`}>
{isAuthError ? '需要重新登入' : '載入失敗'}
</h2>
<p className="text-gray-600 mb-6">{error}</p>
<div className="flex flex-col sm:flex-row gap-3 justify-center">
{isAuthError ? (
<button
onClick={() => window.location.href = '/login'}
className="px-8 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold"
>
</button>
) : (
<button
onClick={handleRestart}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
</button>
)}
<button
onClick={() => window.location.href = '/'}
className="px-6 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors"
>
</button>
</div>
</div>
</div>
</div>
</div>
)
}
// 情境 1: 新用戶 - 一張詞卡都沒有
if (!isLoading && !error && totalFlashcardsCount === 0) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-white rounded-xl shadow-lg p-8 text-center">
{/* 歡迎圖標 */}
<div className="mb-6">
<div className="w-24 h-24 bg-gradient-to-br from-blue-400 to-blue-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-4xl text-white">👋</span>
</div>
</div>
{/* 歡迎標題 */}
<h1 className="text-3xl font-bold text-gray-900 mb-4">
DramaLing
</h1>
{/* 說明文字 */}
<p className="text-lg text-gray-600 mb-8">
</p>
{/* 功能介紹卡片 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div className="bg-gradient-to-br from-green-50 to-green-100 rounded-lg p-6">
<div className="text-2xl text-green-600 mb-2">🎯</div>
<h3 className="font-semibold text-gray-900"></h3>
<p className="text-sm text-gray-600 mt-2">
AI
</p>
</div>
<div className="bg-gradient-to-br from-yellow-50 to-yellow-100 rounded-lg p-6">
<div className="text-2xl text-yellow-600 mb-2">🧠</div>
<h3 className="font-semibold text-gray-900"></h3>
<p className="text-sm text-gray-600 mt-2">
</p>
</div>
</div>
{/* 主要行動按鈕 */}
<div className="mb-6">
<button
onClick={() => window.location.href = '/generate'}
className="px-10 py-4 bg-gradient-to-r from-blue-600 to-blue-700 text-white rounded-lg hover:from-blue-700 hover:to-blue-800 transition-all font-semibold text-lg flex items-center justify-center gap-3 mx-auto"
>
<span className="text-xl">🚀</span>
</button>
</div>
{/* 次要功能 */}
<div className="flex flex-col sm:flex-row gap-3 justify-center">
<button
onClick={() => window.location.href = '/flashcards'}
className="px-6 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors font-medium"
>
</button>
</div>
{/* 學習提示 */}
<div className="mt-8 p-4 bg-blue-50 rounded-lg border border-blue-200">
<p className="text-sm text-blue-800">
💡 <strong></strong>:
AI
</p>
</div>
</div>
</div>
</div>
</div>
)
}
// 情境 2: 有詞卡但都已訓練完成
if (!isLoading && !error && totalFlashcardsCount && totalFlashcardsCount > 0 && flashcards.length === 0) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-white rounded-xl shadow-lg p-8 text-center">
{/* 慶祝圖標 */}
<div className="mb-6">
<div className="w-24 h-24 bg-gradient-to-br from-green-400 to-green-600 rounded-full flex items-center justify-center mx-auto mb-4">
<span className="text-4xl text-white">🎉</span>
</div>
</div>
{/* 主要標題 */}
<h1 className="text-3xl font-bold text-gray-900 mb-4">
</h1>
{/* 次標題 */}
<p className="text-lg text-gray-600 mb-4">
<span className="font-semibold text-green-600">{totalFlashcardsCount}</span>
</p>
<p className="text-md text-gray-500 mb-8">
</p>
{/* 統計卡片 */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div className="bg-gradient-to-br from-blue-50 to-blue-100 rounded-lg p-6">
<div className="text-2xl text-blue-600 mb-2">📚</div>
<h3 className="font-semibold text-gray-900"></h3>
<p className="text-sm text-gray-600 mt-2">
</p>
</div>
<div className="bg-gradient-to-br from-purple-50 to-purple-100 rounded-lg p-6">
<div className="text-2xl text-purple-600 mb-2">📈</div>
<h3 className="font-semibold text-gray-900"></h3>
<p className="text-sm text-gray-600 mt-2">
</p>
</div>
<div className="bg-gradient-to-br from-green-50 to-green-100 rounded-lg p-6">
<div className="text-2xl text-green-600 mb-2"></div>
<h3 className="font-semibold text-gray-900"></h3>
<p className="text-sm text-gray-600 mt-2">
</p>
</div>
</div>
{/* 行動按鈕 */}
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={() => window.location.href = '/generate'}
className="px-8 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold flex items-center justify-center gap-2"
>
<span></span>
</button>
<button
onClick={() => window.location.href = '/flashcards'}
className="px-8 py-3 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors font-semibold flex items-center justify-center gap-2"
>
<span>📋</span>
</button>
</div>
{/* 提示文字 */}
<div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
<p className="text-sm text-yellow-800">
💡 <strong></strong>:
</p>
</div>
</div>
</div>
</div>
</div>
)
}
// 顯示結果頁面
if (isComplete) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<QuizResult
score={score}
totalCards={flashcards.length}
onRestart={handleRestart}
/>
{/* 線性測驗完成統計 */}
<div className="mt-6 bg-white rounded-lg shadow p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4"></h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-center">
<div>
<div className="text-2xl font-bold text-blue-600">{completedQuizItems}</div>
<div className="text-sm text-gray-600"></div>
</div>
<div>
<div className="text-2xl font-bold text-green-600">{flashcards.length}</div>
<div className="text-sm text-gray-600"></div>
</div>
<div>
<div className="text-2xl font-bold text-purple-600">
{score.total > 0 ? Math.round((score.correct / score.total) * 100) : 0}%
</div>
<div className="text-sm text-gray-600"></div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
// 主要線性測驗頁面
// 只有在有可用測驗項目時才顯示測驗界面
if (!isLoading && !error && totalFlashcardsCount !== null && totalFlashcardsCount > 0 && flashcards.length > 0 && currentQuizItem && currentCard) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
{/* 使用簡化的 ReviewProgress 組件 */}
<QuizProgress
currentQuizItem={currentQuizItem}
totalQuizItems={totalQuizItems}
completedQuizItems={completedQuizItems}
score={score}
/>
{/* 根據當前測驗項目類型渲染對應組件 */}
{currentQuizItem && currentCard && (
<>
{currentQuizItem.quizType === 'flip-card' && (
<FlipMemory
card={currentCard}
onAnswer={handleAnswer}
onSkip={handleSkip}
/>
)}
{currentQuizItem.quizType === 'vocab-choice' && (
<VocabChoiceQuiz
card={currentCard}
options={vocabOptions}
onAnswer={handleAnswer}
onSkip={handleSkip}
/>
)}
</>
)}
</div>
</div>
</div>
)
}
// Fallback 狀態 - 處理其他未預期情況
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
<Navigation />
<div className="py-8">
<div className="max-w-4xl mx-auto px-4">
<div className="bg-white rounded-xl shadow-lg p-8 text-center">
<div className="text-4xl mb-4">🤔</div>
<h2 className="text-xl font-semibold text-gray-700 mb-2"></h2>
<p className="text-gray-600 mb-4">
</p>
<p className="text-sm text-gray-500 mb-6">
</p>
<button
onClick={handleRestart}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
</button>
</div>
</div>
</div>
</div>
)
}