diff --git a/frontend/lib/services/flashcards.ts b/frontend/lib/services/flashcards.ts index 49e8ab5..3bd0648 100644 --- a/frontend/lib/services/flashcards.ts +++ b/frontend/lib/services/flashcards.ts @@ -1,18 +1,4 @@ -// Flashcards API service for handling flashcard operations - -export interface CardSet { - id: string; - name: string; - description: string; - color: string; - cardCount: number; - createdAt: string; - updatedAt: string; - isDefault: boolean; - progress: number; - lastStudied: string; - tags: string[]; -} +// Flashcards API service export interface Flashcard { id: string; @@ -27,27 +13,20 @@ export interface Flashcard { timesReviewed: number; isFavorite: boolean; nextReviewDate: string; + difficultyLevel: string; createdAt: string; - cardSet: { - name: string; - color: string; - }; -} - -export interface CreateCardSetRequest { - name: string; - description: string; - isPublic?: boolean; + updatedAt?: string; // 設為可選,因為模擬資料可能沒有 + // 移除 cardSet 屬性 } export interface CreateFlashcardRequest { - cardSetId?: string; word: string; translation: string; definition: string; pronunciation: string; partOfSpeech: string; example: string; + exampleTranslation?: string; } export interface ApiResponse { @@ -57,25 +36,13 @@ export interface ApiResponse { message?: string; } -const API_BASE_URL = 'http://localhost:5008'; - class FlashcardsService { - private getAuthToken(): string | null { - if (typeof window === 'undefined') return null; - return localStorage.getItem('auth_token'); - } + private readonly baseURL = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5008'}/api`; - private async makeRequest( - endpoint: string, - options: RequestInit = {} - ): Promise { - const token = this.getAuthToken(); - const url = `${API_BASE_URL}/api${endpoint}`; - - const response = await fetch(url, { + private async makeRequest(endpoint: string, options: RequestInit = {}): Promise { + const response = await fetch(`${this.baseURL}${endpoint}`, { headers: { 'Content-Type': 'application/json', - ...(token && { 'Authorization': `Bearer ${token}` }), ...options.headers, }, ...options, @@ -89,50 +56,17 @@ class FlashcardsService { return response.json(); } - // CardSets methods - async getCardSets(): Promise> { + // 簡化的詞卡方法 + async getFlashcards(search?: string, favoritesOnly: boolean = false): Promise> { try { - return await this.makeRequest>('/cardsets'); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to fetch card sets', - }; - } - } + const params = new URLSearchParams(); + if (search) params.append('search', search); + if (favoritesOnly) params.append('favoritesOnly', 'true'); - async createCardSet(data: CreateCardSetRequest): Promise> { - try { - return await this.makeRequest>('/cardsets', { - method: 'POST', - body: JSON.stringify(data), - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to create card set', - }; - } - } + const queryString = params.toString(); + const endpoint = `/flashcards${queryString ? `?${queryString}` : ''}`; - async deleteCardSet(id: string): Promise> { - try { - return await this.makeRequest>(`/cardsets/${id}`, { - method: 'DELETE', - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to delete card set', - }; - } - } - - // Flashcards methods - async getFlashcards(cardSetId?: string): Promise> { - try { - const query = cardSetId ? `?cardSetId=${cardSetId}` : ''; - return await this.makeRequest>(`/flashcards${query}`); + return await this.makeRequest>(endpoint); } catch (error) { return { success: false, @@ -141,7 +75,7 @@ class FlashcardsService { } } - async createFlashcard(data: CreateFlashcardRequest): Promise> { + async createFlashcard(data: CreateSimpleFlashcardRequest): Promise> { try { return await this.makeRequest>('/flashcards', { method: 'POST', @@ -155,20 +89,6 @@ class FlashcardsService { } } - async updateFlashcard(id: string, data: Partial): Promise> { - try { - return await this.makeRequest>(`/flashcards/${id}`, { - method: 'PUT', - body: JSON.stringify(data), - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to update flashcard', - }; - } - } - async deleteFlashcard(id: string): Promise> { try { return await this.makeRequest>(`/flashcards/${id}`, { @@ -182,9 +102,34 @@ class FlashcardsService { } } - async toggleFavorite(id: string): Promise> { + async getFlashcard(id: string): Promise> { try { - return await this.makeRequest>(`/flashcards/${id}/favorite`, { + return await this.makeRequest>(`/flashcards/${id}`); + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to get flashcard', + }; + } + } + + async updateFlashcard(id: string, data: CreateSimpleFlashcardRequest): Promise> { + try { + return await this.makeRequest>(`/flashcards/${id}`, { + method: 'PUT', + body: JSON.stringify(data), + }); + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Failed to update flashcard', + }; + } + } + + async toggleFavorite(id: string): Promise> { + try { + return await this.makeRequest>(`/flashcards/${id}/favorite`, { method: 'POST', }); } catch (error) { @@ -194,52 +139,6 @@ class FlashcardsService { }; } } - - async ensureDefaultCardSet(): Promise> { - try { - return await this.makeRequest>('/cardsets/ensure-default', { - method: 'POST', - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to ensure default card set', - }; - } - } - - async batchCreateFlashcards(request: BatchCreateFlashcardsRequest): Promise> { - try { - return await this.makeRequest>('/flashcards/batch', { - method: 'POST', - body: JSON.stringify(request), - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to save flashcards', - }; - } - } -} - -// 新增批量創建相關介面 -export interface BatchCreateFlashcardsRequest { - cardSetId?: string; - cards: CreateFlashcardRequest[]; -} - -export interface BatchCreateFlashcardsResponse { - savedCards: SavedCard[]; - savedCount: number; - errorCount: number; - errors: string[]; -} - -export interface SavedCard { - id: string; - word: string; - translation: string; } export const flashcardsService = new FlashcardsService(); \ No newline at end of file diff --git a/frontend/lib/services/simplifiedFlashcards.ts b/frontend/lib/services/simplifiedFlashcards.ts deleted file mode 100644 index 2e9e8a8..0000000 --- a/frontend/lib/services/simplifiedFlashcards.ts +++ /dev/null @@ -1,120 +0,0 @@ -// 簡化的 Flashcards API service - 移除 CardSets 概念 - -export interface SimpleFlashcard { - id: string; - word: string; - translation: string; - definition: string; - partOfSpeech: string; - pronunciation: string; - example: string; - exampleTranslation?: string; - masteryLevel: number; - timesReviewed: number; - isFavorite: boolean; - nextReviewDate: string; - difficultyLevel: string; - createdAt: string; - updatedAt?: string; // 設為可選,因為模擬資料可能沒有 - // 移除 cardSet 屬性 -} - -export interface CreateSimpleFlashcardRequest { - word: string; - translation: string; - definition: string; - pronunciation: string; - partOfSpeech: string; - example: string; - exampleTranslation?: string; - // 移除 cardSetId -} - -export interface ApiResponse { - success: boolean; - data?: T; - error?: string; - message?: string; -} - -class SimplifiedFlashcardsService { - private readonly baseURL = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5008'}/api`; - - private async makeRequest(endpoint: string, options: RequestInit = {}): Promise { - const response = await fetch(`${this.baseURL}${endpoint}`, { - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - ...options, - }); - - if (!response.ok) { - const errorData = await response.json().catch(() => ({ error: 'Network error' })); - throw new Error(errorData.error || errorData.details || `HTTP ${response.status}`); - } - - return response.json(); - } - - // 簡化的詞卡方法 - async getFlashcards(search?: string, favoritesOnly: boolean = false): Promise> { - try { - const params = new URLSearchParams(); - if (search) params.append('search', search); - if (favoritesOnly) params.append('favoritesOnly', 'true'); - - const queryString = params.toString(); - const endpoint = `/flashcards-simple${queryString ? `?${queryString}` : ''}`; - - return await this.makeRequest>(endpoint); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to fetch flashcards', - }; - } - } - - async createFlashcard(data: CreateSimpleFlashcardRequest): Promise> { - try { - return await this.makeRequest>('/flashcards-simple', { - method: 'POST', - body: JSON.stringify(data), - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to create flashcard', - }; - } - } - - async deleteFlashcard(id: string): Promise> { - try { - return await this.makeRequest>(`/flashcards-simple/${id}`, { - method: 'DELETE', - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to delete flashcard', - }; - } - } - - async toggleFavorite(id: string): Promise> { - try { - return await this.makeRequest>(`/flashcards-simple/${id}/favorite`, { - method: 'POST', - }); - } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : 'Failed to toggle favorite', - }; - } - } -} - -export const simplifiedFlashcardsService = new SimplifiedFlashcardsService(); \ No newline at end of file