UI & Features: Einkaufsliste im Kochbuch-Design, Supermarkt-Bereiche mit Laufweg-Sortierung, Textumbruch & schlanker Header

This commit is contained in:
2026-10-15 17:31:29 +02:00
parent 56d6512461
commit 111966c3ae
4 changed files with 1521 additions and 298 deletions
+96 -3
View File
@@ -1,4 +1,5 @@
import os
import json
import uuid
import random
import shutil
@@ -49,7 +50,14 @@ from .database import (
delete_shopping_item,
delete_checked_shopping_items,
clear_shopping_list,
get_meal_plan_ingredients
get_meal_plan_ingredients,
get_shopping_categories,
add_shopping_category,
update_shopping_category,
delete_shopping_category,
reorder_shopping_categories,
reset_default_shopping_categories,
update_shopping_item_category
)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -185,10 +193,27 @@ class ShoppingItemCreate(BaseModel):
amount: Optional[str] = ""
unit: Optional[str] = ""
source: Optional[str] = ""
category: Optional[str] = None
class ShoppingBulkCreate(BaseModel):
items: List[ShoppingItemCreate]
class ShoppingCategoryCreate(BaseModel):
name: str
icon: Optional[str] = "🛒"
sort_order: Optional[int] = None
class ShoppingCategoryUpdate(BaseModel):
name: str
icon: Optional[str] = "🛒"
sort_order: Optional[int] = None
class ShoppingReorderRequest(BaseModel):
category_ids: List[int]
class ShoppingItemCategoryUpdate(BaseModel):
category: str
# ==========================================
# AUTH VIEWS
@@ -281,13 +306,26 @@ async def home_view(request: Request):
async def shopping_list_view(request: Request):
"""Einkaufsliste Übersicht"""
items = get_shopping_list()
categories = get_shopping_categories()
today = date.today()
iso_year, iso_week, _ = today.isocalendar()
def json_serial(obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
return str(obj)
items_json = json.dumps(items, default=json_serial)
categories_json = json.dumps(categories, default=json_serial)
return templates.TemplateResponse(
request=request,
name="shopping_list.html",
context={
"items": items,
"categories": categories,
"items_json": items_json,
"categories_json": categories_json,
"current_year": iso_year,
"current_week": iso_week
}
@@ -914,7 +952,8 @@ def api_clear_mealplan_week(year: int = Query(...), week: int = Query(...)):
@app.get("/api/shopping-list")
def api_get_shopping_list():
items = get_shopping_list()
return {"status": "ok", "items": items}
categories = get_shopping_categories()
return {"status": "ok", "items": items, "categories": categories}
@app.post("/api/shopping-list")
@@ -925,7 +964,8 @@ def api_add_shopping_item(payload: ShoppingItemCreate):
item_name=payload.item_name,
amount=payload.amount or "",
unit=payload.unit or "",
source=payload.source or ""
source=payload.source or "",
category=payload.category
)
return {"status": "ok", "item": item}
@@ -945,6 +985,14 @@ def api_toggle_shopping_item(item_id: int):
return {"status": "ok", "item": updated}
@app.post("/api/shopping-list/{item_id}/category")
def api_update_item_category(item_id: int, payload: ShoppingItemCategoryUpdate):
updated = update_shopping_item_category(item_id, payload.category)
if not updated:
raise HTTPException(status_code=404, detail="Eintrag nicht gefunden.")
return {"status": "ok", "item": updated}
@app.delete("/api/shopping-list/checked")
def api_delete_checked_shopping():
count = delete_checked_shopping_items()
@@ -963,6 +1011,51 @@ def api_delete_shopping_item(item_id: int):
return {"status": "ok", "deleted": success}
# ==========================================
# SHOPPING CATEGORIES API (SUPERMARKT-BEREICHE)
# ==========================================
@app.get("/api/shopping-categories")
def api_get_shopping_categories():
categories = get_shopping_categories()
return {"status": "ok", "categories": categories}
@app.post("/api/shopping-categories")
def api_add_shopping_category(payload: ShoppingCategoryCreate):
try:
cat = add_shopping_category(payload.name, payload.icon or "🛒", payload.sort_order)
return {"status": "ok", "category": cat}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@app.put("/api/shopping-categories/{cat_id}")
def api_update_shopping_category(cat_id: int, payload: ShoppingCategoryUpdate):
cat = update_shopping_category(cat_id, payload.name, payload.icon or "🛒", payload.sort_order)
if not cat:
raise HTTPException(status_code=404, detail="Bereich nicht gefunden.")
return {"status": "ok", "category": cat}
@app.delete("/api/shopping-categories/{cat_id}")
def api_delete_shopping_category(cat_id: int):
success = delete_shopping_category(cat_id)
return {"status": "ok", "deleted": success}
@app.post("/api/shopping-categories/reorder")
def api_reorder_shopping_categories(payload: ShoppingReorderRequest):
reorder_shopping_categories(payload.category_ids)
return {"status": "ok", "categories": get_shopping_categories()}
@app.post("/api/shopping-categories/reset-defaults")
def api_reset_default_shopping_categories():
cats = reset_default_shopping_categories()
return {"status": "ok", "categories": cats}
# ==========================================
# MEAL PLAN INGREDIENTS API
# ==========================================