- Public event detail page renders description/series-description/content
as markdown via useMarkdown, with prose styles; agenda becomes an
unordered list with the same custom bullets.
- Events list API returns `isRegistered` per event (derived from the
requester's registrations, ignoring cancelled rows), and the list page
shows a "Registered" tag. Stops exposing the full registrations array
in the list response.
- Removes the seats/sold-out/limited capacity UI from list and detail
pages.
- EventTicketPurchase: minor template formatting (self-closing inputs,
prettier wrapping).
Sidebar (EventsMiniSidebar), public events list, member dashboard
"Upcoming" block, and EventTicketPurchase all formatted dates in
viewer-local TZ. Switch each formatter to accept the event (or an
eventTimezone prop) and pass it to Intl.DateTimeFormat so the
displayed wall-clock matches the event's intended zone.
Event detail page formatted dates in viewer-local time, so a Lisbon
viewer of a Toronto ET event saw the time in WEST. Format with
event.displayTimezone instead so attendees see the event's intended
wall-clock + zone suffix ("6:00 AM EDT") regardless of where they sit.
useEventDateUtils.formatDate / formatTime / formatDateRange / isToday
now accept a { timeZone } option and pass it to Intl.DateTimeFormat.
Existing call sites that don't pass timeZone fall through to viewer-
local, matching prior behaviour.
Events are often scheduled before the platform (Zoom link, Slack
channel) is chosen. The current workaround is a placeholder URL like
"https://us02web.zoom.us/j/TBD", which leaks to the public page as a
broken link.
Accept the literal "TBD" (case-insensitive) in both the Mongoose
validator and the form-side validator. The public detail page renders
"Platform TBD" instead of a link when the location matches.