se agregatron cambios a expedientes datastage y documentos
This commit is contained in:
@@ -128,6 +128,7 @@ export default function Datastage() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [form, setForm] = useState({ archivo: null, contribuyente: '' });
|
||||
const [importadores, setImportadores] = useState([]);
|
||||
const [editingId, setEditingId] = useState(null);
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
@@ -256,9 +257,21 @@ export default function Datastage() {
|
||||
};
|
||||
|
||||
// Abrir modal de creación
|
||||
const openCreateModal = () => {
|
||||
const openCreateModal = async () => {
|
||||
setForm({ archivo: null, contribuyente: '' });
|
||||
setEditingId(null);
|
||||
// Fetch importadores
|
||||
try {
|
||||
const res = await fetchWithAuth(`${import.meta.env.VITE_EFC_API_URL}/customs/importadores/`, { method: 'GET' });
|
||||
const data = await res.json();
|
||||
if (Array.isArray(data)) {
|
||||
setImportadores(data);
|
||||
} else {
|
||||
setImportadores([]);
|
||||
}
|
||||
} catch {
|
||||
setImportadores([]);
|
||||
}
|
||||
setShowCreateModal(true);
|
||||
};
|
||||
|
||||
@@ -563,43 +576,132 @@ export default function Datastage() {
|
||||
{/* 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">
|
||||
<form onSubmit={handleCreate} className="relative mx-auto w-full max-w-2xl bg-white rounded-2xl shadow-2xl transform transition-all duration-300 animate-in slide-in-from-bottom-4">
|
||||
{/* Header formal con gradiente */}
|
||||
<div className="bg-gradient-to-r from-blue-700 via-blue-800 to-blue-900 rounded-t-2xl p-6 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" />
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="bg-blue-500 bg-opacity-30 backdrop-blur-sm rounded-xl p-3 border border-blue-400 border-opacity-30 shadow-lg">
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<ellipse cx="12" cy="7" rx="8" ry="3" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M4 7v10c0 1.657 3.582 3 8 3s8-1.343 8-3V7" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M4 17c0 1.657 3.582 3 8 3s8-1.343 8-3" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</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>
|
||||
<h3 className="text-xl font-bold tracking-wide mb-1">Nuevo Datastage</h3>
|
||||
<p className="text-blue-200 text-sm 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">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(false)}
|
||||
className="text-blue-100 hover:text-white hover:bg-blue-600 transition-all duration-200 p-2 hover:bg-opacity-50 rounded-lg border border-blue-400 border-opacity-30 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-blue-800"
|
||||
>
|
||||
<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 className="p-6 space-y-6">
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 text-red-700 text-sm flex items-start space-x-3">
|
||||
<svg className="w-5 h-5 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sección de Archivo */}
|
||||
<div className="bg-slate-50 rounded-xl p-5 border border-slate-200">
|
||||
<div className="flex items-center mb-4 pb-2 border-b border-slate-300">
|
||||
<div className="bg-blue-600 rounded-lg p-2 mr-3 shadow-sm">
|
||||
<svg className="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-semibold text-slate-800">Archivo de Datos</h4>
|
||||
<p className="text-xs text-slate-600">Selecciona el archivo ZIP a procesar</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="block text-xs font-semibold text-slate-700">
|
||||
Archivo (.zip) <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="file"
|
||||
accept=".zip"
|
||||
onChange={e => setForm(f => ({ ...f, archivo: e.target.files[0] }))}
|
||||
required
|
||||
className="w-full px-4 py-2.5 border-2 border-slate-300 border-dashed rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 text-sm hover:border-blue-500 cursor-pointer file:mr-4 file:py-1 file:px-4 file:border-0 file:text-sm file:bg-blue-50 file:text-blue-700 file:rounded-full hover:file:bg-blue-100"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
Formato soportado: .ZIP (máximo 100MB)
|
||||
</p>
|
||||
</div>
|
||||
</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 />
|
||||
|
||||
{/* Sección de Contribuyente */}
|
||||
<div className="bg-slate-50 rounded-xl p-5 border border-slate-200">
|
||||
<div className="flex items-center mb-4 pb-2 border-b border-slate-300">
|
||||
<div className="bg-green-600 rounded-lg p-2 mr-3 shadow-sm">
|
||||
<svg className="w-4 h-4 text-white" 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>
|
||||
<h4 className="text-sm font-semibold text-slate-800">Datos del Contribuyente</h4>
|
||||
<p className="text-xs text-slate-600">Selecciona el RFC del contribuyente</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="block text-xs font-semibold text-slate-700">
|
||||
RFC del Contribuyente <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
className="w-full px-3 py-2.5 border border-slate-300 rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white text-slate-900 text-sm"
|
||||
value={form.contribuyente}
|
||||
onChange={e => setForm(f => ({ ...f, contribuyente: e.target.value }))}
|
||||
required
|
||||
>
|
||||
<option value="" disabled>Selecciona un RFC</option>
|
||||
{importadores.map(imp => (
|
||||
<option key={imp.rfc} value={imp.rfc} className="font-mono">
|
||||
{imp.rfc}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className="text-xs text-slate-500 mt-1">
|
||||
Selecciona el RFC del contribuyente asociado a este datastage
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Botones de acción */}
|
||||
<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>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowCreateModal(false)}
|
||||
className="w-full sm:w-auto px-6 py-2.5 border border-slate-300 rounded-lg shadow-sm text-sm font-medium 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.5 border border-transparent rounded-lg shadow-lg text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-blue-800 hover:from-blue-700 hover:to-blue-900 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"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<span>Crear Datastage</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user