Introduces the Go photo-api service, nginx/systemd deploy wiring, and Next.js gallery/lightbox pages so event photos can be managed and browsed. Co-authored-by: Cursor <cursoragent@cursor.com>
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import type { Metadata } from 'next';
|
||
import { Suspense } from 'react';
|
||
import type { PhotoGallery, Photo } from '@/lib/api';
|
||
import GalleryClient from './GalleryClient';
|
||
|
||
const photoApiUrl = process.env.PHOTO_API_URL || 'http://localhost:3003';
|
||
|
||
interface PageProps {
|
||
params: { slug: string };
|
||
}
|
||
|
||
// Public galleries render server-side (SEO + fast first paint); link and
|
||
// ticket galleries return null here and are fetched client-side with the
|
||
// viewer's token / share token.
|
||
async function getPublicGallery(
|
||
slug: string
|
||
): Promise<{ gallery: PhotoGallery; photos: Photo[] } | null> {
|
||
try {
|
||
const res = await fetch(
|
||
`${photoApiUrl}/api/photos/public/galleries/${encodeURIComponent(slug)}`,
|
||
{ next: { revalidate: 300 } }
|
||
);
|
||
if (!res.ok) return null;
|
||
return await res.json();
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||
const data = await getPublicGallery(params.slug);
|
||
if (!data) {
|
||
return { title: 'Photo Gallery', robots: { index: false } };
|
||
}
|
||
return {
|
||
title: `${data.gallery.title} – Photos`,
|
||
description:
|
||
data.gallery.description ||
|
||
`Photos from ${data.gallery.title}, a Spanglish language exchange event in Asunción.`,
|
||
};
|
||
}
|
||
|
||
export default async function GalleryPage({ params }: PageProps) {
|
||
const initial = await getPublicGallery(params.slug);
|
||
return (
|
||
// Suspense boundary required by useSearchParams() in the client child.
|
||
<Suspense>
|
||
<GalleryClient slug={params.slug} initial={initial} />
|
||
</Suspense>
|
||
);
|
||
}
|