Files
Spanglish/frontend/src/app/sitemap.ts
T
MichilisandCursor f5fe87613f Add stable /next and /featured URLs that redirect to the current event.
These short links always resolve to the latest upcoming or featured event so they can be shared without updating when events rotate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-27 05:35:52 +00:00

125 lines
3.1 KiB
TypeScript

import { MetadataRoute } from 'next';
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://spanglish.com.py';
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
interface SitemapEvent {
id: string;
slug: string;
status: string;
startDatetime: string;
updatedAt: string;
}
/**
* Fetch all indexable events: published, completed, and cancelled.
* Sold-out / past events stay in the index (marked as expired, not removed).
* Only draft and archived events are excluded.
*/
async function getIndexableEvents(): Promise<SitemapEvent[]> {
try {
const [publishedRes, completedRes] = await Promise.all([
fetch(`${apiUrl}/api/events?status=published`, {
next: { tags: ['events-sitemap'] },
}),
fetch(`${apiUrl}/api/events?status=completed`, {
next: { tags: ['events-sitemap'] },
}),
]);
const published = publishedRes.ok
? ((await publishedRes.json()).events as SitemapEvent[]) || []
: [];
const completed = completedRes.ok
? ((await completedRes.json()).events as SitemapEvent[]) || []
: [];
return [...published, ...completed];
} catch {
return [];
}
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const events = await getIndexableEvents();
const now = new Date();
// Static pages
const staticPages: MetadataRoute.Sitemap = [
{
url: siteUrl,
lastModified: now,
changeFrequency: 'weekly',
priority: 1,
},
{
url: `${siteUrl}/events`,
lastModified: now,
changeFrequency: 'daily',
priority: 0.9,
},
{
url: `${siteUrl}/next`,
lastModified: now,
changeFrequency: 'daily',
priority: 0.8,
},
{
url: `${siteUrl}/featured`,
lastModified: now,
changeFrequency: 'daily',
priority: 0.8,
},
{
url: `${siteUrl}/community`,
lastModified: now,
changeFrequency: 'monthly',
priority: 0.7,
},
{
url: `${siteUrl}/contact`,
lastModified: now,
changeFrequency: 'monthly',
priority: 0.6,
},
{
url: `${siteUrl}/faq`,
lastModified: now,
changeFrequency: 'monthly',
priority: 0.6,
},
// Legal pages
{
url: `${siteUrl}/legal/terms-policy`,
lastModified: now,
changeFrequency: 'yearly',
priority: 0.3,
},
{
url: `${siteUrl}/legal/privacy-policy`,
lastModified: now,
changeFrequency: 'yearly',
priority: 0.3,
},
{
url: `${siteUrl}/legal/refund-cancelation-policy`,
lastModified: now,
changeFrequency: 'yearly',
priority: 0.3,
},
];
// Dynamic event pages — upcoming events get higher priority
const eventPages: MetadataRoute.Sitemap = events.map((event) => {
const isUpcoming = new Date(event.startDatetime) > now;
return {
url: `${siteUrl}/events/${event.slug}`,
lastModified: new Date(event.updatedAt),
changeFrequency: isUpcoming ? ('weekly' as const) : ('monthly' as const),
priority: isUpcoming ? 0.8 : 0.5,
};
});
return [...staticPages, ...eventPages];
}