156 lines
4.6 KiB
TypeScript
156 lines
4.6 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import { flashcardsService, type Flashcard } from '@/lib/services/flashcards'
|
|
import { getReviewTypesByCEFR } from '@/lib/utils/cefrUtils'
|
|
|
|
// 擴展的Flashcard接口
|
|
interface ExtendedFlashcard extends Omit<Flashcard, 'nextReviewDate'> {
|
|
nextReviewDate?: string
|
|
currentInterval?: number
|
|
isOverdue?: boolean
|
|
overdueDays?: number
|
|
baseMasteryLevel?: number
|
|
lastReviewDate?: string
|
|
synonyms?: string[]
|
|
exampleImage?: string
|
|
}
|
|
|
|
// 複習模式類型
|
|
type ReviewMode = 'flip-memory' | 'vocab-choice' | 'vocab-listening' | 'sentence-listening' | 'sentence-fill' | 'sentence-reorder' | 'sentence-speaking'
|
|
|
|
// Hook狀態接口
|
|
interface ReviewSessionState {
|
|
currentCard: ExtendedFlashcard | null
|
|
dueCards: ExtendedFlashcard[]
|
|
currentCardIndex: number
|
|
isLoadingCard: boolean
|
|
mode: ReviewMode
|
|
isAutoSelecting: boolean
|
|
showNoDueCards: boolean
|
|
showComplete: boolean
|
|
}
|
|
|
|
// Hook返回接口
|
|
interface UseReviewSessionReturn extends ReviewSessionState {
|
|
loadDueCards: () => Promise<void>
|
|
setCurrentCard: (card: ExtendedFlashcard | null) => void
|
|
setCurrentCardIndex: (index: number) => void
|
|
setMode: (mode: ReviewMode) => void
|
|
setIsAutoSelecting: (selecting: boolean) => void
|
|
setShowNoDueCards: (show: boolean) => void
|
|
setShowComplete: (show: boolean) => void
|
|
nextCard: () => void
|
|
previousCard: () => void
|
|
restart: () => Promise<void>
|
|
}
|
|
|
|
|
|
export const useReviewSession = (): UseReviewSessionReturn => {
|
|
// 核心複習狀態
|
|
const [currentCard, setCurrentCard] = useState<ExtendedFlashcard | null>(null)
|
|
const [dueCards, setDueCards] = useState<ExtendedFlashcard[]>([])
|
|
const [currentCardIndex, setCurrentCardIndex] = useState(0)
|
|
const [isLoadingCard, setIsLoadingCard] = useState(false)
|
|
const [mode, setMode] = useState<ReviewMode>('flip-memory')
|
|
const [isAutoSelecting, setIsAutoSelecting] = useState(true)
|
|
const [showNoDueCards, setShowNoDueCards] = useState(false)
|
|
const [showComplete, setShowComplete] = useState(false)
|
|
|
|
// 載入到期詞卡
|
|
const loadDueCards = async (): Promise<void> => {
|
|
try {
|
|
setIsLoadingCard(true)
|
|
console.log('🔍 開始載入到期詞卡...')
|
|
|
|
const apiResult = await flashcardsService.getDueFlashcards(50)
|
|
console.log('📡 API回應結果:', apiResult)
|
|
|
|
if (apiResult.success && apiResult.data && apiResult.data.length > 0) {
|
|
const cardsToUse = apiResult.data
|
|
console.log('✅ 載入後端API數據成功:', cardsToUse.length, '張詞卡')
|
|
|
|
setDueCards(cardsToUse)
|
|
setCurrentCardIndex(0)
|
|
setCurrentCard(cardsToUse[0])
|
|
|
|
// 自動選擇複習模式
|
|
const userCEFRLevel = localStorage.getItem('userEnglishLevel') || 'A2'
|
|
const wordCEFRLevel = cardsToUse[0].difficultyLevel || 'A2'
|
|
const reviewTypes = getReviewTypesByCEFR(userCEFRLevel, wordCEFRLevel)
|
|
|
|
if (reviewTypes.length > 0) {
|
|
const selectedMode = reviewTypes[0] as ReviewMode
|
|
setMode(selectedMode)
|
|
}
|
|
|
|
setIsAutoSelecting(false)
|
|
setShowNoDueCards(false)
|
|
setShowComplete(false)
|
|
} else {
|
|
console.log('❌ 沒有到期詞卡')
|
|
setDueCards([])
|
|
setCurrentCard(null)
|
|
setShowNoDueCards(true)
|
|
setShowComplete(false)
|
|
}
|
|
} catch (error) {
|
|
console.error('💥 載入到期詞卡失敗:', error)
|
|
setDueCards([])
|
|
setCurrentCard(null)
|
|
setShowNoDueCards(true)
|
|
} finally {
|
|
setIsLoadingCard(false)
|
|
}
|
|
}
|
|
|
|
// 下一張詞卡
|
|
const nextCard = (): void => {
|
|
if (currentCardIndex < dueCards.length - 1) {
|
|
const nextIndex = currentCardIndex + 1
|
|
setCurrentCardIndex(nextIndex)
|
|
setCurrentCard(dueCards[nextIndex])
|
|
} else {
|
|
setShowComplete(true)
|
|
}
|
|
}
|
|
|
|
// 上一張詞卡
|
|
const previousCard = (): void => {
|
|
if (currentCardIndex > 0) {
|
|
const prevIndex = currentCardIndex - 1
|
|
setCurrentCardIndex(prevIndex)
|
|
setCurrentCard(dueCards[prevIndex])
|
|
}
|
|
}
|
|
|
|
// 重新開始
|
|
const restart = async (): Promise<void> => {
|
|
setCurrentCardIndex(0)
|
|
setShowComplete(false)
|
|
setShowNoDueCards(false)
|
|
await loadDueCards()
|
|
}
|
|
|
|
return {
|
|
// 狀態
|
|
currentCard,
|
|
dueCards,
|
|
currentCardIndex,
|
|
isLoadingCard,
|
|
mode,
|
|
isAutoSelecting,
|
|
showNoDueCards,
|
|
showComplete,
|
|
|
|
// 操作函數
|
|
loadDueCards,
|
|
setCurrentCard,
|
|
setCurrentCardIndex,
|
|
setMode,
|
|
setIsAutoSelecting,
|
|
setShowNoDueCards,
|
|
setShowComplete,
|
|
nextCard,
|
|
previousCard,
|
|
restart
|
|
}
|
|
} |