fix(release): 0.2.8 harden admin proxy, cart stock caps, selfpay and refund timeline

- admin proxy: 25s timeout, body guards, structured failure logs
- cart: addItem enforces stock cap (409 INSUFFICIENT_STOCK), UI clamps qty
- tpv selfpay: hide sidebar/discounts/save-pending, rename button, receipt-settings 400 fix
- pos admin: quick products slot count aligned to 8
- returns: human-readable history message + metadata jsonb (migrations 064-065) + admin fallback formatter
- storefront: product card white background
- product page: remove duplicate stock label under add-to-cart button
This commit is contained in:
Deploy
2026-08-25 23:41:29 +02:00
parent b6adf681d1
commit b6af852b54
29 changed files with 671 additions and 279 deletions

View File

@@ -62,7 +62,7 @@ export function AddToCart({ productId, productName, unitPriceCents, imageUrl }:
const existing = items.find((it) => it.variantId === productId);
const newQty = existing ? existing.quantity + qty : qty;
if (newQty > stock) {
setError(`Solo hay ${stock} unidades disponibles.`);
setError(`Solo hay ${stock} unidades disponibles en total (ya tienes ${existing?.quantity ?? 0} en el carrito).`);
return;
}
const next = existing
@@ -93,7 +93,16 @@ export function AddToCart({ productId, productName, unitPriceCents, imageUrl }:
min={1}
max={stock}
value={qty}
onChange={(e) => setQty(Math.max(1, parseInt(e.target.value, 10) || 1))}
onChange={(e) => {
const parsed = parseInt(e.target.value, 10);
if (!Number.isFinite(parsed)) {
setQty(1);
return;
}
// F-138: never let the buyer enter a quantity outside [1, stock].
const clamped = Math.max(1, Math.min(stock, parsed));
setQty(clamped);
}}
disabled={disabled}
className="w-24 rounded-lg border border-stone-300 px-3 py-2 text-sm focus:ring-2 focus:ring-emerald-700 outline-none disabled:opacity-50"
/>

View File

@@ -8,7 +8,7 @@ export function ProductCard({ product }: Readonly<{ product: ProductSummaryDto }
href={product.url}
className="group block overflow-hidden rounded-3xl border border-emerald-900/10 bg-white shadow-sm transition hover:-translate-y-0.5 hover:border-emerald-700"
>
<div className="flex w-full max-h-72 items-center justify-center bg-emerald-50 text-sm text-emerald-900 overflow-hidden">
<div className="flex w-full max-h-72 items-center justify-center bg-white text-sm text-emerald-900 overflow-hidden">
{mainImage ? (
// Keep plain img for remote/local URL compatibility until image pipeline configuration exists.
// eslint-disable-next-line @next/next/no-img-element