From 9665e245c2e7514b3cd8e907f6314c42cf7813a9 Mon Sep 17 00:00:00 2001 From: kobold-ai Date: Thu, 15 Oct 2026 22:11:02 +0200 Subject: [PATCH] Sort items alphabetically within categories, move live pill next to menu, fix category add button wrap, and fix meal plan ingredients import --- app/database.py | 4 +- app/main.py | 5 +- app/templates/shopping_list.html | 228 ++++++++++++++++++++----------- 3 files changed, 156 insertions(+), 81 deletions(-) diff --git a/app/database.py b/app/database.py index f4c297a..ca3e74a 100755 --- a/app/database.py +++ b/app/database.py @@ -1255,6 +1255,7 @@ def get_meal_plan_ingredients(year: int, week: int) -> List[Dict[str, Any]]: "slot_label": slot_label, "raw": raw_text, "name": name, + "item_name": name, "amount": amt, "unit": unit }) @@ -1264,7 +1265,8 @@ def get_meal_plan_ingredients(year: int, week: int) -> List[Dict[str, Any]]: "recipe_id": recipe["id"], "recipe_title": recipe["title"], "slot_label": slot_label, - "items": items + "items": items, + "ingredients": items }) return recipe_groups diff --git a/app/main.py b/app/main.py index 2df2d28..9ca0235 100755 --- a/app/main.py +++ b/app/main.py @@ -1069,8 +1069,9 @@ async def api_update_shopping_item(item_id: int, payload: ShoppingItemUpdate): async def api_add_shopping_bulk(payload: ShoppingBulkCreate): items_dicts = [it.model_dump() for it in payload.items] count = add_shopping_items_bulk(items_dicts) - await shopping_ws_manager.broadcast({"action": "items_updated", "items": get_shopping_list()}) - return {"status": "ok", "added_count": count} + current_items = get_shopping_list() + await shopping_ws_manager.broadcast({"action": "items_updated", "items": current_items}) + return {"status": "ok", "added_count": count, "items": current_items} @app.post("/api/shopping-list/{item_id}/toggle") diff --git a/app/templates/shopping_list.html b/app/templates/shopping_list.html index 13f69d0..f8b1f92 100644 --- a/app/templates/shopping_list.html +++ b/app/templates/shopping_list.html @@ -402,64 +402,68 @@ 🛒

Einkaufsliste

- ● Live - -
- - - - - - 🏠 Startseite - - - 📖 Kochbuch - - - 🚪 Abmelden - -
+ +
+ ● Live - -
- -
- - - -
- -
- + 🏠 Startseite - + 📖 Kochbuch -
- + 🚪 Abmelden
+ + +
+ +
+ + + +
+ +
+ + 🏠 Startseite + + + 📖 Kochbuch + +
+ + 🚪 Abmelden + +
+
@@ -701,10 +705,12 @@

Neuen Bereich anlegen

-
- - - + +
+ + +
+
@@ -1008,6 +1014,8 @@ let html = ''; groupNames.forEach(catName => { const group = groups[catName]; + group.open.sort((a, b) => (a.item_name || '').localeCompare(b.item_name || '', 'de', { sensitivity: 'base' })); + group.checked.sort((a, b) => (a.item_name || '').localeCompare(b.item_name || '', 'de', { sensitivity: 'base' })); const allInGroup = [...group.open, ...group.checked]; if (allInGroup.length === 0) return; @@ -1296,61 +1304,97 @@ // ========================================== // MODAL: WOCHENPLAN ZUTATEN IMPORTIEREN // ========================================== - async function openMealPlanImportModal() { + let mealPlanYear = null; + let mealPlanWeek = null; + + async function openMealPlanImportModal(year, week) { openModal('modal-import-mealplan'); const body = document.getElementById('mealplan-import-body'); const confirmBtn = document.getElementById('btn-confirm-import-mealplan'); - if (confirmBtn) confirmBtn.disabled = true; + if (confirmBtn) { + confirmBtn.disabled = true; + confirmBtn.textContent = 'Ausgewählte übernehmen'; + } body.innerHTML = `
- ⏳ Zutaten des aktuellen Wochenplans werden geladen... + ⏳ Zutaten des Wochenplans werden geladen...
`; try { - const res = await fetch('/api/mealplan/ingredients'); + let url = '/api/mealplan/ingredients'; + if (year && week) { + url += `?year=${encodeURIComponent(year)}&week=${encodeURIComponent(week)}`; + } + const res = await fetch(url); if (!res.ok) throw new Error('Fehler beim Laden'); const data = await res.json(); + mealPlanYear = data.year; + mealPlanWeek = data.week; const groups = data.groups || []; + let navHeader = ` +
+
+ + KW ${data.week} / ${data.year} + +
+
+ + | + +
+
+ `; + if (groups.length === 0) { - body.innerHTML = ` + body.innerHTML = navHeader + `
-

Keine Rezepte im Wochenplan gefunden.

-

Plane zuerst Gerichte im Kochbuch-Wochenmenüplan ein!

+ 🍽️ +

Keine Rezepte in dieser Woche geplant

+

Blättere mit ◀ oder ▶ zu einer anderen Woche oder trage Gerichte im Kochbuch-Wochenmenüplan ein.

`; return; } - let html = ` -
- KW ${data.week} / ${data.year} - -
-
+ let totalItems = 0; + let html = navHeader + ` +
`; groups.forEach((g, gIdx) => { + const items = g.items || g.ingredients || []; + totalItems += items.length; html += `
-
- 🍳 ${escapeHtml(g.recipe_title)} +
+
+ 🍳 ${escapeHtml(g.recipe_title)} +
+ ${g.slot_label ? `${escapeHtml(g.slot_label)}` : ''}
- ${g.ingredients.map((ing, iIdx) => ` - - `).join('')} + ${items.map((ing, iIdx) => { + const ingName = ing.name || ing.item_name || ing.raw || ''; + const amtStr = formatAmount(ing.amount, ing.unit); + return ` + + `; + }).join('')}
`; @@ -1358,25 +1402,46 @@ html += `
`; body.innerHTML = html; - if (confirmBtn) confirmBtn.disabled = false; + if (confirmBtn) { + confirmBtn.disabled = totalItems === 0; + confirmBtn.textContent = `Ausgewählte übernehmen (${totalItems})`; + } } catch (err) { + console.error("Fehler beim Laden des Wochenplans:", err); body.innerHTML = ` -
+
Fehler beim Laden des Wochenplans. Bitte stelle sicher, dass du online bist.
`; } } + function changeMealPlanImportWeek(delta) { + if (!mealPlanYear || !mealPlanWeek) return; + let w = mealPlanWeek + delta; + let y = mealPlanYear; + if (w < 1) { + y -= 1; + w = 52; + } else if (w > 52) { + y += 1; + w = 1; + } + openMealPlanImportModal(y, w); + } + function toggleAllMealPlanChecks(val) { document.querySelectorAll('.mealplan-ing-checkbox').forEach(cb => cb.checked = val); updateMealPlanConfirmBtn(); } function updateMealPlanConfirmBtn() { - const anyChecked = Array.from(document.querySelectorAll('.mealplan-ing-checkbox')).some(cb => cb.checked); + const checkedBoxes = Array.from(document.querySelectorAll('.mealplan-ing-checkbox:checked')); const btn = document.getElementById('btn-confirm-import-mealplan'); - if (btn) btn.disabled = !anyChecked; + if (btn) { + btn.disabled = checkedBoxes.length === 0; + btn.textContent = `Ausgewählte übernehmen (${checkedBoxes.length})`; + } } async function confirmImportMealPlanIngredients() { @@ -1402,13 +1467,20 @@ }); if (res.ok) { const d = await res.json(); - allItems = d.items || []; + if (d.items && Array.isArray(d.items)) { + allItems = d.items; + } else { + await refreshDataFromServer(); + } localStorage.setItem('wtc_shop_items_cache', JSON.stringify(allItems)); renderCategoryFilterChips(); renderShoppingList(); - showToast(`${itemsToAdd.length} Zutaten übernommen`); + showToast(`✓ ${itemsToAdd.length} Zutaten übernommen`); + } else { + showToast('Fehler beim Übernehmen'); } } catch (err) { + console.error("Fehler beim Importieren der Zutaten:", err); showToast('Fehler beim Übernehmen'); } }