75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import type { PortfolioFilters } from "@/actions/portfolio/getPortfolioArtworksPage";
|
|
import PortfolioFiltersBar from "@/components/portfolio/PortfolioFiltersBar";
|
|
import PortfolioGallery from "@/components/portfolio/PortfolioGallery";
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
type SearchParams = {
|
|
year?: string;
|
|
q?: string;
|
|
};
|
|
|
|
function parseFilters(sp: SearchParams): PortfolioFilters {
|
|
const filters: PortfolioFilters = {};
|
|
|
|
const yearRaw = sp.year?.trim();
|
|
if (yearRaw && yearRaw !== "all") {
|
|
const y = Number(yearRaw);
|
|
if (Number.isFinite(y) && y > 0) filters.year = y;
|
|
}
|
|
|
|
const qRaw = sp.q?.trim();
|
|
if (qRaw) filters.q = qRaw;
|
|
|
|
return filters;
|
|
}
|
|
|
|
async function getExistingArtworkYears(): Promise<number[]> {
|
|
const rows = await prisma.artwork.findMany({
|
|
where: {
|
|
published: true,
|
|
year: { not: null },
|
|
},
|
|
select: { year: true },
|
|
distinct: ["year"],
|
|
orderBy: { year: "desc" },
|
|
});
|
|
|
|
return rows
|
|
.map((r) => r.year)
|
|
.filter((y): y is number => typeof y === "number");
|
|
}
|
|
|
|
export default async function PortfolioPage({
|
|
searchParams,
|
|
}: {
|
|
// Per your requirement: catch searchParams async
|
|
searchParams: Promise<SearchParams>;
|
|
}) {
|
|
const sp = await searchParams;
|
|
const [years, filters] = await Promise.all([
|
|
getExistingArtworkYears().catch(() => []), // never let this break rendering
|
|
Promise.resolve(parseFilters(sp)),
|
|
]);
|
|
|
|
return (
|
|
<div className="mx-auto w-full max-w-6xl px-4 py-8">
|
|
<header className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
|
|
<div className="space-y-1">
|
|
<h1 className="text-2xl font-semibold tracking-tight sm:text-3xl">
|
|
Portfolio
|
|
</h1>
|
|
<p className="text-sm text-muted-foreground">
|
|
Browse all published artworks.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
|
|
<PortfolioFiltersBar years={years} />
|
|
</div>
|
|
</header>
|
|
|
|
<PortfolioGallery filters={filters} />
|
|
</div>
|
|
);
|
|
}
|