UI & Features: Einkaufsliste im Kochbuch-Design, Supermarkt-Bereiche mit Laufweg-Sortierung, Textumbruch & schlanker Header
This commit is contained in:
+96
-3
@@ -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
|
||||
# ==========================================
|
||||
|
||||
Reference in New Issue
Block a user