diff --git a/src/manage_packing_list_items.php b/src/manage_packing_list_items.php index ba4d73d..c14a7f0 100644 --- a/src/manage_packing_list_items.php +++ b/src/manage_packing_list_items.php @@ -57,10 +57,11 @@ if ($current_user_household_id) { $placeholders = implode(',', array_fill(0, count($household_member_ids), '?')); $types = str_repeat('i', count($household_member_ids)); -$sql_all_articles = "SELECT a.id, a.name, a.weight_grams, a.quantity_owned, a.product_designation, a.consumable, a.parent_article_id, a.image_url, c.name as category_name, m.name as manufacturer_name +$sql_all_articles = "SELECT a.id, a.name, a.weight_grams, a.quantity_owned, a.product_designation, a.consumable, a.parent_article_id, a.image_url, c.name as category_name, m.name as manufacturer_name, sl.name as storage_location_name FROM articles a LEFT JOIN categories c ON a.category_id = c.id LEFT JOIN manufacturers m ON a.manufacturer_id = m.id + LEFT JOIN storage_locations sl ON a.storage_location_id = sl.id WHERE a.user_id IN ($placeholders)"; $all_params = $household_member_ids; $all_types = $types; @@ -150,7 +151,7 @@ $conn->close(); /* Lager Grid */ .lager-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; padding: 5px; } .lager-card { @@ -160,7 +161,7 @@ $conn->close(); } .lager-card:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.05); } .lager-img-wrapper { - height: 130px; margin-bottom: 8px; display: flex; + height: 160px; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; } .lager-img-wrapper img { @@ -222,8 +223,9 @@ $conn->close();
Lagerbestand
-
-
+
+
+
@@ -288,6 +290,7 @@ $conn->close(); const tsOptions = { create: false, sortField: { field: "text", direction: "asc" }, allowEmptyOption: true, onChange: function() { this.input.dispatchEvent(new Event('change')); } }; new TomSelect('#filter-category', tsOptions); new TomSelect('#filter-manufacturer', tsOptions); + new TomSelect('#group-by', tsOptions); const tooltip = document.getElementById('image-preview-tooltip'); if (tooltip) { @@ -314,6 +317,7 @@ $conn->close(); document.getElementById('filter-text').addEventListener(evt, renderLager); document.getElementById('filter-category').addEventListener(evt, renderLager); document.getElementById('filter-manufacturer').addEventListener(evt, renderLager); + document.getElementById('group-by').addEventListener(evt, renderLager); }); document.getElementById('table-container').addEventListener('click', handlePackedItemActions); @@ -334,6 +338,7 @@ $conn->close(); const filterText = document.getElementById('filter-text').value.toLowerCase(); const filterCategory = document.getElementById('filter-category').value; const filterManufacturer = document.getElementById('filter-manufacturer').value; + const groupBy = document.getElementById('group-by').value; const tableQuantities = {}; const backpackQuantities = {}; @@ -349,7 +354,8 @@ $conn->close(); } }); - let html = '
'; + let groups = {}; + allArticles.forEach(article => { if (article.parent_article_id) return; @@ -371,7 +377,7 @@ $conn->close(); const imgUrl = article.image_url ? article.image_url : 'assets/images/keinbild.png'; const plusBtnClass = qtyTable > 0 ? 'btn-success' : 'btn-outline-primary'; - html += ` + const cardHtml = `
@@ -386,9 +392,18 @@ $conn->close(); ${qtyTable} auf dem Tisch
`; + + let groupKey = groupBy ? (article[groupBy] || 'Ohne Zuordnung') : 'Alle Artikel'; + if (!groups[groupKey]) groups[groupKey] = ''; + groups[groupKey] += cardHtml; } }); - html += '
'; + + let html = ''; + Object.keys(groups).sort().forEach(key => { + if (groupBy) html += `
${key}
`; + html += `
${groups[key]}
`; + }); document.getElementById('lager-container').innerHTML = html; } @@ -436,13 +451,22 @@ $conn->close(); function renderTable() { const container = document.getElementById('table-container'); + + Object.keys(sortableInstances).forEach(k => { + if (k === 'table' || k.startsWith('table_nested_')) { + if(sortableInstances[k]) { + try { sortableInstances[k].destroy(); } catch(e){} + } + delete sortableInstances[k]; + } + }); + container.innerHTML = ''; const tableItems = packedItems.filter(item => item.carrier_user_id == null && !item.backpack_id && !item.backpack_compartment_id && !item.parent_packing_list_item_id); - renderRecursive(tableItems, container, packedItems); + renderRecursive(tableItems, container, packedItems, 'table_'); - if(sortableInstances['table']) sortableInstances['table'].destroy(); sortableInstances['table'] = new Sortable(container, { group: 'nested', animation: 150, @@ -456,9 +480,17 @@ $conn->close(); function renderCarriersAndPackedItems() { const container = document.getElementById('carriers-container'); - container.innerHTML = ''; - Object.keys(sortableInstances).forEach(k => { if(k !== 'table') sortableInstances[k].destroy(); }); + Object.keys(sortableInstances).forEach(k => { + if (k.startsWith('carrier_')) { + if(sortableInstances[k]) { + try { sortableInstances[k].destroy(); } catch(e){} + } + delete sortableInstances[k]; + } + }); + + container.innerHTML = ''; carriers.forEach(carrier => { const carrierId = carrier.id; // Sonstiges removed, so carrier.id is never null @@ -484,7 +516,7 @@ $conn->close(); } }); - renderRecursive(rootItems, carrierRootList, itemsById); + renderRecursive(rootItems, carrierRootList, itemsById, 'carrier_'); sortableInstances['carrier_'+carrierId] = new Sortable(carrierRootList, { group: 'nested', @@ -498,7 +530,7 @@ $conn->close(); }); } - function renderRecursive(items, container, contextMap) { + function renderRecursive(items, container, contextMap, prefix) { items.forEach(item => { let children = item.children || []; if (!item.children && Array.isArray(contextMap)) { @@ -509,10 +541,10 @@ $conn->close(); container.appendChild(itemEl); const nestedContainer = itemEl.querySelector('.nested-sortable'); if (children && children.length > 0) { - renderRecursive(children, nestedContainer, contextMap); + renderRecursive(children, nestedContainer, contextMap, prefix); } - sortableInstances['nested_'+item.id] = new Sortable(nestedContainer, { + sortableInstances[prefix + 'nested_'+item.id] = new Sortable(nestedContainer, { group: 'nested', animation: 150, handle: '.packed-item-content', fallbackOnBody: true, swapThreshold: 0.65, ghostClass: 'sortable-ghost', onEnd: function() { syncListState(); }