84d6cfeb07
List, detail, new, edit pages. Server-side pagination, dietary tags, difficulty. Photo upload to S3-compatible storage. Version history. Multi-select grid with bulk delete/visibility. Print view. Delete confirmation dialog.
49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { headers } from "next/headers";
|
|
import { auth } from "@/lib/auth/server";
|
|
import { db, recipes, recipeIngredients } from "@epicure/db";
|
|
import { eq, desc, and, ilike, or, sql } from "@epicure/db";
|
|
import { RecipesHeader } from "@/components/recipe/recipes-header";
|
|
import { RecipesEmptyState } from "@/components/recipe/recipes-empty-state";
|
|
import { RecipesGrid } from "@/components/recipe/recipes-grid";
|
|
|
|
export const metadata: Metadata = { title: "Recipes" };
|
|
|
|
type SearchParams = Promise<{ q?: string }>;
|
|
|
|
export default async function RecipesPage({ searchParams }: { searchParams: SearchParams }) {
|
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
if (!session) return null;
|
|
|
|
const { q } = await searchParams;
|
|
const query = q?.trim() ?? "";
|
|
|
|
const whereClause = query
|
|
? and(
|
|
eq(recipes.authorId, session.user.id),
|
|
or(
|
|
ilike(recipes.title, `%${query}%`),
|
|
ilike(recipes.description, `%${query}%`)
|
|
)
|
|
)
|
|
: eq(recipes.authorId, session.user.id);
|
|
|
|
const userRecipes = await db.query.recipes.findMany({
|
|
where: whereClause,
|
|
orderBy: desc(recipes.updatedAt),
|
|
with: { photos: true },
|
|
});
|
|
|
|
const totalCount = query ? undefined : userRecipes.length;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<RecipesHeader count={totalCount ?? userRecipes.length} initialQuery={query} />
|
|
|
|
<RecipesEmptyState query={query} count={userRecipes.length} />
|
|
|
|
<RecipesGrid recipes={userRecipes} />
|
|
</div>
|
|
);
|
|
}
|