The Events system is accessible atDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/asubap/website/llms.txt
Use this file to discover all available pages before exploring further.
/events (list view) and /events/:eventId (detail view, ViewEvent). Both routes are wrapped in ProtectedRoute. EventsPage is the primary interface; it fetches all events, partitions them into three time-based sections, supports text search, and renders one EventCard per event. Each card encapsulates the RSVP widget (EventRSVP) and the geolocation check-in widget (EventCheckIn). A CalendarSubscribeButton in the page header lets authenticated, non-alumni, non-sponsor members subscribe to an ICS feed.
Event Type System
The platform distinguishes between events as seen by members and as seen by administrators. Both extendBaseEvent.
Page Data Fetching
EventsPage uses useEffect with an AbortController to cancel stale requests on cleanup:
GET /member-info/me so that the page can gate the RSVP and check-in buttons before the event list arrives. Both fetches are refired on visibilitychange and window.focus events to keep the rank current after tab switches.
Event Partitioning
After filtering by the search query and the admin hidden/standard toggle, events are bucketed:PAST_EVENTS_INCREMENT = 3).
Search
A plain substring search (not fuzzy) is applied across three fields:CalendarSubscribeButton share the header row via a flex container.
EventCard
EventCard is the single presentational unit for all event types across the platform (EventsPage, EventMember dashboard panel, and the admin view). Key props:
!isPastisLoggedIn!loading(auth context not loading)!propRankLoading!isAlumniUser(derived fromisAlumni(propUserRank))
formatDateTime helper used in the card:
RSVP Flow
EventRSVP is a self-contained toggle button. It maintains local localRSVPed state (seeded from the user_rsvped prop) so the UI responds immediately without waiting for a refetch.
User clicks RSVP / Un-RSVP
A confirmation
Modal is shown with the event name and the action label ("RSVP" or "Un-RSVP").Success handling
localRSVPed is toggled, a react-hot-toast message is shown, and the optional onRSVPChange callback fires (used by admins to refetch participants).Check-In Flow
EventCheckIn uses the browser’s Geolocation API. The backend validates that the submitted coordinates are within the configured check_in_radius.
Session window check
isEventInSession() is evaluated on click. If the event has not started or has already ended (based on event_date, event_time, and event_hours), a toast error fires and the function returns early:Check-in window enforcement
A separate deadline is computed:
checkInDeadline = start + checkInWindowMinutes * 60 * 1000. If the current time is past this deadline, check-in is blocked with a descriptive toast.checkInWindowMinutes defaults to 15 if not provided via the check_in_window field on the event.Pre-flight guards
Before requesting location, the component verifies (in order):
- The event is currently in-session
navigator.geolocationis supported- A valid
session.access_tokenexists - The user has not already checked in (
userAttended || localCheckedIn) - The user is RSVP’d (
userRsvped === true)
Geolocation request
Status becomes
"locating" and navigator.geolocation.getCurrentPosition() is called with:Backend submission
Status advances to The backend computes the Haversine distance between the submitted coordinates and
"sending". Coordinates and accuracy are POSTed:event_lat/event_long and accepts the check-in only if within check_in_radius metres.Button states
| State | Button label | Button colour | Disabled? |
|---|---|---|---|
idle, not in session | Check In | Gray | ✅ |
idle, in session, not RSVP’d | Check In | Red | ❌ (shows toast on click) |
idle, in session, RSVP’d | Check In | Red | ❌ |
locating | Getting Location… | Gray | ✅ |
sending | Checking in… | Gray | ✅ |
success | ✓ Checked In | Green | ✅ |
error | Try Again | Red | ❌ |
| Already attended | Checked In | Gray | ✅ |
canCheckIn (from MemberEvent.can_check_in) is received as a prop but the component currently computes in-session state locally via isEventInSession. The backend-provided value is stored as _canCheckIn (prefixed underscore) and not used directly in the button logic.Calendar Subscription
CalendarSubscribeButton renders only for authenticated users who are not sponsors and not alumni:
VITE_BACKEND_URL at runtime (no auth token — the ICS feed is publicly accessible by URL).
Google Calendar instructions (shown in modal)
Google Calendar instructions (shown in modal)
Open Google Calendar → Settings (gear icon) → Add calendar → From URL → Paste the ICS URL → Add calendar.
Apple Calendar instructions (shown in modal)
Apple Calendar instructions (shown in modal)
File → New Calendar Subscription → Paste URL → Subscribe.
Outlook instructions (shown in modal)
Outlook instructions (shown in modal)
Calendar → Add Calendar → From Internet → Paste URL → OK.
ViewEvent Page
/events/:eventId fetches a single event via POST /events with { event_id: eventId } in the body. It is a lightweight read-only detail view that renders name, location, date, time, description, dress code, sponsors, RSVP count, and attendance count. This page is not currently used as the primary event UI — EventCard on /events is the richer interactive surface.
Alumni Restrictions
Alumni (rank === "alumni") are blocked from RSVP and check-in by isAlumni() in EventCard:
CalendarSubscribeButton also hides itself for alumni.
Extending Events
To add a new event field visible to members:- Add the field to
BaseEventintypes/index.ts. - Include it in the backend response for
GET /events. - Render it inside the
EventCardgrid (the two-columndiv.gridsection).
checkInDeadline logic in EventCheckIn with the backend-provided check_in_window field that already arrives with MemberEvent.