Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/Common/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import clsx from "clsx";

import Link from "@/components/Common/Link";
import type { EventEnriched } from "@/content";
import { formatDate } from "@/utils/formatDate";

import EventCardDescription from "./EventCardDescription";
import EventCardImage from "./EventCardImage";
Expand All @@ -22,7 +23,8 @@ function EventCard({
className?: string;
style?: React.CSSProperties;
}) {
const eventUrl = `/events/${event.id}`;
const date = formatDate(event.data.dateTime, "date");
const eventUrl = `/events/${event.id}-${date}`;

const [springs, api] = useSpring(() => ({
scale: 1,
Expand Down
3 changes: 2 additions & 1 deletion src/components/Common/MarkdownContent.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const { markdown, class: className = "prose prose-lg max-w-none" } = Astro.props
const markdownFiles = import.meta.glob("/content/**/*.md");

// Normalize the path to match the glob pattern
const fullPath = `/content/${markdown}`;
// check markdown file name without date
const fullPath = `/content/${markdown}`.replace(/-(\d{4}-\d{2}-\d{2})\//, "/");

if (!markdownFiles[fullPath]) {
throw new Error(`Markdown file not found: ${fullPath}`);
Expand Down
4 changes: 3 additions & 1 deletion src/content/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { FALLBACK_COVER, SHOW_DEV_ENTRIES } from "@/constants";
import { type GalleryImage, getGalleryImages } from "@/content/gallery";
import { type ProcessedVenue, processVenue } from "@/content/venues";
import { isEventUpcoming } from "@/utils/eventFilters";
import { replaceDate } from "@/utils/formatSlug";
import { memoize } from "@/utils/memoize";
import { type ResponsiveImageData, getResponsiveImage } from "@/utils/responsiveImage";

Expand Down Expand Up @@ -120,7 +121,8 @@ export async function eventsLoader() {
}

export const getEvent = memoize(async (eventSlug: string) => {
const event = await getEntry("events", eventSlug);
const eventSlugWithoutDate = replaceDate(eventSlug);
const event = await getEntry("events", eventSlugWithoutDate);
if (!event) throw new Error(`No event found for slug ${eventSlug}`);
let venueSlug: string | undefined;
let venueData: ProcessedVenue | undefined;
Expand Down
7 changes: 5 additions & 2 deletions src/pages/events/[eventSlug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import EventTags from "@/components/Event/EventTags";
import EventActionAlert from "@/components/Event/EventActionAlert";
import MarketingRedirect from "@/components/Event/MarketingRedirect";
import { isEventUpcoming } from "@/utils/eventFilters";
import { formatDate } from "@/utils/formatDate";

export async function getStaticPaths() {
const events = await getEvents();

return events.map(({ id }) => {
return events.map((event) => {
const eventDate = formatDate(event.data.dateTime, "date");

return {
params: { eventSlug: id },
params: { eventSlug: `${event.id}-${eventDate}` },
};
});
}
Expand Down
6 changes: 5 additions & 1 deletion src/utils/formatDate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type DateFormat = "long" | "short" | "short-no-year" | "datetime";
export type DateFormat = "long" | "short" | "short-no-year" | "datetime" | "date";

export function formatDate(date: Date | string, format: DateFormat = "short"): string {
const dateObj = typeof date === "string" ? new Date(date) : date;
Expand All @@ -21,6 +21,10 @@ export function formatDate(date: Date | string, format: DateFormat = "short"): s
});
}

if (format === "date") {
return dateObj.toISOString().split("T")[0];
}

if (format === "datetime") {
const year = dateObj.getUTCFullYear();
const month = String(dateObj.getUTCMonth() + 1).padStart(2, "0");
Expand Down
3 changes: 3 additions & 0 deletions src/utils/formatSlug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function replaceDate(slug: string): string {
return slug.replace(/-\d{4}-\d{2}-\d{2}$/, "");
}
2 changes: 1 addition & 1 deletion test/e2e/latest-event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ test.describe("Latest Event Visibility", () => {
});

test("latest event detail page exists with correct information", async ({ page }) => {
const eventUrl = `/events/${latestEvent!.slug}`;
const eventUrl = `/events/${latestEvent!.slug}-${formatDate(latestEvent!.dateTime, "date")}`;
await page.goto(eventUrl);

// Check the title is on the page
Expand Down
6 changes: 3 additions & 3 deletions test/helpers/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

// Test event constants - these are development-only events that should be used in tests
export const TEST_EVENTS = {
PRIMARY: "999999999-example-dev-event",
SECONDARY: "999999998-example-dev-event-2",
REAL_EVENT: "308580120-agentic-sentiments", // Real event for slug testing
PRIMARY: "999999999-example-dev-event-2027-04-15",
SECONDARY: "999999998-example-dev-event-2-2027-03-15",
REAL_EVENT: "308580120-agentic-sentiments-2025-07-19", // Real event for slug testing
} as const;

// Test venue constants that are used by test events
Expand Down