Feature: Einstiegsseite, Einkaufsliste, Wochenplan-Live-Suche & Zufallsgenerator-Optimierung

This commit is contained in:
2026-10-15 13:05:08 +02:00
parent 2b8c4a35cf
commit 0d6d0deb69
6 changed files with 2240 additions and 67 deletions
+134 -5
View File
@@ -41,7 +41,15 @@ from .database import (
get_meal_plan,
set_meal_plan_slot,
delete_meal_plan_slot,
clear_meal_plan_week
clear_meal_plan_week,
get_shopping_list,
add_shopping_item,
add_shopping_items_bulk,
toggle_shopping_item,
delete_shopping_item,
delete_checked_shopping_items,
clear_shopping_list,
get_meal_plan_ingredients
)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -172,6 +180,15 @@ class MealPlanSlotRequest(BaseModel):
recipe_id: Optional[int] = None
custom_text: Optional[str] = None
class ShoppingItemCreate(BaseModel):
item_name: str
amount: Optional[str] = ""
unit: Optional[str] = ""
source: Optional[str] = ""
class ShoppingBulkCreate(BaseModel):
items: List[ShoppingItemCreate]
# ==========================================
# AUTH VIEWS
@@ -238,10 +255,43 @@ async def logout():
# VIEWS
# ==========================================
@app.get("/")
async def index_view():
"""Hauptroute leitet direkt auf das Kochbuch um"""
return RedirectResponse(url="/cookbook", status_code=302)
@app.get("/", response_class=HTMLResponse)
async def home_view(request: Request):
"""Einstiegsseite: Ausgeklapptes Menü / Hub"""
all_recipes = get_all_recipes()
today = date.today()
iso_year, iso_week, _ = today.isocalendar()
shopping_items = get_shopping_list()
open_shopping_count = sum(1 for it in shopping_items if not it.get("checked"))
return templates.TemplateResponse(
request=request,
name="home.html",
context={
"recipe_count": len(all_recipes),
"current_year": iso_year,
"current_week": iso_week,
"open_shopping_count": open_shopping_count,
"chapters": CHAPTERS
}
)
@app.get("/shopping-list", response_class=HTMLResponse)
@app.get("/groceries", response_class=HTMLResponse)
async def shopping_list_view(request: Request):
"""Einkaufsliste Übersicht"""
items = get_shopping_list()
today = date.today()
iso_year, iso_week, _ = today.isocalendar()
return templates.TemplateResponse(
request=request,
name="shopping_list.html",
context={
"items": items,
"current_year": iso_year,
"current_week": iso_week
}
)
@app.get("/cookbook", response_class=HTMLResponse)
async def cookbook_view(
@@ -854,3 +904,82 @@ def api_clear_mealplan_week(year: int = Query(...), week: int = Query(...)):
count = clear_meal_plan_week(year, week)
return {"status": "ok", "cleared_count": count}
# ==========================================
# SHOPPING LIST API
# ==========================================
@app.get("/api/shopping-list")
def api_get_shopping_list():
items = get_shopping_list()
return {"status": "ok", "items": items}
@app.post("/api/shopping-list")
def api_add_shopping_item(payload: ShoppingItemCreate):
if not payload.item_name.strip():
raise HTTPException(status_code=400, detail="Name des Eintrags darf nicht leer sein.")
item = add_shopping_item(
item_name=payload.item_name,
amount=payload.amount or "",
unit=payload.unit or "",
source=payload.source or ""
)
return {"status": "ok", "item": item}
@app.post("/api/shopping-list/bulk")
def api_add_shopping_bulk(payload: ShoppingBulkCreate):
items_dicts = [it.model_dump() for it in payload.items]
count = add_shopping_items_bulk(items_dicts)
return {"status": "ok", "added_count": count}
@app.post("/api/shopping-list/{item_id}/toggle")
def api_toggle_shopping_item(item_id: int):
updated = toggle_shopping_item(item_id)
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()
return {"status": "ok", "deleted_count": count}
@app.delete("/api/shopping-list/all")
def api_clear_shopping_list():
count = clear_shopping_list()
return {"status": "ok", "cleared_count": count}
@app.delete("/api/shopping-list/{item_id}")
def api_delete_shopping_item(item_id: int):
success = delete_shopping_item(item_id)
return {"status": "ok", "deleted": success}
# ==========================================
# MEAL PLAN INGREDIENTS API
# ==========================================
@app.get("/api/mealplan/ingredients")
def api_get_mealplan_ingredients(
year: Optional[int] = Query(None),
week: Optional[int] = Query(None)
):
today = date.today()
iso_year, iso_week, _ = today.isocalendar()
y = year or iso_year
w = week or iso_week
groups = get_meal_plan_ingredients(y, w)
return {
"status": "ok",
"year": y,
"week": w,
"groups": groups
}