Use same-origin /api in the browser so builds are not stuck with baked-in localhost. Server-side fetches use INTERNAL_API_URL, NEXT_PUBLIC_API_URL, or loopback. Centralize logic in lib/api-base.ts. Made-with: Cursor
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import type { Metadata } from "next";
|
|
import EventDetailClient from "./EventDetailClient";
|
|
import { EventJsonLd, BreadcrumbJsonLd } from "@/components/public/JsonLd";
|
|
import { apiUrl } from "@/lib/api-base";
|
|
|
|
async function fetchEvent(id: string) {
|
|
try {
|
|
const res = await fetch(apiUrl(`/meetups/${id}`), {
|
|
next: { revalidate: 300 },
|
|
});
|
|
if (!res.ok) return null;
|
|
return res.json();
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
interface Props {
|
|
params: Promise<{ id: string }>;
|
|
}
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { id } = await params;
|
|
const event = await fetchEvent(id);
|
|
if (!event) {
|
|
return { title: "Event Not Found" };
|
|
}
|
|
|
|
const description =
|
|
event.description?.slice(0, 160) ||
|
|
`Bitcoin meetup: ${event.title}${event.location ? ` in ${event.location}` : ""}. Organized by the Belgian Bitcoin Embassy.`;
|
|
|
|
const ogImage = event.imageId
|
|
? `/media/${event.imageId}`
|
|
: `/og?title=${encodeURIComponent(event.title)}&type=event`;
|
|
|
|
return {
|
|
title: event.title,
|
|
description,
|
|
openGraph: {
|
|
type: "article",
|
|
title: event.title,
|
|
description,
|
|
images: [{ url: ogImage, width: 1200, height: 630, alt: event.title }],
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: event.title,
|
|
description,
|
|
images: [ogImage],
|
|
},
|
|
alternates: { canonical: `/events/${id}` },
|
|
};
|
|
}
|
|
|
|
export default async function EventDetailPage({ params }: Props) {
|
|
const { id } = await params;
|
|
const event = await fetchEvent(id);
|
|
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://belgianbitcoinembassy.org";
|
|
|
|
return (
|
|
<>
|
|
{event && (
|
|
<>
|
|
<EventJsonLd
|
|
name={event.title}
|
|
description={event.description}
|
|
startDate={event.date}
|
|
location={event.location}
|
|
url={`${siteUrl}/events/${id}`}
|
|
imageUrl={event.imageId ? `${siteUrl}/media/${event.imageId}` : undefined}
|
|
/>
|
|
<BreadcrumbJsonLd
|
|
items={[
|
|
{ name: "Home", href: "/" },
|
|
{ name: "Events", href: "/events" },
|
|
{ name: event.title, href: `/events/${id}` },
|
|
]}
|
|
/>
|
|
</>
|
|
)}
|
|
<EventDetailClient id={id} />
|
|
</>
|
|
);
|
|
}
|