Add data-driven public pages (home, news, profile)
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.
This commit is contained in:
1 parent
8fca407f0f
commit
6e34d485d4
9 files changed
+327
-7
No files matched your search
@@ -0,0 +1,35 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import Link from "next/link";
|
||||
import { excerpt } from "@/lib/format";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
function formatDate(d: Date | null): string {
|
||||
return d ? d.toISOString().slice(0, 10) : "";
|
||||
}
|
||||
|
||||
export default async function NewsPage() {
|
||||
const articles = await prisma.websiteArticles.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 30,
|
||||
});
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>News</h1>
|
||||
{articles.length === 0 ? (
|
||||
<p className="muted">No articles yet.</p>
|
||||
) : (
|
||||
<div className="grid">
|
||||
{articles.map((a) => (
|
||||
<article key={a.slug} className="card">
|
||||
<h3 style={{ margin: "0 0 0.25rem" }}>
|
||||
<Link href={`/news/${a.slug}`}>{a.title}</Link>
|
||||
</h3>
|
||||
<p className="muted" style={{ marginTop: 0 }}>
|
||||
{formatDate(a.createdAt)}
|
||||
</p>
|
||||
<p style={{ margin: 0 }}>{excerpt(a.shortStory, 200)}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user