+
+
${esc(stockValueLabel)}
+ ${stockSubLabel ? `
${esc(stockSubLabel)}
` : ''}
+
@@ -443,10 +428,10 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
const nextQty = usesPackStep
? normalizeQty((Number(input?.value) || 0) * step)
: normalizeQty(input?.value ?? state.stockDraftQty ?? qty);
- if (state.productId) {
- setPantryProductQty(state.ingredientId, state.productId, nextQty);
+ if (product) {
+ setPantryProductQty(def.id, product.id, nextQty);
} else {
- setPantryQty(state.ingredientId, nextQty);
+ setPantryQty(def.id, nextQty);
}
state.stockEditorOpen = false;
state.stockDraftQty = null;
@@ -455,76 +440,13 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
});
}
- function productRowHtml(ingredientId, productId, pantry, selectedProductId) {
- const def = INGREDIENTS[ingredientId];
- const product = PRODUCTS[productId];
- const icon = CATEGORY_ICONS[def.category] || 'fa-jar';
- const qty = getPantryProducts(ingredientId, pantry).find((i) => i.productId === productId)?.qty || 0;
- const isSelected = selectedProductId === productId;
- return `
`;
- }
-
- function renderProducts() {
- const wrap = el('products');
- if (!wrap || !state.ingredientId) return;
- if (!ingredientHasProducts(state.ingredientId) || !state.allowProductSelection) {
- wrap.innerHTML = '';
- return;
- }
-
- const pantry = loadPantry();
- const products = sortProductsByStock(getProductsForIngredient(state.ingredientId), getPantryProducts(state.ingredientId, pantry));
- const selectedProductId = state.selectedProductId || state.productId;
- const subtitle = state.productId
- ? 'Wróć lub wybierz inny wariant.'
- : 'Wybierz wariant, aby zobaczyć szczegóły.';
-
- wrap.innerHTML = `
-
Produkty
-
${esc(subtitle)}
-
- ${products.map((product) => productRowHtml(state.ingredientId, product.id, pantry, selectedProductId)).join('')}
-
`;
-
- wrap.querySelectorAll('.ingredient-card-product-row').forEach((btn) => {
- btn.addEventListener('click', () => {
- const nextProductId = btn.dataset.productId || null;
- state.productId = nextProductId;
- state.selectedProductId = nextProductId;
- resetInlineEditors();
- if (nextProductId) state.onProductChange?.(nextProductId);
- render();
- state.onAfterChange?.();
- });
- });
- }
-
- function renderShop() {
- const wrap = el('shop');
- if (!wrap || !state.ingredientId) return;
- const def = INGREDIENTS[state.ingredientId];
- if (!def) return;
-
- const product = state.productId ? PRODUCTS[state.productId] : null;
+ function renderShopEditorInto(wrap, def, product) {
const { step, usesPackStep } = getQtyStepMeta(def, product);
const packSize = product?.packSize || def.purchasePack?.amount;
const packLabel = product?.packLabel || def.purchasePack?.label;
const usesPacks = Boolean(packSize && packSize > 0);
const defaultAmount = step;
- const shoppingItem = getCurrentShoppingItem(def);
+ const shoppingItem = getShoppingItemFor(def, product);
const hasShoppingItem = Boolean(shoppingItem);
const shoppingAmount = shoppingItem?.amount || 0;
const draftQty = state.shopEditorOpen
@@ -542,7 +464,7 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
? formatPreciseQty(draftQty / step)
: formatPreciseQty(draftQty);
const shopInputUnit = usesPackStep ? 'opak.' : unitLabel(def.pantryUnit);
- const actionLabel = state.shopEditorOpen ? 'Anuluj' : 'Zmień';
+ const actionLabel = state.shopEditorOpen ? 'Anuluj' : (hasShoppingItem ? 'Zmień' : 'Dodaj');
wrap.innerHTML = `
Lista zakupów
@@ -632,14 +554,14 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
} else if (nextAmount > 0) {
const note = usesPacks ? (packLabel || `${formatQty(packSize)} ${unitLabel(def.pantryUnit)}`) : undefined;
const line = {
- ingredientId: state.ingredientId,
+ ingredientId: def.id,
amount: nextAmount,
unit: unitLabel(def.pantryUnit),
name: product?.name || def.name,
category: def.category,
sourceNote: note || state.sourceNote || defaultSourceNote,
};
- if (state.productId) line.productId = state.productId;
+ if (product) line.productId = product.id;
addOrMergeShoppingLines([line]);
toastText = `Dodano ${product?.name || def.name}.`;
}
@@ -652,6 +574,111 @@ export function createIngredientCardController({ idBase, defaultSourceNote = 'Ze
});
}
+ function renderStock() {
+ const wrap = el('stock');
+ if (!wrap || !state.ingredientId) return;
+ const def = INGREDIENTS[state.ingredientId];
+ if (!def) return;
+
+ const hasProducts = ingredientHasProducts(state.ingredientId);
+ const isListMode = hasProducts && state.allowProductSelection && !state.productId;
+ if (isListMode) {
+ wrap.innerHTML = '';
+ return;
+ }
+
+ const pantry = loadPantry();
+ const product = state.productId ? PRODUCTS[state.productId] : null;
+ renderStockEditorInto(wrap, def, product, pantry);
+ }
+
+ function productRowHtml(ingredientId, productId, pantry, kitchenItems) {
+ const def = INGREDIENTS[ingredientId];
+ const product = PRODUCTS[productId];
+ const icon = CATEGORY_ICONS[def.category] || 'fa-jar';
+ const unit = unitLabel(def.pantryUnit);
+ const pantryQty = getPantryProducts(ingredientId, pantry).find((i) => i.productId === productId)?.qty || 0;
+ const shoppingItem = kitchenItems.find((item) => !item.checked
+ && item.ingredientId === ingredientId
+ && item.unit === unit
+ && (item.productId || '') === productId);
+ const shoppingAmount = shoppingItem?.amount || 0;
+
+ const pantryLabel = pantryQty > 0 ? `${formatQty(pantryQty)} ${unit}` : '—';
+ const pantryColor = pantryQty > 0 ? '#ddd6ca' : '#6d6c67';
+ const shoppingLabel = shoppingAmount > 0 ? `${formatQty(shoppingAmount)} ${unit}` : '';
+
+ return `
`;
+ }
+
+ function renderProducts() {
+ const wrap = el('products');
+ if (!wrap || !state.ingredientId) return;
+ const hasProducts = ingredientHasProducts(state.ingredientId);
+ const isListMode = hasProducts && state.allowProductSelection && !state.productId;
+ if (!isListMode) {
+ wrap.innerHTML = '';
+ return;
+ }
+
+ const pantry = loadPantry();
+ const products = sortProductsByStock(getProductsForIngredient(state.ingredientId), getPantryProducts(state.ingredientId, pantry));
+ const shopping = loadShoppingState();
+ const kitchen = shopping.lists.find((list) => list.id === KITCHEN_LIST_ID && list.type === 'kitchen');
+ const kitchenItems = (kitchen && kitchen.type === 'kitchen') ? kitchen.items : [];
+
+ wrap.innerHTML = `
+
Produkty
+
+ ${products.map((product) => productRowHtml(state.ingredientId, product.id, pantry, kitchenItems)).join('')}
+
`;
+
+ wrap.querySelectorAll('.ingredient-card-product-row').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ const nextProductId = btn.dataset.productId || null;
+ if (!nextProductId) return;
+ state.productId = nextProductId;
+ state.selectedProductId = nextProductId;
+ resetInlineEditors();
+ state.onProductChange?.(nextProductId);
+ render();
+ state.onAfterChange?.();
+ });
+ });
+ }
+
+ function renderShop() {
+ const wrap = el('shop');
+ if (!wrap || !state.ingredientId) return;
+ const def = INGREDIENTS[state.ingredientId];
+ if (!def) return;
+
+ const hasProducts = ingredientHasProducts(state.ingredientId);
+ const isListMode = hasProducts && state.allowProductSelection && !state.productId;
+ if (isListMode) {
+ wrap.innerHTML = '';
+ return;
+ }
+
+ const product = state.productId ? PRODUCTS[state.productId] : null;
+ renderShopEditorInto(wrap, def, product);
+ }
+
function render() {
if (!state.ingredientId) return;
const def = INGREDIENTS[state.ingredientId];
diff --git a/js/ui/mealPlanEditor.js b/js/ui/mealPlanEditor.js
index 66cb7e7..80515aa 100644
--- a/js/ui/mealPlanEditor.js
+++ b/js/ui/mealPlanEditor.js
@@ -24,7 +24,7 @@ import {
renderCalendarGrid,
syncCalendarTodayButton,
} from './mealCalendar.js?v=11';
-import { createIngredientCardController, getIngredientCardHTML } from './ingredientCard.js?v=20260410-107';
+import { createIngredientCardController, getIngredientCardHTML } from './ingredientCard.js?v=20260417-113';
function esc(s) {
return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
diff --git a/js/views/Pantry.js b/js/views/Pantry.js
index 6609f5f..3848b43 100644
--- a/js/views/Pantry.js
+++ b/js/views/Pantry.js
@@ -13,7 +13,7 @@ import {
renderCalendarGrid,
syncCalendarTodayButton,
} from '../ui/mealCalendar.js?v=11';
-import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260410-107';
+import { createIngredientCardController, getIngredientCardHTML } from '../ui/ingredientCard.js?v=20260417-113';
/* ── helpers ── */
@@ -253,12 +253,8 @@ export function getPantryHTML() {
-
- ${getIngredientCardHTML({
- idBase: 'pv2-card',
- overlayClass: 'absolute inset-0 z-[60] hidden opacity-0 transition-opacity duration-200 flex items-center justify-center p-5',
- })}
-