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:
4
project/storefront/package-lock.json
generated
4
project/storefront/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mercadodevida-storefront",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mercadodevida-storefront",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.8",
|
||||
"dependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.17",
|
||||
"next": "^16.0.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mercadodevida-storefront",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.8",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "mercadodevida customer storefront shell",
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user