Registro de horas: hacer descubrible como regresar una partida pagada a "Por pagar"
El boton de revertir solo aparecia en la vista "Pagadas", pero el filtro por defecto
es "Por pagar", que oculta las pagadas -> el usuario no encontraba como corregirlas.
Ahora:
- Las tarjetas de resumen "Por pagar" / "Pagado" son clicables y filtran la tabla; la
de "Pagado" muestra el hint "Ver / editar" y lleva a las partidas pagadas.
- Cuando no hay pendientes pero si pagadas, el estado vacio ofrece un boton
"Ver N pagada(s) para editar o regresar a Por pagar".
- Los botones de accion por fila ahora llevan texto ("Pagada" / "Por pagar"), no solo
icono, para que revertir sea evidente.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
63b14fc8b8
commit
1aab45f29c
@@ -450,9 +450,19 @@ export function RegistroHorasPanel({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Resumen separado: pendiente vs pagado (nunca se acumulan). */}
|
||||
{/* Resumen separado: pendiente vs pagado (nunca se acumulan). Cada tarjeta
|
||||
funciona ademas como filtro: al hacer clic muestra esas partidas abajo.
|
||||
La de "Pagado" es el camino para editar/regresar a por pagar una partida. */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4">
|
||||
<div className="rounded-lg border border-amber-200 bg-amber-50/60 p-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEstadoFiltro("por_pagar")}
|
||||
className={`text-left rounded-lg border p-3 transition ${
|
||||
estadoFiltro === "por_pagar"
|
||||
? "border-amber-400 bg-amber-50 ring-1 ring-amber-300"
|
||||
: "border-amber-200 bg-amber-50/60 hover:bg-amber-50"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 text-amber-800 text-sm font-medium">
|
||||
<CircleDashed className="w-4 h-4" /> Por pagar
|
||||
</div>
|
||||
@@ -463,10 +473,23 @@ export function RegistroHorasPanel({
|
||||
{resumen.porPagar.horas.toFixed(2)} h · {resumen.porPagar.count} registro(s)
|
||||
{incluirIva ? " · IVA incluido" : ""}
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-lg border border-green-200 bg-green-50/60 p-3">
|
||||
<div className="flex items-center gap-2 text-green-800 text-sm font-medium">
|
||||
<CheckCircle2 className="w-4 h-4" /> Pagado
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEstadoFiltro("pagada")}
|
||||
className={`text-left rounded-lg border p-3 transition ${
|
||||
estadoFiltro === "pagada"
|
||||
? "border-green-400 bg-green-50 ring-1 ring-green-300"
|
||||
: "border-green-200 bg-green-50/60 hover:bg-green-50"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2 text-green-800 text-sm font-medium">
|
||||
<span className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-4 h-4" /> Pagado
|
||||
</span>
|
||||
{resumen.pagada.count > 0 && (
|
||||
<span className="text-xs font-normal text-green-700/90 underline">Ver / editar</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-1 text-2xl font-bold text-green-900">
|
||||
{formatCurrency(resumen.pagada.importe * ivaFactor)}
|
||||
@@ -475,7 +498,7 @@ export function RegistroHorasPanel({
|
||||
{resumen.pagada.horas.toFixed(2)} h · {resumen.pagada.count} registro(s)
|
||||
{incluirIva ? " · IVA incluido" : ""}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Formulario de alta / edicion */}
|
||||
@@ -617,14 +640,26 @@ export function RegistroHorasPanel({
|
||||
|
||||
{/* Tabla */}
|
||||
{filtrados.length === 0 ? (
|
||||
<p className="text-muted text-sm py-6 text-center">
|
||||
{estadoFiltro === "pagada"
|
||||
? "No hay horas marcadas como pagadas"
|
||||
: estadoFiltro === "por_pagar"
|
||||
? "No hay horas pendientes de pago"
|
||||
: "Aún no hay registros de horas"}
|
||||
{from || to ? " en este periodo" : ""}.
|
||||
</p>
|
||||
<div className="py-6 text-center">
|
||||
<p className="text-muted text-sm">
|
||||
{estadoFiltro === "pagada"
|
||||
? "No hay horas marcadas como pagadas"
|
||||
: estadoFiltro === "por_pagar"
|
||||
? "No hay horas pendientes de pago"
|
||||
: "Aún no hay registros de horas"}
|
||||
{from || to ? " en este periodo" : ""}.
|
||||
</p>
|
||||
{estadoFiltro === "por_pagar" && resumen.pagada.count > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEstadoFiltro("pagada")}
|
||||
className="mt-2 inline-flex items-center gap-1.5 text-sm text-primary hover:underline"
|
||||
>
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
Ver {resumen.pagada.count} pagada(s) para editar o regresar a “Por pagar”
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
@@ -672,31 +707,33 @@ export function RegistroHorasPanel({
|
||||
<button
|
||||
onClick={() => regresarPorPagar(r)}
|
||||
disabled={togglingId === r.id}
|
||||
className="p-1 text-muted hover:text-amber-600 disabled:opacity-50"
|
||||
className="inline-flex items-center gap-1 px-2 py-1 rounded border border-amber-300 text-amber-700 hover:bg-amber-50 text-xs align-middle disabled:opacity-50"
|
||||
title="Regresar a Por pagar"
|
||||
>
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
<RotateCcw className="w-3.5 h-3.5" />
|
||||
Por pagar
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => cambiarEstado(r, "pagada")}
|
||||
disabled={togglingId === r.id}
|
||||
className="p-1 text-muted hover:text-green-600 disabled:opacity-50"
|
||||
className="inline-flex items-center gap-1 px-2 py-1 rounded border border-green-300 text-green-700 hover:bg-green-50 text-xs align-middle disabled:opacity-50"
|
||||
title="Marcar como pagada"
|
||||
>
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
Pagada
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handleEdit(r)}
|
||||
className="p-1 text-muted hover:text-primary"
|
||||
className="p-1 text-muted hover:text-primary align-middle"
|
||||
title="Editar"
|
||||
>
|
||||
<Pencil className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDelete(r.id)}
|
||||
className="p-1 text-muted hover:text-red-600"
|
||||
className="p-1 text-muted hover:text-red-600 align-middle"
|
||||
title="Eliminar"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
|
||||
Reference in New Issue
Block a user