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(); }