From 7e9e3ba87ea7689f25bb1249a1b1b8f84f87f966 Mon Sep 17 00:00:00 2001 From: dmolinari Date: Fri, 5 Dec 2025 13:21:24 -0300 Subject: [PATCH] Feat: Estetico - Se aplican estilos al resto de controles por uniformidad. --- chatbot-admin/src/components/AdminPanel.tsx | 73 ++++++--- .../src/components/ContextManager.tsx | 155 +++++++++--------- chatbot-admin/src/components/Login.tsx | 129 +++++++++------ chatbot-admin/src/components/LogsViewer.tsx | 39 +++-- .../src/components/SourceManager.tsx | 44 ++++- 5 files changed, 267 insertions(+), 173 deletions(-) diff --git a/chatbot-admin/src/components/AdminPanel.tsx b/chatbot-admin/src/components/AdminPanel.tsx index fdaf32a..acbdf62 100644 --- a/chatbot-admin/src/components/AdminPanel.tsx +++ b/chatbot-admin/src/components/AdminPanel.tsx @@ -1,12 +1,12 @@ // EN: src/components/AdminPanel.tsx import React, { useState } from 'react'; -import { Box, Typography, AppBar, Toolbar, IconButton, Tabs, Tab } from '@mui/material'; +import { Box, Typography, AppBar, Toolbar, IconButton, Tabs, Tab, Container } from '@mui/material'; import LogoutIcon from '@mui/icons-material/Logout'; +import SmartToyIcon from '@mui/icons-material/SmartToy'; import ContextManager from './ContextManager'; import LogsViewer from './LogsViewer'; import SourceManager from './SourceManager'; - import SystemPromptManager from './SystemPromptManager'; interface AdminPanelProps { @@ -21,28 +21,57 @@ const AdminPanel: React.FC = ({ onLogout }) => { }; return ( - - - - - Panel de Administración del Chatbot - - - - - - - - - - - + + + + + + + Chatbot Admin + + + + + + + + + + + + - {currentTab === 0 && } - {currentTab === 1 && } - {currentTab === 2 && } - {currentTab === 3 && } + + + {currentTab === 0 && } + {currentTab === 1 && } + {currentTab === 2 && } + {currentTab === 3 && } + + ); }; diff --git a/chatbot-admin/src/components/ContextManager.tsx b/chatbot-admin/src/components/ContextManager.tsx index 4311ee5..39d9b07 100644 --- a/chatbot-admin/src/components/ContextManager.tsx +++ b/chatbot-admin/src/components/ContextManager.tsx @@ -1,9 +1,9 @@ -// src/components/AdminPanel.tsx +// src/components/ContextManager.tsx import React, { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import { DataGrid, GridActionsCellItem } from '@mui/x-data-grid'; import type { GridColDef } from '@mui/x-data-grid'; -import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Alert, DialogContentText, TextField } from '@mui/material'; +import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Alert, DialogContentText, TextField, Card, Typography } from '@mui/material'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import AddIcon from '@mui/icons-material/Add'; @@ -122,90 +122,99 @@ const ContextManager: React.FC = ({ onAuthError }) => { icon={} label="Editar" onClick={() => handleOpen(params.row as ContextoItem)} + color="inherit" />, } label="Eliminar" - // Llama a la función que abre el diálogo onClick={() => handleDeleteClick(params.id as number)} + color="inherit" />, ], }, ]; return ( - - {error && {error}} - - - - - - {error && {error}} - - - - - - {/* --- DIÁLOGO DE EDICIÓN/CREACIÓN --- */} - - {isEdit ? 'Editar Item' : 'Añadir Nuevo Item'} - - setCurrentRow({ ...currentRow, clave: e.target.value })} - helperText={!isEdit ? "Esta clave no se podrá modificar en el futuro." : ""} - /> - setCurrentRow({ ...currentRow, valor: e.target.value })} - /> - setCurrentRow({ ...currentRow, descripcion: e.target.value })} - /> - - - - - - - - {/* --- DIÁLOGO DE CONFIRMACIÓN DE BORRADO --- */} - + + Gestor de Contexto + - - - + Nuevo Item + + + {error && {error}} + + + + + + + + {/* --- DIÁLOGO DE EDICIÓN/CREACIÓN --- */} + + {isEdit ? 'Editar Item' : 'Añadir Nuevo Item'} + + setCurrentRow({ ...currentRow, clave: e.target.value })} + helperText={!isEdit ? "Esta clave no se podrá modificar en el futuro." : ""} + /> + setCurrentRow({ ...currentRow, valor: e.target.value })} + /> + setCurrentRow({ ...currentRow, descripcion: e.target.value })} + /> + + + + + + + + {/* --- DIÁLOGO DE CONFIRMACIÓN DE BORRADO --- */} + + Confirmar Eliminación + + + ¿Estás seguro de que quieres eliminar este item? Esta acción no se puede deshacer. + + + + + + + ); }; diff --git a/chatbot-admin/src/components/Login.tsx b/chatbot-admin/src/components/Login.tsx index f6fc235..36aa1a6 100644 --- a/chatbot-admin/src/components/Login.tsx +++ b/chatbot-admin/src/components/Login.tsx @@ -1,6 +1,7 @@ // src/components/Login.tsx import React from 'react'; -import { Box, Button, TextField, Typography, Paper, Alert } from '@mui/material'; +import { Box, Button, TextField, Typography, Card, CardContent, Alert } from '@mui/material'; +import apiClient from '../api/apiClient'; interface LoginProps { onLoginSuccess: (token: string) => void; @@ -10,70 +11,94 @@ const Login: React.FC = ({ onLoginSuccess }) => { const [username, setUsername] = React.useState(''); const [password, setPassword] = React.useState(''); const [error, setError] = React.useState(''); + const [loading, setLoading] = React.useState(false); const handleLogin = async (event: React.FormEvent) => { event.preventDefault(); setError(''); + setLoading(true); try { - // Usamos la variable de entorno para la URL de la API - const response = await fetch(`${import.meta.env.VITE_API_BASE_URL}/api/auth/login`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username, password }), - }); + // Using apiClient ensures consistently handled headers/configs + const response = await apiClient.post('/api/auth/login', { username, password }); - if (response.ok) { - const data = await response.json(); - onLoginSuccess(data.token); + // Axios returns data directly in response.data + if (response.data && response.data.token) { + onLoginSuccess(response.data.token); } else { - setError('Usuario o contraseña incorrectos.'); + setError('Respuesta inesperada del servidor.'); } - } catch (err) { - setError('No se pudo conectar con el servidor. Inténtalo de nuevo más tarde.'); + } catch (err: any) { + console.error(err); + if (err.response && err.response.status === 401) { + setError('Usuario o contraseña incorrectos.'); + } else { + setError('No se pudo conectar con el servidor.'); + } + } finally { + setLoading(false); } }; return ( - - - - Iniciar Sesión - - - Gestor de Contexto del Chatbot - -
- setUsername(e.target.value)} - autoFocus - /> - setPassword(e.target.value)} - /> - {error && {error}} - - -
+ + + + + + Bienvenido + + + Inicia sesión para gestionar el Chatbot + + + +
+ setUsername(e.target.value)} + autoFocus + sx={{ bgcolor: 'rgba(255,255,255,0.05)' }} + /> + setPassword(e.target.value)} + sx={{ bgcolor: 'rgba(255,255,255,0.05)' }} + /> + + {error && {error}} + + + +
+
); }; diff --git a/chatbot-admin/src/components/LogsViewer.tsx b/chatbot-admin/src/components/LogsViewer.tsx index 03ec727..704d4b6 100644 --- a/chatbot-admin/src/components/LogsViewer.tsx +++ b/chatbot-admin/src/components/LogsViewer.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import { DataGrid, type GridColDef } from '@mui/x-data-grid'; -import { Box, Typography, Alert } from '@mui/material'; +import { Box, Typography, Alert, Card } from '@mui/material'; import apiClient from '../api/apiClient'; interface ConversacionLog { @@ -66,23 +66,28 @@ const LogsViewer: React.FC = ({ onAuthError }) => { ]; return ( - - - Historial de Conversaciones - - {error && {error}} - - + + + Historial de Conversaciones + + {error && {error}} + + + + + + ); }; diff --git a/chatbot-admin/src/components/SourceManager.tsx b/chatbot-admin/src/components/SourceManager.tsx index de183b8..2b67d34 100644 --- a/chatbot-admin/src/components/SourceManager.tsx +++ b/chatbot-admin/src/components/SourceManager.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import { DataGrid, GridActionsCellItem } from '@mui/x-data-grid'; import type { GridColDef } from '@mui/x-data-grid'; -import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Alert, TextField, Chip, Switch, FormControlLabel } from '@mui/material'; +import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Alert, TextField, Chip, Switch, FormControlLabel, Card, Typography } from '@mui/material'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import AddIcon from '@mui/icons-material/Add'; @@ -109,7 +109,12 @@ const SourceManager: React.FC = ({ onAuthError }) => { headerName: 'Activo', width: 100, renderCell: (params) => ( - + ), }, { @@ -121,25 +126,45 @@ const SourceManager: React.FC = ({ onAuthError }) => { icon={} label="Editar" onClick={() => handleOpen(params.row as FuenteContexto)} + color="inherit" />, } label="Eliminar" onClick={() => handleDeleteClick(params.id as number)} + color="inherit" // Keeping it generic to avoid type errors />, ], }, ]; return ( - - {error && {error}} - - - + + + Gestor de Fuentes + + + {error && {error}} + + + + + + + {isEdit ? 'Editar Fuente' : 'Añadir Nueva Fuente'} @@ -186,6 +211,7 @@ const SourceManager: React.FC = ({ onAuthError }) => { /> } label="Fuente activa" + sx={{ mt: 2 }} />