Real App Router pages reading the converted Prisma models: - home: latest 4 articles (websiteArticles) + hotel_name from settings - /news + /news/[slug]: article index and detail - /u/[username]: profile (avatar via imager helper, motto, rank, credits, online) - shared SiteNav (reads session via auth() + hotel_name), globals.css - src/lib/format.ts: avatarImageUrl + excerpt helpers (unit-tested) Verified: tsc exit 0, vitest 43/43, next build exit 0 (7 routes). Pages render against a live DB (deferred until DATABASE_URL is provided). i18n to be layered on next.
36 lines
933 B
TypeScript
36 lines
933 B
TypeScript
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { prisma } from "@/lib/prisma";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function ArticlePage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ slug: string }>;
|
|
}) {
|
|
const { slug } = await params;
|
|
const article = await prisma.websiteArticles.findUnique({ where: { slug } });
|
|
if (!article) notFound();
|
|
|
|
return (
|
|
<main>
|
|
<p className="muted">
|
|
<Link href="/news">← News</Link>
|
|
</p>
|
|
<h1>{article.title}</h1>
|
|
{article.createdAt ? (
|
|
<p className="muted">{article.createdAt.toISOString().slice(0, 10)}</p>
|
|
) : null}
|
|
{article.image ? (
|
|
<img
|
|
src={article.image}
|
|
alt=""
|
|
style={{ width: "100%", borderRadius: 10, margin: "1rem 0" }}
|
|
/>
|
|
) : null}
|
|
<div style={{ whiteSpace: "pre-wrap" }}>{article.fullStory}</div>
|
|
</main>
|
|
);
|
|
}
|