Hard-filter /portfolio/:slug when it matches a category
Category chips (e.g. /portfolio/photography) now show only that category — empty if none. Audience views like /portfolio/game-dev still use prioritization.
This commit is contained in:
@@ -69,15 +69,41 @@ export async function publicRoutes(app: FastifyInstance) {
|
||||
const page = Math.max(1, parseInt(req.query.page || "1", 10) || 1);
|
||||
const perPage = Math.min(100, Math.max(1, parseInt(req.query.perPage || "24", 10) || 24));
|
||||
const sort = req.query.sort || "priority";
|
||||
const category = req.query.category;
|
||||
let category = req.query.category;
|
||||
const tag = req.query.tag;
|
||||
const featured =
|
||||
req.query.featured === "true" ? true : req.query.featured === "false" ? false : undefined;
|
||||
const q = req.query.q;
|
||||
const viewSlug = req.query.view;
|
||||
|
||||
// Portfolio view prioritization
|
||||
/**
|
||||
* /portfolio/:slug resolution:
|
||||
* 1) If slug matches a **category** → hard filter to only that category
|
||||
* (empty categories return zero results — used by category chips)
|
||||
* 2) Else if slug matches an audience **portfolio view** (game-dev, etc.)
|
||||
* → prioritize ordered categories; optionally include the rest
|
||||
*/
|
||||
let matchedCategory:
|
||||
| { id: string; name: string; slug: string; description: string | null }
|
||||
| null = null;
|
||||
|
||||
if (viewSlug && !category) {
|
||||
matchedCategory = await prisma.category.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ slug: viewSlug },
|
||||
{ name: { equals: viewSlug, mode: "insensitive" } },
|
||||
],
|
||||
},
|
||||
select: { id: true, name: true, slug: true, description: true },
|
||||
});
|
||||
if (matchedCategory) {
|
||||
category = matchedCategory.slug;
|
||||
}
|
||||
}
|
||||
|
||||
// Audience portfolio view prioritization (only when not a category slug)
|
||||
if (viewSlug && !matchedCategory && !req.query.category) {
|
||||
const view = await prisma.portfolioView.findFirst({
|
||||
where: { slug: viewSlug, isActive: true },
|
||||
include: {
|
||||
@@ -141,6 +167,7 @@ export async function publicRoutes(app: FastifyInstance) {
|
||||
perPage,
|
||||
total,
|
||||
totalPages: Math.ceil(total / perPage),
|
||||
mode: "view" as const,
|
||||
view: {
|
||||
slug: view.slug,
|
||||
name: view.name,
|
||||
@@ -233,6 +260,21 @@ export async function publicRoutes(app: FastifyInstance) {
|
||||
perPage,
|
||||
total,
|
||||
totalPages: Math.ceil(total / perPage),
|
||||
...(matchedCategory
|
||||
? {
|
||||
mode: "category" as const,
|
||||
category: matchedCategory,
|
||||
view: {
|
||||
slug: matchedCategory.slug,
|
||||
name: matchedCategory.name,
|
||||
description:
|
||||
matchedCategory.description ||
|
||||
`Projects in ${matchedCategory.name}.`,
|
||||
},
|
||||
}
|
||||
: category
|
||||
? { mode: "category" as const }
|
||||
: { mode: "all" as const }),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user