feat: merge Explore and Activity Feed, unify recipe cards

Explore and Feed covered overlapping ground (recommendations, following,
trending) in two separate places with three different card designs.
Explore now hosts Discover/Following/For You tabs, and every recipe
card everywhere on the page matches the Recipes page's cover-photo
card instead of the old text-only search result.

v0.36.0
This commit is contained in:
Arnaud
2026-07-17 16:06:17 +02:00
parent 1577b8de01
commit 5763bd3318
17 changed files with 601 additions and 445 deletions
+13 -2
View File
@@ -12,6 +12,8 @@ import {
desc,
} from "@epicure/db";
import { getAvgRatingsByRecipeId } from "@/lib/recipe-ratings";
import { attachCardExtras } from "@/lib/recipe-card-extras";
import { getOptionalSession } from "@/lib/api-auth";
const VALID_DIETARY = ["vegan", "vegetarian", "glutenFree", "dairyFree"] as const;
type DietaryTag = (typeof VALID_DIETARY)[number];
@@ -130,6 +132,11 @@ export async function GET(req: NextRequest) {
baseServings: recipes.baseServings,
prepMins: recipes.prepMins,
cookMins: recipes.cookMins,
visibility: recipes.visibility,
tags: recipes.tags,
isBatchCook: recipes.isBatchCook,
sourceUrl: recipes.sourceUrl,
recipeType: recipes.recipeType,
authorId: recipes.authorId,
authorName: users.name,
createdAt: recipes.createdAt,
@@ -150,8 +157,12 @@ export async function GET(req: NextRequest) {
const total = countResult[0]?.total ?? 0;
const ratingByRecipe = await getAvgRatingsByRecipeId(rows.map((r) => r.id));
const data = rows.map((r) => ({
const session = await getOptionalSession();
const [ratingByRecipe, rowsWithExtras] = await Promise.all([
getAvgRatingsByRecipeId(rows.map((r) => r.id)),
attachCardExtras(rows, session?.user.id),
]);
const data = rowsWithExtras.map((r) => ({
...r,
avgRating: ratingByRecipe.get(r.id)?.avgRating ?? null,
ratingCount: ratingByRecipe.get(r.id)?.ratingCount ?? 0,