fix: show dish calories in search and fix portion sheet layout crash

- DishSearchResult now carries calories_per_serving (backend entity + repo
  LEFT JOIN recipes / MIN / GROUP BY; Flutter model + fromJson)
- _FoodTile.fromDish shows kcal/serving subtitle when available
- _DishPortionSheet quick-select buttons: Row → Wrap to avoid
  BoxConstraints infinite-width crash inside DraggableScrollableSheet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dbastrikin
2026-03-21 16:08:20 +02:00
parent 6af7d2fade
commit bf8dce36c5
4 changed files with 31 additions and 23 deletions

View File

@@ -61,10 +61,11 @@ type RecipeStep struct {
// DishSearchResult is a lightweight dish returned by the search endpoint.
type DishSearchResult struct {
ID string `json:"id"`
Name string `json:"name"`
ImageURL *string `json:"image_url,omitempty"`
AvgRating float64 `json:"avg_rating"`
ID string `json:"id"`
Name string `json:"name"`
ImageURL *string `json:"image_url,omitempty"`
AvgRating float64 `json:"avg_rating"`
CaloriesPerServing *float64 `json:"calories_per_serving,omitempty"`
}
// CreateRequest is the body used to create a new dish + recipe at once.

View File

@@ -111,6 +111,7 @@ func (r *Repository) Search(ctx context.Context, query string, limit int) ([]*Di
COALESCE(dt.name, d.name) AS name,
d.image_url,
d.avg_rating,
MIN(r.calories_per_serving) AS calories_per_serving,
GREATEST(
ts_rank(to_tsvector('english', d.name), plainto_tsquery('english', $1)),
ts_rank(to_tsvector('simple', COALESCE(dt.name, '')), plainto_tsquery('simple', $1)),
@@ -118,6 +119,7 @@ func (r *Repository) Search(ctx context.Context, query string, limit int) ([]*Di
) AS rank
FROM dishes d
LEFT JOIN dish_translations dt ON dt.dish_id = d.id AND dt.lang = $3
LEFT JOIN recipes r ON r.dish_id = d.id
WHERE (
to_tsvector('english', d.name) @@ plainto_tsquery('english', $1)
OR to_tsvector('simple', COALESCE(dt.name, '')) @@ plainto_tsquery('simple', $1)
@@ -125,6 +127,7 @@ func (r *Repository) Search(ctx context.Context, query string, limit int) ([]*Di
OR dt.name ILIKE '%' || $1 || '%'
OR similarity(COALESCE(dt.name, d.name), $1) > 0.3
)
GROUP BY d.id, dt.name, d.name, d.image_url, d.avg_rating
ORDER BY rank DESC
LIMIT $2`
@@ -138,7 +141,7 @@ func (r *Repository) Search(ctx context.Context, query string, limit int) ([]*Di
for rows.Next() {
var result DishSearchResult
var rank float64
if scanError := rows.Scan(&result.ID, &result.Name, &result.ImageURL, &result.AvgRating, &rank); scanError != nil {
if scanError := rows.Scan(&result.ID, &result.Name, &result.ImageURL, &result.AvgRating, &result.CaloriesPerServing, &rank); scanError != nil {
return nil, fmt.Errorf("scan dish search result: %w", scanError)
}
results = append(results, &result)