Event templates

This commit is contained in:
2026-06-20 17:37:29 -04:00
parent 17b2a5d835
commit 569c8cf80d
11 changed files with 173 additions and 35 deletions
+75 -2
View File
@@ -52,6 +52,22 @@ type DirectusFile = {
type?: string;
};
type EventTemplateRecord = {
id: number;
title?: string;
slug?: string;
description?: string;
image?: string;
logo?: string;
booking_url?: string;
};
type EventDateRecord = {
id: number;
date?: string;
template?: EventTemplateRecord | number | null;
};
function directusHeaders(): Record<string, string> | undefined {
if (!directusToken) return undefined;
return { Authorization: `Bearer ${directusToken}` };
@@ -97,7 +113,7 @@ async function readDirectusEndpoint<T>(endpoint: URL): Promise<T[]> {
return payload.data ?? [];
}
function resolveDirectusAssetUrl(fileId: string): string {
export function resolveDirectusAssetUrl(fileId: string): string {
return new URL(`/assets/${fileId}`, directusPublicUrl).toString();
}
@@ -138,6 +154,56 @@ async function getImagesFromFolder(folderName: string, fallbackImages: HomepageB
export const getHomepageBannerImages = () => getImagesFromFolder(homepageBannerFolder, fallbackHomepageBannerImages);
export const getCafePageImages = () => getImagesFromFolder(cafePageFolder, fallbackCafePageImages);
function stripHtml(value = ''): string {
return value
.replace(/<[^>]*>/g, ' ')
.replace(/&nbsp;/g, ' ')
.replace(/&amp;/g, '&')
.replace(/&rsquo;/g, "'")
.replace(/&lsquo;/g, "'")
.replace(/&ldquo;/g, '"')
.replace(/&rdquo;/g, '"')
.replace(/\s+/g, ' ')
.trim();
}
function mapEventDateToEventItem(eventDate: EventDateRecord): EventItem | null {
if (!eventDate.date || !eventDate.template || typeof eventDate.template === 'number') return null;
const template = eventDate.template;
if (!template.title || !template.slug) return null;
const description = template.description ?? '';
const summary = stripHtml(description).slice(0, 180);
return {
id: `${template.id}-${eventDate.id}`,
date_id: eventDate.id,
template_id: template.id,
title: template.title,
slug: template.slug,
summary: summary ? `${summary}${summary.length === 180 ? '...' : ''}` : undefined,
description,
start_datetime: eventDate.date,
realimage: template.image,
logo: template.logo ? resolveDirectusAssetUrl(template.logo) : undefined,
registration_link: template.booking_url,
};
}
async function getRecurringEvents(): Promise<EventItem[]> {
const endpoint = new URL('/items/event_dates', directusUrl);
endpoint.searchParams.set('limit', '100');
endpoint.searchParams.set('sort', 'date');
endpoint.searchParams.set(
'fields',
'id,date,template.id,template.title,template.slug,template.description,template.image,template.logo,template.booking_url',
);
const eventDates = await readDirectusEndpoint<EventDateRecord>(endpoint);
return eventDates.map(mapEventDateToEventItem).filter((event): event is EventItem => event !== null);
}
function fallbackFor(collection: CollectionName) {
switch (collection) {
case 'news':
@@ -156,7 +222,14 @@ function fallbackFor(collection: CollectionName) {
}
export const getNews = () => readCollection<NewsItem>('news');
export const getEvents = () => readCollection<EventItem>('events');
export async function getEvents(): Promise<EventItem[]> {
try {
const recurringEvents = await getRecurringEvents();
return recurringEvents.length > 0 ? recurringEvents : readCollection<EventItem>('events');
} catch {
return readCollection<EventItem>('events');
}
}
export const getNotices = () => readCollection<Notice>('notices');
export const getFuelPrices = () => readCollection<FuelPrice>('fuel_prices');
export const getDocuments = () => readCollection<DocumentItem>('documents');