feat(events): add calendar email support

Help registrants add events to their calendars and keep waitlisted places distinct from confirmed attendance.
This commit is contained in:
2026-09-27 15:57:43 +02:00
parent 8e502b4a01
commit 5310272715
6 changed files with 388 additions and 18 deletions
+30 -12
View File
@@ -50,7 +50,7 @@ import {
useTranslation,
type Locale,
} from "~/i18n";
import { buildBreadcrumbJsonLd, buildMeta } from "~/lib/seo";
import { buildBreadcrumbJsonLd, buildEventJsonLd, buildMeta } from "~/lib/seo";
import type { Route } from "./+types/events-calendar";
import {
@@ -185,10 +185,25 @@ export async function loader({ params, request }: Route.LoaderArgs) {
};
}
export function meta({ location, matches }: Route.MetaArgs) {
export function meta({ location, matches, loaderData }: Route.MetaArgs) {
const root = readRootSeo(matches);
const copy = getRouteCopy(root.locale);
const search = new URLSearchParams(location.search);
const eventJsonLd = (loaderData?.events ?? []).map((event) =>
buildEventJsonLd({
siteUrl: root.siteUrl,
locale: root.locale,
name: event.title,
pathname: `${sectionPath("events", root.locale)}/${encodeURIComponent(event.slug)}`,
startDate: toIsoDate(event.start) ?? event.start,
...(event.end ? { endDate: toIsoDate(event.end) ?? event.end } : {}),
...(event.summary ? { description: event.summary } : {}),
...(event.image ? { image: event.image.src } : {}),
...(event.place ? { locationName: event.place } : {}),
...(event.region ? { addressLocality: event.region } : {}),
isOnline: event.format === "online" || event.format === "hybrid",
}),
);
return buildMeta({
locale: root.locale,
@@ -204,16 +219,19 @@ export function meta({ location, matches }: Route.MetaArgs) {
search.has("page") ||
search.has("view") ||
search.has("month"),
jsonLd: buildBreadcrumbJsonLd(root.siteUrl, [
{
name: translate(root.locale, "nav.sections.home"),
pathname: localizedPath("/", root.locale),
},
{
name: translate(root.locale, "nav.sections.events"),
pathname: sectionPath("events", root.locale),
},
]),
jsonLd: [
buildBreadcrumbJsonLd(root.siteUrl, [
{
name: translate(root.locale, "nav.sections.home"),
pathname: localizedPath("/", root.locale),
},
{
name: translate(root.locale, "nav.sections.events"),
pathname: sectionPath("events", root.locale),
},
]),
...eventJsonLd,
],
});
}