From 570281140ce889501252e457f9bca12711f686cf Mon Sep 17 00:00:00 2001 From: godie Date: Wed, 29 Apr 2026 19:44:35 -0400 Subject: [PATCH] feat(kb): add API-driven knowledge base --- src/components/admin/ExamenRow.jsx | 33 +--- .../facebook/FacebookLoginContainer.jsx | 4 + src/services/KnowledgeBaseService.js | 17 ++ src/v2/pages/V2KnowledgeBase.jsx | 177 ++++++++++-------- 4 files changed, 132 insertions(+), 99 deletions(-) create mode 100644 src/services/KnowledgeBaseService.js diff --git a/src/components/admin/ExamenRow.jsx b/src/components/admin/ExamenRow.jsx index 55a02f2..a3a9407 100644 --- a/src/components/admin/ExamenRow.jsx +++ b/src/components/admin/ExamenRow.jsx @@ -1,40 +1,25 @@ -import PropTypes from 'prop-types'; -import CustomButton from '../custom/CustomButton'; +import { CustomButton } from '../CustomButton'; -const ExamenRow = ({ exam, onDelete }) => { +export const ExamenRow = ({ exam, onDelete }) => { return ( {exam.name} {exam.description || 'Sin descripción'} - {exam.exam_questions?.length || 0} + {exam.clinical_cases_count ?? (exam.exam_questions?.length || 0)} onDelete(exam)} - tooltip="Eliminar Examen" + icon="delete" /> ); }; - -ExamenRow.propTypes = { - exam: PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string, - description: PropTypes.string, - exam_questions: PropTypes.array, - }).isRequired, - onDelete: PropTypes.func.isRequired, -}; - -export default ExamenRow; diff --git a/src/components/facebook/FacebookLoginContainer.jsx b/src/components/facebook/FacebookLoginContainer.jsx index 06145c1..ec87b6e 100644 --- a/src/components/facebook/FacebookLoginContainer.jsx +++ b/src/components/facebook/FacebookLoginContainer.jsx @@ -11,12 +11,16 @@ export default function FacebookLoginContainer() { console.log("FB status change:", response); if (response.status === "connected") { + const authResponse = response.authResponse; + const accessToken = authResponse?.accessToken; + // Retrieve user info from Facebook window.FB.api("/me", { fields: "id,name,email" }, (fbRes) => { const params = { name: fbRes.name, facebook_id: fbRes.id, email: fbRes.email || "no_mail", + facebook_access_token: accessToken, // Send token for server-side verification }; // Persist in localStorage and backend diff --git a/src/services/KnowledgeBaseService.js b/src/services/KnowledgeBaseService.js new file mode 100644 index 0000000..f93289d --- /dev/null +++ b/src/services/KnowledgeBaseService.js @@ -0,0 +1,17 @@ +import axios from 'axios'; +import BaseService from './BaseService'; + +export default class KnowledgeBaseService extends BaseService { + static getTopics() { + const headers = this.getHeaders(); + return axios.get(BaseService.getURL('v2/knowledge-base'), headers); + } + + static searchTopics(search) { + const headers = this.getHeaders(); + return axios.get(BaseService.getURL('v2/knowledge-base'), { + ...headers, + params: { search } + }); + } +} diff --git a/src/v2/pages/V2KnowledgeBase.jsx b/src/v2/pages/V2KnowledgeBase.jsx index 56b6c08..70aafe6 100644 --- a/src/v2/pages/V2KnowledgeBase.jsx +++ b/src/v2/pages/V2KnowledgeBase.jsx @@ -1,53 +1,72 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { alertSuccess } from '../../services/AlertService'; +import KnowledgeBaseService from '../../services/KnowledgeBaseService'; import '../styles/v2-theme.css'; const V2KnowledgeBase = () => { const [search, setSearch] = useState(''); - const [expandedCategory, setExpandedCategory] = useState(null); + const [expandedTopic, setExpandedTopic] = useState(null); + const [topics, setTopics] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - const [data] = useState({ - categories: [ - { - id: '1', - title: 'Guías de Práctica Clínica', - description: 'Repositorio oficial de GPCs vigentes en México', - topics: [ - { id: 't1', title: 'GPC Hipertensión Arterial Sistémica' }, - { id: 't2', title: 'GPC Diabetes Mellitus Tipo 2' }, - { id: 't3', title: 'GPC Insuficiencia Cardiaca' } - ] - }, - { - id: '2', - title: 'Esquemas de Vacunación', - description: 'Actualización 2024 de cartillas nacionales de salud', - topics: [ - { id: 't4', title: 'Esquema Infantil (0-9 años)' }, - { id: 't5', title: 'Esquema Adolescente (10-19 años)' }, - { id: 't6', title: 'Esquema Adulto Mayor' } - ] - }, - { - id: '3', - title: 'Algoritmos Diagnósticos', - description: 'Diagramas de flujo para toma de decisiones clínicas', - topics: [ - { id: 't7', title: 'Algoritmo Sepsis y Choque Séptico' }, - { id: 't8', title: 'Algoritmo Manejo de Asma Aguda' }, - { id: 't9', title: 'Algoritmo Código Infarto' } - ] - } - ] - }); + useEffect(() => { + loadTopics(); + }, []); - const filteredCategories = data.categories.map(cat => ({ - ...cat, - topics: cat.topics.filter(topic => - topic.title.toLowerCase().includes(search.toLowerCase()) || - cat.title.toLowerCase().includes(search.toLowerCase()) + const loadTopics = async () => { + try { + setLoading(true); + setError(null); + const response = await KnowledgeBaseService.getTopics(); + setTopics(response.data.topics || []); + } catch (err) { + console.error('Error loading knowledge base:', err); + setError('Error al cargar la base de conocimientos'); + setTopics([]); + } finally { + setLoading(false); + } + }; + + const filteredTopics = topics.filter(topic => + topic.title.toLowerCase().includes(search.toLowerCase()) || + topic.articles?.some(article => + article.title.toLowerCase().includes(search.toLowerCase()) ) - })).filter(cat => cat.topics.length > 0); + ); + + const handleArticleClick = (articleTitle) => { + alertSuccess('Próximamente', `${articleTitle} estará disponible pronto.`); + }; + + if (loading) { + return ( +
+
+ sync +
+

Cargando base de conocimientos...

+
+ ); + } + + if (error) { + return ( +
+
+ error_outline +
+

{error}

+ +
+ ); + } return (
@@ -68,58 +87,66 @@ const V2KnowledgeBase = () => { />
- {/* Categories List */} + {/* Topics List */}
- {filteredCategories.map(cat => ( -
+ {filteredTopics.map(topic => ( +
setExpandedCategory(expandedCategory === cat.id ? null : cat.id)} + onClick={() => setExpandedTopic(expandedTopic === topic.id ? null : topic.id)} role='button' tabIndex={0} - aria-expanded={expandedCategory === cat.id} - aria-label={cat.title} - onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setExpandedCategory(expandedCategory === cat.id ? null : cat.id); } }} + aria-expanded={expandedTopic === topic.id} + aria-label={topic.title} + onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setExpandedTopic(expandedTopic === topic.id ? null : topic.id); } }} >
-

{cat.title}

-

{cat.description}

+

{topic.title}

+

+ {topic.articles?.length || 0} artículo{topic.articles?.length !== 1 ? 's' : ''} disponible{topic.articles?.length !== 1 ? 's' : ''} +

-