EventBuilder Component
EventBuilder Component
Component: src/features/events/components/EventBuilder.tsx Route: /app/fundraising/events/new or /app/fundraising/events/:id/edit Access: Authenticated users with Fundraising Hub write access Last Updated: January 29, 2026
---
Recent Updates (January 2026)
Feature: YouTube Video URL Support (Jan 30, 2026)
- Added: YouTube video URL option alongside existing media options
- Options:
- None - No media (default)
- Upload Image - Upload JPG, PNG, GIF up to 10MB
- VideoBlast Library - Select a thumbnail from existing VideoBlast videos
- YouTube Video - Paste a YouTube URL to embed video on event page
- YouTube URL Formats Supported:
https://www.youtube.com/watch?v=VIDEO_IDhttps://youtu.be/VIDEO_IDhttps://www.youtube.com/embed/VIDEO_ID- Display: YouTube videos appear as embedded player in hero section on public event page
- Files Modified:
src/features/events/components/EventBuilder.tsx- Added YouTube URL input and previewsrc/features/events/components/PublicEventPage.tsx- Added YouTube embed rendering
Feature: Event Image Upload & VideoBlast Integration (Jan 29, 2026)
- Added: Optional event image upload in the Basics step
- Storage: Images uploaded to
event-mediaSupabase storage bucket - Display: Image appears as hero banner on public event page
- VideoBlast Integration: If no videos exist, shows "Create New" button linking to VideoBlast tool
- Files Modified:
src/features/events/components/EventBuilder.tsx- Added media upload UIsrc/lib/db.ts- AddeduploadEventImage()anddeleteEventMedia()functions
Bug Fix: Ticket Type Editing for Existing Events (Jan 29, 2026)
- Fixed: Ticket type fields (name, price, quantity) could not be edited when editing an existing event
- Typing in fields would not register / appear frozen
- Root Cause: Same issue as custom fields - component used
localTicketTypesstate for updates but displayedticketTypesfrom database when editing existing events - Solution:
updateTicketType()now callsupdateTicketTypeMutationfor existing events - Technical Details:
- Added
updateTicketTypeMutation = useUpdateTicketType()instantiation - For existing events: mutation updates database directly, React Query cache invalidates and UI refreshes
- For new events: local state is still used (unchanged behavior)
Bug Fix: Custom Fields & Checklist Editing for Existing Events (Jan 23, 2026)
- Fixed: Custom fields and checklist items could not be edited when editing an existing event
- Typing in field names would revert immediately
- Drag-and-drop reordering would slide back to original position
- Root Cause: Component used
localCustomFieldsstate for mutations but displayedcustomFieldsfrom database when editing existing events - Solution:
updateCustomField()andupdateChecklistItem()now call database mutations for existing eventshandleCustomFieldDragEnd()andhandleChecklistDragEnd()now use correct state source and persistsort_orderto database- Technical Details:
- Added
useUpdateCustomFieldanduseUpdateChecklistItemhooks - For existing events: mutations update database directly, React Query cache invalidates and UI refreshes
- For new events: local state is still used (unchanged behavior)
Feature: Sales Tax Collection (Jan 22, 2026)
- Added: "Collect Sales Tax" toggle in the Tickets step
- Integration: Stripe Tax automatically calculates and collects applicable sales tax
- Stored:
collect_sales_taxfield on Event record - Passed: Setting flows through to
create-event-checkoutEdge Function
Feature: Custom Field & Checklist Reordering (Jan 21, 2026)
- Added: Up/down arrow controls for reordering custom fields and checklist items
- Uses: Shared
ReorderControlscomponent fromsrc/components/shared/ReorderControls.tsx - Benefit: Users can now arrange fields in logical order (e.g., group spouse fields together)
Bug Fix: Unique Slug Generation (Jan 1, 2026)
- Fixed: Events with duplicate names caused "Failed to save event" error
- Root cause: Local slug generator didn't check for uniqueness
- Database has
UNIQUE(organization_id, slug)constraint - Solution: Now uses
generateUniqueEventSlug()which appends-1,-2, etc. if slug exists - Also Fixed: Update operations no longer pass
organization_id(type mismatch)
---
Overview
The EventBuilder is a multi-step wizard for creating and editing events. Steps are dynamically shown/hidden based on the selected event type.
Features
- Multi-step wizard - 6 possible steps based on event type
- Event type selection - Determines available features
- Auto-generated slugs - URL-safe identifier from event name
- Step validation - Blocks forward navigation until requirements met
- Draft saving - Save progress without publishing
Event Types
| Type | Steps Shown | Key Features |
|------|-------------|--------------|
| **Simple** | Basics, Time Slots | Appointment scheduling |
| **Standard** | Basics, Tickets, Fields, Promo | General events |
| **Retreat** | Basics, Tickets, Fields, Checklist, Promo | Weekend retreats |
| **Camp** | Basics, Tickets, Fields, Checklist, Promo | Youth camps |
| **Trip** | Basics, Tickets, Fields, Checklist, Promo | Mission trips |
| **Gala** | Basics, Tickets, Fields, Promo | Fundraising dinners |
| **Auction** | Basics, Tickets, Auction, Promo | Silent/live auctions |
Wizard Steps
1. Basics
- Event name and description
- Event type selection (cards with checkmarks)
- Start/end date and time
- Location (in-person vs virtual)
- Capacity and waitlist settings
- Registration open/close dates
- Event Image (Optional): Upload image or select from VideoBlast library
2. Tickets
- Collect Sales Tax toggle - Enable Stripe Tax for automatic tax calculation
- Add multiple ticket types
- Name, description, price
- Quantity available (optional)
- Max per order limit
3. Time Slots (Simple events only)
- Add time slots for appointments
- Start time, end time, capacity
4. Fields (Custom registration fields)
- Add custom form fields
- Types: text, textarea, select, checkbox, date, number
- Required/optional setting
- Applies to: registrant, guest, or both
- Reorderable: Use up/down arrows to arrange fields in desired order
5. Checklist (Retreat, Camp, Trip only)
- Add pre-event requirements
- Types: waiver, upload, confirmation, link
- Required vs optional
- Requires review toggle
- Due date setting
- Reorderable: Use up/down arrows to arrange items in desired order
6. Auction (Auction events only)
- Add auction items
- Item name, category, description
- Starting bid, bid increment
- Fair market value
7. Promo Codes
- Add discount codes
- Percentage or fixed amount
- Max uses limit
- Valid date range
8. Review
- Summary of all settings
- Publish or save as draft
UI Layout
┌─────────────────────────────────────────────────────────┐
│ ← Back Create Event │
├─────────────────────────────────────────────────────────┤
│ │
│ ○ Basics ○ Tickets ○ Fields ○ Promo ● Review │
│ │
├─────────────────────────────────────────────────────────┤
│ │
│ [Step Content Area] │
│ │
│ │
│ │
├─────────────────────────────────────────────────────────┤
│ [Back] [Next / Save / Publish]│
└─────────────────────────────────────────────────────────┘State Management
const [currentStep, setCurrentStep] = useState(0);
const [eventData, setEventData] = useState<EventFormData>({
name: '',
description: '',
event_type: 'standard',
start_date: '',
end_date: '',
// ... more fields
});
const [tickets, setTickets] = useState<TicketType[]>([]);
const [customFields, setCustomFields] = useState<CustomField[]>([]);
const [checklistItems, setChecklistItems] = useState<ChecklistItem[]>([]);
const [promoCodes, setPromoCodes] = useState<PromoCode[]>([]);
const [auctionItems, setAuctionItems] = useState<AuctionItem[]>([]);
const [timeSlots, setTimeSlots] = useState<TimeSlot[]>([]);Step Validation
| Step | Validation Rules |
|------|------------------|
| Basics | Name required, event type selected, start date required |
| Tickets | At least one ticket type required |
| Time Slots | At least one slot for Simple events |
| Fields | No validation (optional) |
| Checklist | No validation (optional) |
| Auction | At least one item for Auction events |
| Promo | No validation (optional) |
Save Logic
const handleSave = async () => {
// 1. Create/update event record
const event = await upsertEvent(eventData);
// 2. Save related records
await saveTicketTypes(event.id, tickets);
await saveCustomFields(event.id, customFields);
await saveChecklistItems(event.id, checklistItems);
await savePromoCodes(event.id, promoCodes);
await saveAuctionItems(event.id, auctionItems);
await saveTimeSlots(event.id, timeSlots);
// 3. Optionally publish
if (shouldPublish) {
await publishEvent(event.id);
}
};Related Components
EventsManager- Parent list viewEventDashboard- Post-creation metrics
Related Documentation
- Main Events Doc:
../06-EVENTS-TICKETING.md - Events Manager:
./01-EVENTS-MANAGER.md
Synced from IFMmvp-Frontend documentation: pages/marketing/events/02-EVENT-BUILDER.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