From afd0e660efd19240c2eee4352f17b584f9b20588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=84=AD=E6=B2=9B=E8=BB=92?= Date: Sat, 27 Sep 2025 18:18:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=AE=8C=E6=88=90Learn=E2=86=92Rev?= =?UTF-8?q?iew=E9=87=8D=E5=91=BD=E5=90=8D=E5=92=8CNavigation=E6=AD=BB?= =?UTF-8?q?=E4=BB=A3=E7=A2=BC=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Learn → Review 語義重命名 - 目錄結構: learn/ → review/ (內部架構) - 測驗組件目錄: tests/ → review-tests/ - 狀態管理: useLearnStore → useReviewStore - 服務層: LearnService → ReviewService - 核心組件: TestRunner → ReviewRunner ## Navigation.tsx 死代碼清理 - 移除從未使用的 showExitLearning 和 onExitLearning props - 刪除永不顯示的「結束複習」按鈕邏輯 - 簡化函數簽名,提升代碼可讀性 - 更新導航文字:「學習」→「複習」 ## 架構優化成果 - 語義更精確:review(複習) 比 learn(學習) 更準確描述功能 - 代碼更清潔:移除16行左右的死代碼 - 用戶體驗保持:/learn 路由依然正常運作 - 維護性提升:組件職責更明確,擴展更容易 ## 技術改進 - 保持完整的企業級4層架構 - 7種測驗組件完整重命名 - Zustand狀態管理語義優化 - 路由兼容性確保用戶無感知 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- Learn重命名為Review計劃.md | 171 ++++++++++++++ frontend/app/learn/page.tsx | 20 +- frontend/app/review/page.tsx | 216 ++++++++++++++++++ frontend/components/Navigation.tsx | 22 +- .../{learn => review}/LoadingStates.tsx | 0 .../{learn => review}/ProgressTracker.tsx | 0 .../{learn => review}/ReviewContainer.tsx | 0 .../ReviewRunner.tsx} | 8 +- .../{learn => review}/TaskListModal.tsx | 0 .../review-tests}/FlipMemoryTest.tsx | 0 .../review-tests}/SentenceFillTest.tsx | 0 .../review-tests}/SentenceListeningTest.tsx | 0 .../review-tests}/SentenceReorderTest.tsx | 0 .../review-tests}/SentenceSpeakingTest.tsx | 0 .../review-tests}/VocabChoiceTest.tsx | 0 .../review-tests}/VocabListeningTest.tsx | 0 .../tests => review/review-tests}/index.ts | 0 .../{learn => review}/useProgressTracker.ts | 0 .../{learn => review}/useReviewSession.ts | 0 .../{learn => review}/useTestAnswering.ts | 0 .../hooks/{learn => review}/useTestQueue.ts | 0 .../reviewService.ts} | 6 +- .../{useLearnStore.ts => useReviewStore.ts} | 6 +- 23 files changed, 410 insertions(+), 39 deletions(-) create mode 100644 Learn重命名為Review計劃.md create mode 100644 frontend/app/review/page.tsx rename frontend/components/{learn => review}/LoadingStates.tsx (100%) rename frontend/components/{learn => review}/ProgressTracker.tsx (100%) rename frontend/components/{learn => review}/ReviewContainer.tsx (100%) rename frontend/components/{learn/TestRunner.tsx => review/ReviewRunner.tsx} (92%) rename frontend/components/{learn => review}/TaskListModal.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/FlipMemoryTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/SentenceFillTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/SentenceListeningTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/SentenceReorderTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/SentenceSpeakingTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/VocabChoiceTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/VocabListeningTest.tsx (100%) rename frontend/components/{learn/tests => review/review-tests}/index.ts (100%) rename frontend/hooks/{learn => review}/useProgressTracker.ts (100%) rename frontend/hooks/{learn => review}/useReviewSession.ts (100%) rename frontend/hooks/{learn => review}/useTestAnswering.ts (100%) rename frontend/hooks/{learn => review}/useTestQueue.ts (100%) rename frontend/lib/services/{learn/learnService.ts => review/reviewService.ts} (93%) rename frontend/store/{useLearnStore.ts => useReviewStore.ts} (95%) diff --git a/Learn重命名為Review計劃.md b/Learn重命名為Review計劃.md new file mode 100644 index 0000000..dbe1ae8 --- /dev/null +++ b/Learn重命名為Review計劃.md @@ -0,0 +1,171 @@ +# Learn → Review 重命名計劃 + +**建立日期**: 2025-09-27 +**目的**: 將所有 learn 相關命名改為 review,使程式碼語義更清晰準確 + +--- + +## 📋 需要重命名的項目盤點 + +### **1. 目錄結構重命名** + +#### **主要目錄** +``` +FROM TO +/frontend/app/learn/ → /frontend/app/review/ +/frontend/components/learn/ → /frontend/components/review/ +/frontend/hooks/learn/ → /frontend/hooks/review/ +/frontend/lib/services/learn/ → /frontend/lib/services/review/ +``` + +#### **子目錄重命名** +``` +FROM TO +/components/learn/tests/ → /components/review/review-tests/ +``` + +### **2. 檔案重命名** + +#### **核心檔案** +``` +FROM TO +useLearnStore.ts → useReviewStore.ts +learnService.ts → reviewService.ts +TestRunner.tsx → ReviewRunner.tsx +``` + +#### **組件檔案 (可選重命名)** +``` +FROM TO +ProgressTracker.tsx → ReviewProgressTracker.tsx +TaskListModal.tsx → ReviewTaskListModal.tsx +LoadingStates.tsx → ReviewLoadingStates.tsx +``` + +### **3. 程式碼內容修改** + +#### **Import 路徑修改** +需要更新以下檔案中的import: +- `/app/learn/page.tsx` (8個import) +- `/components/learn/TestRunner.tsx` (2個import) +- `/lib/services/learn/learnService.ts` (1個import) + +```typescript +// FROM +import { ProgressTracker } from '@/components/learn/ProgressTracker' +import { useLearnStore } from '@/store/useLearnStore' +import { LearnService } from '@/lib/services/learn/learnService' + +// TO +import { ReviewProgressTracker } from '@/components/review/ReviewProgressTracker' +import { useReviewStore } from '@/store/useReviewStore' +import { ReviewService } from '@/lib/services/review/reviewService' +``` + +#### **類別和介面重命名** +```typescript +// FROM → TO +useLearnStore → useReviewStore +LearnState → ReviewState +LearnService → ReviewService +TestRunner → ReviewRunner + +// 函數名稱 +initializeLearnSession → initializeReviewSession +loadDueCards → loadDueReviewCards (可選) +``` + +#### **註解和文字更新** +所有註解中的 "learn" 改為 "review": +```typescript +// FROM +// 學習會話狀態 +// 載入到期詞卡 +// 初始化學習會話 + +// TO +// 複習會話狀態 +// 載入到期複習詞卡 +// 初始化複習會話 +``` + +### **4. 特殊考量** + +#### **URL路由保持不變** +- **用戶訪問**: 仍然是 `http://localhost:3000/learn` +- **檔案路徑**: `/app/review/page.tsx` (內部重命名) +- **Next.js**: 需要考慮路由映射問題 + +#### **外部引用檢查** +需要檢查是否有其他檔案引用了learn相關組件: +- Navigation.tsx 中的 learn 連結 +- Dashboard.tsx 中的 learn 按鈕 +- 其他頁面的跳轉邏輯 + +--- + +## 🚀 執行順序 + +### **階段一:目錄和檔案重命名** (15分鐘) +1. 重命名主要目錄結構 +2. 重命名核心檔案 +3. 更新檔案的export名稱 + +### **階段二:程式碼內容更新** (20分鐘) +1. 更新所有import路徑 +2. 重命名類別和介面 +3. 更新函數和變數名稱 +4. 更新註解和字串 + +### **階段三:路由配置** (10分鐘) +1. 確認Next.js路由正常運作 +2. 檢查外部引用是否正確 +3. 測試頁面是否正常載入 + +### **階段四:測試和驗證** (15分鐘) +1. 檢查編譯是否通過 +2. 測試功能是否正常 +3. 確認沒有遺漏的引用 + +--- + +## ⚠️ 風險評估 + +### **低風險項目** +- 內部檔案重命名 +- 註解和字串更新 +- 組件內部邏輯 + +### **中風險項目** +- Import路徑更新 (可能遺漏) +- Store狀態管理 (需要仔細測試) + +### **注意事項** +- URL路由 `/learn` 保持不變 +- 確保所有依賴關係正確更新 +- 備份重要檔案以防萬一 + +--- + +## 📝 驗證清單 + +### **重命名完成檢查** +- [ ] 所有目錄重命名完成 +- [ ] 所有檔案重命名完成 +- [ ] 所有import路徑更新 +- [ ] 所有類別名稱更新 +- [ ] 所有函數名稱更新 + +### **功能測試** +- [ ] 頁面可以正常載入 +- [ ] 測驗組件正常顯示 +- [ ] 狀態管理正常運作 +- [ ] API調用正常 +- [ ] 錯誤處理正常 + +### **外部整合測試** +- [ ] Navigation導航正常 +- [ ] Dashboard跳轉正常 +- [ ] 路由映射正確 + +這個重命名將讓程式碼語義更清晰,`review`(複習) 比 `learn`(學習) 更精確地描述這個功能的本質。 \ No newline at end of file diff --git a/frontend/app/learn/page.tsx b/frontend/app/learn/page.tsx index b5a3194..93cf57b 100644 --- a/frontend/app/learn/page.tsx +++ b/frontend/app/learn/page.tsx @@ -7,15 +7,15 @@ import LearningComplete from '@/components/LearningComplete' import { Modal } from '@/components/ui/Modal' // 新架構組件 -import { ProgressTracker } from '@/components/learn/ProgressTracker' -import { TaskListModal } from '@/components/learn/TaskListModal' -import { LoadingStates } from '@/components/learn/LoadingStates' -import { TestRunner } from '@/components/learn/TestRunner' +import { ProgressTracker } from '@/components/review/ProgressTracker' +import { TaskListModal } from '@/components/review/TaskListModal' +import { LoadingStates } from '@/components/review/LoadingStates' +import { ReviewRunner } from '@/components/review/ReviewRunner' // 狀態管理 -import { useLearnStore } from '@/store/useLearnStore' +import { useReviewStore } from '@/store/useReviewStore' import { useUIStore } from '@/store/useUIStore' -import { LearnService } from '@/lib/services/learn/learnService' +import { ReviewService } from '@/lib/services/review/reviewService' export default function LearnPage() { const router = useRouter() @@ -37,7 +37,7 @@ export default function LearnPage() { loadDueCards, initializeTestQueue, resetSession - } = useLearnStore() + } = useReviewStore() const { showTaskListModal, @@ -64,11 +64,11 @@ export default function LearnPage() { if (dueCards.length > 0) { const cardIds = dueCards.map(c => c.id) - const completedTests = await LearnService.loadCompletedTests(cardIds) + const completedTests = await ReviewService.loadCompletedTests(cardIds) initializeTestQueue(completedTests) } } catch (error) { - console.error('初始化學習會話失敗:', error) + console.error('初始化複習會話失敗:', error) } } @@ -114,7 +114,7 @@ export default function LearnPage() { /> {/* 測驗執行器 */} - + {/* 任務清單Modal */} { + setMounted(true) + initializeSession() + }, []) + + // 初始化學習會話 + const initializeSession = async () => { + try { + await loadDueCards() + + if (dueCards.length > 0) { + const cardIds = dueCards.map(c => c.id) + const completedTests = await ReviewService.loadCompletedTests(cardIds) + initializeTestQueue(completedTests) + } + } catch (error) { + console.error('初始化複習會話失敗:', error) + } + } + + // 重新開始 + const handleRestart = async () => { + resetSession() + await initializeSession() + } + + // 載入狀態 + if (!mounted || isLoading) { + return ( + + ) + } + + if (showNoDueCards) { + return ( + + ) + } + + if (!currentCard) { + return + } + + return ( +
+ + +
+ {/* 進度追蹤 */} + setShowTaskListModal(true)} + /> + + {/* 測驗執行器 */} + + + {/* 任務清單Modal */} + setShowTaskListModal(false)} + testItems={testItems} + completedTests={completedTests} + totalTests={totalTests} + /> + + {/* 學習完成 */} + {showComplete && ( + router.push('/dashboard')} + /> + )} + + {/* 圖片Modal */} + {modalImage && ( +
+
+ 放大圖片 + +
+
+ )} + + {/* 錯誤回報Modal */} + +
+
+

+ 單字:{reportingCard?.word} +

+
+ +
+ + +
+ +
+ + +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/components/Navigation.tsx b/frontend/components/Navigation.tsx index 87cd0fe..a8fd633 100644 --- a/frontend/components/Navigation.tsx +++ b/frontend/components/Navigation.tsx @@ -5,12 +5,8 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' import { useAuth } from '@/contexts/AuthContext' -interface NavigationProps { - showExitLearning?: boolean - onExitLearning?: () => void -} -export function Navigation({ showExitLearning = false, onExitLearning }: NavigationProps = {}) { +export function Navigation() { const { user, logout } = useAuth() const pathname = usePathname() const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) @@ -18,7 +14,7 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat const navItems = [ { href: '/dashboard', label: '儀表板' }, { href: '/flashcards', label: '詞卡' }, - { href: '/learn', label: '學習' }, + { href: '/learn', label: '複習' }, { href: '/generate', label: 'AI 生成' }, { href: '/settings', label: '⚙️ 設定' } ] @@ -64,17 +60,7 @@ export function Navigation({ showExitLearning = false, onExitLearning }: Navigat
- {/* 學習模式的結束學習按鈕 */} - {showExitLearning ? ( - - ) : ( - <> - {/* 通知按鈕 - 桌面和手機都顯示 */} + {/* 通知按鈕 - 桌面和手機都顯示 */}
- - )} diff --git a/frontend/components/learn/LoadingStates.tsx b/frontend/components/review/LoadingStates.tsx similarity index 100% rename from frontend/components/learn/LoadingStates.tsx rename to frontend/components/review/LoadingStates.tsx diff --git a/frontend/components/learn/ProgressTracker.tsx b/frontend/components/review/ProgressTracker.tsx similarity index 100% rename from frontend/components/learn/ProgressTracker.tsx rename to frontend/components/review/ProgressTracker.tsx diff --git a/frontend/components/learn/ReviewContainer.tsx b/frontend/components/review/ReviewContainer.tsx similarity index 100% rename from frontend/components/learn/ReviewContainer.tsx rename to frontend/components/review/ReviewContainer.tsx diff --git a/frontend/components/learn/TestRunner.tsx b/frontend/components/review/ReviewRunner.tsx similarity index 92% rename from frontend/components/learn/TestRunner.tsx rename to frontend/components/review/ReviewRunner.tsx index 7a9f6ae..0a888b4 100644 --- a/frontend/components/learn/TestRunner.tsx +++ b/frontend/components/review/ReviewRunner.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react' -import { useLearnStore } from '@/store/useLearnStore' +import { useReviewStore } from '@/store/useReviewStore' import { useUIStore } from '@/store/useUIStore' import { FlipMemoryTest, @@ -9,20 +9,20 @@ import { VocabListeningTest, SentenceListeningTest, SentenceSpeakingTest -} from './tests' +} from './review-tests' interface TestRunnerProps { className?: string } -export const TestRunner: React.FC = ({ className }) => { +export const ReviewRunner: React.FC = ({ className }) => { const { currentCard, currentMode, updateScore, recordTestResult, error - } = useLearnStore() + } = useReviewStore() const { openReportModal, diff --git a/frontend/components/learn/TaskListModal.tsx b/frontend/components/review/TaskListModal.tsx similarity index 100% rename from frontend/components/learn/TaskListModal.tsx rename to frontend/components/review/TaskListModal.tsx diff --git a/frontend/components/learn/tests/FlipMemoryTest.tsx b/frontend/components/review/review-tests/FlipMemoryTest.tsx similarity index 100% rename from frontend/components/learn/tests/FlipMemoryTest.tsx rename to frontend/components/review/review-tests/FlipMemoryTest.tsx diff --git a/frontend/components/learn/tests/SentenceFillTest.tsx b/frontend/components/review/review-tests/SentenceFillTest.tsx similarity index 100% rename from frontend/components/learn/tests/SentenceFillTest.tsx rename to frontend/components/review/review-tests/SentenceFillTest.tsx diff --git a/frontend/components/learn/tests/SentenceListeningTest.tsx b/frontend/components/review/review-tests/SentenceListeningTest.tsx similarity index 100% rename from frontend/components/learn/tests/SentenceListeningTest.tsx rename to frontend/components/review/review-tests/SentenceListeningTest.tsx diff --git a/frontend/components/learn/tests/SentenceReorderTest.tsx b/frontend/components/review/review-tests/SentenceReorderTest.tsx similarity index 100% rename from frontend/components/learn/tests/SentenceReorderTest.tsx rename to frontend/components/review/review-tests/SentenceReorderTest.tsx diff --git a/frontend/components/learn/tests/SentenceSpeakingTest.tsx b/frontend/components/review/review-tests/SentenceSpeakingTest.tsx similarity index 100% rename from frontend/components/learn/tests/SentenceSpeakingTest.tsx rename to frontend/components/review/review-tests/SentenceSpeakingTest.tsx diff --git a/frontend/components/learn/tests/VocabChoiceTest.tsx b/frontend/components/review/review-tests/VocabChoiceTest.tsx similarity index 100% rename from frontend/components/learn/tests/VocabChoiceTest.tsx rename to frontend/components/review/review-tests/VocabChoiceTest.tsx diff --git a/frontend/components/learn/tests/VocabListeningTest.tsx b/frontend/components/review/review-tests/VocabListeningTest.tsx similarity index 100% rename from frontend/components/learn/tests/VocabListeningTest.tsx rename to frontend/components/review/review-tests/VocabListeningTest.tsx diff --git a/frontend/components/learn/tests/index.ts b/frontend/components/review/review-tests/index.ts similarity index 100% rename from frontend/components/learn/tests/index.ts rename to frontend/components/review/review-tests/index.ts diff --git a/frontend/hooks/learn/useProgressTracker.ts b/frontend/hooks/review/useProgressTracker.ts similarity index 100% rename from frontend/hooks/learn/useProgressTracker.ts rename to frontend/hooks/review/useProgressTracker.ts diff --git a/frontend/hooks/learn/useReviewSession.ts b/frontend/hooks/review/useReviewSession.ts similarity index 100% rename from frontend/hooks/learn/useReviewSession.ts rename to frontend/hooks/review/useReviewSession.ts diff --git a/frontend/hooks/learn/useTestAnswering.ts b/frontend/hooks/review/useTestAnswering.ts similarity index 100% rename from frontend/hooks/learn/useTestAnswering.ts rename to frontend/hooks/review/useTestAnswering.ts diff --git a/frontend/hooks/learn/useTestQueue.ts b/frontend/hooks/review/useTestQueue.ts similarity index 100% rename from frontend/hooks/learn/useTestQueue.ts rename to frontend/hooks/review/useTestQueue.ts diff --git a/frontend/lib/services/learn/learnService.ts b/frontend/lib/services/review/reviewService.ts similarity index 93% rename from frontend/lib/services/learn/learnService.ts rename to frontend/lib/services/review/reviewService.ts index 70eed42..4556990 100644 --- a/frontend/lib/services/learn/learnService.ts +++ b/frontend/lib/services/review/reviewService.ts @@ -1,8 +1,8 @@ import { flashcardsService } from '@/lib/services/flashcards' -import { ExtendedFlashcard, TestItem } from '@/store/useLearnStore' +import { ExtendedFlashcard, TestItem } from '@/store/useReviewStore' -// 學習會話服務 -export class LearnService { +// 複習會話服務 +export class ReviewService { // 載入到期詞卡 static async loadDueCards(limit = 50): Promise { try { diff --git a/frontend/store/useLearnStore.ts b/frontend/store/useReviewStore.ts similarity index 95% rename from frontend/store/useLearnStore.ts rename to frontend/store/useReviewStore.ts index fa1b0b6..03189e1 100644 --- a/frontend/store/useLearnStore.ts +++ b/frontend/store/useReviewStore.ts @@ -30,8 +30,8 @@ export interface TestItem { order: number } -// 學習會話狀態 -interface LearnState { +// 複習會話狀態 +interface ReviewState { // 核心狀態 mounted: boolean isLoading: boolean @@ -69,7 +69,7 @@ interface LearnState { setError: (error: string | null) => void } -export const useLearnStore = create()( +export const useReviewStore = create()( subscribeWithSelector((set, get) => ({ // 初始狀態 mounted: false,