Public Access
feat: Phase 8 Feedback UI + API endpoints
- New backend/app/api/feedback.py: GET/POST for meal_plan_item feedback - MealDetail.tsx: star rating, never-suggest checkbox, reason dropdown, free-text comments, displays saved feedback - frontend/src/api/index.ts + types: feedback API + TypeScript interface - backend/app/schemas/__init__.py: model_validator maps qty→quantity for RecipeIngredient (fixes Pydantic validation on recipe JSONB) - docs/HANDOFF.md: mark Phase 8 complete, update file map and date
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import FamilyProfile, Feedback, MealPlanItem
|
||||
from app.schemas import FeedbackCreate, FeedbackResponse
|
||||
from app.security import require_session
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/{meal_plan_item_id}", response_model=FeedbackResponse | None)
|
||||
def get_feedback(
|
||||
meal_plan_item_id: UUID,
|
||||
db: Session = Depends(get_db),
|
||||
family_id: str = Depends(require_session),
|
||||
):
|
||||
"""Get existing feedback for a meal plan item."""
|
||||
item = db.query(MealPlanItem).filter(MealPlanItem.id == meal_plan_item_id).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Meal plan item not found")
|
||||
|
||||
feedback = (
|
||||
db.query(Feedback)
|
||||
.filter(
|
||||
Feedback.meal_plan_item_id == meal_plan_item_id,
|
||||
Feedback.family_profile_id == UUID(family_id),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
return feedback
|
||||
|
||||
|
||||
@router.post("", response_model=FeedbackResponse)
|
||||
def create_feedback(
|
||||
data: FeedbackCreate,
|
||||
db: Session = Depends(get_db),
|
||||
family_id: str = Depends(require_session),
|
||||
):
|
||||
"""Create or update feedback for a meal plan item."""
|
||||
item = db.query(MealPlanItem).filter(
|
||||
MealPlanItem.id == data.meal_plan_item_id
|
||||
).first()
|
||||
if not item:
|
||||
raise HTTPException(status_code=404, detail="Meal plan item not found")
|
||||
|
||||
profile = db.query(FamilyProfile).filter(FamilyProfile.id == UUID(family_id)).first()
|
||||
if not profile:
|
||||
raise HTTPException(status_code=404, detail="Family profile not found")
|
||||
|
||||
existing = (
|
||||
db.query(Feedback)
|
||||
.filter(
|
||||
Feedback.meal_plan_item_id == data.meal_plan_item_id,
|
||||
Feedback.family_profile_id == UUID(family_id),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if existing:
|
||||
existing.rating = data.rating
|
||||
existing.never_suggest = data.never_suggest
|
||||
existing.denial_reason = data.denial_reason.value if data.denial_reason else None
|
||||
existing.feedback_text = data.feedback_text
|
||||
db.commit()
|
||||
db.refresh(existing)
|
||||
return existing
|
||||
|
||||
feedback = Feedback(
|
||||
family_profile_id=UUID(family_id),
|
||||
meal_plan_item_id=data.meal_plan_item_id,
|
||||
rating=data.rating,
|
||||
never_suggest=data.never_suggest,
|
||||
denial_reason=data.denial_reason.value if data.denial_reason else None,
|
||||
feedback_text=data.feedback_text,
|
||||
)
|
||||
db.add(feedback)
|
||||
db.commit()
|
||||
db.refresh(feedback)
|
||||
return feedback
|
||||
Reference in New Issue
Block a user