Se agrego progress bar en procesos
This commit is contained in:
@@ -40,7 +40,7 @@ export default function Procesos() {
|
|||||||
const [isSelectAll, setIsSelectAll] = useState(false);
|
const [isSelectAll, setIsSelectAll] = useState(false);
|
||||||
|
|
||||||
// Función para mostrar toast
|
// Función para mostrar toast
|
||||||
const showToast = (type, title, message, details = '') => {
|
const showToast = (type, title, message, details = '', persistent = false, progress = null) => {
|
||||||
const id = Date.now();
|
const id = Date.now();
|
||||||
const newToast = {
|
const newToast = {
|
||||||
id,
|
id,
|
||||||
@@ -48,16 +48,29 @@ export default function Procesos() {
|
|||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
details,
|
details,
|
||||||
isVisible: true
|
isVisible: true,
|
||||||
|
persistent,
|
||||||
|
progress
|
||||||
};
|
};
|
||||||
|
|
||||||
setToasts(prev => [...prev, newToast]);
|
setToasts(prev => [...prev, newToast]);
|
||||||
|
|
||||||
// Auto remover el toast después de 5 segundos (8 segundos para info)
|
// Auto remover el toast después de 5 segundos (8 segundos para info) solo si no es persistente
|
||||||
|
if (!persistent) {
|
||||||
const timeout = type === 'info' ? 8000 : 5000;
|
const timeout = type === 'info' ? 8000 : 5000;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeToast(id);
|
removeToast(id);
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id; // Retornar el ID para poder actualizar el toast
|
||||||
|
};
|
||||||
|
|
||||||
|
// Función para actualizar toast existente (especialmente útil para progreso)
|
||||||
|
const updateToast = (id, updates) => {
|
||||||
|
setToasts(prev => prev.map(toast =>
|
||||||
|
toast.id === id ? { ...toast, ...updates } : toast
|
||||||
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para remover toast
|
// Función para remover toast
|
||||||
@@ -102,12 +115,43 @@ export default function Procesos() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('info', 'Iniciando procesamiento masivo', `Procesando ${procesosEjecutables.length} procesos de la página actual...`);
|
// Calcular tiempo estimado (aproximadamente 2-3 segundos por proceso)
|
||||||
|
const tiempoEstimadoSegundos = procesosEjecutables.length * 2.5;
|
||||||
|
const minutos = Math.floor(tiempoEstimadoSegundos / 60);
|
||||||
|
const segundos = Math.round(tiempoEstimadoSegundos % 60);
|
||||||
|
const tiempoTexto = minutos > 0 ? `${minutos}m ${segundos}s` : `${segundos}s`;
|
||||||
|
|
||||||
|
// Crear toast persistente con progreso
|
||||||
|
const progressToastId = showToast('info', 'Procesamiento Masivo en Progreso',
|
||||||
|
`Procesando ${procesosEjecutables.length} procesos...\n⏱️ Tiempo estimado: ${tiempoTexto}`,
|
||||||
|
'',
|
||||||
|
true, // persistente
|
||||||
|
{ current: 0, total: procesosEjecutables.length, percentage: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const inicioTiempo = Date.now();
|
||||||
let exitosos = 0;
|
let exitosos = 0;
|
||||||
let errores = 0;
|
let errores = 0;
|
||||||
|
|
||||||
for (const proc of procesosEjecutables) {
|
for (let i = 0; i < procesosEjecutables.length; i++) {
|
||||||
|
const proc = procesosEjecutables[i];
|
||||||
|
|
||||||
|
// Actualizar progreso en tiempo real
|
||||||
|
const tiempoTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
|
const progresoPercentage = Math.round(((i + 1) / procesosEjecutables.length) * 100);
|
||||||
|
const tiempoRestanteEstimado = i > 0 ? Math.round((tiempoTranscurrido / i) * (procesosEjecutables.length - i)) : tiempoEstimadoSegundos;
|
||||||
|
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
message: `Procesando ${procesosEjecutables.length} procesos...\n⏱️ Transcurrido: ${tiempoTranscurrido}s | Restante: ~${tiempoRestanteEstimado}s\n📊 Proceso actual: ${proc.pedimento?.numero || proc.pedimento} (${i + 1}/${procesosEjecutables.length})`,
|
||||||
|
progress: {
|
||||||
|
current: i + 1,
|
||||||
|
total: procesosEjecutables.length,
|
||||||
|
percentage: progresoPercentage,
|
||||||
|
exitosos,
|
||||||
|
errores
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cambiar estado visual a "Procesando"
|
// Cambiar estado visual a "Procesando"
|
||||||
updateProcesoEstado(proc.id, 2);
|
updateProcesoEstado(proc.id, 2);
|
||||||
@@ -151,8 +195,25 @@ export default function Procesos() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('success', 'Procesamiento masivo completado',
|
const tiempoTotalTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
`Resultados: ${exitosos} exitosos, ${errores} errores de ${procesosEjecutables.length} procesos.`);
|
const minutosTotales = Math.floor(tiempoTotalTranscurrido / 60);
|
||||||
|
const segundosTotales = tiempoTotalTranscurrido % 60;
|
||||||
|
const tiempoTotalTexto = minutosTotales > 0 ? `${minutosTotales}m ${segundosTotales}s` : `${segundosTotales}s`;
|
||||||
|
|
||||||
|
// Actualizar toast final
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
type: 'success',
|
||||||
|
title: '✅ Procesamiento Completado',
|
||||||
|
message: `Resultados finales:\n✓ ${exitosos} exitosos | ✗ ${errores} errores\n⏱️ Tiempo total: ${tiempoTotalTexto}`,
|
||||||
|
progress: {
|
||||||
|
current: procesosEjecutables.length,
|
||||||
|
total: procesosEjecutables.length,
|
||||||
|
percentage: 100,
|
||||||
|
exitosos,
|
||||||
|
errores,
|
||||||
|
completed: true
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para procesar seleccionados
|
// Función para procesar seleccionados
|
||||||
@@ -171,12 +232,43 @@ export default function Procesos() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('info', 'Iniciando procesamiento de seleccionados', `Procesando ${procesosAEjecutar.length} procesos seleccionados...`);
|
// Calcular tiempo estimado (aproximadamente 2-3 segundos por proceso)
|
||||||
|
const tiempoEstimadoSegundos = procesosAEjecutar.length * 2.5;
|
||||||
|
const minutos = Math.floor(tiempoEstimadoSegundos / 60);
|
||||||
|
const segundos = Math.round(tiempoEstimadoSegundos % 60);
|
||||||
|
const tiempoTexto = minutos > 0 ? `${minutos}m ${segundos}s` : `${segundos}s`;
|
||||||
|
|
||||||
|
// Crear toast persistente con progreso
|
||||||
|
const progressToastId = showToast('info', 'Procesamiento de Seleccionados en Progreso',
|
||||||
|
`Procesando ${procesosAEjecutar.length} procesos seleccionados...\n⏱️ Tiempo estimado: ${tiempoTexto}`,
|
||||||
|
'',
|
||||||
|
true, // persistente
|
||||||
|
{ current: 0, total: procesosAEjecutar.length, percentage: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const inicioTiempo = Date.now();
|
||||||
let exitosos = 0;
|
let exitosos = 0;
|
||||||
let errores = 0;
|
let errores = 0;
|
||||||
|
|
||||||
for (const proc of procesosAEjecutar) {
|
for (let i = 0; i < procesosAEjecutar.length; i++) {
|
||||||
|
const proc = procesosAEjecutar[i];
|
||||||
|
|
||||||
|
// Actualizar progreso en tiempo real
|
||||||
|
const tiempoTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
|
const progresoPercentage = Math.round(((i + 1) / procesosAEjecutar.length) * 100);
|
||||||
|
const tiempoRestanteEstimado = i > 0 ? Math.round((tiempoTranscurrido / i) * (procesosAEjecutar.length - i)) : tiempoEstimadoSegundos;
|
||||||
|
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
message: `Procesando ${procesosAEjecutar.length} procesos seleccionados...\n⏱️ Transcurrido: ${tiempoTranscurrido}s | Restante: ~${tiempoRestanteEstimado}s\n📊 Proceso actual: ${proc.pedimento?.numero || proc.pedimento} (${i + 1}/${procesosAEjecutar.length})`,
|
||||||
|
progress: {
|
||||||
|
current: i + 1,
|
||||||
|
total: procesosAEjecutar.length,
|
||||||
|
percentage: progresoPercentage,
|
||||||
|
exitosos,
|
||||||
|
errores
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cambiar estado visual a "Procesando"
|
// Cambiar estado visual a "Procesando"
|
||||||
updateProcesoEstado(proc.id, 2);
|
updateProcesoEstado(proc.id, 2);
|
||||||
@@ -224,8 +316,25 @@ export default function Procesos() {
|
|||||||
setSelectedProcesos([]);
|
setSelectedProcesos([]);
|
||||||
setIsSelectAll(false);
|
setIsSelectAll(false);
|
||||||
|
|
||||||
showToast('success', 'Procesamiento de seleccionados completado',
|
const tiempoTotalTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
`Resultados: ${exitosos} exitosos, ${errores} errores de ${procesosAEjecutar.length} procesos.`);
|
const minutosTotales = Math.floor(tiempoTotalTranscurrido / 60);
|
||||||
|
const segundosTotales = tiempoTotalTranscurrido % 60;
|
||||||
|
const tiempoTotalTexto = minutosTotales > 0 ? `${minutosTotales}m ${segundosTotales}s` : `${segundosTotales}s`;
|
||||||
|
|
||||||
|
// Actualizar toast final
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
type: 'success',
|
||||||
|
title: '✅ Procesamiento de Seleccionados Completado',
|
||||||
|
message: `Resultados finales:\n✓ ${exitosos} exitosos | ✗ ${errores} errores\n⏱️ Tiempo total: ${tiempoTotalTexto}`,
|
||||||
|
progress: {
|
||||||
|
current: procesosAEjecutar.length,
|
||||||
|
total: procesosAEjecutar.length,
|
||||||
|
percentage: 100,
|
||||||
|
exitosos,
|
||||||
|
errores,
|
||||||
|
completed: true
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para pasar página entera a En Espera
|
// Función para pasar página entera a En Espera
|
||||||
@@ -237,12 +346,43 @@ export default function Procesos() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('info', 'Iniciando cambio masivo de estado', `Pasando ${procesosEnError.length} procesos a "En Espera"...`);
|
// Calcular tiempo estimado (aproximadamente 1 segundo por proceso)
|
||||||
|
const tiempoEstimadoSegundos = procesosEnError.length * 1;
|
||||||
|
const minutos = Math.floor(tiempoEstimadoSegundos / 60);
|
||||||
|
const segundos = Math.round(tiempoEstimadoSegundos % 60);
|
||||||
|
const tiempoTexto = minutos > 0 ? `${minutos}m ${segundos}s` : `${segundos}s`;
|
||||||
|
|
||||||
|
// Crear toast persistente con progreso
|
||||||
|
const progressToastId = showToast('info', 'Cambio Masivo de Estado en Progreso',
|
||||||
|
`Pasando ${procesosEnError.length} procesos a "En Espera"...\n⏱️ Tiempo estimado: ${tiempoTexto}`,
|
||||||
|
'',
|
||||||
|
true, // persistente
|
||||||
|
{ current: 0, total: procesosEnError.length, percentage: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const inicioTiempo = Date.now();
|
||||||
let exitosos = 0;
|
let exitosos = 0;
|
||||||
let errores = 0;
|
let errores = 0;
|
||||||
|
|
||||||
for (const proc of procesosEnError) {
|
for (let i = 0; i < procesosEnError.length; i++) {
|
||||||
|
const proc = procesosEnError[i];
|
||||||
|
|
||||||
|
// Actualizar progreso en tiempo real
|
||||||
|
const tiempoTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
|
const progresoPercentage = Math.round(((i + 1) / procesosEnError.length) * 100);
|
||||||
|
const tiempoRestanteEstimado = i > 0 ? Math.round((tiempoTranscurrido / i) * (procesosEnError.length - i)) : tiempoEstimadoSegundos;
|
||||||
|
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
message: `Pasando ${procesosEnError.length} procesos a "En Espera"...\n⏱️ Transcurrido: ${tiempoTranscurrido}s | Restante: ~${tiempoRestanteEstimado}s\n📊 Proceso actual: ${proc.pedimento?.numero || proc.pedimento} (${i + 1}/${procesosEnError.length})`,
|
||||||
|
progress: {
|
||||||
|
current: i + 1,
|
||||||
|
total: procesosEnError.length,
|
||||||
|
percentage: progresoPercentage,
|
||||||
|
exitosos,
|
||||||
|
errores
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cambiar estado visual a "Procesando" temporalmente
|
// Cambiar estado visual a "Procesando" temporalmente
|
||||||
updateProcesoEstado(proc.id, 2);
|
updateProcesoEstado(proc.id, 2);
|
||||||
@@ -275,8 +415,25 @@ export default function Procesos() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('success', 'Cambio masivo de estado completado',
|
const tiempoTotalTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
`Resultados: ${exitosos} exitosos, ${errores} errores de ${procesosEnError.length} procesos.`);
|
const minutosTotales = Math.floor(tiempoTotalTranscurrido / 60);
|
||||||
|
const segundosTotales = tiempoTotalTranscurrido % 60;
|
||||||
|
const tiempoTotalTexto = minutosTotales > 0 ? `${minutosTotales}m ${segundosTotales}s` : `${segundosTotales}s`;
|
||||||
|
|
||||||
|
// Actualizar toast final
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
type: 'success',
|
||||||
|
title: '✅ Cambio Masivo de Estado Completado',
|
||||||
|
message: `Resultados finales:\n✓ ${exitosos} exitosos | ✗ ${errores} errores\n⏱️ Tiempo total: ${tiempoTotalTexto}`,
|
||||||
|
progress: {
|
||||||
|
current: procesosEnError.length,
|
||||||
|
total: procesosEnError.length,
|
||||||
|
percentage: 100,
|
||||||
|
exitosos,
|
||||||
|
errores,
|
||||||
|
completed: true
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para pasar seleccionados a En Espera
|
// Función para pasar seleccionados a En Espera
|
||||||
@@ -295,12 +452,43 @@ export default function Procesos() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast('info', 'Iniciando cambio de estado de seleccionados', `Pasando ${procesosACambiar.length} procesos seleccionados a "En Espera"...`);
|
// Calcular tiempo estimado (aproximadamente 1 segundo por proceso)
|
||||||
|
const tiempoEstimadoSegundos = procesosACambiar.length * 1;
|
||||||
|
const minutos = Math.floor(tiempoEstimadoSegundos / 60);
|
||||||
|
const segundos = Math.round(tiempoEstimadoSegundos % 60);
|
||||||
|
const tiempoTexto = minutos > 0 ? `${minutos}m ${segundos}s` : `${segundos}s`;
|
||||||
|
|
||||||
|
// Crear toast persistente con progreso
|
||||||
|
const progressToastId = showToast('info', 'Cambio de Estado de Seleccionados en Progreso',
|
||||||
|
`Pasando ${procesosACambiar.length} procesos seleccionados a "En Espera"...\n⏱️ Tiempo estimado: ${tiempoTexto}`,
|
||||||
|
'',
|
||||||
|
true, // persistente
|
||||||
|
{ current: 0, total: procesosACambiar.length, percentage: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
const inicioTiempo = Date.now();
|
||||||
let exitosos = 0;
|
let exitosos = 0;
|
||||||
let errores = 0;
|
let errores = 0;
|
||||||
|
|
||||||
for (const proc of procesosACambiar) {
|
for (let i = 0; i < procesosACambiar.length; i++) {
|
||||||
|
const proc = procesosACambiar[i];
|
||||||
|
|
||||||
|
// Actualizar progreso en tiempo real
|
||||||
|
const tiempoTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
|
const progresoPercentage = Math.round(((i + 1) / procesosACambiar.length) * 100);
|
||||||
|
const tiempoRestanteEstimado = i > 0 ? Math.round((tiempoTranscurrido / i) * (procesosACambiar.length - i)) : tiempoEstimadoSegundos;
|
||||||
|
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
message: `Pasando ${procesosACambiar.length} procesos seleccionados a "En Espera"...\n⏱️ Transcurrido: ${tiempoTranscurrido}s | Restante: ~${tiempoRestanteEstimado}s\n📊 Proceso actual: ${proc.pedimento?.numero || proc.pedimento} (${i + 1}/${procesosACambiar.length})`,
|
||||||
|
progress: {
|
||||||
|
current: i + 1,
|
||||||
|
total: procesosACambiar.length,
|
||||||
|
percentage: progresoPercentage,
|
||||||
|
exitosos,
|
||||||
|
errores
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cambiar estado visual a "Procesando" temporalmente
|
// Cambiar estado visual a "Procesando" temporalmente
|
||||||
updateProcesoEstado(proc.id, 2);
|
updateProcesoEstado(proc.id, 2);
|
||||||
@@ -337,8 +525,25 @@ export default function Procesos() {
|
|||||||
setSelectedProcesos([]);
|
setSelectedProcesos([]);
|
||||||
setIsSelectAll(false);
|
setIsSelectAll(false);
|
||||||
|
|
||||||
showToast('success', 'Cambio de estado de seleccionados completado',
|
const tiempoTotalTranscurrido = Math.round((Date.now() - inicioTiempo) / 1000);
|
||||||
`Resultados: ${exitosos} exitosos, ${errores} errores de ${procesosACambiar.length} procesos.`);
|
const minutosTotales = Math.floor(tiempoTotalTranscurrido / 60);
|
||||||
|
const segundosTotales = tiempoTotalTranscurrido % 60;
|
||||||
|
const tiempoTotalTexto = minutosTotales > 0 ? `${minutosTotales}m ${segundosTotales}s` : `${segundosTotales}s`;
|
||||||
|
|
||||||
|
// Actualizar toast final
|
||||||
|
updateToast(progressToastId, {
|
||||||
|
type: 'success',
|
||||||
|
title: '✅ Cambio de Estado de Seleccionados Completado',
|
||||||
|
message: `Resultados finales:\n✓ ${exitosos} exitosos | ✗ ${errores} errores\n⏱️ Tiempo total: ${tiempoTotalTexto}`,
|
||||||
|
progress: {
|
||||||
|
current: procesosACambiar.length,
|
||||||
|
total: procesosACambiar.length,
|
||||||
|
percentage: 100,
|
||||||
|
exitosos,
|
||||||
|
errores,
|
||||||
|
completed: true
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Función para cambiar estado de Error a En Espera
|
// Función para cambiar estado de Error a En Espera
|
||||||
@@ -1302,7 +1507,7 @@ export default function Procesos() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h4 className="text-sm font-semibold mb-1">{toast.title}</h4>
|
<h4 className="text-sm font-semibold mb-1">{toast.title}</h4>
|
||||||
<p className="text-sm opacity-90">{toast.message}</p>
|
<p className="text-sm opacity-90 whitespace-pre-line">{toast.message}</p>
|
||||||
{toast.details && (
|
{toast.details && (
|
||||||
<details className="mt-2 cursor-pointer">
|
<details className="mt-2 cursor-pointer">
|
||||||
<summary className="text-xs opacity-70 hover:opacity-100 transition-opacity">
|
<summary className="text-xs opacity-70 hover:opacity-100 transition-opacity">
|
||||||
@@ -1323,19 +1528,77 @@ export default function Procesos() {
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
)}
|
)}
|
||||||
|
{/* Barra de progreso tipo tqdm */}
|
||||||
|
{toast.progress && (
|
||||||
|
<div className="mt-3">
|
||||||
|
<div className="flex items-center justify-between mb-1">
|
||||||
|
<span className="text-xs font-medium">
|
||||||
|
{toast.progress.current}/{toast.progress.total}
|
||||||
|
({toast.progress.percentage}%)
|
||||||
|
</span>
|
||||||
|
{toast.progress.exitosos !== undefined && toast.progress.errores !== undefined && (
|
||||||
|
<span className="text-xs">
|
||||||
|
<span className="text-green-600">✓{toast.progress.exitosos}</span>
|
||||||
|
{toast.progress.errores > 0 && (
|
||||||
|
<span className="text-red-600 ml-1">✗{toast.progress.errores}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`w-full bg-gray-200 rounded-full h-2 overflow-hidden ${
|
||||||
|
toast.type === 'success' ? 'bg-green-100' :
|
||||||
|
toast.type === 'error' ? 'bg-red-100' :
|
||||||
|
toast.type === 'warning' ? 'bg-orange-100' :
|
||||||
|
'bg-blue-100'
|
||||||
|
}`}>
|
||||||
|
<div
|
||||||
|
className={`h-2 rounded-full transition-all duration-300 ease-out ${
|
||||||
|
toast.type === 'success' ? 'bg-green-500' :
|
||||||
|
toast.type === 'error' ? 'bg-red-500' :
|
||||||
|
toast.type === 'warning' ? 'bg-orange-500' :
|
||||||
|
'bg-blue-500'
|
||||||
|
}`}
|
||||||
|
style={{ width: `${toast.progress.percentage}%` }}
|
||||||
|
>
|
||||||
|
{/* Barra de progreso animada */}
|
||||||
|
{!toast.progress.completed && (
|
||||||
|
<div className="h-full w-full bg-gradient-to-r from-transparent via-white to-transparent opacity-30 animate-pulse"></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Indicador de velocidad/rate (similar a tqdm) */}
|
||||||
|
{toast.progress.current > 0 && !toast.progress.completed && (
|
||||||
|
<div className="text-xs opacity-70 mt-1">
|
||||||
|
📈 {((toast.progress.current / (Date.now() - (toast.id || Date.now()))) * 1000 * 60).toFixed(1)} items/min
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* Botón de cerrar - solo visible si es persistente o completado */}
|
||||||
|
{(toast.persistent || (toast.progress && toast.progress.completed)) && (
|
||||||
<button
|
<button
|
||||||
onClick={() => removeToast(toast.id)}
|
onClick={() => removeToast(toast.id)}
|
||||||
className="flex-shrink-0 ml-2 opacity-60 hover:opacity-100 transition-opacity"
|
className="flex-shrink-0 ml-2 opacity-60 hover:opacity-100 transition-opacity p-1 rounded-full hover:bg-black/10"
|
||||||
>
|
>
|
||||||
<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">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
|
{/* Indicador de toast automático */}
|
||||||
|
{!toast.persistent && (!toast.progress || !toast.progress.completed) && (
|
||||||
|
<div className="flex-shrink-0 ml-2 opacity-40">
|
||||||
|
<svg className="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Barra de progreso */}
|
{/* Barra de progreso de tiempo (solo para toasts automáticos sin progreso personalizado) */}
|
||||||
|
{!toast.persistent && !toast.progress && (
|
||||||
<div className={`h-1 ${
|
<div className={`h-1 ${
|
||||||
toast.type === 'success'
|
toast.type === 'success'
|
||||||
? 'bg-green-200'
|
? 'bg-green-200'
|
||||||
@@ -1366,6 +1629,7 @@ export default function Procesos() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user