Versión 1.0: Aplicación funcionalmente completa con todas las características principales implementadas.
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
// frontend/src/components/TablaTitulares.tsx
|
||||
|
||||
import {
|
||||
Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Chip, IconButton, Typography
|
||||
Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Chip, IconButton, Typography, Link
|
||||
} from '@mui/material';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import DragHandleIcon from '@mui/icons-material/DragHandle'; // Importar el ícono
|
||||
import DragHandleIcon from '@mui/icons-material/DragHandle';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import { DndContext, closestCenter, PointerSensor, useSensor, useSensors, type DragEndEvent } from '@dnd-kit/core';
|
||||
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import type { Titular } from '../types';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
|
||||
// La prop `onDelete` se añade para comunicar el evento al componente padre
|
||||
interface SortableRowProps {
|
||||
titular: Titular;
|
||||
onDelete: (id: number) => void;
|
||||
@@ -26,28 +25,45 @@ const SortableRow = ({ titular, onDelete, onEdit }: SortableRowProps) => {
|
||||
transition,
|
||||
};
|
||||
|
||||
const getChipColor = (tipo: Titular['tipo']) => {
|
||||
const getChipColor = (tipo: Titular['tipo']): "success" | "warning" | "info" => {
|
||||
if (tipo === 'Edited') return 'warning';
|
||||
if (tipo === 'Manual') return 'info';
|
||||
return 'success';
|
||||
};
|
||||
|
||||
const formatFuente = (fuente: string | null) => {
|
||||
if (!fuente) return 'N/A';
|
||||
try {
|
||||
const url = new URL(fuente);
|
||||
return url.hostname.replace('www.', '');
|
||||
} catch {
|
||||
return fuente;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow ref={setNodeRef} style={style} {...attributes} >
|
||||
{/* El handle de arrastre ahora es un ícono */}
|
||||
<TableCell sx={{ cursor: 'grab' }} {...listeners}>
|
||||
<DragHandleIcon />
|
||||
<TableRow ref={setNodeRef} style={style} {...attributes} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
|
||||
<TableCell sx={{ cursor: 'grab', verticalAlign: 'middle' }} {...listeners}>
|
||||
<DragHandleIcon sx={{ color: 'text.secondary' }} />
|
||||
</TableCell>
|
||||
<TableCell>{titular.texto}</TableCell>
|
||||
<TableCell>
|
||||
<TableCell sx={{ verticalAlign: 'middle' }}>{titular.texto}</TableCell>
|
||||
<TableCell sx={{ verticalAlign: 'middle' }}>
|
||||
<Chip label={titular.tipo || 'Scraped'} color={getChipColor(titular.tipo)} size="small" />
|
||||
</TableCell>
|
||||
<TableCell>{titular.fuente}</TableCell>
|
||||
<TableCell>
|
||||
<TableCell sx={{ verticalAlign: 'middle' }}>
|
||||
{titular.urlFuente ? (
|
||||
<Link href={titular.urlFuente} target="_blank" rel="noopener noreferrer" underline="hover" color="primary.light">
|
||||
{formatFuente(titular.fuente)}
|
||||
</Link>
|
||||
) : (
|
||||
formatFuente(titular.fuente)
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell sx={{ verticalAlign: 'middle', textAlign: 'right' }}>
|
||||
<IconButton size="small" onClick={(e) => { e.stopPropagation(); onEdit(titular); }}>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton size="small" onClick={(e) => { e.stopPropagation(); onDelete(titular.id); }}>
|
||||
<IconButton size="small" onClick={(e) => { e.stopPropagation(); onDelete(titular.id); }} sx={{ color: '#ef4444' }}>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
@@ -63,39 +79,38 @@ interface TablaTitularesProps {
|
||||
}
|
||||
|
||||
const TablaTitulares = ({ titulares, onReorder, onDelete, onEdit }: TablaTitularesProps) => {
|
||||
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 5 } })); // Evita activar el drag con un simple clic
|
||||
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } }));
|
||||
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (over && active.id !== over.id) {
|
||||
const oldIndex = titulares.findIndex((item) => item.id === active.id);
|
||||
const newIndex = titulares.findIndex((item) => item.id === over.id);
|
||||
const newArray = arrayMove(titulares, oldIndex, newIndex);
|
||||
onReorder(newArray); // Pasamos el nuevo array al padre para que gestione el estado y la llamada a la API
|
||||
onReorder(arrayMove(titulares, oldIndex, newIndex));
|
||||
}
|
||||
};
|
||||
|
||||
if (titulares.length === 0) {
|
||||
return (
|
||||
<Paper elevation={3} sx={{ padding: 3, textAlign: 'center' }}>
|
||||
<Paper elevation={0} sx={{ p: 3, textAlign: 'center' }}>
|
||||
<Typography>No hay titulares para mostrar.</Typography>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper elevation={3}>
|
||||
<Paper elevation={0} sx={{ overflow: 'hidden' }}>
|
||||
<TableContainer>
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={titulares.map(t => t.id)} strategy={verticalListSortingStrategy}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={{ width: 50 }}></TableCell>
|
||||
<TableCell>Texto del Titular</TableCell>
|
||||
<TableCell>Tipo</TableCell>
|
||||
<TableCell>Fuente</TableCell>
|
||||
<TableCell>Acciones</TableCell>
|
||||
<TableRow sx={{ '& .MuiTableCell-root': { borderBottom: '1px solid rgba(255, 255, 255, 0.12)' } }}>
|
||||
<TableCell sx={{ width: 50 }} />
|
||||
<TableCell sx={{ textTransform: 'uppercase', color: 'text.secondary', letterSpacing: '0.05em' }}>Texto del Titular</TableCell>
|
||||
<TableCell sx={{ textTransform: 'uppercase', color: 'text.secondary', letterSpacing: '0.05em' }}>Tipo</TableCell>
|
||||
<TableCell sx={{ textTransform: 'uppercase', color: 'text.secondary', letterSpacing: '0.05em' }}>Fuente</TableCell>
|
||||
<TableCell sx={{ textTransform: 'uppercase', color: 'text.secondary', letterSpacing: '0.05em', textAlign: 'right' }}>Acciones</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
|
||||
Reference in New Issue
Block a user