Skip to content

Add a public Events page with RSVPs, private until launch - #113

Merged
getvindicated2day merged 1 commit into
mainfrom
events-page
Oct 20, 2026
Merged

getvindicated2day merged 1 commit into
mainfrom
events-page

Conversation

@getvindicated2day

@getvindicated2day getvindicated2day commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Adds a public Events page with RSVPs. It stays private until launch: nothing changes for visitors until EVENTS_PUBLIC=true is set in Railway. Don't merge yet.

Private until launch

EVENTS_PUBLIC must be exactly true for the page to be public. Until then:

  • /[locale]/events returns the normal 404 to the public.
  • A visitor signed in to either board hub as admin can open it, with the banner "Private preview: only admins can see this page." Hub members (non-admin) still get the 404.
  • No "Events" header link, no home strip, not in the sitemap, and <meta name="robots" content="noindex, nofollow">.
  • The RSVP, calendar-file, flyer and next-event APIs all return 404 to the public. Admins can RSVP to test.

When EVENTS_PUBLIC=true: "Events" appears in the header between Team and Learning Resources, and the next-event strip appears under the home hero.

BOARD_SETUP.md has a new "Public events" section explaining how to launch (set EVENTS_PUBLIC=true and redeploy) and how to hide it again. .env.example lists the variable, blank.

Events page

  • Header: title "Events", the intro line, and an Upcoming / Past toggle. Past means the end time has passed.
  • Each card:
    • flyer on the left, which enlarges on click. Until a flyer is uploaded, a date box shows instead.
    • tag, title, date and time (Pacific), "Online, on Zoom" with "The link is emailed to you when you RSVP" (or the address), host name and title, and the description
    • "RSVP, it's free"
    • "N people are going", only when the event has "Show RSVP count" on
  • The RSVP form opens on the card:
    • Name, Email, School or affiliation (UC Berkeley, UCLA, UC Santa Cruz, Another school, Not a student)
    • an optional question for the host
    • "Email me about future VINdicated events", on by default
    • name, email and school are checked in the browser and on the server
  • After submitting: "You're in!", "Thanks, {first name}. We sent the Zoom link to {email}.", "Add to Google Calendar" and "Download for Apple / Outlook" (.ics).
  • Home strip: date box, title, "Thursday, 6 PM · Online · Free" and an RSVP button that links to the event's card.
  • Look: rounded corners, the site's fonts and purple, works at phone width.
  • i18n: every string is in the eventsPage section of en.json (plus nav.events and route metadata). The other languages fall back to English until the translation work fills them in.

Emails

  • On RSVP: a confirmation with the event details, the meeting link and an event.ics (METHOD:PUBLISH).
  • Duplicate RSVP (same email and event, any capitalization): no second row; the confirmation is resent.
  • The meeting link is private:
    • It's stored on the event and only appears in confirmation and reminder emails.
    • Public pages select every column except meeting_link.
    • The public "Download for Apple / Outlook" .ics leaves it out and points people to their confirmation email instead.
  • Reminders: no cron. Each event has "Send reminder to everyone", with a confirm step showing the count. It emails every RSVP the link again and is noted in the change log.

Admin (both hubs)

  • A new Events tab, visible to admins only:
    • add, edit and delete events: title, tag, start and end date/time, online or in person, private meeting link or address, host name and title, description, flyer, "Show RSVP count"
    • flyers use the same upload and storage as hub photos
  • Per event:
    • the RSVP list (name, email, school, question, opted in, time) with a count
    • "Copy emails", "Download CSV" and the reminder button
    • CSV cells a spreadsheet would run as a formula are escaped
  • RSVP names and emails are only on this tab and in the CSV, never on the public page.
  • Change log: adds, edits and deletes are logged. A deleted event can be restored from the Changes tab, and its RSVPs come back with it.
  • Chapter: shown on the form but not editable. An event belongs to the hub it's made on, which sets its sender and keeps each hub's change log working. UCLA events are made on the UCLA hub.

Seed

Created once on first load, and editable by admins:

  • "Negotiation Workshop with Emily Epstein", tag "Workshop · UC Berkeley", chapter Berkeley
  • Thursday Nov 19 2026, 6:00–7:00 PM Pacific, online on Zoom
  • host Emily Epstein, with the title and description as given
  • "Show RSVP count" off
  • Still needed from an admin before launch: the meeting link and the flyer.

Tests (local Postgres, outbox mode)

  • EVENTS_PUBLIC unset:
    • The public gets a 404 on /en/events and /es/events, and on the RSVP, next, ics and flyer APIs.
    • No nav link, no home strip, no sitemap entry.
    • A Berkeley or UCLA admin session sees the page with the banner and noindex, and can RSVP. A UCLA member session still gets the 404.
  • EVENTS_PUBLIC=true:
    • The header shows Home | About | Team | Events | Learning Resources.
    • The home strip shows "Thursday, 6 PM · Online · Free".
    • The sitemap lists /events in all 10 languages.
    • The public can RSVP.
  • RSVP:
    • One confirmation per RSVP. The .ics parses with the icalendar library: METHOD:PUBLISH, 18:00–19:00 America/Los_Angeles, which is 02:00Z.
    • A second RSVP with ADA@example.com vs ada@example.com kept one row and resent the confirmation.
    • Missing name, a bad email, an unknown school, a past event and a missing event are all refused.
    • Both the outbox path and the Brevo API path were exercised.
  • Meeting link: a test link was set on the event and never appeared in /en, /en/events, /es/events, /api/events/next, /api/events/1/ics or any RSVP response.
  • Admin, through the browser:
    • created an event with a flyer upload, then edited it
    • opened the RSVPs; Copy emails put the right list on the clipboard
    • the CSV downloads with the right columns
    • "Send reminder to everyone" showed "Email a reminder … to 3 people?" and sent 3, then 1 for the other event
    • add, edit, delete and restore all landed in the change log
    • members don't see the tab; the other hub's admin and members get 404s on this hub's event APIs
  • Regression: a board meeting test invite still goes out with the text/calendar; method=REQUEST part. /board and /board/ucla still load.
  • Fresh database: setup creates the tables and seeds exactly the one event.
  • Browser: desktop (1440) and phone (390), English and Spanish, no sideways scroll.
  • Checks: lint has 0 errors (the same 4 existing warnings), typecheck passes, and pnpm build passes with and without EVENTS_PUBLIC.

Screenshots

Desktop and phone, side by side. The screenshots with RSVPs or a flyer use test data (example.com addresses and a placeholder flyer).

Before launch: the public sees a 404, and an admin sees the preview banner.

After launch: the header link, the home strip and the Events page.

RSVP: the form, then the success state.

A card with a flyer, the enlarged flyer, and the Past view:

Hub Events tab: the RSVP list with the reminder confirmation, and the edit form.

The screenshots are on the images-only pr-screenshots-events branch, which can be deleted after review.


Generated by Claude Code

- /[locale]/events: Upcoming / Past, one card per event (flyer that
  enlarges, tag, date and time in Pacific, online or address, host,
  description, optional RSVP count) and an RSVP form on the card. After
  RSVPing: "You're in!", Add to Google Calendar and an .ics download.
- Private until EVENTS_PUBLIC is exactly "true": a 404 for the public,
  a "Private preview" banner for board admins of either hub, noindex,
  no nav link, home strip or sitemap entry, and the RSVP API refuses.
  Once public: "Events" in the header and the next-event strip on home.
- RSVP confirmations and "Send reminder to everyone" go out like board
  invites (SMTP on 2525, Brevo API fallback, outbox for tests) from the
  chapter's sender, with a PUBLISH .ics. The meeting link is stored on
  the event and only appears in those emails. A repeat RSVP with the
  same email resends the confirmation instead of adding a second one.
- Hub: an admin-only Events tab on both hubs to add, edit and delete
  events (flyers use the hub photo upload), with each event's RSVP list,
  Copy emails, Download CSV and the reminder (with a confirm step).
  Changes go in the change log and can be restored.
- Seeds the first event (Negotiation Workshop with Emily Epstein,
  Nov 19, 6-7 PM, online), with the meeting link and flyer left for an
  admin to add.
- Strings are in en.json for the other languages to fill in.
- BOARD_SETUP.md explains how to launch and how to hide it again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@getvindicated2day
getvindicated2day merged commit 23bcfa9 into main Oct 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants