feat(F-130): completed feature
This commit is contained in:
@@ -18,6 +18,10 @@ interface ProductRow {
|
||||
editingEan: boolean;
|
||||
editEanValue: string;
|
||||
savingEan: boolean;
|
||||
// F-130: caducidad editable inline
|
||||
editingExp: boolean;
|
||||
editExpValue: string;
|
||||
savingExp: boolean;
|
||||
}
|
||||
|
||||
type RowFilter = 'all' | 'in_stock' | 'low_stock' | 'out_of_stock' | 'expiring' | 'low_margin';
|
||||
@@ -122,6 +126,9 @@ export default function InventoryPage() {
|
||||
editingEan: false,
|
||||
editEanValue: '',
|
||||
savingEan: false,
|
||||
editingExp: false,
|
||||
editExpValue: product.expirationDate?.slice(0, 10) ?? '',
|
||||
savingExp: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,6 +183,30 @@ export default function InventoryPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Save expiration date inline (F-130)
|
||||
const handleSaveExp = async (variantId: string, productId: string, value: string) => {
|
||||
setRows((prev) => prev.map((r) => (r.variant.id === variantId ? { ...r, savingExp: true } : r)));
|
||||
try {
|
||||
const updated = await productsApi.update(productId, { expirationDate: value || null });
|
||||
const newIso = updated.expirationDate ?? null;
|
||||
setRows((prev) =>
|
||||
prev.map((r) =>
|
||||
r.variant.id === variantId
|
||||
? {
|
||||
...r,
|
||||
expirationDate: newIso,
|
||||
editExpValue: newIso?.slice(0, 10) ?? '',
|
||||
editingExp: false,
|
||||
savingExp: false,
|
||||
}
|
||||
: r,
|
||||
),
|
||||
);
|
||||
} catch {
|
||||
setRows((prev) => prev.map((r) => (r.variant.id === variantId ? { ...r, savingExp: false } : r)));
|
||||
}
|
||||
};
|
||||
|
||||
// Save Stock inline (used by Stock cell on blur/Enter)
|
||||
const saveStockInline = async (variantId: string, value: string) => {
|
||||
const qty = parseInt(value, 10);
|
||||
@@ -387,7 +418,48 @@ export default function InventoryPage() {
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<ExpirationCell dateIso={row.expirationDate} />
|
||||
{row.editingExp ? (
|
||||
<input
|
||||
autoFocus
|
||||
type="date"
|
||||
value={row.editExpValue}
|
||||
onChange={(e) =>
|
||||
setRows((prev) =>
|
||||
prev.map((r) =>
|
||||
r.variant.id === row.variant.id
|
||||
? { ...r, editExpValue: e.target.value }
|
||||
: r,
|
||||
),
|
||||
)
|
||||
}
|
||||
onBlur={() => handleSaveExp(row.variant.id, row.productId, row.editExpValue)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') handleSaveExp(row.variant.id, row.productId, row.editExpValue);
|
||||
if (e.key === 'Escape')
|
||||
setRows((prev) =>
|
||||
prev.map((r) =>
|
||||
r.variant.id === row.variant.id ? { ...r, editingExp: false } : r,
|
||||
),
|
||||
);
|
||||
}}
|
||||
disabled={row.savingExp}
|
||||
className="px-2 py-1 border border-[#2D6A4F] rounded text-xs focus:ring-1 focus:ring-[#2D6A4F] outline-none disabled:opacity-50"
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
onClick={() =>
|
||||
setRows((prev) =>
|
||||
prev.map((r) =>
|
||||
r.variant.id === row.variant.id ? { ...r, editingExp: true } : r,
|
||||
),
|
||||
)
|
||||
}
|
||||
title="Clic para editar caducidad"
|
||||
className="cursor-pointer text-left"
|
||||
>
|
||||
<ExpirationCell dateIso={row.expirationDate} />
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{margin === null ? (
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user