se agrego paginacion a datastage

This commit is contained in:
2025-08-21 12:54:35 -06:00
parent da454447a9
commit c401bb7889

View File

@@ -117,6 +117,8 @@ function downloadDatastageFile(id, filename) {
export default function Datastage() {
const focusKeeperRef = useRef(null);
const [datastages, setDatastages] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const [selected, setSelected] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
@@ -347,7 +349,7 @@ export default function Datastage() {
</tr>
</thead>
<tbody>
{datastages.map(item => (
{datastages.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage).map(item => (
<tr key={item.id} className="hover:bg-slate-50 transition-colors">
<td className="border px-2 py-2 text-center">{item.id}</td>
<td className="border px-2 py-2 max-w-xs truncate">
@@ -415,12 +417,12 @@ export default function Datastage() {
</button>
<button
onClick={() => procesarDatastage(item, setDatastages, setSuccess, setError, setRegistrosCargados, setShowRegistrosModal)}
className={`inline-flex items-center justify-center w-9 h-9 rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-1 ${item.procesado ? 'bg-gray-100 border-gray-200 cursor-not-allowed opacity-50' : 'bg-green-50 border-green-200 hover:bg-green-100 hover:border-green-300 focus:ring-green-500 cursor-pointer'}`}
title={item.procesado ? 'Ya procesado' : 'Procesar'}
disabled={item.procesado}
className={`inline-flex items-center justify-center w-9 h-9 rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-1 ${item.procesado ? 'bg-gray-100 border-gray-200 cursor-not-allowed opacity-50' : 'bg-green-50 border-green-200 hover:bg-green-100 hover:border-green-300 focus:ring-green-500 cursor-pointer'}`}
title={item.procesado ? 'Ya procesado' : 'Procesar'}
disabled={item.procesado}
>
<svg className="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
<path d="M8 5v14l11-7z" />
</svg>
</button>
</td>
@@ -428,6 +430,40 @@ export default function Datastage() {
))}
</tbody>
</table>
{/* Paginación */}
{datastages.length > itemsPerPage && (
<div className="flex flex-col sm:flex-row items-center justify-between gap-2 px-4 py-4 border-t border-gray-200">
<div className="text-xs text-gray-700">
Mostrando <span className="font-medium">{((currentPage - 1) * itemsPerPage) + 1}</span> a <span className="font-medium">{Math.min(currentPage * itemsPerPage, datastages.length)}</span> de <span className="font-medium">{datastages.length}</span> registros
</div>
<div className="flex items-center gap-1">
<button
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
disabled={currentPage === 1}
className="px-2 py-1 rounded border text-xs bg-white hover:bg-blue-50 disabled:opacity-50"
>Anterior</button>
{Array.from({ length: Math.ceil(datastages.length / itemsPerPage) }, (_, i) => i + 1).map(pageNum => (
<button
key={pageNum}
onClick={() => setCurrentPage(pageNum)}
className={`px-2 py-1 rounded text-xs border ${currentPage === pageNum ? 'bg-blue-600 text-white' : 'bg-white hover:bg-blue-50'}`}
>{pageNum}</button>
))}
<button
onClick={() => setCurrentPage(p => Math.min(Math.ceil(datastages.length / itemsPerPage), p + 1))}
disabled={currentPage === Math.ceil(datastages.length / itemsPerPage)}
className="px-2 py-1 rounded border text-xs bg-white hover:bg-blue-50 disabled:opacity-50"
>Siguiente</button>
<select
value={itemsPerPage}
onChange={e => { setItemsPerPage(Number(e.target.value)); setCurrentPage(1); }}
className="ml-2 px-2 py-1 border rounded text-xs"
>
{[10, 20, 50, 100].map(n => (<option key={n} value={n}>{n} por página</option>))}
</select>
</div>
</div>
)}
</div>
{/* Tarjetas para móvil/tablet */}
<div className="lg:hidden space-y-4 p-2">
@@ -497,7 +533,7 @@ export default function Datastage() {
disabled={item.procesado}
>
<svg className="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z"/>
<path d="M8 5v14l11-7z" />
</svg>
</button>
</div>
@@ -509,140 +545,140 @@ export default function Datastage() {
{/* Modales */}
{/* Modal de creación - estilo Users/Importers */}
{showCreateModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<form onSubmit={handleCreate} className="relative mx-auto w-full max-w-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-blue-700 to-blue-900 rounded-t-2xl p-4 text-white border-b-2 border-blue-500">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-blue-500 bg-opacity-30 rounded-xl p-2 border border-blue-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Nuevo Datastage</h3>
<p className="text-blue-200 text-xs font-medium">Carga un archivo .zip y asigna un contribuyente</p>
</div>
</div>
<button type="button" onClick={() => setShowCreateModal(false)} className="text-blue-100 hover:text-white hover:bg-blue-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-blue-500 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
{error && <div className="text-red-500 mb-2">{error}</div>}
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Archivo (.zip)</label>
<input type="file" accept=".zip" className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" onChange={e => setForm(f => ({ ...f, archivo: e.target.files[0] }))} required />
</div>
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Contribuyente</label>
<input className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" value={form.contribuyente} onChange={e => setForm(f => ({ ...f, contribuyente: e.target.value }))} required />
</div>
<div className="flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3 pt-4 border-t border-slate-200">
<button type="button" onClick={() => setShowCreateModal(false)} className="w-full sm:w-auto px-6 py-2 border border-slate-300 rounded-md shadow-sm text-sm font-semibold text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="submit" className="w-full sm:w-auto px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-blue-700 to-blue-900 hover:from-blue-800 hover:to-blue-950 focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Crear</button>
</div>
</div>
</form>
</div>
)}
{/* Modal de edición - estilo Users/Importers */}
{showEditModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<form onSubmit={handleEdit} className="relative mx-auto w-full max-w-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-yellow-600 to-yellow-800 rounded-t-2xl p-4 text-white border-b-2 border-yellow-400">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-yellow-500 bg-opacity-30 rounded-xl p-2 border border-yellow-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15.232 5.232l3.536 3.536M9 13l6-6 3.536 3.536a2 2 0 010 2.828l-7.072 7.072a2 2 0 01-2.828 0l-3.536-3.536a2 2 0 010-2.828l7.072-7.072z" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Editar Datastage</h3>
<p className="text-yellow-200 text-xs font-medium">Actualiza el archivo o el contribuyente</p>
</div>
</div>
<button type="button" onClick={handleCancelEdit} className="text-yellow-100 hover:text-white hover:bg-yellow-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-yellow-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
{error && <div className="text-red-500 mb-2">{error}</div>}
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Archivo (.zip)</label>
<input type="file" accept=".zip" className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-yellow-500 focus:border-yellow-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" onChange={e => setForm(f => ({ ...f, archivo: e.target.files[0] }))} />
</div>
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Contribuyente</label>
<input className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-yellow-500 focus:border-yellow-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" value={form.contribuyente} onChange={e => setForm(f => ({ ...f, contribuyente: e.target.value }))} required />
</div>
<div className="flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3 pt-4 border-t border-slate-200">
<button type="button" onClick={handleCancelEdit} className="w-full sm:w-auto px-6 py-2 border border-slate-300 rounded-md shadow-sm text-sm font-semibold text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="submit" className="w-full sm:w-auto px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-yellow-600 to-yellow-800 hover:from-yellow-700 hover:to-yellow-900 focus:ring-yellow-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Actualizar</button>
</div>
</div>
</form>
</div>
)}
{/* Modal de eliminación - estilo Users/Importers */}
{showDeleteModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<div className="relative mx-auto w-full max-w-md bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-red-700 to-red-900 rounded-t-2xl p-4 text-white border-b-2 border-red-500">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-red-500 bg-opacity-30 rounded-xl p-2 border border-red-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Eliminar Datastage</h3>
<p className="text-red-200 text-xs font-medium">Esta acción no se puede deshacer.</p>
</div>
</div>
<button type="button" onClick={() => setShowDeleteModal(false)} className="text-red-100 hover:text-white hover:bg-red-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-red-500 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 text-center">
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 mb-4">
<svg className="h-6 w-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">¿Eliminar este datastage?</h3>
<p className="text-sm text-gray-500 mb-4">¿Seguro que deseas eliminar este datastage? Esta acción no se puede deshacer.</p>
<div className="flex justify-center space-x-3 pt-4">
<button type="button" onClick={() => setShowDeleteModal(false)} className="px-6 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-semibold text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="button" onClick={handleDelete} className="px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-red-700 to-red-900 hover:from-red-800 hover:to-red-950 focus:ring-red-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Eliminar</button>
</div>
</div>
{/* Modal de creación - estilo Users/Importers */}
{showCreateModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<form onSubmit={handleCreate} className="relative mx-auto w-full max-w-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-blue-700 to-blue-900 rounded-t-2xl p-4 text-white border-b-2 border-blue-500">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-blue-500 bg-opacity-30 rounded-xl p-2 border border-blue-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Nuevo Datastage</h3>
<p className="text-blue-200 text-xs font-medium">Carga un archivo .zip y asigna un contribuyente</p>
</div>
</div>
)}
<button type="button" onClick={() => setShowCreateModal(false)} className="text-blue-100 hover:text-white hover:bg-blue-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-blue-500 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4 ">
{error && <div className="text-red-500 mb-2">{error}</div>}
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Archivo (.zip)</label>
<input type="file" accept=".zip" className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" onChange={e => setForm(f => ({ ...f, archivo: e.target.files[0] }))} required />
</div>
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Contribuyente</label>
<input className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" value={form.contribuyente} onChange={e => setForm(f => ({ ...f, contribuyente: e.target.value }))} required />
</div>
<div className="flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3 pt-4 border-t border-slate-200">
<button type="button" onClick={() => setShowCreateModal(false)} className="w-full sm:w-auto px-6 py-2 border border-slate-300 rounded-md shadow-sm text-sm font-semibold text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="submit" className="w-full sm:w-auto px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-blue-700 to-blue-900 hover:from-blue-800 hover:to-blue-950 focus:ring-blue-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Crear</button>
</div>
</div>
</form>
</div>
)}
{/* Modal de edición - estilo Users/Importers */}
{showEditModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<form onSubmit={handleEdit} className="relative mx-auto w-full max-w-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-yellow-600 to-yellow-800 rounded-t-2xl p-4 text-white border-b-2 border-yellow-400">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-yellow-500 bg-opacity-30 rounded-xl p-2 border border-yellow-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15.232 5.232l3.536 3.536M9 13l6-6 3.536 3.536a2 2 0 010 2.828l-7.072 7.072a2 2 0 01-2.828 0l-3.536-3.536a2 2 0 010-2.828l7.072-7.072z" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Editar Datastage</h3>
<p className="text-yellow-200 text-xs font-medium">Actualiza el archivo o el contribuyente</p>
</div>
</div>
<button type="button" onClick={handleCancelEdit} className="text-yellow-100 hover:text-white hover:bg-yellow-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-yellow-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
{error && <div className="text-red-500 mb-2">{error}</div>}
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Archivo (.zip)</label>
<input type="file" accept=".zip" className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-yellow-500 focus:border-yellow-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" onChange={e => setForm(f => ({ ...f, archivo: e.target.files[0] }))} />
</div>
<div>
<label className="block text-xs font-semibold text-slate-700 mb-1">Contribuyente</label>
<input className="w-full border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-yellow-500 focus:border-yellow-500 transition-all duration-200 bg-white text-slate-900 placeholder-slate-400 text-sm" value={form.contribuyente} onChange={e => setForm(f => ({ ...f, contribuyente: e.target.value }))} required />
</div>
<div className="flex flex-col sm:flex-row justify-end space-y-2 sm:space-y-0 sm:space-x-3 pt-4 border-t border-slate-200">
<button type="button" onClick={handleCancelEdit} className="w-full sm:w-auto px-6 py-2 border border-slate-300 rounded-md shadow-sm text-sm font-semibold text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="submit" className="w-full sm:w-auto px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-yellow-600 to-yellow-800 hover:from-yellow-700 hover:to-yellow-900 focus:ring-yellow-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Actualizar</button>
</div>
</div>
</form>
</div>
)}
{/* Modal de eliminación - estilo Users/Importers */}
{showDeleteModal && (
<div className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4">
<div className="relative mx-auto w-full max-w-md bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
{/* Header */}
<div className="bg-gradient-to-r from-red-700 to-red-900 rounded-t-2xl p-4 text-white border-b-2 border-red-500">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<div className="bg-red-500 bg-opacity-30 rounded-xl p-2 border border-red-400 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<div>
<h3 className="text-lg font-semibold tracking-wide">Eliminar Datastage</h3>
<p className="text-red-200 text-xs font-medium">Esta acción no se puede deshacer.</p>
</div>
</div>
<button type="button" onClick={() => setShowDeleteModal(false)} className="text-red-100 hover:text-white hover:bg-red-600 transition-colors p-2 hover:bg-opacity-50 rounded-lg border border-red-500 border-opacity-30">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* Content */}
<div className="p-6 text-center">
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 mb-4">
<svg className="h-6 w-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">¿Eliminar este datastage?</h3>
<p className="text-sm text-gray-500 mb-4">¿Seguro que deseas eliminar este datastage? Esta acción no se puede deshacer.</p>
<div className="flex justify-center space-x-3 pt-4">
<button type="button" onClick={() => setShowDeleteModal(false)} className="px-6 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-semibold text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500 transition-all duration-200">Cancelar</button>
<button type="button" onClick={handleDelete} className="px-6 py-2 border border-transparent rounded-md shadow-lg text-sm font-semibold text-white bg-gradient-to-r from-red-700 to-red-900 hover:from-red-800 hover:to-red-950 focus:ring-red-500 focus:outline-none focus:ring-2 focus:ring-offset-2 transition-all duration-200 flex items-center justify-center space-x-2">Eliminar</button>
</div>
</div>
</div>
</div>
)}
{/* Modal de detalle */}
{showDetailModal && selected && (