213 lines
6.8 KiB
TypeScript
213 lines
6.8 KiB
TypeScript
// 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; |