fix: 修復收藏詞卡分頁數量顯示和統計同步問題
- 新增 totalCounts 狀態追蹤所有詞卡和收藏詞卡的總數量 - 新增 loadTotalCounts 函數分別載入全部和收藏詞卡數量統計 - 修復收藏詞卡分頁使用後端 filteredCards 而非前端假資料篩選 - 優化分頁標籤顯示實際的統計數量而非動態計算 - 確保所有 CRUD 操作後都會重新載入統計數據: * 創建詞卡後更新統計 * 刪除詞卡後更新統計 * 收藏切換後更新統計 - 分離 C1 和 C2 快速篩選按鈕,提供更精準的等級篩選 現在收藏詞卡功能完全基於後端 API,分頁數量顯示準確且即時同步。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c6d5bb6ce3
commit
bfa353bd6b
|
|
@ -37,6 +37,7 @@ function FlashcardsContent() {
|
||||||
const [flashcards, setFlashcards] = useState<Flashcard[]>([])
|
const [flashcards, setFlashcards] = useState<Flashcard[]>([])
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [totalCounts, setTotalCounts] = useState({ all: 0, favorites: 0 })
|
||||||
|
|
||||||
// 臨時使用學習功能的例句圖片作為測試
|
// 臨時使用學習功能的例句圖片作為測試
|
||||||
const getExampleImage = (word: string): string => {
|
const getExampleImage = (word: string): string => {
|
||||||
|
|
@ -84,10 +85,28 @@ function FlashcardsContent() {
|
||||||
{ id: 'mock6', word: 'ubiquitous', translation: '無處不在的', partOfSpeech: 'adjective', pronunciation: '/juːˈbɪkwɪtəs/', masteryLevel: 15, timesReviewed: 1, isFavorite: false, nextReviewDate: '2025-09-17', difficultyLevel: 'C2', definition: 'Present everywhere', example: 'Smartphones are ubiquitous', createdAt: '2025-09-12', updatedAt: '2025-09-12' }
|
{ id: 'mock6', word: 'ubiquitous', translation: '無處不在的', partOfSpeech: 'adjective', pronunciation: '/juːˈbɪkwɪtəs/', masteryLevel: 15, timesReviewed: 1, isFavorite: false, nextReviewDate: '2025-09-17', difficultyLevel: 'C2', definition: 'Present everywhere', example: 'Smartphones are ubiquitous', createdAt: '2025-09-12', updatedAt: '2025-09-12' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 載入總數統計
|
||||||
|
const loadTotalCounts = async () => {
|
||||||
|
try {
|
||||||
|
// 載入所有詞卡數量
|
||||||
|
const allResult = await flashcardsService.getFlashcards()
|
||||||
|
const allCount = allResult.success && allResult.data ? allResult.data.count : 0
|
||||||
|
|
||||||
|
// 載入收藏詞卡數量
|
||||||
|
const favoritesResult = await flashcardsService.getFlashcards(undefined, true)
|
||||||
|
const favoritesCount = favoritesResult.success && favoritesResult.data ? favoritesResult.data.count : 0
|
||||||
|
|
||||||
|
setTotalCounts({ all: allCount, favorites: favoritesCount })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('載入統計失敗:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load data from API
|
// Load data from API
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 移除 loadCardSets() 調用,直接載入詞卡
|
// 載入詞卡和統計
|
||||||
loadFlashcards()
|
loadFlashcards()
|
||||||
|
loadTotalCounts()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// 監聽搜尋和篩選條件變化,重新載入資料
|
// 監聽搜尋和篩選條件變化,重新載入資料
|
||||||
|
|
@ -140,10 +159,11 @@ function FlashcardsContent() {
|
||||||
// }, [selectedSet])
|
// }, [selectedSet])
|
||||||
|
|
||||||
// Handle form operations
|
// Handle form operations
|
||||||
const handleFormSuccess = () => {
|
const handleFormSuccess = async () => {
|
||||||
setShowForm(false)
|
setShowForm(false)
|
||||||
setEditingCard(null)
|
setEditingCard(null)
|
||||||
loadFlashcards()
|
await loadFlashcards()
|
||||||
|
await loadTotalCounts()
|
||||||
// 移除 loadCardSets() 調用
|
// 移除 loadCardSets() 調用
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +180,8 @@ function FlashcardsContent() {
|
||||||
try {
|
try {
|
||||||
const result = await flashcardsService.deleteFlashcard(card.id)
|
const result = await flashcardsService.deleteFlashcard(card.id)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
loadFlashcards()
|
await loadFlashcards()
|
||||||
|
await loadTotalCounts()
|
||||||
alert(`詞卡「${card.word}」已刪除`)
|
alert(`詞卡「${card.word}」已刪除`)
|
||||||
} else {
|
} else {
|
||||||
alert(result.error || '刪除失敗')
|
alert(result.error || '刪除失敗')
|
||||||
|
|
@ -182,7 +203,10 @@ function FlashcardsContent() {
|
||||||
// 真實API調用
|
// 真實API調用
|
||||||
const result = await flashcardsService.toggleFavorite(card.id)
|
const result = await flashcardsService.toggleFavorite(card.id)
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
loadFlashcards()
|
// 重新載入詞卡以反映最新的收藏狀態
|
||||||
|
await loadFlashcards()
|
||||||
|
// 重新載入統計數量
|
||||||
|
await loadTotalCounts()
|
||||||
alert(`${card.isFavorite ? '已取消收藏' : '已加入收藏'}「${card.word}」`)
|
alert(`${card.isFavorite ? '已取消收藏' : '已加入收藏'}「${card.word}」`)
|
||||||
} else {
|
} else {
|
||||||
alert(result.error || '操作失敗')
|
alert(result.error || '操作失敗')
|
||||||
|
|
@ -301,7 +325,7 @@ function FlashcardsContent() {
|
||||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
所有詞卡 ({filteredCards.length})
|
所有詞卡 ({totalCounts.all})
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveTab('favorites')}
|
onClick={() => setActiveTab('favorites')}
|
||||||
|
|
@ -312,7 +336,7 @@ function FlashcardsContent() {
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span className="text-yellow-500">⭐</span>
|
<span className="text-yellow-500">⭐</span>
|
||||||
收藏詞卡 ({allCards.filter(card => card.isFavorite).length})
|
收藏詞卡 ({totalCounts.favorites})
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/* 進階搜尋區域 */}
|
{/* 進階搜尋區域 */}
|
||||||
|
|
@ -511,10 +535,10 @@ function FlashcardsContent() {
|
||||||
{activeTab === 'favorites' && (
|
{activeTab === 'favorites' && (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<h3 className="text-lg font-semibold">共 {allCards.filter(card => card.isFavorite).length} 個詞卡</h3>
|
<h3 className="text-lg font-semibold">共 {filteredCards.length} 個詞卡</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{allCards.filter(card => card.isFavorite).length === 0 ? (
|
{filteredCards.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<div className="text-yellow-500 text-6xl mb-4">⭐</div>
|
<div className="text-yellow-500 text-6xl mb-4">⭐</div>
|
||||||
<p className="text-gray-500 mb-4">還沒有收藏的詞卡</p>
|
<p className="text-gray-500 mb-4">還沒有收藏的詞卡</p>
|
||||||
|
|
@ -522,7 +546,7 @@ function FlashcardsContent() {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{allCards.filter(card => card.isFavorite).map(card => (
|
{filteredCards.map(card => (
|
||||||
<div key={card.id} className="bg-white border border-gray-200 rounded-lg hover:shadow-md transition-all duration-200 relative">
|
<div key={card.id} className="bg-white border border-gray-200 rounded-lg hover:shadow-md transition-all duration-200 relative">
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
{/* 收藏詞卡內容 - 與普通詞卡相同的佈局 */}
|
{/* 收藏詞卡內容 - 與普通詞卡相同的佈局 */}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue