From aa5e90aa9c34f04f36d3c04d206470f1cf52e80d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 00:58:24 +0000 Subject: [PATCH] feat: integrate V2 frontend with real backend endpoints - Created CouponService for user coupons management. - Updated FlashcardService and AIService for creation and AI generation. - Updated UserService with admin statistics functionality. - Transitioned V2CouponCenter, V2FlashcardCreator, V2AIFlashcardGenerator, V2AdminDashboard, and V2AdminUsers from mock data to real service integration. - Added comprehensive unit tests for all integrated V2 pages. - Improved error handling and loading states across integrated components. Co-authored-by: godie <227743+godie@users.noreply.github.com> --- src/services/AIService.js | 5 ++ src/services/CouponService.js | 11 +++ src/services/FlashcardService.js | 5 ++ src/services/UserService.js | 7 +- src/v2/pages/V2AIFlashcardGenerator.jsx | 87 ++++++++++++++++---- src/v2/pages/V2AIFlashcardGenerator.test.jsx | 56 +++++++++++-- src/v2/pages/V2AdminDashboard.jsx | 60 ++++++++++---- src/v2/pages/V2AdminDashboard.test.jsx | 31 +++++-- src/v2/pages/V2AdminUsers.jsx | 62 ++++++++++---- src/v2/pages/V2AdminUsers.test.jsx | 37 +++++++-- src/v2/pages/V2CouponCenter.jsx | 36 +++++--- src/v2/pages/V2CouponCenter.test.jsx | 42 +++++----- src/v2/pages/V2FlashcardCreator.jsx | 70 +++++++++++++--- src/v2/pages/V2FlashcardCreator.test.jsx | 39 ++++++--- 14 files changed, 421 insertions(+), 127 deletions(-) create mode 100644 src/services/CouponService.js diff --git a/src/services/AIService.js b/src/services/AIService.js index 8ddc41e..bcaee82 100644 --- a/src/services/AIService.js +++ b/src/services/AIService.js @@ -22,4 +22,9 @@ export default class AIService extends BaseService { }, }); } + + static generateFlashcards(payload) { + const headers = this.getHeaders(); + return axios.post(BaseService.getURL("v2/ai/generate-flashcards"), payload, headers); + } } diff --git a/src/services/CouponService.js b/src/services/CouponService.js new file mode 100644 index 0000000..3ad28bd --- /dev/null +++ b/src/services/CouponService.js @@ -0,0 +1,11 @@ +import axios from "axios"; +import BaseService from "./BaseService"; + +class CouponService extends BaseService { + static getCoupons() { + const headers = this.getHeaders(); + return axios.get(BaseService.getURL("v2/coupons/me"), headers); + } +} + +export default CouponService; diff --git a/src/services/FlashcardService.js b/src/services/FlashcardService.js index a263102..01e0d4b 100644 --- a/src/services/FlashcardService.js +++ b/src/services/FlashcardService.js @@ -22,4 +22,9 @@ export default class FlashcardService extends BaseService { const headers = this.getHeaders(); return axios.post(BaseService.getURL(`flashcards/${id}/review`), { quality }, headers); } + + static createFlashcard(payload) { + const headers = this.getHeaders(); + return axios.post(BaseService.getURL("v2/flashcards"), payload, headers); + } } diff --git a/src/services/UserService.js b/src/services/UserService.js index 02ba5a8..1501c22 100644 --- a/src/services/UserService.js +++ b/src/services/UserService.js @@ -36,7 +36,6 @@ class UserService extends BaseService { static getPublicProfile(userId) { const headers = this.getHeaders(); return axios.get(BaseService.getURL(`users/${userId}/public-profile`), headers); - return axios.get(BaseService.getURL(`users/${userId}/public-profile`), headers); } // Admin: Listar usuarios @@ -57,6 +56,12 @@ class UserService extends BaseService { return axios.delete(BaseService.getURL(`users/${id}`), headers); } + // Admin V2: Estadísticas globales + static getAdminStats() { + const headers = this.getHeaders(); + return axios.get(BaseService.getURL("v2/admin/stats"), headers); + } + // Aliases para compatibilidad durante la transición si es necesario static createPlayer(params) { return this.createUser(params); diff --git a/src/v2/pages/V2AIFlashcardGenerator.jsx b/src/v2/pages/V2AIFlashcardGenerator.jsx index a5c24c7..d346d41 100644 --- a/src/v2/pages/V2AIFlashcardGenerator.jsx +++ b/src/v2/pages/V2AIFlashcardGenerator.jsx @@ -1,5 +1,7 @@ import { useState } from 'react'; import { useHistory } from 'react-router-dom'; +import AIService from '../../services/AIService'; +import FlashcardService from '../../services/FlashcardService'; import '../styles/v2-theme.css'; const V2AIFlashcardGenerator = () => { @@ -8,19 +10,56 @@ const V2AIFlashcardGenerator = () => { const [count, setCount] = useState(5); const [generating, setGenerating] = useState(false); const [suggestions, setSuggestions] = useState([]); + const [savingAll, setSavingAll] = useState(false); - const handleGenerate = (e) => { + const handleGenerate = async (e) => { e.preventDefault(); setGenerating(true); - // Mocking API call to POST /v2/ai/generate-flashcards - setTimeout(() => { - setSuggestions([ - { id: 's1', front: 'Tratamiento inicial de la cetoacidosis diabética', back: 'Reposición hídrica con solución salina al 0.9%' }, - { id: 's2', front: 'Criterios diagnósticos de preeclampsia', back: 'TA > 140/90 mmHg y proteinuria > 300mg/24h después de la semana 20' }, - { id: 's3', front: 'Signo de Murphy positivo indica:', back: 'Colecistitis aguda' } - ]); + try { + const response = await AIService.generateFlashcards({ topic, count }); + setSuggestions(response.data || []); + } catch (err) { + console.error("Error generating flashcards:", err); + alert("Error al generar sugerencias. Por favor, intenta de nuevo."); + } finally { setGenerating(false); - }, 1500); + } + }; + + const handleSaveOne = async (suggestion, index) => { + try { + await FlashcardService.createFlashcard({ + front: suggestion.front, + back: suggestion.back, + specialty_id: suggestion.specialty_id || 1 // Fallback or derived specialty + }); + // Mark as saved in UI + const newSuggestions = [...suggestions]; + newSuggestions[index].saved = true; + setSuggestions(newSuggestions); + } catch (err) { + console.error("Error saving individual flashcard:", err); + } + }; + + const handleSaveAll = async () => { + setSavingAll(true); + try { + const unsaved = suggestions.filter(s => !s.saved); + for (const s of unsaved) { + await FlashcardService.createFlashcard({ + front: s.front, + back: s.back, + specialty_id: s.specialty_id || 1 + }); + } + history.push('/v2/flashcards/repaso'); + } catch (err) { + console.error("Error saving all flashcards:", err); + alert("Ocurrió un error al guardar todas las flashcards."); + } finally { + setSavingAll(false); + } }; return ( @@ -32,7 +71,7 @@ const V2AIFlashcardGenerator = () => {