Proyecto ChatBot Con Gemini
This commit is contained in:
213
chatbot-admin/src/components/ContextManager.tsx
Normal file
213
chatbot-admin/src/components/ContextManager.tsx
Normal file
@@ -0,0 +1,213 @@
|
||||
// src/components/AdminPanel.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 EditIcon from '@mui/icons-material/Edit';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import apiClient from '../api/apiClient';
|
||||
|
||||
interface ContextoItem {
|
||||
id: number;
|
||||
clave: string;
|
||||
valor: string;
|
||||
descripcion: string;
|
||||
fechaActualizacion: string;
|
||||
}
|
||||
|
||||
interface ContextManagerProps {
|
||||
onAuthError: () => void;
|
||||
}
|
||||
|
||||
const ContextManager: React.FC<ContextManagerProps> = ({ onAuthError }) => {
|
||||
const [rows, setRows] = useState<ContextoItem[]>([]);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [currentRow, setCurrentRow] = useState<Partial<ContextoItem>>({});
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Estado para el diálogo de confirmación de borrado
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [itemToDelete, setItemToDelete] = useState<number | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
const response = await apiClient.get('/api/admin/contexto');
|
||||
setRows(response.data);
|
||||
} catch (err) {
|
||||
setError('No se pudieron cargar los datos.');
|
||||
if (axios.isAxiosError(err) && err.response?.status === 401) {
|
||||
onAuthError();
|
||||
}
|
||||
}
|
||||
}, [onAuthError]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
const handleOpen = (item?: ContextoItem) => {
|
||||
if (item) {
|
||||
setIsEdit(true);
|
||||
setCurrentRow(item);
|
||||
} else {
|
||||
setIsEdit(false);
|
||||
setCurrentRow({ clave: '', valor: '', descripcion: '' });
|
||||
}
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
if (isEdit) {
|
||||
await apiClient.put(`/api/admin/contexto/${currentRow.id}`, currentRow);
|
||||
} else {
|
||||
await apiClient.post('/api/admin/contexto', currentRow);
|
||||
}
|
||||
fetchData();
|
||||
handleClose();
|
||||
} catch (err) {
|
||||
setError('Error al guardar el item.');
|
||||
}
|
||||
};
|
||||
|
||||
// Abre el diálogo de confirmación
|
||||
const handleDeleteClick = (id: number) => {
|
||||
setItemToDelete(id);
|
||||
setConfirmOpen(true);
|
||||
};
|
||||
|
||||
// Cierra el diálogo de confirmación
|
||||
const handleConfirmClose = () => {
|
||||
setConfirmOpen(false);
|
||||
setItemToDelete(null);
|
||||
};
|
||||
|
||||
// Ejecuta la eliminación si se confirma
|
||||
const handleConfirmDelete = async () => {
|
||||
if (itemToDelete !== null) {
|
||||
try {
|
||||
await apiClient.delete(`/api/admin/contexto/${itemToDelete}`);
|
||||
fetchData();
|
||||
} catch (err) {
|
||||
setError('Error al eliminar el item.');
|
||||
} finally {
|
||||
handleConfirmClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const columns: GridColDef[] = [
|
||||
{ field: 'clave', headerName: 'Clave', width: 200 },
|
||||
{ field: 'valor', headerName: 'Valor', width: 350 },
|
||||
{ field: 'descripcion', headerName: 'Descripción', flex: 1 },
|
||||
{
|
||||
field: 'fechaActualizacion',
|
||||
headerName: 'Última Actualización',
|
||||
width: 200,
|
||||
valueGetter: (value) => new Date(value).toLocaleString(),
|
||||
},
|
||||
{
|
||||
field: 'actions',
|
||||
type: 'actions',
|
||||
width: 100,
|
||||
getActions: (params) => [
|
||||
<GridActionsCellItem
|
||||
icon={<EditIcon />}
|
||||
label="Editar"
|
||||
onClick={() => handleOpen(params.row as ContextoItem)}
|
||||
/>,
|
||||
<GridActionsCellItem
|
||||
icon={<DeleteIcon />}
|
||||
label="Eliminar"
|
||||
// Llama a la función que abre el diálogo
|
||||
onClick={() => handleDeleteClick(params.id as number)}
|
||||
/>,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 4 }}>
|
||||
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
|
||||
<Button startIcon={<AddIcon />} variant="contained" onClick={() => handleOpen()} sx={{ mb: 1 }}>
|
||||
Añadir Nuevo Item
|
||||
</Button>
|
||||
<Box sx={{ height: 600, width: '100%' }}>
|
||||
<DataGrid rows={rows} columns={columns} pageSizeOptions={[10, 25, 50, 100]} />
|
||||
</Box>
|
||||
<Box sx={{ p: 4 }}>
|
||||
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
|
||||
<Button startIcon={<AddIcon />} variant="contained" onClick={() => handleOpen()} sx={{ mb: 1 }}>
|
||||
Añadir Nuevo Item
|
||||
</Button>
|
||||
<Box sx={{ height: 600, width: '100%' }}>
|
||||
<DataGrid rows={rows} columns={columns} pageSizeOptions={[10, 25, 50, 100]} />
|
||||
</Box>
|
||||
|
||||
{/* --- DIÁLOGO DE EDICIÓN/CREACIÓN --- */}
|
||||
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="sm">
|
||||
<DialogTitle>{isEdit ? 'Editar Item' : 'Añadir Nuevo Item'}</DialogTitle>
|
||||
<DialogContent>
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="Clave"
|
||||
fullWidth
|
||||
value={currentRow.clave || ''}
|
||||
disabled={isEdit} // La clave no se puede editar una vez creada
|
||||
onChange={(e) => setCurrentRow({ ...currentRow, clave: e.target.value })}
|
||||
helperText={!isEdit ? "Esta clave no se podrá modificar en el futuro." : ""}
|
||||
/>
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="Valor"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
value={currentRow.valor || ''}
|
||||
onChange={(e) => setCurrentRow({ ...currentRow, valor: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="Descripción"
|
||||
fullWidth
|
||||
value={currentRow.descripcion || ''}
|
||||
onChange={(e) => setCurrentRow({ ...currentRow, descripcion: e.target.value })}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose}>Cancelar</Button>
|
||||
<Button onClick={handleSave} variant="contained">Guardar</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* --- DIÁLOGO DE CONFIRMACIÓN DE BORRADO --- */}
|
||||
<Dialog
|
||||
open={confirmOpen}
|
||||
onClose={handleConfirmClose}
|
||||
>
|
||||
<DialogTitle>Confirmar Eliminación</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
¿Estás seguro de que quieres eliminar este item? Esta acción no se puede deshacer.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleConfirmClose}>Cancelar</Button>
|
||||
<Button onClick={handleConfirmDelete} color="error" variant="contained">
|
||||
Eliminar
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContextManager;
|
||||
Reference in New Issue
Block a user