Skip to main content

EventsManager Component

EventsManager Component

Component: src/features/events/components/EventsManager.tsx Route: /app/fundraising/events Access: Authenticated users with Fundraising Hub access Last Updated: March 1, 2026

---

Recent Updates (March 2026)

Fix: Parent Org Event Creation Blocked (Mar 19, 2026)

  • Reporter: Steven James (InFocus Ministries)
  • Fixed: Parent organizations with child funds could not create events — handleCreateEvent() had an isAdminView guard that blocked creation and showed "Please select a specific organization" toast
  • Root Cause: Overly conservative guard from Jan 2026 assumed parent orgs should always select a child fund first. But EventBuilder.handleSave already correctly resolves organization_id via getActualOrgId(selectedEntity) for parent orgs.
  • Solution: Removed the isAdminView + hasChildEntities guard entirely. Parent orgs now proceed directly to EventBuilder.
  • Also Added: Optional fund selector dropdown in EventBuilder Basics step — visible only for parent_org users with child funds. Allows attributing an event to a specific fund for accounting/reporting. Defaults to parent org.
  • Files Modified:
  • src/features/events/components/EventsManager.tsx — Removed admin-view guard + unused imports
  • src/features/events/components/EventBuilder.tsx — Added fund selector UI + isAdminView import
  • src/i18n/locales/{en,es,fr,de,zh,th}/events.json — Added builder.fundAttribution* keys

Fix: Timezone-Naive Timestamp Comparison (Mar 1, 2026)

  • Fixed: fetchEvents upcoming/past filters used new Date().toISOString() (with Z suffix) against a timestamp without time zone column, causing edge-case mismatches for same-day events
  • Solution: Strip Z suffix from ISO string before comparison to make intent explicit

Improvement: i18n Sweep (Mar 1, 2026)

  • Fixed: 30+ hardcoded English strings in EventsManager replaced with t() calls
  • Added: manager.* keys to all 6 locale files (en, es, fr, de, zh, th)

Improvement: Shared Constants (Mar 1, 2026)

  • Fixed: EVENT_TYPE_LABELS and STATUS_COLORS were duplicated between EventsManager and EventBuilder
  • Solution: Extracted to src/types/events.ts as EVENT_TYPE_LABELS and EVENT_STATUS_COLORS

Improvement: EventDashboard keepPreviousData (Mar 1, 2026)

  • Fixed: Registrations query in EventDashboard lacked placeholderData: keepPreviousData, causing UI flash when switching tabs
  • Solution: Added keepPreviousData consistent with §8 caching standard

Recent Updates (February 2026)

Fix: Events Query Hardening (Feb 14, 2026)

  • Fixed: Events list could show "0 events found" due to stale React Query cache
  • Solution: Added staleTime: 30_000, retry: 2, refetchOnMount: true to useEvents hook

Fix: Auction Item Creation Bug (Feb 14, 2026)

  • Fixed: Auction items created during new event creation silently failed — raw supabase.from() call was missing item_number (NOT NULL column)
  • Solution: Replaced raw Supabase call with createAuctionItem mutation in EventBuilder save handler

Fix: .single().maybeSingle() (Feb 14, 2026)

  • Fixed: fetchEventBySlug and validatePromoCode used .single() which throws on 0 rows
  • Solution: Changed to .maybeSingle() for graceful null handling

Edge Function: get-public-event v17 (Feb 14, 2026)

  • Added: collect_sales_tax field to public event response

Migration: RLS Policy Normalization (Feb 14, 2026)

  • Fixed: event_ticket_holds and event_ticket_hold_items used is_parent_org() instead of is_parent_org_admin()
  • Solution: Normalized to match all other event table policies

Recent Updates (January 2026)

Feature: QR Code Button for Events (Jan 21, 2026)

  • Added: QR Code button next to Check-In button in event list
  • Feature: Opens modal with QR code for event registration URL
  • Download: Users can download QR code as PNG for marketing materials
  • Implementation: Uses external API (api.qrserver.com) consistent with existing QR code usage in DonorPortal and EventRegistrationSuccess

Bug Fix: Admin View Guard (Jan 13, 2026)

  • Fixed: Users could enter the EventBuilder from admin view, fill out the entire form, then receive an error at save time
  • Solution: Added early guard in handleCreateEvent() that checks isAdminView(selectedEntity) and shows toast error before entering the builder

Bug Fix: Supabase Client Auth (Jan 13, 2026)

  • Fixed: EventDashboard and EventCheckIn were using raw REST API calls with anon key instead of authenticated Supabase client
  • Solution: Replaced fetch() calls with supabase.from() queries for proper JWT authentication and RLS enforcement

---

Overview

The EventsManager is the main list view for managing events within the Fundraising Hub. It provides filtering, searching, and quick actions for all organization events.

Features

  • Event List - Card-based display of all events
  • Status Badges - Draft, Published, Closed, Canceled
  • Search - Filter by event name
  • Filters - Status, event type, time period (upcoming/past)
  • Quick Actions - View, Edit, Copy URL, Publish, End Registration, Delete
  • Metrics Display - Registration count and revenue per event

UI Layout

┌─────────────────────────────────────────────────────────┐
│ ← Back to Fundraising Hub          + Create Event         │
├─────────────────────────────────────────────────────────┤
│ [Search...]  [Status ▼]  [Type ▼]                       │
│                                                         │
│              [ Upcoming | Past ]                        │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Event Name                           [Published]    │ │
│ │ Dec 25, 2025 • Location Name                        │ │
│ │ 45 registrations • $2,250 revenue                   │ │
│ │                                                     │ │
│ │ [Check-In] [QR] [Copy] [Edit] [⋮]                   │ │
│ └─────────────────────────────────────────────────────┘ │
│                                                         │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Another Event                            [Draft]    │ │
│ │ ...                                                 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘

State Management

const [events, setEvents] = useState<Event[]>([]);
const [searchQuery, setSearchQuery] = useState('');
const [statusFilter, setStatusFilter] = useState<string>('all');
const [typeFilter, setTypeFilter] = useState<string>('all');
const [timeFilter, setTimeFilter] = useState<'upcoming' | 'past'>('upcoming');
const [view, setView] = useState<'list' | 'detail' | 'checkin' | 'builder'>('list');
const [selectedEvent, setSelectedEvent] = useState<Event | null>(null);

Actions

| Action | Description | Confirmation |
|--------|-------------|--------------|
| **View** | Opens EventDashboard | No |
| **Check-In** | Opens EventCheckIn | No |
| **QR Code** | Opens modal with QR code for registration URL | No |
| **Edit** | Opens EventBuilder | Warning if published |
| **Copy URL** | Copies public URL to clipboard | Toast notification |
| **Publish** | Changes status to 'published' | No |
| **End Registration** | Changes status to 'closed' | Yes |
| **Delete** | Removes event | Yes |

View Modes

The component manages multiple views internally:

| View | Component | Trigger |
|------|-----------|---------|
| `list` | Event cards list | Default |
| `detail` | `EventDashboard` | Click event card |
| `checkin` | `EventCheckIn` | Click "Check-In" button |
| `builder` | `EventBuilder` | Click "Create Event" or "Edit" |

Filtering Logic

Filtering is done server-side via the useEvents hook which calls db.fetchEvents(). The hook passes EventFilters to Supabase:

// Server-side filters passed to fetchEvents()
const filters: EventFilters = {
  status: statusFilter !== 'all' ? statusFilter : undefined,
  event_type: typeFilter !== 'all' ? typeFilter : undefined,
  search: searchQuery || undefined,
  upcoming: timeFilter === 'upcoming',
  past: timeFilter === 'past',
};

The upcoming and past filters use .gte('start_date', ...) and .lt('start_date', ...) respectively, with timezone-naive timestamps to match the timestamp without time zone column type.

Related Components

  • EventBuilder - Create/edit events
  • EventDashboard - Event metrics and reporting
  • EventCheckIn - Check-in interface
  • MarketingHub - Parent navigation hub

Related Documentation

  • Main Events Doc: ../06-EVENTS-TICKETING.md
  • Event Builder: ./02-EVENT-BUILDER.md
  • Event Dashboard: ./03-EVENT-DASHBOARD.md

Synced from IFMmvp-Frontend documentation: pages/fundraising/events/01-EVENTS-MANAGER.md

Ready to Get Started?

See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.

Questions? Email us at steven@getalignmint.org

Ready to get started?Start Plus Trial