Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
Merged Directus and PostgreSQL project data, implemented single project fetch from CMS, and modernized the NotFound component with liquid design.
90 lines
2.4 KiB
TypeScript
90 lines
2.4 KiB
TypeScript
import { prisma } from "@/lib/prisma";
|
|
import ProjectsPageClient from "@/app/_ui/ProjectsPageClient";
|
|
import type { Metadata } from "next";
|
|
import { getLanguageAlternates, toAbsoluteUrl } from "@/lib/seo";
|
|
import { getProjects as getDirectusProjects } from "@/lib/directus";
|
|
|
|
export const revalidate = 300;
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string }>;
|
|
}): Promise<Metadata> {
|
|
const { locale } = await params;
|
|
const languages = getLanguageAlternates({ pathWithoutLocale: "projects" });
|
|
return {
|
|
alternates: {
|
|
canonical: toAbsoluteUrl(`/${locale}/projects`),
|
|
languages,
|
|
},
|
|
};
|
|
}
|
|
|
|
export default async function ProjectsPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string }>;
|
|
}) {
|
|
const { locale } = await params;
|
|
|
|
// Fetch from PostgreSQL
|
|
const dbProjects = await prisma.project.findMany({
|
|
where: { published: true },
|
|
orderBy: { createdAt: "desc" },
|
|
include: {
|
|
translations: {
|
|
select: { title: true, description: true, locale: true },
|
|
},
|
|
},
|
|
});
|
|
|
|
// Fetch from Directus
|
|
let directusProjects: any[] = [];
|
|
try {
|
|
const fetched = await getDirectusProjects(locale, { published: true });
|
|
if (fetched) {
|
|
directusProjects = fetched.map(p => ({
|
|
...p,
|
|
id: parseInt(p.id) || 0,
|
|
}));
|
|
}
|
|
} catch (err) {
|
|
console.error("Directus projects fetch failed:", err);
|
|
}
|
|
|
|
const localizedDb = dbProjects.map((p) => {
|
|
const trPreferred = p.translations?.find((t) => t.locale === locale && (t?.title || t?.description));
|
|
const trDefault = p.translations?.find(
|
|
(t) => t.locale === p.defaultLocale && (t?.title || t?.description),
|
|
);
|
|
const tr = trPreferred ?? trDefault;
|
|
const { translations: _translations, ...rest } = p;
|
|
return {
|
|
...rest,
|
|
title: tr?.title ?? p.title,
|
|
description: tr?.description ?? p.description,
|
|
};
|
|
});
|
|
|
|
// Merge projects, prioritizing DB ones if slugs match
|
|
const allProjects = [...localizedDb];
|
|
const dbSlugs = new Set(localizedDb.map(p => p.slug));
|
|
|
|
for (const dp of directusProjects) {
|
|
if (!dbSlugs.has(dp.slug)) {
|
|
allProjects.push(dp);
|
|
}
|
|
}
|
|
|
|
// Final sort by date
|
|
allProjects.sort((a, b) => {
|
|
const dateA = new Date(a.date || a.createdAt || 0).getTime();
|
|
const dateB = new Date(b.date || b.createdAt || 0).getTime();
|
|
return dateB - dateA;
|
|
});
|
|
|
|
return <ProjectsPageClient projects={allProjects} locale={locale} />;
|
|
}
|
|
|