'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' import { useRouter } from 'next/navigation' function FlashcardsContent() { const router = useRouter() const [activeTab, setActiveTab] = useState('all-cards') const [selectedSet, setSelectedSet] = useState(null) const [searchTerm, setSearchTerm] = useState('') const [showAdvancedSearch, setShowAdvancedSearch] = useState(false) const [searchFilters, setSearchFilters] = useState({ cefrLevel: '', partOfSpeech: '', masteryLevel: '', onlyFavorites: false }) // 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 availableImages = [ '/images/examples/bring_up.png', '/images/examples/instinct.png', '/images/examples/warrant.png' ] const imageMap: {[key: string]: string} = { 'brought': '/images/examples/bring_up.png', 'instincts': '/images/examples/instinct.png', 'warrants': '/images/examples/warrant.png', 'hello': '/images/examples/bring_up.png', 'beautiful': '/images/examples/instinct.png', 'understand': '/images/examples/warrant.png', 'elaborate': '/images/examples/bring_up.png', 'sophisticated': '/images/examples/instinct.png', 'ubiquitous': '/images/examples/warrant.png' } // 根據詞彙返回對應圖片,如果沒有則根據字母分配 const mappedImage = imageMap[word?.toLowerCase()] if (mappedImage) return mappedImage // 根據首字母分配圖片 const firstChar = (word || 'a')[0].toLowerCase() const charCode = firstChar.charCodeAt(0) - 97 // a=0, b=1, c=2... const imageIndex = charCode % availableImages.length return availableImages[imageIndex] } // 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', definition: 'A greeting word', example: 'Hello, how are you?', createdAt: '2025-09-17' }, { 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', definition: 'Pleasing to look at', example: 'The beautiful sunset', createdAt: '2025-09-16' }, { 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', definition: 'To comprehend', example: 'I understand the concept', createdAt: '2025-09-15' }, { 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', definition: 'To explain in detail', example: 'Please elaborate on your idea', createdAt: '2025-09-14' }, { 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', definition: 'Highly developed', example: 'A sophisticated system', createdAt: '2025-09-13' }, { 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', definition: 'Present everywhere', example: 'Smartphones are ubiquitous', createdAt: '2025-09-12' } ] // 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' // 預設灰色 } } const allCards = [...flashcards, ...mockFlashcards] // 合併真實和假資料 // 進階搜尋邏輯 const filteredCards = allCards.filter(card => { // 基本文字搜尋 if (searchTerm) { const searchLower = searchTerm.toLowerCase() const matchesText = card.word?.toLowerCase().includes(searchLower) || card.translation?.toLowerCase().includes(searchLower) || card.definition?.toLowerCase().includes(searchLower) if (!matchesText) return false } // CEFR等級篩選 if (searchFilters.cefrLevel && (card as any).difficultyLevel !== searchFilters.cefrLevel) { return false } // 詞性篩選 if (searchFilters.partOfSpeech && card.partOfSpeech !== searchFilters.partOfSpeech) { return false } // 掌握度篩選 if (searchFilters.masteryLevel) { const mastery = card.masteryLevel || 0 if (searchFilters.masteryLevel === 'high' && mastery < 80) return false if (searchFilters.masteryLevel === 'medium' && (mastery < 60 || mastery >= 80)) return false if (searchFilters.masteryLevel === 'low' && mastery >= 60) return false } // 收藏篩選 if (searchFilters.onlyFavorites && !card.isFavorite) { return false } return true }) // 清除所有篩選 const clearAllFilters = () => { setSearchTerm('') setSearchFilters({ cefrLevel: '', partOfSpeech: '', masteryLevel: '', onlyFavorites: false }) } // 檢查是否有活動篩選 const hasActiveFilters = searchTerm || searchFilters.cefrLevel || searchFilters.partOfSpeech || searchFilters.masteryLevel || searchFilters.onlyFavorites // 搜尋結果高亮函數 const highlightSearchTerm = (text: string, searchTerm: string) => { if (!searchTerm || !text) return text const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi') const parts = text.split(regex) return parts.map((part, index) => regex.test(part) ? ( {part} ) : ( part ) ) } // Add loading and error states if (loading) { return (
載入中...
) } if (error) { return (
{error}
) } return (
{/* Navigation */} {/* Main Content */}
{/* Page Header */}

我的詞卡

AI 生成詞卡
{/* 簡化的Tabs - 移除卡組功能 */}
{/* 進階搜尋區域 */}

搜尋詞卡

{/* 主要搜尋框 */}
setSearchTerm(e.target.value)} placeholder="搜尋詞彙、翻譯或定義..." className="w-full pl-12 pr-20 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent text-base" onKeyDown={(e) => { if (e.key === 'Escape') { setSearchTerm('') } }} />
{(searchTerm || hasActiveFilters) && (
{filteredCards.length} 結果
)}
{/* 進階篩選選項 */} {showAdvancedSearch && (
{/* CEFR等級篩選 */}
{/* 詞性篩選 */}
{/* 掌握度篩選 */}
{/* 收藏篩選 */}
{/* 快速篩選按鈕 */}
快速篩選: {hasActiveFilters && ( )}
)} {/* 搜尋結果統計 */} {(searchTerm || hasActiveFilters) && (
找到 {filteredCards.length} 個詞卡 {searchTerm && ( ,包含 "{searchTerm}" )}
{hasActiveFilters && ( )}
)}
{/* Favorites Tab */} {activeTab === 'favorites' && (

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

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

還沒有收藏的詞卡

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

) : (
{allCards.filter(card => card.isFavorite).map(card => (
{/* 收藏詞卡內容 - 與普通詞卡相同的佈局 */}
{(card as any).difficultyLevel || 'A1'}
{`${card.word} { const target = e.target as HTMLImageElement target.style.display = 'none' target.parentElement!.innerHTML = `
例句圖
` }} />

{searchTerm ? highlightSearchTerm(card.word || '未設定', searchTerm) : (card.word || '未設定')}

{card.partOfSpeech || 'unknown'}
{searchTerm ? highlightSearchTerm(card.translation || '未設定', searchTerm) : (card.translation || '未設定')} {card.pronunciation && (
{card.pronunciation}
)}
創建: {new Date(card.createdAt).toLocaleDateString()} 掌握度: {card.masteryLevel}%
{/* 右側:重新設計的操作按鈕區 */}
{/* 收藏按鈕 */} {/* 編輯按鈕 */} {/* 刪除按鈕 */} {/* 查看詳情按鈕 - 導航到詳細頁面 */}
))}
)}
)} {/* All Cards Tab */} {activeTab === 'all-cards' && (

共 {filteredCards.length} 個詞卡

{filteredCards.length === 0 ? (

沒有找到詞卡

創建新詞卡
) : (
{filteredCards.map(card => (
{/* 詞卡右上角CEFR標註 */}
{(card as any).difficultyLevel || 'A1'}
{/* 左側:詞彙基本信息 */}
{/* 例句圖片 - 超大尺寸 */}
{`${card.word} { // 圖片載入失敗時顯示佔位符 const target = e.target as HTMLImageElement target.style.display = 'none' target.parentElement!.innerHTML = `
例句圖
` }} />

{searchTerm ? highlightSearchTerm(card.word || '未設定', searchTerm) : (card.word || '未設定')}

{card.partOfSpeech || 'unknown'}
{searchTerm ? highlightSearchTerm(card.translation || '未設定', searchTerm) : (card.translation || '未設定')} {card.pronunciation && (
{card.pronunciation}
)}
{/* 簡要統計 */}
創建: {new Date(card.createdAt).toLocaleDateString()} 掌握度: {card.masteryLevel}%
{/* 右側:操作按鈕 */}
{/* 重新設計的操作按鈕區 */}
{/* 收藏按鈕 */} {/* 編輯按鈕 */} {/* 刪除按鈕 */} {/* 查看詳情按鈕 - 導航到詳細頁面 */}
))}
)}
)}
{/* 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 ( ) }