60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
/**
|
|
* /u/[handle] — public profile, Posts tab (default).
|
|
*
|
|
* Server shell that exists for three reasons:
|
|
*
|
|
* 1. Export `generateMetadata` so direct shares of this URL
|
|
* (https://prabhupadasays.org/u/<handle>) get a rich OG card
|
|
* pointing at /api/og/profile/<handle>. The layout and the body
|
|
* below are client components; only this file is server.
|
|
* 2. Emit server-rendered ProfilePage/Person JSON-LD so crawlers + LLMs
|
|
* can resolve the profile (the layout is a client component and
|
|
* fetches the profile after hydration, too late for crawlers).
|
|
* 3. Mount the client tree (<PostsGrid />), which reads the
|
|
* ProfileContext provided by the parent layout.
|
|
*/
|
|
|
|
import type { Metadata } from "next";
|
|
import { bff } from "@/lib/bff";
|
|
import { JsonLd } from "@/components/seo/json-ld";
|
|
import { profileJsonLd } from "@/lib/jsonld";
|
|
import { PostsGrid } from "./posts-grid";
|
|
import { metadataForHandle } from "./profile-og";
|
|
|
|
type Props = { params: Promise<{ handle: string }> };
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { handle } = await params;
|
|
return metadataForHandle(handle);
|
|
}
|
|
|
|
export default async function PublicProfilePage({ params }: Props) {
|
|
const { handle } = await params;
|
|
|
|
let person: object | null = null;
|
|
try {
|
|
const profile = await bff<{
|
|
handle: string;
|
|
name: string;
|
|
avatar_url?: string | null;
|
|
}>(`/u/${encodeURIComponent(handle)}`, { revalidate: 60 });
|
|
if (profile) {
|
|
person = profileJsonLd({
|
|
path: `/u/${profile.handle}`,
|
|
name: profile.name,
|
|
handle: profile.handle,
|
|
image: profile.avatar_url ?? null,
|
|
});
|
|
}
|
|
} catch {
|
|
// Profile unavailable — skip JSON-LD rather than fail the page.
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{person ? <JsonLd data={person} /> : null}
|
|
<PostsGrid params={params} />
|
|
</>
|
|
);
|
|
}
|