5763bd3318
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
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
import { db, recipePhotos, recipeBatchDishes, favorites, inArray, eq, and } from "@epicure/db";
|
|
|
|
export type CardExtras = {
|
|
photos: { storageKey: string; isCover: boolean }[];
|
|
dishCount: number;
|
|
isFavorited: boolean;
|
|
};
|
|
|
|
/** Batches the photo/batch-dish/favorite lookups a recipe grid card needs, for
|
|
* list endpoints whose main query selects individual recipe columns rather
|
|
* than going through `db.query.recipes.findMany`'s relational loader. */
|
|
export async function attachCardExtras<T extends { id: string }>(
|
|
recipeList: T[],
|
|
viewerId?: string
|
|
): Promise<(T & CardExtras)[]> {
|
|
const ids = recipeList.map((r) => r.id);
|
|
if (ids.length === 0) return [];
|
|
|
|
const [photoRows, dishRows, favoritedRows] = await Promise.all([
|
|
db
|
|
.select({ recipeId: recipePhotos.recipeId, storageKey: recipePhotos.storageKey, isCover: recipePhotos.isCover })
|
|
.from(recipePhotos)
|
|
.where(inArray(recipePhotos.recipeId, ids)),
|
|
db
|
|
.select({ recipeId: recipeBatchDishes.recipeId })
|
|
.from(recipeBatchDishes)
|
|
.where(inArray(recipeBatchDishes.recipeId, ids)),
|
|
viewerId
|
|
? db
|
|
.select({ recipeId: favorites.recipeId })
|
|
.from(favorites)
|
|
.where(and(eq(favorites.userId, viewerId), inArray(favorites.recipeId, ids)))
|
|
: Promise.resolve([]),
|
|
]);
|
|
|
|
const photosByRecipe = new Map<string, { storageKey: string; isCover: boolean }[]>();
|
|
for (const p of photoRows) {
|
|
const arr = photosByRecipe.get(p.recipeId) ?? [];
|
|
arr.push({ storageKey: p.storageKey, isCover: p.isCover });
|
|
photosByRecipe.set(p.recipeId, arr);
|
|
}
|
|
|
|
const dishCountByRecipe = new Map<string, number>();
|
|
for (const d of dishRows) dishCountByRecipe.set(d.recipeId, (dishCountByRecipe.get(d.recipeId) ?? 0) + 1);
|
|
|
|
const favoritedSet = new Set(favoritedRows.map((f) => f.recipeId));
|
|
|
|
return recipeList.map((r) => ({
|
|
...r,
|
|
photos: photosByRecipe.get(r.id) ?? [],
|
|
dishCount: dishCountByRecipe.get(r.id) ?? 0,
|
|
isFavorited: favoritedSet.has(r.id),
|
|
}));
|
|
}
|