Fix duplicate item display immediately after adding to shopping list

This commit is contained in:
2026-10-23 15:08:42 +02:00
parent e3bf88f018
commit a9f8e83202
2 changed files with 40 additions and 12 deletions
+3 -2
View File
@@ -1181,8 +1181,9 @@ async def api_add_shopping_item(payload: ShoppingItemCreate):
category=payload.category,
note=payload.note or ""
)
await shopping_ws_manager.broadcast({"action": "items_updated", "items": get_shopping_list()})
return {"status": "ok", "item": item}
current_items = get_shopping_list()
await shopping_ws_manager.broadcast({"action": "items_updated", "items": current_items})
return {"status": "ok", "item": item, "items": current_items}
@app.put("/api/shopping-list/{item_id}")
+37 -10
View File
@@ -955,10 +955,25 @@
localStorage.setItem('wtc_shop_cats_cache', JSON.stringify(allCategories));
}
function deduplicateItems(items) {
if (!Array.isArray(items)) return [];
const seenIds = new Set();
const unique = [];
for (const item of items) {
if (!item) continue;
const key = item.id ? `id_${item.id}` : `name_${(item.item_name || '').toLowerCase().trim()}_${item.checked ? '1' : '0'}`;
if (!seenIds.has(key)) {
seenIds.add(key);
unique.push(item);
}
}
return unique;
}
function saveLocalCache(items) {
allItems = items;
allItems = deduplicateItems(items);
try {
localStorage.setItem('wtc_shop_items_cache', JSON.stringify(items));
localStorage.setItem('wtc_shop_items_cache', JSON.stringify(allItems));
} catch (e) {
console.warn('LocalStorage voll oder nicht verfügbar:', e);
}
@@ -1227,8 +1242,8 @@
const emptyState = document.getElementById('empty-state');
if (!container) return;
// Filter anwenden
let filtered = allItems;
// Filter anwenden (dedupliziert gegen parallele WebSocket- & Fetch-Ereignisse)
let filtered = deduplicateItems(allItems);
if (currentFilterCategory !== null) {
filtered = filtered.filter(it => (it.category || 'Sonstiges') === currentFilterCategory);
}
@@ -1459,12 +1474,19 @@
});
if (res.ok) {
const data = await res.json();
if (data.item) {
allItems.push(data.item);
saveLocalCache(allItems);
renderShoppingList();
renderCategoryFilterChips();
if (data.items && Array.isArray(data.items)) {
allItems = data.items;
} else if (data.item) {
const existingIdx = allItems.findIndex(it => it.id === data.item.id);
if (existingIdx >= 0) {
allItems[existingIdx] = data.item;
} else {
allItems.push(data.item);
}
}
saveLocalCache(allItems);
renderShoppingList();
renderCategoryFilterChips();
} else {
throw new Error('Server-Fehler');
}
@@ -1480,7 +1502,12 @@
checked: false,
source: ''
};
allItems.push(tempItem);
const existingIdx = allItems.findIndex(it => (it.item_name || '').toLowerCase().trim() === name.toLowerCase().trim() && !it.checked);
if (existingIdx >= 0) {
allItems[existingIdx] = tempItem;
} else {
allItems.push(tempItem);
}
pushOfflineQueue({ method: 'POST', url: '/api/shopping-list', body: payload });
saveLocalCache(allItems);
renderShoppingList();