52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
/**
|
|
* /c/[id] — public collection.
|
|
*
|
|
* Server shell: exports `generateMetadata` so a shared collection link
|
|
* unfurls with a rich OG card (pointing at /api/og/collection/<id>), then
|
|
* mounts the client body. The server fetch is unauthenticated, so only
|
|
* public collections produce a card — private ones fall back to the default
|
|
* (and never leak).
|
|
*/
|
|
|
|
import type { Metadata } from "next";
|
|
import { bff } from "@/lib/bff";
|
|
import { ogDefault, ogForCollection } from "@/lib/og";
|
|
import { CollectionContent } from "./collection-content";
|
|
|
|
type Props = { params: Promise<{ id: string }> };
|
|
|
|
type CollectionEnvelope = {
|
|
collection: {
|
|
id: string;
|
|
title: string;
|
|
description: string | null;
|
|
is_public: boolean;
|
|
item_count: number;
|
|
};
|
|
};
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { id } = await params;
|
|
try {
|
|
const data = await bff<CollectionEnvelope>(
|
|
`/collections/${encodeURIComponent(id)}`,
|
|
{ revalidate: 60 },
|
|
);
|
|
const c = data?.collection;
|
|
if (!c || !c.is_public) return ogDefault();
|
|
return ogForCollection({
|
|
id: c.id,
|
|
title: c.title,
|
|
description: c.description,
|
|
itemCount: c.item_count,
|
|
});
|
|
} catch {
|
|
// Private (403) / unreachable → fall back to the site card.
|
|
return ogDefault();
|
|
}
|
|
}
|
|
|
|
export default function PublicCollectionPage({ params }: Props) {
|
|
return <CollectionContent params={params} />;
|
|
}
|