Actualiser assets/js/app.js
CI / PHP Syntax Check (push) Has been cancelled
CI / JavaScript Lint (push) Has been cancelled
CI / Docker Build Test (push) Has been cancelled
CI / Validate Translation Files (push) Has been cancelled
CI / Auto-merge develop → main (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled

This commit is contained in:
2026-06-18 17:14:19 +00:00
parent 7c3fb41b43
commit 55d562e0a3
+34 -16
View File
@@ -7820,7 +7820,7 @@ window._editingProduct = {
<div class="qty-control-with-unit"> <div class="qty-control-with-unit">
<div class="qty-control"> <div class="qty-control">
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', -1)"></button> <button type="button" class="qty-btn" onclick="adjustQty('edit-qty', -1)"></button>
<input type="number" id="edit-qty" value="${item.quantity}" min="0" step="any" class="qty-input"> <input type="number" id="edit-qty" value="${_displayQtyForItem(item)}" min="0" step="any" class="qty-input">
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', 1)">+</button> <button type="button" class="qty-btn" onclick="adjustQty('edit-qty', 1)">+</button>
</div> </div>
<span class="qty-unit-badge" id="edit-qty-unit" aria-live="polite">${escapeHtml(getUnitDisplayLabel(item.unit || 'pz'))}</span> <span class="qty-unit-badge" id="edit-qty-unit" aria-live="polite">${escapeHtml(getUnitDisplayLabel(item.unit || 'pz'))}</span>
@@ -7837,7 +7837,8 @@ window._editingProduct = {
<div class="form-group"> <div class="form-group">
<label>${t('product.unit_label')}</label> <label>${t('product.unit_label')}</label>
<select id="edit-unit" class="form-input" onchange="onEditUnitChange()"> <select id="edit-unit" class="form-input" onchange="onEditUnitChange()">
${['pz','g','ml','conf'].map(u => `<option value="${u}" ${(item.unit||'pz') === u ? 'selected' : ''}>${u === 'pz' ? 'pz (' + t('units.pieces') + ')' : u === 'g' ? 'g (' + t('units.grams') + ')' : u === 'ml' ? 'ml (' + t('units.millilitres') + ')' : u === 'conf' ? 'conf (' + t('units.boxes') + ')' : u}</option>`).join('')} ${['pz','g','ml','conf'].map(u => `<option value="${u}" ${(!item.display_unit_key && (item.unit||'pz') === u) ? 'selected' : ''}>${u === 'pz' ? 'pz (' + t('units.pieces') + ')' : u === 'g' ? 'g (' + t('units.grams') + ')' : u === 'ml' ? 'ml (' + t('units.millilitres') + ')' : u === 'conf' ? 'conf (' + t('units.boxes') + ')' : u}</option>`).join('')}
${_customUnitOptionsHtml(item.display_unit_key)}
</select> </select>
</div> </div>
<div class="form-group" id="edit-conf-size-group" style="display:${isConf ? 'block' : 'none'}"> <div class="form-group" id="edit-conf-size-group" style="display:${isConf ? 'block' : 'none'}">
@@ -7919,12 +7920,13 @@ async function submitEditInventory(e, id, productId) {
document.getElementById('edit-inv-subcategory')?.focus(); document.getElementById('edit-inv-subcategory')?.focus();
return; return;
} }
const qty = parseFloat(document.getElementById('edit-qty').value); const { realUnit, factor, displayUnitKey } = resolveUnitSelection('edit-unit');
const qty = (parseFloat(document.getElementById('edit-qty').value) || 0) * factor;
const loc = document.getElementById('edit-loc').value; const loc = document.getElementById('edit-loc').value;
const noExpiryChecked = document.getElementById('edit-expiry-no-expiry')?.checked || false; const noExpiryChecked = document.getElementById('edit-expiry-no-expiry')?.checked || false;
if (noExpiryChecked) _dismissNoExpiry(productId); else _undismissNoExpiry(productId); if (noExpiryChecked) _dismissNoExpiry(productId); else _undismissNoExpiry(productId);
const expiry = noExpiryChecked ? null : (document.getElementById('edit-expiry').value || null); const expiry = noExpiryChecked ? null : (document.getElementById('edit-expiry').value || null);
const unit = document.getElementById('edit-unit').value; const unit = realUnit;
if (unit === 'conf') { if (unit === 'conf') {
const confSize = parseFloat(document.getElementById('edit-conf-size')?.value); const confSize = parseFloat(document.getElementById('edit-conf-size')?.value);
@@ -7944,6 +7946,7 @@ async function submitEditInventory(e, id, productId) {
} }
const payload = { id, quantity: qty, location: loc, expiry_date: expiry, unit, product_id: productId, const payload = { id, quantity: qty, location: loc, expiry_date: expiry, unit, product_id: productId,
display_unit_key: displayUnitKey,
vacuum_sealed: document.getElementById('edit-vacuum')?.checked ? 1 : 0, vacuum_sealed: document.getElementById('edit-vacuum')?.checked ? 1 : 0,
expiry_user_set: _expiryUserSetPayload('edit-expiry') }; expiry_user_set: _expiryUserSetPayload('edit-expiry') };
@@ -9233,6 +9236,19 @@ function onPfUnitChange() {
if (confRow) confRow.style.display = unit === 'conf' ? 'block' : 'none'; if (confRow) confRow.style.display = unit === 'conf' ? 'block' : 'none';
} }
function _customUnitOptionsHtml(selectedKey) {
return CUSTOM_UNITS.map(u => `<option value="${u.key}" ${selectedKey === u.key ? 'selected' : ''}>${u.icon} ${u.label}</option>`).join('');
}
function resolveUnitSelection(selectId) {
const val = document.getElementById(selectId)?.value || 'pz';
const cu = CUSTOM_UNITS.find(u => u.key === val);
if (cu) return { realUnit: cu.base_unit, factor: cu.factor, displayUnitKey: cu.key };
return { realUnit: val, factor: 1, displayUnitKey: null };
}
function _displayQtyForItem(item) {
const cu = item && item.display_unit_key ? CUSTOM_UNITS.find(u => u.key === item.display_unit_key) : null;
return cu ? (parseFloat(item.quantity) / cu.factor) : item.quantity;
}
function _updateBarcodeHint(inputId = 'pf-barcode', hintId = 'pf-barcode-hint') { function _updateBarcodeHint(inputId = 'pf-barcode', hintId = 'pf-barcode-hint') {
const hint = document.getElementById(hintId); const hint = document.getElementById(hintId);
const val = (document.getElementById(inputId)?.value || '').trim(); const val = (document.getElementById(inputId)?.value || '').trim();
@@ -9784,7 +9800,7 @@ function editActionInventoryItem(inventoryId) {
<div class="qty-control-with-unit"> <div class="qty-control-with-unit">
<div class="qty-control"> <div class="qty-control">
<button type="button" class="qty-btn" onclick="adjustQty('action-edit-qty', -1)"></button> <button type="button" class="qty-btn" onclick="adjustQty('action-edit-qty', -1)"></button>
<input type="number" id="action-edit-qty" value="${item.quantity}" min="0" step="any" class="qty-input"> <input type="number" id="action-edit-qty" value="${_displayQtyForItem(item)}" min="0" step="any" class="qty-input">
<button type="button" class="qty-btn" onclick="adjustQty('action-edit-qty', 1)">+</button> <button type="button" class="qty-btn" onclick="adjustQty('action-edit-qty', 1)">+</button>
</div> </div>
<span class="qty-unit-badge" id="action-edit-qty-unit" aria-live="polite">${escapeHtml(getUnitDisplayLabel(item.unit || 'pz'))}</span> <span class="qty-unit-badge" id="action-edit-qty-unit" aria-live="polite">${escapeHtml(getUnitDisplayLabel(item.unit || 'pz'))}</span>
@@ -9793,7 +9809,8 @@ function editActionInventoryItem(inventoryId) {
<div class="form-group"> <div class="form-group">
<label>${t('product.unit_label')}</label> <label>${t('product.unit_label')}</label>
<select id="action-edit-unit" class="form-input" onchange="onActionEditUnitChange()"> <select id="action-edit-unit" class="form-input" onchange="onActionEditUnitChange()">
${['pz','g','ml','conf'].map(u => `<option value="${u}" ${(item.unit||'pz') === u ? 'selected' : ''}>${u === 'pz' ? 'pz (' + t('units.pieces') + ')' : u === 'g' ? 'g (' + t('units.grams') + ')' : u === 'ml' ? 'ml (' + t('units.millilitres') + ')' : u === 'conf' ? 'conf (' + t('units.boxes') + ')' : u}</option>`).join('')} ${['pz','g','ml','conf'].map(u => `<option value="${u}" ${(!item.display_unit_key && (item.unit||'pz') === u) ? 'selected' : ''}>${u === 'pz' ? 'pz (' + t('units.pieces') + ')' : u === 'g' ? 'g (' + t('units.grams') + ')' : u === 'ml' ? 'ml (' + t('units.millilitres') + ')' : u === 'conf' ? 'conf (' + t('units.boxes') + ')' : u}</option>`).join('')}
${_customUnitOptionsHtml(item.display_unit_key)}
</select> </select>
</div> </div>
<div class="form-group" id="action-edit-conf-group" style="display:${isConf ? 'block' : 'none'}"> <div class="form-group" id="action-edit-conf-group" style="display:${isConf ? 'block' : 'none'}">
@@ -9849,14 +9866,15 @@ function onActionEditUnitChange() {
async function submitActionEditInventory(e, id, productId) { async function submitActionEditInventory(e, id, productId) {
e.preventDefault(); e.preventDefault();
const qty = parseFloat(document.getElementById('action-edit-qty').value); const { realUnit, factor, displayUnitKey } = resolveUnitSelection('action-edit-unit');
const qty = (parseFloat(document.getElementById('action-edit-qty').value) || 0) * factor;
const loc = document.getElementById('action-edit-loc').value; const loc = document.getElementById('action-edit-loc').value;
const noExpiryChecked = document.getElementById('action-edit-expiry-no-expiry')?.checked || false; const noExpiryChecked = document.getElementById('action-edit-expiry-no-expiry')?.checked || false;
if (noExpiryChecked) _dismissNoExpiry(productId); else _undismissNoExpiry(productId); if (noExpiryChecked) _dismissNoExpiry(productId); else _undismissNoExpiry(productId);
const expiry = noExpiryChecked ? null : (document.getElementById('action-edit-expiry').value || null); const expiry = noExpiryChecked ? null : (document.getElementById('action-edit-expiry').value || null);
const unit = document.getElementById('action-edit-unit').value; const unit = realUnit;
const payload = { id, quantity: qty, location: loc, expiry_date: expiry, unit, product_id: productId, const payload = { id, quantity: qty, location: loc, expiry_date: expiry, unit, product_id: productId,
display_unit_key: displayUnitKey,
vacuum_sealed: document.getElementById('action-edit-vacuum')?.checked ? 1 : 0, vacuum_sealed: document.getElementById('action-edit-vacuum')?.checked ? 1 : 0,
expiry_user_set: _expiryUserSetPayload('action-edit-expiry') }; expiry_user_set: _expiryUserSetPayload('action-edit-expiry') };
@@ -10714,10 +10732,8 @@ function _confirmRecentDuplicateAdd(recent, productName, addQty, unit, defQty, p
async function submitAdd(e) { async function submitAdd(e) {
e.preventDefault(); e.preventDefault();
const { realUnit: selectedUnit, factor: _addUnitFactor, displayUnitKey: _addDisplayUnitKey } = resolveUnitSelection('add-unit');
const selectedUnit = document.getElementById('add-unit').value;
const productUnit = currentProduct.unit || 'pz'; const productUnit = currentProduct.unit || 'pz';
if (selectedUnit === 'conf') { if (selectedUnit === 'conf') {
const confSize = parseFloat(document.getElementById('add-conf-size')?.value); const confSize = parseFloat(document.getElementById('add-conf-size')?.value);
if (!confSize || confSize <= 0) { if (!confSize || confSize <= 0) {
@@ -10726,9 +10742,8 @@ async function submitAdd(e) {
return; return;
} }
} }
const location = document.getElementById('add-location').value; const location = document.getElementById('add-location').value;
const addQty = parseFloat(document.getElementById('add-quantity').value) || 1; const addQty = (parseFloat(document.getElementById('add-quantity').value) || 1) * _addUnitFactor;
const pkgUnit = selectedUnit === 'conf' ? (document.getElementById('add-conf-unit')?.value || null) : null; const pkgUnit = selectedUnit === 'conf' ? (document.getElementById('add-conf-unit')?.value || null) : null;
const pkgSize = selectedUnit === 'conf' ? (parseFloat(document.getElementById('add-conf-size')?.value) || null) : null; const pkgSize = selectedUnit === 'conf' ? (parseFloat(document.getElementById('add-conf-size')?.value) || null) : null;
const unitForAdd = selectedUnit !== productUnit ? selectedUnit : productUnit; const unitForAdd = selectedUnit !== productUnit ? selectedUnit : productUnit;
@@ -10756,11 +10771,12 @@ async function submitAdd(e) {
if (noExpiryChecked) _dismissNoExpiry(currentProduct.id); if (noExpiryChecked) _dismissNoExpiry(currentProduct.id);
const result = await api('inventory_add', {}, 'POST', { const result = await api('inventory_add', {}, 'POST', {
product_id: currentProduct.id, product_id: currentProduct.id,
quantity: parseFloat(document.getElementById('add-quantity').value) || 1, quantity: addQty,
location: document.getElementById('add-location').value, location: document.getElementById('add-location').value,
expiry_date: noExpiryChecked ? null : (document.getElementById('add-expiry').value || null), expiry_date: noExpiryChecked ? null : (document.getElementById('add-expiry').value || null),
expiry_user_set: _expiryUserSetPayload('add-expiry'), expiry_user_set: _expiryUserSetPayload('add-expiry'),
unit: selectedUnit !== productUnit ? selectedUnit : null, unit: selectedUnit,
display_unit_key: _addDisplayUnitKey,
package_unit: selectedUnit === 'conf' ? (document.getElementById('add-conf-unit')?.value || null) : null, package_unit: selectedUnit === 'conf' ? (document.getElementById('add-conf-unit')?.value || null) : null,
package_size: selectedUnit === 'conf' ? (parseFloat(document.getElementById('add-conf-size')?.value) || null) : null, package_size: selectedUnit === 'conf' ? (parseFloat(document.getElementById('add-conf-size')?.value) || null) : null,
vacuum_sealed: document.getElementById('add-vacuum-sealed')?.checked ? 1 : 0, vacuum_sealed: document.getElementById('add-vacuum-sealed')?.checked ? 1 : 0,
@@ -20657,6 +20673,8 @@ async function _initApp() {
// Load recipe tags (used by the "Mes recettes" form and filter bar) // Load recipe tags (used by the "Mes recettes" form and filter bar)
await loadRecipeTags(); await loadRecipeTags();
await loadCustomUnits(); await loadCustomUnits();
const addUnitSelect = document.getElementById('add-unit');
if (addUnitSelect) addUnitSelect.insertAdjacentHTML('beforeend', _customUnitOptionsHtml());
// Check for setup wizard resume (after language change) // Check for setup wizard resume (after language change)
const resumeStep = localStorage.getItem('evershelf_setup_step'); const resumeStep = localStorage.getItem('evershelf_setup_step');