feat: rating stars on recipe cards (Search, Explore)
New lib/recipe-ratings.ts helper batches avg score + review count for a set of recipe ids in one grouped query, kept separate from the main paginated/sorted search query rather than joining+grouping it directly (would've forced grouping by every selected column). Wired into /api/v1/search and the Explore page's trending/recent queries; SearchResultCard renders the star only when a recipe has at least one rating. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import Link from "next/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Clock, ChefHat } from "lucide-react";
|
||||
import { Clock, ChefHat, Star } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const DIFFICULTY_COLORS: Record<string, string> = {
|
||||
@@ -20,6 +20,8 @@ export type SearchResultRecipe = {
|
||||
prepMins: number | null;
|
||||
cookMins: number | null;
|
||||
authorName: string | null;
|
||||
avgRating?: number | null;
|
||||
ratingCount?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -58,6 +60,13 @@ export function SearchResultCard({ recipe, className }: { recipe: SearchResultRe
|
||||
{recipe.description && (
|
||||
<p className="mt-1 text-sm text-muted-foreground line-clamp-2">{recipe.description}</p>
|
||||
)}
|
||||
{!!recipe.ratingCount && recipe.avgRating != null && (
|
||||
<div className="mt-1.5 flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<Star className="h-3.5 w-3.5 fill-yellow-400 text-yellow-400" />
|
||||
<span className="font-medium text-foreground">{recipe.avgRating.toFixed(1)}</span>
|
||||
<span>({recipe.ratingCount})</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-3 flex items-center gap-3 text-xs text-muted-foreground">
|
||||
{totalMins > 0 && (
|
||||
<span className="flex items-center gap-1">
|
||||
|
||||
@@ -28,6 +28,8 @@ type SearchRecipeResult = {
|
||||
prepMins: number | null;
|
||||
cookMins: number | null;
|
||||
authorName: string | null;
|
||||
avgRating: number | null;
|
||||
ratingCount: number;
|
||||
};
|
||||
|
||||
type SearchResponse = {
|
||||
|
||||
Reference in New Issue
Block a user