Se agrego modificacon de creacion de importador
This commit is contained in:
@@ -201,7 +201,12 @@ export default function Importers() {
|
|||||||
</h3>
|
</h3>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => { setModalMode('create'); setModalData({ rfc: '', nombre: '', organizacion: '' }); setErrorMsg(''); setModalOpen(true); }}
|
onClick={() => {
|
||||||
|
setModalMode('create');
|
||||||
|
setModalData({ rfc: '', nombre: '', organizacion: '' });
|
||||||
|
setErrorMsg('');
|
||||||
|
setModalOpen(true);
|
||||||
|
}}
|
||||||
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-semibold text-xs sm:text-sm shadow-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-semibold text-xs sm:text-sm shadow-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -279,183 +284,183 @@ export default function Importers() {
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
{/* Modal moved outside table for valid JSX and Users.jsx style will be applied below */}
|
|
||||||
{/* MODALS: Styled like Users.jsx, rendered outside the table for valid JSX */}
|
|
||||||
{modalOpen && (
|
|
||||||
<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-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
|
|
||||||
{/* Modal Header */}
|
|
||||||
<div className={`bg-gradient-to-r ${modalMode === 'delete' ? 'from-red-700 to-red-900 border-red-500' : 'from-blue-700 to-blue-900 border-blue-500'} rounded-t-2xl p-4 text-white border-b-2`}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<div className={`${modalMode === 'delete' ? 'bg-red-500 border-red-400' : 'bg-blue-500 border-blue-400'} bg-opacity-30 rounded-xl p-2 border border-opacity-30`}>
|
|
||||||
{modalMode === 'delete' ? (
|
|
||||||
<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>
|
|
||||||
) : (
|
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="text-lg font-semibold tracking-wide">
|
|
||||||
{modalMode === 'delete' ? 'Eliminar Importador' : modalMode === 'edit' ? 'Editar Importador' : 'Ver Importador'}
|
|
||||||
</h3>
|
|
||||||
<p className={`${modalMode === 'delete' ? 'text-red-200' : 'text-blue-200'} text-xs font-medium`}>
|
|
||||||
{modalMode === 'delete' ? 'Esta acción no se puede deshacer.' : 'Sistema de Gestión de Importadores'}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={closeModal}
|
|
||||||
className={`${modalMode === 'delete' ? 'text-red-100 hover:text-white hover:bg-red-600' : 'text-blue-100 hover:text-white hover:bg-blue-600'} transition-colors p-2 hover:bg-opacity-50 rounded-lg border ${modalMode === 'delete' ? 'border-red-500' : '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>
|
|
||||||
|
|
||||||
{/* Modal Content */}
|
|
||||||
<div className="p-6">
|
|
||||||
{modalMode === 'delete' ? (
|
|
||||||
<div className="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 Importador?</h3>
|
|
||||||
<div className="mt-2 px-7 py-3">
|
|
||||||
<p className="text-sm text-gray-500 mb-4">
|
|
||||||
¿Estás seguro que deseas eliminar el importador <strong>{modalData.nombre}</strong> (RFC: <strong>{modalData.rfc}</strong>)?
|
|
||||||
</p>
|
|
||||||
<div className="bg-gray-50 rounded-md p-3 mb-4">
|
|
||||||
<div className="flex items-center justify-center">
|
|
||||||
<div className="h-10 w-10 rounded-full bg-gray-300 flex items-center justify-center">
|
|
||||||
<svg className="h-6 w-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div className="ml-3 text-left">
|
|
||||||
<p className="text-sm font-medium text-gray-900">{modalData.nombre}</p>
|
|
||||||
<p className="text-xs text-gray-500">RFC: {modalData.rfc}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{errorMsg && <div className="text-red-500 mb-2 w-full">{errorMsg}</div>}
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-center space-x-3 pt-4">
|
|
||||||
<button type="button" onClick={closeModal} disabled={modalLoading} 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 disabled:opacity-50">Cancelar</button>
|
|
||||||
<button type="button" onClick={handleDeleteConfirm} disabled={modalLoading} 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 disabled:opacity-50 disabled:cursor-not-allowed">{modalLoading ? (<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>) : null}{modalLoading ? 'Eliminando...' : 'Eliminar Importador'}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<form onSubmit={async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setModalLoading(true);
|
|
||||||
setErrorMsg('');
|
|
||||||
try {
|
|
||||||
let res;
|
|
||||||
if (modalMode === 'edit') {
|
|
||||||
res = await fetchWithAuth(`${API_URL}/customs/importadores/${modalData.rfc}/`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ rfc: modalData.rfc, nombre: modalData.nombre, organizacion: modalData.organizacion })
|
|
||||||
});
|
|
||||||
if (!res.ok) throw new Error('Error al actualizar importador');
|
|
||||||
} else if (modalMode === 'create') {
|
|
||||||
res = await fetchWithAuth(`${API_URL}/customs/importadores/`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ rfc: modalData.rfc, nombre: modalData.nombre, organizacion: modalData.organizacion })
|
|
||||||
});
|
|
||||||
if (!res.ok) throw new Error('Error al crear importador');
|
|
||||||
}
|
|
||||||
// Refrescar lista
|
|
||||||
const res2 = await fetchWithAuth(`${API_URL}/customs/importadores/`);
|
|
||||||
if (!res2.ok) throw new Error('Error al obtener importadores');
|
|
||||||
const data = await res2.json();
|
|
||||||
setImporters(Array.isArray(data) ? data : []);
|
|
||||||
closeModal();
|
|
||||||
} catch {
|
|
||||||
setErrorMsg(modalMode === 'create' ? 'Error al crear importador' : 'Error al actualizar importador');
|
|
||||||
} finally {
|
|
||||||
setModalLoading(false);
|
|
||||||
}
|
|
||||||
}} className="space-y-5">
|
|
||||||
<div>
|
|
||||||
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">RFC</label>
|
|
||||||
<input
|
|
||||||
name="rfc"
|
|
||||||
type="text"
|
|
||||||
value={modalData.rfc}
|
|
||||||
readOnly={modalMode !== 'create'}
|
|
||||||
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'create' ? 'bg-white' : 'bg-gray-100'} text-slate-900 placeholder-slate-400 text-sm`}
|
|
||||||
onChange={modalMode === 'create' ? handleModalChange : undefined}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">Nombre</label>
|
|
||||||
<input
|
|
||||||
name="nombre"
|
|
||||||
type="text"
|
|
||||||
value={modalData.nombre}
|
|
||||||
onChange={modalMode !== 'view' ? handleModalChange : undefined}
|
|
||||||
readOnly={modalMode === 'view'}
|
|
||||||
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'view' ? 'bg-gray-100' : 'bg-white'} text-slate-900 placeholder-slate-400 text-sm`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">Organización</label>
|
|
||||||
<input
|
|
||||||
name="organizacion"
|
|
||||||
type="text"
|
|
||||||
value={modalData.organizacion}
|
|
||||||
onChange={modalMode !== 'view' ? handleModalChange : undefined}
|
|
||||||
readOnly={modalMode === 'view'}
|
|
||||||
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'view' ? 'bg-gray-100' : 'bg-white'} text-slate-900 placeholder-slate-400 text-sm`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{errorMsg && <div className="text-red-500 mt-2 text-sm text-center">{errorMsg}</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">
|
|
||||||
{modalMode !== 'view' && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={closeModal}
|
|
||||||
disabled={modalLoading}
|
|
||||||
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 disabled:opacity-50"
|
|
||||||
>
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{(modalMode === 'edit' || modalMode === 'create') && (
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
disabled={modalLoading}
|
|
||||||
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 disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
||||||
>
|
|
||||||
{modalLoading && (
|
|
||||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
|
||||||
)}
|
|
||||||
{modalLoading ? (modalMode === 'create' ? 'Creando...' : 'Actualizando...') : (modalMode === 'create' ? 'Crear' : 'Actualizar')}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
{/* Modal rendering outside table and empty state, always available */}
|
||||||
|
{modalOpen && (
|
||||||
|
<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-xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
|
||||||
|
{/* Modal Header */}
|
||||||
|
<div className={`bg-gradient-to-r ${modalMode === 'delete' ? 'from-red-700 to-red-900 border-red-500' : 'from-blue-700 to-blue-900 border-blue-500'} rounded-t-2xl p-4 text-white border-b-2`}>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
<div className={`${modalMode === 'delete' ? 'bg-red-500 border-red-400' : 'bg-blue-500 border-blue-400'} bg-opacity-30 rounded-xl p-2 border border-opacity-30`}>
|
||||||
|
{modalMode === 'delete' ? (
|
||||||
|
<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>
|
||||||
|
) : (
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold tracking-wide">
|
||||||
|
{modalMode === 'delete' ? 'Eliminar Importador' : modalMode === 'edit' ? 'Editar Importador' : 'Ver Importador'}
|
||||||
|
</h3>
|
||||||
|
<p className={`${modalMode === 'delete' ? 'text-red-200' : 'text-blue-200'} text-xs font-medium`}>
|
||||||
|
{modalMode === 'delete' ? 'Esta acción no se puede deshacer.' : 'Sistema de Gestión de Importadores'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={closeModal}
|
||||||
|
className={`${modalMode === 'delete' ? 'text-red-100 hover:text-white hover:bg-red-600' : 'text-blue-100 hover:text-white hover:bg-blue-600'} transition-colors p-2 hover:bg-opacity-50 rounded-lg border ${modalMode === 'delete' ? 'border-red-500' : '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>
|
||||||
|
|
||||||
|
{/* Modal Content */}
|
||||||
|
<div className="p-6">
|
||||||
|
{modalMode === 'delete' ? (
|
||||||
|
<div className="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 Importador?</h3>
|
||||||
|
<div className="mt-2 px-7 py-3">
|
||||||
|
<p className="text-sm text-gray-500 mb-4">
|
||||||
|
¿Estás seguro que deseas eliminar el importador <strong>{modalData.nombre}</strong> (RFC: <strong>{modalData.rfc}</strong>)?
|
||||||
|
</p>
|
||||||
|
<div className="bg-gray-50 rounded-md p-3 mb-4">
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<div className="h-10 w-10 rounded-full bg-gray-300 flex items-center justify-center">
|
||||||
|
<svg className="h-6 w-6 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div className="ml-3 text-left">
|
||||||
|
<p className="text-sm font-medium text-gray-900">{modalData.nombre}</p>
|
||||||
|
<p className="text-xs text-gray-500">RFC: {modalData.rfc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{errorMsg && <div className="text-red-500 mb-2 w-full">{errorMsg}</div>}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-center space-x-3 pt-4">
|
||||||
|
<button type="button" onClick={closeModal} disabled={modalLoading} 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 disabled:opacity-50">Cancelar</button>
|
||||||
|
<button type="button" onClick={handleDeleteConfirm} disabled={modalLoading} 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 disabled:opacity-50 disabled:cursor-not-allowed">{modalLoading ? (<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>) : null}{modalLoading ? 'Eliminando...' : 'Eliminar Importador'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setModalLoading(true);
|
||||||
|
setErrorMsg('');
|
||||||
|
try {
|
||||||
|
let res;
|
||||||
|
if (modalMode === 'edit') {
|
||||||
|
res = await fetchWithAuth(`${API_URL}/customs/importadores/${modalData.rfc}/`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ rfc: modalData.rfc, nombre: modalData.nombre, organizacion: modalData.organizacion })
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error('Error al actualizar importador');
|
||||||
|
} else if (modalMode === 'create') {
|
||||||
|
res = await fetchWithAuth(`${API_URL}/customs/importadores/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ rfc: modalData.rfc, nombre: modalData.nombre, organizacion: modalData.organizacion })
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error('Error al crear importador');
|
||||||
|
}
|
||||||
|
// Refrescar lista
|
||||||
|
const res2 = await fetchWithAuth(`${API_URL}/customs/importadores/`);
|
||||||
|
if (!res2.ok) throw new Error('Error al obtener importadores');
|
||||||
|
const data = await res2.json();
|
||||||
|
setImporters(Array.isArray(data) ? data : []);
|
||||||
|
closeModal();
|
||||||
|
} catch {
|
||||||
|
setErrorMsg(modalMode === 'create' ? 'Error al crear importador' : 'Error al actualizar importador');
|
||||||
|
} finally {
|
||||||
|
setModalLoading(false);
|
||||||
|
}
|
||||||
|
}} className="space-y-5">
|
||||||
|
<div>
|
||||||
|
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">RFC</label>
|
||||||
|
<input
|
||||||
|
name="rfc"
|
||||||
|
type="text"
|
||||||
|
value={modalData.rfc}
|
||||||
|
readOnly={modalMode !== 'create'}
|
||||||
|
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'create' ? 'bg-white' : 'bg-gray-100'} text-slate-900 placeholder-slate-400 text-sm`}
|
||||||
|
onChange={modalMode === 'create' ? handleModalChange : undefined}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">Nombre</label>
|
||||||
|
<input
|
||||||
|
name="nombre"
|
||||||
|
type="text"
|
||||||
|
value={modalData.nombre}
|
||||||
|
onChange={modalMode !== 'view' ? handleModalChange : undefined}
|
||||||
|
readOnly={modalMode === 'view'}
|
||||||
|
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'view' ? 'bg-gray-100' : 'bg-white'} text-slate-900 placeholder-slate-400 text-sm`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block text-xs font-semibold text-slate-700 mb-1 text-left">Organización</label>
|
||||||
|
<input
|
||||||
|
name="organizacion"
|
||||||
|
type="text"
|
||||||
|
value={modalData.organizacion}
|
||||||
|
onChange={modalMode !== 'view' ? handleModalChange : undefined}
|
||||||
|
readOnly={modalMode === 'view'}
|
||||||
|
className={`w-full px-3 py-2 border border-slate-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 ${modalMode === 'view' ? 'bg-gray-100' : 'bg-white'} text-slate-900 placeholder-slate-400 text-sm`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{errorMsg && <div className="text-red-500 mt-2 text-sm text-center">{errorMsg}</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">
|
||||||
|
{modalMode !== 'view' && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={closeModal}
|
||||||
|
disabled={modalLoading}
|
||||||
|
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 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{(modalMode === 'edit' || modalMode === 'create') && (
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={modalLoading}
|
||||||
|
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 disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||||
|
>
|
||||||
|
{modalLoading && (
|
||||||
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||||
|
)}
|
||||||
|
{modalLoading ? (modalMode === 'create' ? 'Creando...' : 'Actualizando...') : (modalMode === 'create' ? 'Crear' : 'Actualizar')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -543,7 +548,15 @@ export default function Importers() {
|
|||||||
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-2">No se encontraron importadores</h3>
|
<h3 className="text-base sm:text-lg font-semibold text-gray-900 mb-2">No se encontraron importadores</h3>
|
||||||
<p className="text-gray-500 mb-6">{searchTerm ? 'Intenta con otros términos de búsqueda.' : 'Comienza agregando un nuevo importador.'}</p>
|
<p className="text-gray-500 mb-6">{searchTerm ? 'Intenta con otros términos de búsqueda.' : 'Comienza agregando un nuevo importador.'}</p>
|
||||||
{!searchTerm && (
|
{!searchTerm && (
|
||||||
<button className="inline-flex items-center px-4 py-2 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200 transform hover:scale-105">
|
<button
|
||||||
|
className="inline-flex items-center px-4 py-2 border border-transparent rounded-lg shadow-sm text-xs sm:text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-all duration-200 transform hover:scale-105"
|
||||||
|
onClick={() => {
|
||||||
|
setModalMode('create');
|
||||||
|
setModalData({ rfc: '', nombre: '', organizacion: '' });
|
||||||
|
setErrorMsg('');
|
||||||
|
setModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<svg className="-ml-1 mr-2 h-4 w-4 sm:h-5 sm:w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="-ml-1 mr-2 h-4 w-4 sm:h-5 sm:w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
Reference in New Issue
Block a user