diff --git a/frontend/app/review-simple/hooks/useReviewSession.ts b/frontend/app/review-simple/hooks/useReviewSession.ts deleted file mode 100644 index d9898e2..0000000 --- a/frontend/app/review-simple/hooks/useReviewSession.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { useReducer, useEffect, useMemo } from 'react' -import { SIMPLE_CARDS, CardState, sortCardsByPriority } from '../data' - -interface ReviewState { - cards: CardState[] - score: { correct: number; total: number } - isComplete: boolean -} - -type ReviewAction = - | { type: 'LOAD_PROGRESS'; payload: ReviewState } - | { type: 'ANSWER_CARD'; payload: { cardId: string; confidence: number } } - | { type: 'SKIP_CARD'; payload: { cardId: string } } - | { type: 'RESTART' } - -// 內部狀態更新函數 -const updateCardState = ( - cards: CardState[], - cardIndex: number, - updates: Partial -): CardState[] => { - return cards.map((card, index) => - index === cardIndex - ? { ...card, ...updates } - : card - ) -} - -const reviewReducer = (state: ReviewState, action: ReviewAction): ReviewState => { - switch (action.type) { - case 'LOAD_PROGRESS': - return action.payload - - case 'ANSWER_CARD': { - const { cardId, confidence } = action.payload - const isCorrect = confidence >= 2 - - // 使用 Map 優化查找性能 - const cardMap = new Map(state.cards.map((card, index) => [card.id, { card, index }])) - const cardData = cardMap.get(cardId) - - if (!cardData) return state - - const { index: cardIndex } = cardData - const currentCard = state.cards[cardIndex] - - const updatedCards = updateCardState(state.cards, cardIndex, { - isCompleted: isCorrect, - wrongCount: isCorrect ? currentCard.wrongCount : currentCard.wrongCount + 1 - }) - - const newScore = { - correct: state.score.correct + (isCorrect ? 1 : 0), - total: state.score.total + 1 - } - - const remainingCards = updatedCards.filter(card => !card.isCompleted) - const isComplete = remainingCards.length === 0 - - return { - cards: updatedCards, - score: newScore, - isComplete - } - } - - case 'SKIP_CARD': { - const { cardId } = action.payload - - // 使用 Map 優化查找性能 - const cardMap = new Map(state.cards.map((card, index) => [card.id, { card, index }])) - const cardData = cardMap.get(cardId) - - if (!cardData) return state - - const { index: cardIndex } = cardData - const currentCard = state.cards[cardIndex] - - const updatedCards = updateCardState(state.cards, cardIndex, { - skipCount: currentCard.skipCount + 1 - }) - - const remainingCards = updatedCards.filter(card => !card.isCompleted) - const isComplete = remainingCards.length === 0 - - return { - cards: updatedCards, - score: state.score, - isComplete - } - } - - case 'RESTART': - return { - cards: SIMPLE_CARDS, - score: { correct: 0, total: 0 }, - isComplete: false - } - - default: - return state - } -} - -export function useReviewSession() { - // 使用 useReducer 統一狀態管理 - const [state, dispatch] = useReducer(reviewReducer, { - cards: SIMPLE_CARDS, - score: { correct: 0, total: 0 }, - isComplete: false - }) - - const { cards, score, isComplete } = state - - // 智能排序獲取當前卡片 - 使用 useMemo 優化性能 - const sortedCards = useMemo(() => sortCardsByPriority(cards), [cards]) - const incompleteCards = useMemo(() => - sortedCards.filter((card: CardState) => !card.isCompleted), - [sortedCards] - ) - const currentCard = incompleteCards[0] // 總是選擇優先級最高的未完成卡片 - - // localStorage進度保存和載入 - useEffect(() => { - // 載入保存的進度 - const savedProgress = localStorage.getItem('review-progress') - if (savedProgress) { - try { - const parsed = JSON.parse(savedProgress) - const saveTime = new Date(parsed.timestamp) - const now = new Date() - const isToday = saveTime.toDateString() === now.toDateString() - - if (isToday && parsed.cards) { - dispatch({ - type: 'LOAD_PROGRESS', - payload: { - cards: parsed.cards, - score: parsed.score || { correct: 0, total: 0 }, - isComplete: parsed.isComplete || false - } - }) - console.log('📖 載入保存的複習進度') - } - } catch (error) { - console.warn('進度載入失敗:', error) - localStorage.removeItem('review-progress') - } - } - }, []) - - // 保存進度到localStorage - const saveProgress = () => { - const progress = { - cards, - score, - isComplete, - timestamp: new Date().toISOString() - } - localStorage.setItem('review-progress', JSON.stringify(progress)) - console.log('💾 進度已保存') - } - - // 處理答題 - 使用 dispatch 統一管理 - const handleAnswer = (confidence: number) => { - if (!currentCard) return - - dispatch({ - type: 'ANSWER_CARD', - payload: { cardId: currentCard.id, confidence } - }) - - // 保存進度 - setTimeout(() => saveProgress(), 100) // 延遲一點確保狀態更新 - } - - // 處理跳過 - 使用 dispatch 統一管理 - const handleSkip = () => { - if (!currentCard) return - - dispatch({ - type: 'SKIP_CARD', - payload: { cardId: currentCard.id } - }) - - // 保存進度 - setTimeout(() => saveProgress(), 100) // 延遲一點確保狀態更新 - } - - // 重新開始 - 重置所有狀態 - const handleRestart = () => { - dispatch({ type: 'RESTART' }) - localStorage.removeItem('review-progress') // 清除保存的進度 - console.log('🔄 複習進度已重置') - } - - return { - // 狀態 - cards, - score, - isComplete, - currentCard, - sortedCards, - - // 動作 - handleAnswer, - handleSkip, - handleRestart - } -} \ No newline at end of file diff --git a/frontend/app/review-simple/page.tsx b/frontend/app/review-simple/page.tsx index 3247a8d..6894fbc 100644 --- a/frontend/app/review-simple/page.tsx +++ b/frontend/app/review-simple/page.tsx @@ -2,11 +2,11 @@ import { Navigation } from '@/components/shared/Navigation' import './globals.css' -import { SimpleFlipCard } from './components/SimpleFlipCard' -import { SimpleProgress } from './components/SimpleProgress' -import { SimpleResults } from './components/SimpleResults' -import { SIMPLE_CARDS, CardState } from './data' -import { useReviewSession } from './hooks/useReviewSession' +import { SimpleFlipCard } from '@/components/review/simple/SimpleFlipCard' +import { SimpleProgress } from '@/components/review/simple/SimpleProgress' +import { SimpleResults } from '@/components/review/simple/SimpleResults' +import { SIMPLE_CARDS, CardState } from '@/lib/data/reviewSimpleData' +import { useReviewSession } from '@/hooks/review/useReviewSession' export default function SimpleReviewPage() { // 使用自定義 Hook 管理複習狀態 diff --git a/frontend/app/test-vocab-choice/page.tsx b/frontend/app/test-vocab-choice/page.tsx new file mode 100644 index 0000000..673a1fd --- /dev/null +++ b/frontend/app/test-vocab-choice/page.tsx @@ -0,0 +1,124 @@ +'use client' + +import { useState } from 'react' +import { Navigation } from '@/components/shared/Navigation' +import { VocabChoiceTest } from '@/components/review/simple/VocabChoiceTest' +import { SIMPLE_CARDS, CardState } from '@/lib/data/reviewSimpleData' + +export default function TestVocabChoicePage() { + const [currentCardIndex, setCurrentCardIndex] = useState(0) + const [score, setScore] = useState({ correct: 0, total: 0 }) + + const currentCard = SIMPLE_CARDS[currentCardIndex] + + // 生成測驗選項 (包含正確答案和3個干擾項) + const generateOptions = (correctWord: string) => { + const allWords = SIMPLE_CARDS.map(card => card.word).filter(word => word !== correctWord) + const shuffledWords = allWords.sort(() => Math.random() - 0.5) + const distractors = shuffledWords.slice(0, 3) + + const options = [correctWord, ...distractors] + return options.sort(() => Math.random() - 0.5) // 隨機排列選項 + } + + const handleAnswer = (confidence: number) => { + const isCorrect = confidence >= 2 + setScore(prev => ({ + correct: prev.correct + (isCorrect ? 1 : 0), + total: prev.total + 1 + })) + + // 移動到下一張卡片 + setTimeout(() => { + if (currentCardIndex < SIMPLE_CARDS.length - 1) { + setCurrentCardIndex(prev => prev + 1) + } else { + alert(`測試完成!正確率: ${score.correct + (isCorrect ? 1 : 0)}/${score.total + 1}`) + } + }, 100) + } + + const handleSkip = () => { + setScore(prev => ({ ...prev, total: prev.total + 1 })) + + if (currentCardIndex < SIMPLE_CARDS.length - 1) { + setCurrentCardIndex(prev => prev + 1) + } else { + alert(`測試完成!正確率: ${score.correct}/${score.total + 1}`) + } + } + + const handleRestart = () => { + setCurrentCardIndex(0) + setScore({ correct: 0, total: 0 }) + } + + if (!currentCard) { + return ( +
+ +
+
+

測試完成!

+ +
+
+
+ ) + } + + return ( +
+ + +
+
+ {/* 進度顯示 */} +
+
+

詞彙選擇測驗

+
+ 第 {currentCardIndex + 1} / {SIMPLE_CARDS.length} 題 +
+
+
+
+ 得分: {score.correct} / {score.total} + {score.total > 0 && ` (${Math.round(score.correct / score.total * 100)}%)`} +
+
+
+
+
+
+ + {/* 測驗組件 */} + + + {/* 控制按鈕 */} +
+ +
+
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/components/review/review-tests/VocabChoiceTest.tsx b/frontend/components/review/review-tests/VocabChoiceTest.tsx deleted file mode 100644 index d9e6112..0000000 --- a/frontend/components/review/review-tests/VocabChoiceTest.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useState, useCallback, useMemo, memo } from 'react' -import { ChoiceTestProps } from '@/types/review' -import { - TestResultDisplay, - ChoiceTestContainer, - ChoiceGrid -} from '@/components/review/shared' - -interface VocabChoiceTestProps extends ChoiceTestProps {} - -const VocabChoiceTestComponent: React.FC = ({ - cardData, - options, - onAnswer, - onReportError, - disabled = false -}) => { - const [selectedAnswer, setSelectedAnswer] = useState(null) - const [showResult, setShowResult] = useState(false) - - - const handleAnswerSelect = useCallback((answer: string) => { - if (disabled || showResult) return - setSelectedAnswer(answer) - setShowResult(true) - onAnswer(answer) - }, [disabled, showResult, onAnswer]) - - const isCorrect = useMemo(() => - selectedAnswer === cardData.word - , [selectedAnswer, cardData.word]) - - // 問題顯示區域 - const questionArea = ( -
-
-

定義

-

{cardData.definition}

-
-

- 請選擇符合上述定義的英文詞彙: -

-
- ) - - // 選項區域 - const optionsArea = ( - - ) - - // 結果顯示區域 - const resultArea = showResult ? ( - - ) : null - - return ( - - ) -} - -export const VocabChoiceTest = memo(VocabChoiceTestComponent) -VocabChoiceTest.displayName = 'VocabChoiceTest' \ No newline at end of file diff --git a/frontend/app/review-simple/components/SimpleFlipCard.tsx b/frontend/components/review/simple/SimpleFlipCard.tsx similarity index 94% rename from frontend/app/review-simple/components/SimpleFlipCard.tsx rename to frontend/components/review/simple/SimpleFlipCard.tsx index 0803a71..1d91a8e 100644 --- a/frontend/app/review-simple/components/SimpleFlipCard.tsx +++ b/frontend/components/review/simple/SimpleFlipCard.tsx @@ -1,7 +1,7 @@ 'use client' import { useState, useRef, useEffect, useCallback } from 'react' -import { CardState } from '../data' +import { CardState } from '@/lib/data/reviewSimpleData' import { SimpleTestHeader } from './SimpleTestHeader' interface SimpleFlipCardProps { @@ -188,9 +188,9 @@ export function SimpleFlipCard({ card, onAnswer, onSkip }: SimpleFlipCardProps)
{[ - { level: 1, label: '模糊', color: 'bg-orange-100 text-orange-700 border-orange-200 hover:bg-orange-200' }, - { level: 2, label: '一般', color: 'bg-yellow-100 text-yellow-700 border-yellow-200 hover:bg-yellow-200' }, - { level: 3, label: '熟悉', color: 'bg-green-100 text-green-700 border-green-200 hover:bg-green-200' } + { level: 0, label: '模糊', color: 'bg-orange-100 text-orange-700 border-orange-200 hover:bg-orange-200' }, + { level: 1, label: '一般', color: 'bg-yellow-100 text-yellow-700 border-yellow-200 hover:bg-yellow-200' }, + { level: 2, label: '熟悉', color: 'bg-green-100 text-green-700 border-green-200 hover:bg-green-200' } ].map(({ level, label, color }) => { const isSelected = selectedConfidence === level return ( diff --git a/frontend/app/review-simple/components/SimpleProgress.tsx b/frontend/components/review/simple/SimpleProgress.tsx similarity index 96% rename from frontend/app/review-simple/components/SimpleProgress.tsx rename to frontend/components/review/simple/SimpleProgress.tsx index 017f7b6..6e9dcc1 100644 --- a/frontend/app/review-simple/components/SimpleProgress.tsx +++ b/frontend/components/review/simple/SimpleProgress.tsx @@ -1,4 +1,4 @@ -import { CardState } from '../data' +import { CardState } from '@/lib/data/reviewSimpleData' interface SimpleProgressProps { current: number diff --git a/frontend/app/review-simple/components/SimpleResults.tsx b/frontend/components/review/simple/SimpleResults.tsx similarity index 100% rename from frontend/app/review-simple/components/SimpleResults.tsx rename to frontend/components/review/simple/SimpleResults.tsx diff --git a/frontend/app/review-simple/components/SimpleTestHeader.tsx b/frontend/components/review/simple/SimpleTestHeader.tsx similarity index 100% rename from frontend/app/review-simple/components/SimpleTestHeader.tsx rename to frontend/components/review/simple/SimpleTestHeader.tsx diff --git a/frontend/components/review/simple/VocabChoiceTest.tsx b/frontend/components/review/simple/VocabChoiceTest.tsx new file mode 100644 index 0000000..d338313 --- /dev/null +++ b/frontend/components/review/simple/VocabChoiceTest.tsx @@ -0,0 +1,147 @@ +'use client' + +import { useState, useCallback } from 'react' +import { CardState } from '@/lib/data/reviewSimpleData' +import { SimpleTestHeader } from './SimpleTestHeader' + +interface VocabChoiceTestProps { + card: CardState + options: string[] + onAnswer: (confidence: number) => void + onSkip: () => void +} + +export function VocabChoiceTest({ card, options, onAnswer, onSkip }: VocabChoiceTestProps) { + const [selectedAnswer, setSelectedAnswer] = useState(null) + const [showResult, setShowResult] = useState(false) + + const handleAnswerSelect = useCallback((answer: string) => { + if (showResult) return + + setSelectedAnswer(answer) + setShowResult(true) + + // 判斷答案是否正確,正確給3分,錯誤給1分 + const isCorrect = answer === card.word + const confidence = isCorrect ? 2 : 0 + + // 延遲一點再調用回調,讓用戶看到選擇結果 + setTimeout(() => { + onAnswer(confidence) + // 重置狀態為下一題準備 + setSelectedAnswer(null) + setShowResult(false) + }, 1500) + }, [showResult, card.word, onAnswer]) + + const handleSkipClick = useCallback(() => { + onSkip() + }, [onSkip]) + + const isCorrect = selectedAnswer === card.word + + return ( +
+ + + {/* 問題區域 */} +
+
+

定義

+

{card.definition}

+
+

+ 請選擇符合上述定義的英文詞彙: +

+
+ + {/* 選項區域 */} +
+
+ {options.map((option, index) => { + const isSelected = selectedAnswer === option + const isCorrectOption = option === card.word + + let buttonClass = 'p-4 rounded-lg border-2 text-center font-medium transition-all duration-200 cursor-pointer active:scale-95' + + if (showResult) { + if (isSelected && isCorrectOption) { + // 選中且正確 + buttonClass += ' bg-green-100 text-green-700 border-green-200 ring-2 ring-green-400' + } else if (isSelected && !isCorrectOption) { + // 選中但錯誤 + buttonClass += ' bg-red-100 text-red-700 border-red-200 ring-2 ring-red-400' + } else if (!isSelected && isCorrectOption) { + // 未選中但是正確答案 + buttonClass += ' bg-green-50 text-green-600 border-green-200' + } else { + // 未選中且非正確答案 + buttonClass += ' bg-gray-50 text-gray-500 border-gray-200' + } + } else { + // 未答題狀態 + buttonClass += ' bg-blue-50 text-blue-700 border-blue-200 hover:bg-blue-100' + } + + return ( + + ) + })} +
+
+ + {/* 結果顯示區域 */} + {showResult && ( +
+
+
+ + {isCorrect ? '✅' : '❌'} + +

+ {isCorrect ? '答對了!' : '答錯了'} +

+
+ +
+

+ 正確答案: {card.word} +

+

+ 發音: {card.pronunciation} +

+

+ 例句: "{card.example}" +

+

+ {card.exampleTranslation} +

+
+
+
+ )} + + {/* 跳過按鈕 */} + {!showResult && ( +
+ +
+ )} +
+ ) +} \ No newline at end of file diff --git a/frontend/hooks/review/useReviewSession.ts b/frontend/hooks/review/useReviewSession.ts index 5bd307d..245b0e7 100644 --- a/frontend/hooks/review/useReviewSession.ts +++ b/frontend/hooks/review/useReviewSession.ts @@ -1,84 +1,210 @@ -/** - * 簡化的複習會話 Hook - Store 包裝器 - * 提供便捷的 Store 訪問方式,但所有邏輯都統一在 Store 中 - */ +import { useReducer, useEffect, useMemo } from 'react' +import { SIMPLE_CARDS, CardState, sortCardsByPriority } from '@/lib/data/reviewSimpleData' -import { useReviewSessionStore } from '@/store/review/useReviewSessionStore' -import { flashcardsService } from '@/lib/services/flashcards' -import type { ExtendedFlashcard, ReviewMode } from '@/lib/types/review' - -interface UseReviewSessionReturn { - // 狀態 (從 Store 直接取得) - currentCard: ExtendedFlashcard | null - dueCards: ExtendedFlashcard[] - currentCardIndex: number - isLoadingCard: boolean - mode: ReviewMode - isAutoSelecting: boolean - showNoDueCards: boolean - showComplete: boolean - - // 操作 (Store 的包裝方法) - loadNextCard: () => Promise - setCurrentCard: (card: ExtendedFlashcard | null) => void - setCurrentCardIndex: (index: number) => void - setMode: (mode: ReviewMode) => void - setAutoSelecting: (auto: boolean) => void - setShowNoDueCards: (show: boolean) => void - setShowComplete: (show: boolean) => void - resetSession: () => void +interface ReviewState { + cards: CardState[] + score: { correct: number; total: number } + isComplete: boolean } -export function useReviewSession(): UseReviewSessionReturn { - // 從 Store 取得狀態和操作 - const store = useReviewSessionStore() +type ReviewAction = + | { type: 'LOAD_PROGRESS'; payload: ReviewState } + | { type: 'ANSWER_CARD'; payload: { cardId: string; confidence: number } } + | { type: 'SKIP_CARD'; payload: { cardId: string } } + | { type: 'RESTART' } - // 載入卡片的業務邏輯 (唯一的 Hook 專有邏輯) - const loadNextCard = async () => { - try { - store.setLoading(true) - store.setError(null) +// 內部狀態更新函數 +const updateCardState = ( + cards: CardState[], + cardIndex: number, + updates: Partial +): CardState[] => { + return cards.map((card, index) => + index === cardIndex + ? { ...card, ...updates } + : card + ) +} - const result = await flashcardsService.getDueFlashcards(50) +const reviewReducer = (state: ReviewState, action: ReviewAction): ReviewState => { + switch (action.type) { + case 'LOAD_PROGRESS': + return action.payload - if (result.success && result.data && result.data.length > 0) { - store.setDueCards(result.data) - store.setCurrentCard(result.data[0]) - store.setCurrentCardIndex(0) - store.setShowNoDueCards(false) - } else { - store.setShowNoDueCards(true) - store.setCurrentCard(null) - store.setDueCards([]) + case 'ANSWER_CARD': { + const { cardId, confidence } = action.payload + const isCorrect = confidence >= 2 + + // 使用 Map 優化查找性能 + const cardMap = new Map(state.cards.map((card, index) => [card.id, { card, index }])) + const cardData = cardMap.get(cardId) + + if (!cardData) return state + + const { index: cardIndex } = cardData + const currentCard = state.cards[cardIndex] + + const updatedCards = updateCardState(state.cards, cardIndex, { + isCompleted: isCorrect, + wrongCount: isCorrect ? currentCard.wrongCount : currentCard.wrongCount + 1 + }) + + const newScore = { + correct: state.score.correct + (isCorrect ? 1 : 0), + total: state.score.total + 1 + } + + const remainingCards = updatedCards.filter(card => !card.isCompleted) + const isComplete = remainingCards.length === 0 + + return { + cards: updatedCards, + score: newScore, + isComplete } - } catch (error) { - const errorMessage = error instanceof Error ? error.message : '載入卡片失敗' - store.setError(errorMessage) - store.setShowNoDueCards(true) - } finally { - store.setLoading(false) } + + case 'SKIP_CARD': { + const { cardId } = action.payload + + // 使用 Map 優化查找性能 + const cardMap = new Map(state.cards.map((card, index) => [card.id, { card, index }])) + const cardData = cardMap.get(cardId) + + if (!cardData) return state + + const { index: cardIndex } = cardData + const currentCard = state.cards[cardIndex] + + const updatedCards = updateCardState(state.cards, cardIndex, { + skipCount: currentCard.skipCount + 1 + }) + + const remainingCards = updatedCards.filter(card => !card.isCompleted) + const isComplete = remainingCards.length === 0 + + return { + cards: updatedCards, + score: state.score, + isComplete + } + } + + case 'RESTART': + return { + cards: SIMPLE_CARDS, + score: { correct: 0, total: 0 }, + isComplete: false + } + + default: + return state + } +} + +export function useReviewSession() { + // 使用 useReducer 統一狀態管理 + const [state, dispatch] = useReducer(reviewReducer, { + cards: SIMPLE_CARDS, + score: { correct: 0, total: 0 }, + isComplete: false + }) + + const { cards, score, isComplete } = state + + // 智能排序獲取當前卡片 - 使用 useMemo 優化性能 + const sortedCards = useMemo(() => sortCardsByPriority(cards), [cards]) + const incompleteCards = useMemo(() => + sortedCards.filter((card: CardState) => !card.isCompleted), + [sortedCards] + ) + const currentCard = incompleteCards[0] // 總是選擇優先級最高的未完成卡片 + + // localStorage進度保存和載入 + useEffect(() => { + // 載入保存的進度 + const savedProgress = localStorage.getItem('review-progress') + if (savedProgress) { + try { + const parsed = JSON.parse(savedProgress) + const saveTime = new Date(parsed.timestamp) + const now = new Date() + const isToday = saveTime.toDateString() === now.toDateString() + + if (isToday && parsed.cards) { + dispatch({ + type: 'LOAD_PROGRESS', + payload: { + cards: parsed.cards, + score: parsed.score || { correct: 0, total: 0 }, + isComplete: parsed.isComplete || false + } + }) + console.log('📖 載入保存的複習進度') + } + } catch (error) { + console.warn('進度載入失敗:', error) + localStorage.removeItem('review-progress') + } + } + }, []) + + // 保存進度到localStorage + const saveProgress = () => { + const progress = { + cards, + score, + isComplete, + timestamp: new Date().toISOString() + } + localStorage.setItem('review-progress', JSON.stringify(progress)) + console.log('💾 進度已保存') + } + + // 處理答題 - 使用 dispatch 統一管理 + const handleAnswer = (confidence: number) => { + if (!currentCard) return + + dispatch({ + type: 'ANSWER_CARD', + payload: { cardId: currentCard.id, confidence } + }) + + // 保存進度 + setTimeout(() => saveProgress(), 100) // 延遲一點確保狀態更新 + } + + // 處理跳過 - 使用 dispatch 統一管理 + const handleSkip = () => { + if (!currentCard) return + + dispatch({ + type: 'SKIP_CARD', + payload: { cardId: currentCard.id } + }) + + // 保存進度 + setTimeout(() => saveProgress(), 100) // 延遲一點確保狀態更新 + } + + // 重新開始 - 重置所有狀態 + const handleRestart = () => { + dispatch({ type: 'RESTART' }) + localStorage.removeItem('review-progress') // 清除保存的進度 + console.log('🔄 複習進度已重置') } return { - // 狀態 (直接從 Store 映射) - currentCard: store.currentCard, - dueCards: store.dueCards, - currentCardIndex: store.currentCardIndex, - isLoadingCard: store.isLoading, - mode: store.mode, - isAutoSelecting: store.isAutoSelecting, - showNoDueCards: store.showNoDueCards, - showComplete: store.showComplete, + // 狀態 + cards, + score, + isComplete, + currentCard, + sortedCards, - // 操作 (Store 方法的直接映射 + 業務邏輯) - loadNextCard, - setCurrentCard: store.setCurrentCard, - setCurrentCardIndex: store.setCurrentCardIndex, - setMode: store.setMode, - setAutoSelecting: store.setAutoSelecting, - setShowNoDueCards: store.setShowNoDueCards, - setShowComplete: store.setShowComplete, - resetSession: store.resetSession + // 動作 + handleAnswer, + handleSkip, + handleRestart } } \ No newline at end of file diff --git a/frontend/app/review-simple/components/api_seeds.json b/frontend/lib/data/api_seeds.json similarity index 100% rename from frontend/app/review-simple/components/api_seeds.json rename to frontend/lib/data/api_seeds.json diff --git a/frontend/app/review-simple/data.ts b/frontend/lib/data/reviewSimpleData.ts similarity index 94% rename from frontend/app/review-simple/data.ts rename to frontend/lib/data/reviewSimpleData.ts index 6014212..f3df2b1 100644 --- a/frontend/app/review-simple/data.ts +++ b/frontend/lib/data/reviewSimpleData.ts @@ -1,5 +1,5 @@ // 模擬真實API數據結構 -import apiSeeds from './components/api_seeds.json' +import apiSeeds from './api_seeds.json' // API響應接口 (匹配真實API結構 + 同義詞擴展) export interface ApiFlashcard { diff --git a/frontend/app/review-design/example-data.json b/note/archive/app/review-design/example-data.json similarity index 100% rename from frontend/app/review-design/example-data.json rename to note/archive/app/review-design/example-data.json diff --git a/frontend/app/review-design/page.tsx b/note/archive/app/review-design/page.tsx similarity index 95% rename from frontend/app/review-design/page.tsx rename to note/archive/app/review-design/page.tsx index 4555721..3223a3c 100644 --- a/frontend/app/review-design/page.tsx +++ b/note/archive/app/review-design/page.tsx @@ -6,10 +6,10 @@ import { ReviewRunner } from '@/components/review/core/ReviewRunner' import { ProgressTracker } from '@/components/review/ui/ProgressTracker' // Store imports -import { useReviewSessionStore } from '@/store/review/useReviewSessionStore' -import { useTestQueueStore } from '@/store/review/useTestQueueStore' -import { useTestResultStore } from '@/store/review/useTestResultStore' -import { useReviewDataStore } from '@/store/review/useReviewDataStore' +import { useReviewSessionStore } from '../../store/review/useReviewSessionStore' +import { useTestQueueStore } from '@/archive/store/review/useTestQueueStore' +import { useTestResultStore } from '@/archive/store/review/useTestResultStore' +import { useReviewDataStore } from '@/archive/store/review/useReviewDataStore' import exampleData from './example-data.json' // 動態測試資料集配置 diff --git a/frontend/app/review-old/page.tsx b/note/archive/app/review-old/page.tsx similarity index 93% rename from frontend/app/review-old/page.tsx rename to note/archive/app/review-old/page.tsx index 2d07f4f..6ce96ff 100644 --- a/frontend/app/review-old/page.tsx +++ b/note/archive/app/review-old/page.tsx @@ -13,12 +13,12 @@ import { LoadingStates } from '@/components/review/ui/LoadingStates' import { ReviewRunner } from '@/components/review/core/ReviewRunner' // 狀態管理 -import { useReviewSessionStore } from '@/store/review/useReviewSessionStore' -import { useTestQueueStore } from '@/store/review/useTestQueueStore' -import { useTestResultStore } from '@/store/review/useTestResultStore' -import { useReviewDataStore } from '@/store/review/useReviewDataStore' -import { useReviewUIStore } from '@/store/review/useReviewUIStore' -import { ReviewService } from '@/lib/services/review/reviewService' +import { useReviewSessionStore } from '../../store/review/useReviewSessionStore' +import { useTestQueueStore } from '@/archive/store/review/useTestQueueStore' +import { useTestResultStore } from '@/archive/store/review/useTestResultStore' +import { useReviewDataStore } from '@/archive/store/review/useReviewDataStore' +import { useReviewUIStore } from '@/archive/store/review/useReviewUIStore' +import { ReviewService } from '@/archive/lib/services/review/reviewService' export default function LearnPage() { const router = useRouter() diff --git a/frontend/app/review/page.tsx b/note/archive/app/review/page.tsx similarity index 100% rename from frontend/app/review/page.tsx rename to note/archive/app/review/page.tsx diff --git a/frontend/components/review/__tests__/ProgressTracker.test.tsx b/note/archive/components/review/__tests__/ProgressTracker.test.tsx similarity index 100% rename from frontend/components/review/__tests__/ProgressTracker.test.tsx rename to note/archive/components/review/__tests__/ProgressTracker.test.tsx diff --git a/frontend/components/review/__tests__/shared/AnswerActions.test.tsx b/note/archive/components/review/__tests__/shared/AnswerActions.test.tsx similarity index 100% rename from frontend/components/review/__tests__/shared/AnswerActions.test.tsx rename to note/archive/components/review/__tests__/shared/AnswerActions.test.tsx diff --git a/frontend/components/review/__tests__/shared/BaseTestComponent.test.tsx b/note/archive/components/review/__tests__/shared/BaseTestComponent.test.tsx similarity index 100% rename from frontend/components/review/__tests__/shared/BaseTestComponent.test.tsx rename to note/archive/components/review/__tests__/shared/BaseTestComponent.test.tsx diff --git a/frontend/components/review/__tests__/shared/ConfidenceButtons.test.tsx b/note/archive/components/review/__tests__/shared/ConfidenceButtons.test.tsx similarity index 100% rename from frontend/components/review/__tests__/shared/ConfidenceButtons.test.tsx rename to note/archive/components/review/__tests__/shared/ConfidenceButtons.test.tsx diff --git a/frontend/components/review/core/NavigationController.tsx b/note/archive/components/review/core/NavigationController.tsx similarity index 95% rename from frontend/components/review/core/NavigationController.tsx rename to note/archive/components/review/core/NavigationController.tsx index 3b886d9..9399a5f 100644 --- a/frontend/components/review/core/NavigationController.tsx +++ b/note/archive/components/review/core/NavigationController.tsx @@ -1,5 +1,5 @@ import React, { memo, useCallback, useMemo } from 'react' -import { useTestQueueStore } from '@/store/review/useTestQueueStore' +import { useTestQueueStore } from '@/archive/store/review/useTestQueueStore' /** * 智能導航控制器 diff --git a/frontend/components/review/core/ReviewRunner.tsx b/note/archive/components/review/core/ReviewRunner.tsx similarity index 93% rename from frontend/components/review/core/ReviewRunner.tsx rename to note/archive/components/review/core/ReviewRunner.tsx index 7a6f880..5257ea2 100644 --- a/frontend/components/review/core/ReviewRunner.tsx +++ b/note/archive/components/review/core/ReviewRunner.tsx @@ -1,8 +1,8 @@ import { useEffect, useState, useCallback } from 'react' -import { useReviewSessionStore } from '@/store/review/useReviewSessionStore' -import { useTestQueueStore } from '@/store/review/useTestQueueStore' -import { useTestResultStore } from '@/store/review/useTestResultStore' -import { useReviewUIStore } from '@/store/review/useReviewUIStore' +import { useReviewSessionStore } from '@/archive/store/review/useReviewSessionStore' +import { useTestQueueStore } from '@/archive/store/review/useTestQueueStore' +import { useTestResultStore } from '@/archive/store/review/useTestResultStore' +import { useReviewUIStore } from '@/archive/store/review/useReviewUIStore' import { SmartNavigationController } from './NavigationController' import { ProgressBar } from '../ui/ProgressBar' import { diff --git a/frontend/components/review/modals/TaskListModal.tsx b/note/archive/components/review/modals/TaskListModal.tsx similarity index 95% rename from frontend/components/review/modals/TaskListModal.tsx rename to note/archive/components/review/modals/TaskListModal.tsx index 68bdd20..5314961 100644 --- a/frontend/components/review/modals/TaskListModal.tsx +++ b/note/archive/components/review/modals/TaskListModal.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { TestItem } from '@/store/review/useTestQueueStore' +import { TestItem } from '@/archive/store/review/useTestQueueStore' import { TestStatusIndicator, TestStats, TestProgressBar, TestStatusList } from './TestStatusIndicator' interface TaskListModalProps { diff --git a/frontend/components/review/modals/TestStatusIndicator.tsx b/note/archive/components/review/modals/TestStatusIndicator.tsx similarity index 95% rename from frontend/components/review/modals/TestStatusIndicator.tsx rename to note/archive/components/review/modals/TestStatusIndicator.tsx index 3b2bff6..e83b636 100644 --- a/frontend/components/review/modals/TestStatusIndicator.tsx +++ b/note/archive/components/review/modals/TestStatusIndicator.tsx @@ -1,5 +1,5 @@ import React, { memo } from 'react' -import { TestItem } from '@/store/review/useTestQueueStore' +import { TestItem } from '@/archive/store/review/useTestQueueStore' /** * 測驗狀態指示器 diff --git a/frontend/components/review/review-tests/FlipMemoryTest.tsx b/note/archive/components/review/review-tests/FlipMemoryTest.tsx similarity index 100% rename from frontend/components/review/review-tests/FlipMemoryTest.tsx rename to note/archive/components/review/review-tests/FlipMemoryTest.tsx diff --git a/frontend/components/review/review-tests/SentenceFillTest.tsx b/note/archive/components/review/review-tests/SentenceFillTest.tsx similarity index 100% rename from frontend/components/review/review-tests/SentenceFillTest.tsx rename to note/archive/components/review/review-tests/SentenceFillTest.tsx diff --git a/frontend/components/review/review-tests/SentenceListeningTest.tsx b/note/archive/components/review/review-tests/SentenceListeningTest.tsx similarity index 100% rename from frontend/components/review/review-tests/SentenceListeningTest.tsx rename to note/archive/components/review/review-tests/SentenceListeningTest.tsx diff --git a/frontend/components/review/review-tests/SentenceReorderTest.tsx b/note/archive/components/review/review-tests/SentenceReorderTest.tsx similarity index 100% rename from frontend/components/review/review-tests/SentenceReorderTest.tsx rename to note/archive/components/review/review-tests/SentenceReorderTest.tsx diff --git a/frontend/components/review/review-tests/SentenceSpeakingTest.tsx b/note/archive/components/review/review-tests/SentenceSpeakingTest.tsx similarity index 100% rename from frontend/components/review/review-tests/SentenceSpeakingTest.tsx rename to note/archive/components/review/review-tests/SentenceSpeakingTest.tsx diff --git a/frontend/components/review/review-tests/VocabListeningTest.tsx b/note/archive/components/review/review-tests/VocabListeningTest.tsx similarity index 100% rename from frontend/components/review/review-tests/VocabListeningTest.tsx rename to note/archive/components/review/review-tests/VocabListeningTest.tsx diff --git a/frontend/components/review/review-tests/index.ts b/note/archive/components/review/review-tests/index.ts similarity index 100% rename from frontend/components/review/review-tests/index.ts rename to note/archive/components/review/review-tests/index.ts diff --git a/frontend/components/review/shared/AnswerActions.tsx b/note/archive/components/review/shared/AnswerActions.tsx similarity index 100% rename from frontend/components/review/shared/AnswerActions.tsx rename to note/archive/components/review/shared/AnswerActions.tsx diff --git a/frontend/components/review/shared/BaseTestComponent.tsx b/note/archive/components/review/shared/BaseTestComponent.tsx similarity index 100% rename from frontend/components/review/shared/BaseTestComponent.tsx rename to note/archive/components/review/shared/BaseTestComponent.tsx diff --git a/frontend/components/review/shared/ConfidenceButtons.tsx b/note/archive/components/review/shared/ConfidenceButtons.tsx similarity index 100% rename from frontend/components/review/shared/ConfidenceButtons.tsx rename to note/archive/components/review/shared/ConfidenceButtons.tsx diff --git a/frontend/components/review/shared/ErrorReportButton.tsx b/note/archive/components/review/shared/ErrorReportButton.tsx similarity index 100% rename from frontend/components/review/shared/ErrorReportButton.tsx rename to note/archive/components/review/shared/ErrorReportButton.tsx diff --git a/frontend/components/review/shared/HintPanel.tsx b/note/archive/components/review/shared/HintPanel.tsx similarity index 100% rename from frontend/components/review/shared/HintPanel.tsx rename to note/archive/components/review/shared/HintPanel.tsx diff --git a/frontend/components/review/shared/SentenceInput.tsx b/note/archive/components/review/shared/SentenceInput.tsx similarity index 100% rename from frontend/components/review/shared/SentenceInput.tsx rename to note/archive/components/review/shared/SentenceInput.tsx diff --git a/frontend/components/review/shared/TestContainer.tsx b/note/archive/components/review/shared/TestContainer.tsx similarity index 100% rename from frontend/components/review/shared/TestContainer.tsx rename to note/archive/components/review/shared/TestContainer.tsx diff --git a/frontend/components/review/shared/TestHeader.tsx b/note/archive/components/review/shared/TestHeader.tsx similarity index 100% rename from frontend/components/review/shared/TestHeader.tsx rename to note/archive/components/review/shared/TestHeader.tsx diff --git a/frontend/components/review/shared/TestResultDisplay.tsx b/note/archive/components/review/shared/TestResultDisplay.tsx similarity index 100% rename from frontend/components/review/shared/TestResultDisplay.tsx rename to note/archive/components/review/shared/TestResultDisplay.tsx diff --git a/frontend/components/review/shared/index.ts b/note/archive/components/review/shared/index.ts similarity index 100% rename from frontend/components/review/shared/index.ts rename to note/archive/components/review/shared/index.ts diff --git a/frontend/components/review/ui/LoadingStates.tsx b/note/archive/components/review/ui/LoadingStates.tsx similarity index 100% rename from frontend/components/review/ui/LoadingStates.tsx rename to note/archive/components/review/ui/LoadingStates.tsx diff --git a/frontend/components/review/ui/MasteryIndicator.tsx b/note/archive/components/review/ui/MasteryIndicator.tsx similarity index 100% rename from frontend/components/review/ui/MasteryIndicator.tsx rename to note/archive/components/review/ui/MasteryIndicator.tsx diff --git a/frontend/components/review/ui/ProgressBar.tsx b/note/archive/components/review/ui/ProgressBar.tsx similarity index 100% rename from frontend/components/review/ui/ProgressBar.tsx rename to note/archive/components/review/ui/ProgressBar.tsx diff --git a/frontend/components/review/ui/ProgressTracker.tsx b/note/archive/components/review/ui/ProgressTracker.tsx similarity index 100% rename from frontend/components/review/ui/ProgressTracker.tsx rename to note/archive/components/review/ui/ProgressTracker.tsx diff --git a/frontend/components/review/ui/ReviewTypeIndicator.tsx b/note/archive/components/review/ui/ReviewTypeIndicator.tsx similarity index 100% rename from frontend/components/review/ui/ReviewTypeIndicator.tsx rename to note/archive/components/review/ui/ReviewTypeIndicator.tsx diff --git a/note/archive/hooks/review/useReviewSession.ts b/note/archive/hooks/review/useReviewSession.ts new file mode 100644 index 0000000..92e35b3 --- /dev/null +++ b/note/archive/hooks/review/useReviewSession.ts @@ -0,0 +1,84 @@ +/** + * 簡化的複習會話 Hook - Store 包裝器 + * 提供便捷的 Store 訪問方式,但所有邏輯都統一在 Store 中 + */ + +import { useReviewSessionStore } from '../../../note/archive/store/review/useReviewSessionStore' +import { flashcardsService } from '@/lib/services/flashcards' +import type { ExtendedFlashcard, ReviewMode } from '@/archive/lib/types/review' + +interface UseReviewSessionReturn { + // 狀態 (從 Store 直接取得) + currentCard: ExtendedFlashcard | null + dueCards: ExtendedFlashcard[] + currentCardIndex: number + isLoadingCard: boolean + mode: ReviewMode + isAutoSelecting: boolean + showNoDueCards: boolean + showComplete: boolean + + // 操作 (Store 的包裝方法) + loadNextCard: () => Promise + setCurrentCard: (card: ExtendedFlashcard | null) => void + setCurrentCardIndex: (index: number) => void + setMode: (mode: ReviewMode) => void + setAutoSelecting: (auto: boolean) => void + setShowNoDueCards: (show: boolean) => void + setShowComplete: (show: boolean) => void + resetSession: () => void +} + +export function useReviewSession(): UseReviewSessionReturn { + // 從 Store 取得狀態和操作 + const store = useReviewSessionStore() + + // 載入卡片的業務邏輯 (唯一的 Hook 專有邏輯) + const loadNextCard = async () => { + try { + store.setLoading(true) + store.setError(null) + + const result = await flashcardsService.getDueFlashcards(50) + + if (result.success && result.data && result.data.length > 0) { + store.setDueCards(result.data) + store.setCurrentCard(result.data[0]) + store.setCurrentCardIndex(0) + store.setShowNoDueCards(false) + } else { + store.setShowNoDueCards(true) + store.setCurrentCard(null) + store.setDueCards([]) + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : '載入卡片失敗' + store.setError(errorMessage) + store.setShowNoDueCards(true) + } finally { + store.setLoading(false) + } + } + + return { + // 狀態 (直接從 Store 映射) + currentCard: store.currentCard, + dueCards: store.dueCards, + currentCardIndex: store.currentCardIndex, + isLoadingCard: store.isLoading, + mode: store.mode, + isAutoSelecting: store.isAutoSelecting, + showNoDueCards: store.showNoDueCards, + showComplete: store.showComplete, + + // 操作 (Store 方法的直接映射 + 業務邏輯) + loadNextCard, + setCurrentCard: store.setCurrentCard, + setCurrentCardIndex: store.setCurrentCardIndex, + setMode: store.setMode, + setAutoSelecting: store.setAutoSelecting, + setShowNoDueCards: store.setShowNoDueCards, + setShowComplete: store.setShowComplete, + resetSession: store.resetSession + } +} \ No newline at end of file diff --git a/frontend/hooks/review/useTestQueue.ts b/note/archive/hooks/review/useTestQueue.ts similarity index 100% rename from frontend/hooks/review/useTestQueue.ts rename to note/archive/hooks/review/useTestQueue.ts diff --git a/frontend/lib/mock/reviewMockData.ts b/note/archive/lib/mock/reviewMockData.ts similarity index 93% rename from frontend/lib/mock/reviewMockData.ts rename to note/archive/lib/mock/reviewMockData.ts index d54f046..b2b078f 100644 --- a/frontend/lib/mock/reviewMockData.ts +++ b/note/archive/lib/mock/reviewMockData.ts @@ -1,5 +1,5 @@ // Mock 數據用於複習功能測試 -import { ExtendedFlashcard } from '@/lib/types/review' +import { ExtendedFlashcard } from '@/archive/lib/types/review' export const mockDueCards: ExtendedFlashcard[] = [ { diff --git a/frontend/lib/services/review/__tests__/reviewService.test.ts b/note/archive/lib/services/review/__tests__/reviewService.test.ts similarity index 100% rename from frontend/lib/services/review/__tests__/reviewService.test.ts rename to note/archive/lib/services/review/__tests__/reviewService.test.ts diff --git a/frontend/lib/services/review/reviewService.ts b/note/archive/lib/services/review/reviewService.ts similarity index 92% rename from frontend/lib/services/review/reviewService.ts rename to note/archive/lib/services/review/reviewService.ts index cea6316..be0a725 100644 --- a/frontend/lib/services/review/reviewService.ts +++ b/note/archive/lib/services/review/reviewService.ts @@ -1,7 +1,7 @@ import { flashcardsService } from '@/lib/services/flashcards' -import { ExtendedFlashcard } from '@/lib/types/review' -import { TestItem } from '@/store/review/useTestQueueStore' -import { isTestMode, getMockCompletedTests } from '@/lib/mock/reviewMockData' +import { ExtendedFlashcard } from '@/archive/lib/types/review' +import { TestItem } from '@/archive/store/review/useTestQueueStore' +import { isTestMode, getMockCompletedTests } from '@/archive/lib/mock/reviewMockData' // 複習會話服務 export class ReviewService { diff --git a/frontend/lib/types/review.ts b/note/archive/lib/types/review.ts similarity index 100% rename from frontend/lib/types/review.ts rename to note/archive/lib/types/review.ts diff --git a/frontend/store/review/__tests__/useReviewDataStore.test.ts b/note/archive/store/review/__tests__/useReviewDataStore.test.ts similarity index 95% rename from frontend/store/review/__tests__/useReviewDataStore.test.ts rename to note/archive/store/review/__tests__/useReviewDataStore.test.ts index 2af445e..3faab6c 100644 --- a/frontend/store/review/__tests__/useReviewDataStore.test.ts +++ b/note/archive/store/review/__tests__/useReviewDataStore.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { useReviewDataStore } from '../useReviewDataStore' -import { mockDueCards } from '@/lib/mock/reviewMockData' +import { mockDueCards } from '@/archive/lib/mock/reviewMockData' // Mock flashcardsService vi.mock('@/lib/services/flashcards', () => ({ diff --git a/frontend/store/review/__tests__/useTestQueueStore.simple.test.ts b/note/archive/store/review/__tests__/useTestQueueStore.simple.test.ts similarity index 100% rename from frontend/store/review/__tests__/useTestQueueStore.simple.test.ts rename to note/archive/store/review/__tests__/useTestQueueStore.simple.test.ts diff --git a/frontend/store/review/__tests__/useTestQueueStore.test.ts b/note/archive/store/review/__tests__/useTestQueueStore.test.ts similarity index 95% rename from frontend/store/review/__tests__/useTestQueueStore.test.ts rename to note/archive/store/review/__tests__/useTestQueueStore.test.ts index 38e76c3..81f37f9 100644 --- a/frontend/store/review/__tests__/useTestQueueStore.test.ts +++ b/note/archive/store/review/__tests__/useTestQueueStore.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { useTestQueueStore, TestItem, ReviewMode } from '../useTestQueueStore' -import { mockDueCards } from '@/lib/mock/reviewMockData' +import { mockDueCards } from '@/archive/lib/mock/reviewMockData' // Mock dependencies vi.mock('@/lib/utils/cefrUtils', () => ({ diff --git a/frontend/store/review/__tests__/useTestResultStore.test.ts b/note/archive/store/review/__tests__/useTestResultStore.test.ts similarity index 100% rename from frontend/store/review/__tests__/useTestResultStore.test.ts rename to note/archive/store/review/__tests__/useTestResultStore.test.ts diff --git a/frontend/store/review/useReviewDataStore.ts b/note/archive/store/review/useReviewDataStore.ts similarity index 91% rename from frontend/store/review/useReviewDataStore.ts rename to note/archive/store/review/useReviewDataStore.ts index 6c4fd05..df3c21a 100644 --- a/frontend/store/review/useReviewDataStore.ts +++ b/note/archive/store/review/useReviewDataStore.ts @@ -1,9 +1,9 @@ import { create } from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' import { flashcardsService } from '@/lib/services/flashcards' -import { ExtendedFlashcard } from '@/lib/types/review' -import { isTestMode, getMockDueCards } from '@/lib/mock/reviewMockData' -import { ReviewService } from '@/lib/services/review/reviewService' +import { ExtendedFlashcard } from '@/archive/lib/types/review' +import { isTestMode, getMockDueCards } from '@/archive/lib/mock/reviewMockData' +import { ReviewService } from '@/archive/lib/services/review/reviewService' // 數據狀態接口 interface ReviewDataState { diff --git a/frontend/store/review/useReviewSessionStore.ts b/note/archive/store/review/useReviewSessionStore.ts similarity index 93% rename from frontend/store/review/useReviewSessionStore.ts rename to note/archive/store/review/useReviewSessionStore.ts index be8cba5..94d469e 100644 --- a/frontend/store/review/useReviewSessionStore.ts +++ b/note/archive/store/review/useReviewSessionStore.ts @@ -1,6 +1,6 @@ import { create } from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' -import type { ReviewSessionStore } from '@/lib/types/review' +import type { ReviewSessionStore } from '@/archive/lib/types/review' export const useReviewSessionStore = create()( subscribeWithSelector((set, get) => ({ diff --git a/frontend/store/review/useReviewUIStore.ts b/note/archive/store/review/useReviewUIStore.ts similarity index 100% rename from frontend/store/review/useReviewUIStore.ts rename to note/archive/store/review/useReviewUIStore.ts diff --git a/frontend/store/review/useTestQueueStore.ts b/note/archive/store/review/useTestQueueStore.ts similarity index 96% rename from frontend/store/review/useTestQueueStore.ts rename to note/archive/store/review/useTestQueueStore.ts index c7f5f73..a4e80fb 100644 --- a/frontend/store/review/useTestQueueStore.ts +++ b/note/archive/store/review/useTestQueueStore.ts @@ -1,7 +1,7 @@ import { create } from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' import { getReviewTypesByCEFR } from '@/lib/utils/cefrUtils' -import { isTestMode, getTestModeReviewTypes } from '@/lib/mock/reviewMockData' +import { isTestMode, getTestModeReviewTypes } from '@/archive/lib/mock/reviewMockData' // 複習模式類型 export type ReviewMode = 'flip-memory' | 'vocab-choice' | 'vocab-listening' | 'sentence-listening' | 'sentence-fill' | 'sentence-reorder' | 'sentence-speaking' diff --git a/frontend/store/review/useTestResultStore.ts b/note/archive/store/review/useTestResultStore.ts similarity index 94% rename from frontend/store/review/useTestResultStore.ts rename to note/archive/store/review/useTestResultStore.ts index 3715a74..45432c7 100644 --- a/frontend/store/review/useTestResultStore.ts +++ b/note/archive/store/review/useTestResultStore.ts @@ -2,7 +2,7 @@ import { create } from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' import { flashcardsService } from '@/lib/services/flashcards' import { ReviewMode } from './useTestQueueStore' -import { isTestMode } from '@/lib/mock/reviewMockData' +import { isTestMode } from '@/archive/lib/mock/reviewMockData' // 測試結果狀態接口 interface TestResultState { diff --git a/frontend/types/review.ts b/note/archive/types/review.ts similarity index 100% rename from frontend/types/review.ts rename to note/archive/types/review.ts