'use client' import { useState, useEffect } from 'react' import Link from 'next/link' import { ProtectedRoute } from '@/components/ProtectedRoute' import { Navigation } from '@/components/Navigation' import { FlashcardForm } from '@/components/FlashcardForm' import { flashcardsService, type CardSet, type Flashcard } from '@/lib/services/flashcards' function FlashcardsContent() { const [activeTab, setActiveTab] = useState('my-cards') const [selectedSet, setSelectedSet] = useState(null) const [searchTerm, setSearchTerm] = useState('') // Real data from API const [cardSets, setCardSets] = useState([]) const [flashcards, setFlashcards] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // 臨時使用學習功能的例句圖片作為測試 const getExampleImage = (word: string): string => { const imageMap: {[key: string]: string} = { 'brought': '/images/examples/bring_up.png', 'instincts': '/images/examples/instinct.png', 'warrants': '/images/examples/warrant.png', 'elaborate': '/images/examples/bring_up.png', // 作為預設 'hello': '/images/examples/instinct.png', 'good': '/images/examples/warrant.png' } // 根據詞彙返回對應圖片,如果沒有則返回隨機圖片 return imageMap[word?.toLowerCase()] || imageMap[Object.keys(imageMap)[Math.floor(Math.random() * Object.keys(imageMap).length)]] } // Form states const [showForm, setShowForm] = useState(false) const [editingCard, setEditingCard] = useState(null) // 添加假資料用於展示CEFR效果 const mockFlashcards = [ { id: 'mock1', word: 'hello', translation: '你好', partOfSpeech: 'interjection', pronunciation: '/həˈloʊ/', masteryLevel: 95, timesReviewed: 15, isFavorite: true, nextReviewDate: '2025-09-21', cardSet: { name: '基礎詞彙', color: 'bg-blue-500' }, difficultyLevel: 'A1' }, { id: 'mock2', word: 'beautiful', translation: '美麗的', partOfSpeech: 'adjective', pronunciation: '/ˈbjuːtɪfəl/', masteryLevel: 78, timesReviewed: 8, isFavorite: false, nextReviewDate: '2025-09-22', cardSet: { name: '描述詞彙', color: 'bg-green-500' }, difficultyLevel: 'A2' }, { id: 'mock3', word: 'understand', translation: '理解', partOfSpeech: 'verb', pronunciation: '/ˌʌndərˈstænd/', masteryLevel: 65, timesReviewed: 12, isFavorite: true, nextReviewDate: '2025-09-20', cardSet: { name: '常用動詞', color: 'bg-yellow-500' }, difficultyLevel: 'B1' }, { id: 'mock4', word: 'elaborate', translation: '詳細說明', partOfSpeech: 'verb', pronunciation: '/ɪˈlæbərət/', masteryLevel: 45, timesReviewed: 5, isFavorite: false, nextReviewDate: '2025-09-19', cardSet: { name: '高級詞彙', color: 'bg-purple-500' }, difficultyLevel: 'B2' }, { id: 'mock5', word: 'sophisticated', translation: '精密的', partOfSpeech: 'adjective', pronunciation: '/səˈfɪstɪkeɪtɪd/', masteryLevel: 30, timesReviewed: 3, isFavorite: true, nextReviewDate: '2025-09-18', cardSet: { name: '進階詞彙', color: 'bg-indigo-500' }, difficultyLevel: 'C1' }, { id: 'mock6', word: 'ubiquitous', translation: '無處不在的', partOfSpeech: 'adjective', pronunciation: '/juːˈbɪkwɪtəs/', masteryLevel: 15, timesReviewed: 1, isFavorite: false, nextReviewDate: '2025-09-17', cardSet: { name: '學術詞彙', color: 'bg-red-500' }, difficultyLevel: 'C2' } ] // Load data from API useEffect(() => { loadCardSets() loadFlashcards() }, []) const loadCardSets = async () => { try { const result = await flashcardsService.getCardSets() if (result.success && result.data) { if (result.data.sets.length === 0) { // 如果沒有卡組,確保創建預設卡組 const ensureResult = await flashcardsService.ensureDefaultCardSet() if (ensureResult.success) { // 重新載入卡組 const retryResult = await flashcardsService.getCardSets() if (retryResult.success && retryResult.data) { setCardSets(retryResult.data.sets) } else { setError('Failed to load card sets after creating default') } } else { setError(ensureResult.error || 'Failed to create default card set') } } else { setCardSets(result.data.sets) } } else { setError(result.error || 'Failed to load card sets') } } catch (err) { setError('Failed to load card sets') } } const loadFlashcards = async () => { try { setLoading(true) const result = await flashcardsService.getFlashcards(selectedSet || undefined) if (result.success && result.data) { setFlashcards(result.data.flashcards) } else { setError(result.error || 'Failed to load flashcards') } } catch (err) { setError('Failed to load flashcards') } finally { setLoading(false) } } // Reload flashcards when selectedSet changes useEffect(() => { loadFlashcards() }, [selectedSet]) // Handle form operations const handleFormSuccess = () => { setShowForm(false) setEditingCard(null) loadFlashcards() loadCardSets() } const handleEdit = (card: Flashcard) => { setEditingCard(card) setShowForm(true) } const handleDelete = async (card: Flashcard) => { if (!confirm(`確定要刪除詞卡「${card.word}」嗎?`)) { return } try { const result = await flashcardsService.deleteFlashcard(card.id) if (result.success) { loadFlashcards() loadCardSets() } else { alert(result.error || '刪除失敗') } } catch (err) { alert('刪除失敗,請重試') } } const handleToggleFavorite = async (card: any) => { try { // 如果是假資料,只更新本地狀態 if (card.id.startsWith('mock')) { const updatedMockCards = mockFlashcards.map(mockCard => mockCard.id === card.id ? { ...mockCard, isFavorite: !mockCard.isFavorite } : mockCard ) // 這裡需要更新state,但由於是const,我們直接重新載入頁面來模擬效果 alert(`${card.isFavorite ? '已取消收藏' : '已加入收藏'}「${card.word}」`) return } // 真實API調用 const result = await flashcardsService.toggleFavorite(card.id) if (result.success) { loadFlashcards() alert(`${card.isFavorite ? '已取消收藏' : '已加入收藏'}「${card.word}」`) } else { alert(result.error || '操作失敗') } } catch (err) { alert('操作失敗,請重試') } } // 獲取CEFR等級顏色 const getCEFRColor = (level: string) => { switch (level) { case 'A1': return 'bg-green-100 text-green-700 border-green-200' // 淺綠 - 最基礎 case 'A2': return 'bg-blue-100 text-blue-700 border-blue-200' // 淺藍 - 基礎 case 'B1': return 'bg-yellow-100 text-yellow-700 border-yellow-200' // 淺黃 - 中級 case 'B2': return 'bg-orange-100 text-orange-700 border-orange-200' // 淺橙 - 中高級 case 'C1': return 'bg-red-100 text-red-700 border-red-200' // 淺紅 - 高級 case 'C2': return 'bg-purple-100 text-purple-700 border-purple-200' // 淺紫 - 精通 default: return 'bg-gray-100 text-gray-700 border-gray-200' // 預設灰色 } } // Filter data - 合併真實資料和假資料 const filteredSets = cardSets.filter(set => set.name.toLowerCase().includes(searchTerm.toLowerCase()) || set.description.toLowerCase().includes(searchTerm.toLowerCase()) ) const allCards = [...flashcards, ...mockFlashcards] // 合併真實和假資料 const filteredCards = allCards.filter(card => { if (searchTerm) { return card.word?.toLowerCase().includes(searchTerm.toLowerCase()) || card.translation?.toLowerCase().includes(searchTerm.toLowerCase()) } return true }) // Add loading and error states if (loading) { return (
載入中...
) } if (error) { return (
{error}
) } return (
{/* Navigation */} {/* Main Content */}
{/* Page Header */}

詞卡管理

管理你的詞卡集合

AI 生成詞卡
{/* Tabs */}
{/* Search */}
setSearchTerm(e.target.value)} placeholder="搜尋詞卡或卡組..." className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent" />
{/* Card Sets Tab */} {activeTab === 'my-cards' && (

共 {filteredSets.length} 個卡組

{filteredSets.length === 0 ? (

還沒有詞卡集合

創建第一個卡組
) : (
{filteredSets.map(set => (
{ setSelectedSet(set.id) setActiveTab('all-cards') }} >
{set.isDefault && 📂}

{set.name} {set.isDefault && (預設)}

{set.description}

{set.cardCount} 張詞卡 進度: {set.progress}%
))}
)}
)} {/* Favorites Tab */} {activeTab === 'favorites' && (

收藏詞卡 ({allCards.filter(card => card.isFavorite).length} 個)

{allCards.filter(card => card.isFavorite).length === 0 ? (

還沒有收藏的詞卡

在詞卡列表中點擊星星按鈕來收藏重要的詞彙

) : (
{allCards.filter(card => card.isFavorite).map(card => (
{ alert(`即將進入「${card.word}」的詳細頁面 (開發中)`) }} > {/* 收藏詞卡內容 - 與普通詞卡相同的佈局 */}
{card.difficultyLevel || 'A1'}
{`${card.word} { const target = e.target as HTMLImageElement target.style.display = 'none' target.parentElement!.innerHTML = `
例句圖
` }} />

{card.word || '未設定'}

{card.partOfSpeech || 'unknown'}
{card.translation || '未設定'} {card.pronunciation && (
{card.pronunciation}
)}
卡組: {card.cardSet.name} 掌握度: {card.masteryLevel}%
e.stopPropagation()}>
))}
)}
)} {/* All Cards Tab */} {activeTab === 'all-cards' && (

共 {filteredCards.length} 個詞卡

{selectedSet && ( )}
{/* 未分類提醒 */} {selectedSet && cardSets.find(set => set.id === selectedSet)?.isDefault && filteredCards.length > 15 && (
💡

您有 {filteredCards.length} 個未分類詞卡,建議整理到不同主題的卡組中,有助於更好地組織學習內容。

)} {filteredCards.length === 0 ? (

沒有找到詞卡

創建新詞卡
) : (
{filteredCards.map(card => (
{ // TODO: 導航到詞卡詳細頁面 alert(`即將進入「${card.word}」的詳細頁面 (開發中)`) }} >
{/* 詞卡右上角CEFR標註 */}
{card.difficultyLevel || 'A1'}
{/* 左側:詞彙基本信息 */}
{/* 例句圖片 - 超大尺寸 */}
{`${card.word} { // 圖片載入失敗時顯示佔位符 const target = e.target as HTMLImageElement target.style.display = 'none' target.parentElement!.innerHTML = `
例句圖
` }} />

{card.word || '未設定'}

{card.partOfSpeech || 'unknown'}
{card.translation || '未設定'} {card.pronunciation && (
{card.pronunciation}
)}
{/* 簡要統計 */}
卡組: {card.cardSet.name} 掌握度: {card.masteryLevel}%
{/* 右側:操作按鈕 */}
{/* 快速操作按鈕 */}
e.stopPropagation()}>
{/* 進入詳細頁面箭頭 */}
))}
)}
)}
{/* Flashcard Form Modal */} {showForm && ( cs.name === editingCard.cardSet.name)?.id || cardSets[0]?.id : cardSets[0]?.id, english: editingCard.word, chinese: editingCard.translation, pronunciation: editingCard.pronunciation, partOfSpeech: editingCard.partOfSpeech, example: editingCard.example, } : undefined} isEdit={!!editingCard} onSuccess={handleFormSuccess} onCancel={() => { setShowForm(false) setEditingCard(null) }} /> )}
) } export default function FlashcardsPage() { return ( ) }