diff --git a/app/api/endpoints/meal_plans.py b/app/api/endpoints/meal_plans.py
index ad647e4..5e9ed0e 100644
--- a/app/api/endpoints/meal_plans.py
+++ b/app/api/endpoints/meal_plans.py
@@ -19,6 +19,7 @@ from app.models.schemas.meal_plan import (
PrepTaskSummary,
ShoppingListResponse,
SlotSummary,
+ UpdatePlanRequest,
UpdatePrepTaskRequest,
UpsertSlotRequest,
VALID_MEAL_TYPES,
@@ -113,6 +114,28 @@ async def list_plans(
return result
+@router.patch("/{plan_id}", response_model=PlanSummary)
+async def update_plan(
+ plan_id: int,
+ req: UpdatePlanRequest,
+ session: CloudUser = Depends(get_session),
+ store: Store = Depends(get_store),
+) -> PlanSummary:
+ plan = await asyncio.to_thread(store.get_meal_plan, plan_id)
+ if plan is None:
+ raise HTTPException(status_code=404, detail="Plan not found.")
+ # Free tier stays dinner-only; paid+ may add meal types
+ if can_use("meal_plan_config", session.tier):
+ meal_types = [t for t in req.meal_types if t in VALID_MEAL_TYPES] or ["dinner"]
+ else:
+ meal_types = ["dinner"]
+ updated = await asyncio.to_thread(store.update_meal_plan_types, plan_id, meal_types)
+ if updated is None:
+ raise HTTPException(status_code=404, detail="Plan not found.")
+ slots = await asyncio.to_thread(store.get_plan_slots, plan_id)
+ return _plan_summary(updated, slots)
+
+
@router.get("/{plan_id}", response_model=PlanSummary)
async def get_plan(
plan_id: int,
diff --git a/app/db/store.py b/app/db/store.py
index 7bc7cca..296cc6c 100644
--- a/app/db/store.py
+++ b/app/db/store.py
@@ -1119,6 +1119,12 @@ class Store:
def get_meal_plan(self, plan_id: int) -> dict | None:
return self._fetch_one("SELECT * FROM meal_plans WHERE id = ?", (plan_id,))
+ def update_meal_plan_types(self, plan_id: int, meal_types: list[str]) -> dict | None:
+ return self._fetch_one(
+ "UPDATE meal_plans SET meal_types = ? WHERE id = ? RETURNING *",
+ (json.dumps(meal_types), plan_id),
+ )
+
def list_meal_plans(self) -> list[dict]:
return self._fetch_all("SELECT * FROM meal_plans ORDER BY week_start DESC")
diff --git a/app/models/schemas/meal_plan.py b/app/models/schemas/meal_plan.py
index 6e1a678..dca28c7 100644
--- a/app/models/schemas/meal_plan.py
+++ b/app/models/schemas/meal_plan.py
@@ -22,6 +22,10 @@ class CreatePlanRequest(BaseModel):
return v
+class UpdatePlanRequest(BaseModel):
+ meal_types: list[str]
+
+
class UpsertSlotRequest(BaseModel):
recipe_id: int | None = None
servings: float = Field(2.0, gt=0)
diff --git a/frontend/src/components/MealPlanView.vue b/frontend/src/components/MealPlanView.vue
index 7ee4c1e..c1d4c23 100644
--- a/frontend/src/components/MealPlanView.vue
+++ b/frontend/src/components/MealPlanView.vue
@@ -29,6 +29,70 @@
@add-meal-type="onAddMealType"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Save recipes from the Recipes tab to pick them here.
+
+
+
+
+
+
+
+
+
+
+
Add meal type
+
+
+
+
+
+