feat: bulk event creation and multi-cohort support#15
Merged
AlexVOiceover merged 36 commits intomainfrom Jan 5, 2026
Merged
Conversation
- Add CalendarPicker component for multi-date selection
- Refactor /admin/events page with mode state (list/single/series)
- Move single event form inline, add series creation form
- Add case-insensitive event type validation for Airtable robustness
- Fix EVENT_TYPES to match Airtable's exact casing ("Regular Class")
- Redirect /admin/events/new to main events page
- Add attendanceCount to Event interface and listEvents - Add apprenticeCount to Cohort interface and listCohorts - Display "X/Y" attendance ratio in events table (Y = cohort size) - Show just count for open events without cohort
- Add /api/events/[id]/roster endpoint returning attendees and check-in state - Add getApprenticesByCohortId function to fetch cohort members - Add expandable rows in events table showing attendance roster - Display check-in status with visual indicators (green check / gray dash)
Replace check/cross icons with readable text: 'Checked in at [time]' or 'Not checked in'
…ed status - Display roster as table with Name, Type, and Status columns - Color-code type: blue for Apprentice, purple for Guest - Color-code status: green for Checked in, red for Not checked in
… Late, Excused) - Update roster API to return actual attendance status from Airtable - Display status with color-coded badges: green (Present), red (Absent), yellow (Late), blue (Excused) - Sort roster by status priority: Present > Late > Excused > Absent - Update schema.md to document status field values
Changed detection logic from requiring both name and email to checking if the attendance record has no apprentice link (meaning it's external)
- Fix external attendees not appearing by using event.attendanceIds instead of broken filterByFormula on linked record fields - Add getAttendanceByIds to fetch attendance records by RECORD_ID() - Add getApprenticesByIds to fetch details for non-cohort apprentices - Add attendanceIds to Event type from linked ATTENDANCE field - Separate status badge and check-in time into distinct columns
- Add determineStatus() to compare check-in time with event start time - Mark attendees as 'Late' when checking in after the event begins - Parallelize attendance and cohort API calls with Promise.all - Reduces roster load time from ~1.5s to ~0.9s
…ality - Add Schedule-X calendar with color-coded event types (Regular Class, Workshop, Hackathon) - Centralize event type colors in src/lib/types/event.ts for single source of truth - Add Survey URL column to events table with link icon - Replace separate form with inline editable row for creating events - Add delete button (X) with confirmation dialog for each event - Hide expand arrow only for events with exactly 0 attendance (no cohort) - Events with 0/X attendance still expandable to see who hasn't checked in
- Add sortable table headers with icons (Name, Date/Time, Type, Cohort, Attendance) - Default sort by date descending (newest first) - Add "Hide past events" checkbox filter - Style past events with subtle background color - Fix attendance count to show only Present/Late (not Excused) - Add staff ability to edit attendance status inline in roster view - Create POST /api/attendance endpoint for staff to create attendance records - Create PATCH /api/attendance/[id] endpoint for status updates - Include attendanceId in roster entries for proper record targeting - Recalculate attendance count when roster loads
- Replace Schedule-X calendar with @event-calendar/core library - Enable multi-date selection via dateClick for series creation - Show selected dates as green background events on calendar - Unify calendar component for both list view and series form - Add TypeScript declarations for @Event-calendar packages - Fix variable declaration order for SSR compatibility
Move series creation form above calendar for better UX flow: - Form appears immediately when clicking "Create Series" button - User fills in details then selects dates on calendar below - Selected dates shown as removable pills in form - Panel slides in/out with 300ms transition - Remove separate mode navigation for cleaner interface
- Click calendar event to scroll to corresponding row in table - Add persistent selection indicator with blue outline - Selection wraps both event row and expanded roster when present - Auto-expand roster if event has attendance data
- Replace immediate delete with mark-for-delete toggle - Show red delete icon when event is marked - Display action bar with count and delete button when events marked - Support batch deletion of multiple events - Add cancel option to clear all marks
- Add inline edit row that replaces normal row when editing - Click pencil icon to enter edit mode with yellow highlighted row - Edit all fields: name, date/time, type, cohort, public, survey URL - Save changes via PUT API and update local state without reload - Cancel button to discard changes
- Delete [id]/+page.svelte and [id]/+page.server.ts (edit is now inline) - Delete new/+page.server.ts (creation is now inline) - All event CRUD operations now happen on the main events page
- Add endDateTime field to Event type and Airtable config - Update events API endpoints to handle endDateTime - Create DateTimePicker component using @svelte-plugins/datepicker - Replace native datetime-local inputs with styled date picker - Calendar now displays events with proper end times
- Create DatePicker component for date-only selection - Update events page to use 3 separate inputs: date, start time, end time - Add helper functions to combine/extract date and time values - Fix datepicker styling to not show permanent blue border - Auto-default end time to start + 4 hours Events never span multiple days, so this UI is cleaner while Airtable schema remains unchanged (dateTime + endDateTime fields).
- Create TimePicker component with hour/minute select dropdowns - Limit minutes to 15-min increments (00, 15, 30, 45) - Add minTime prop to disable earlier times on end time picker - Replace native time inputs with TimePicker in all event forms - Add red border on required name fields when empty - Fix timezone bug: calendar date selection was off by one day during DST due to toISOString() converting to UTC
- Disable other table rows when creating new event (dimmed + non-clickable) - Replace survey URL input with dropdown popover for easier pasting - Show grey icon when no survey URL, blue when present - Fix survey URL clearing: send null to API, update local state correctly - Fix DST timezone bug in calendar date selection (toISOString → local methods)
- Show numeric code input when Public checkbox is checked - Support creating and editing event codes (up to 6 digits) - Properly convert and send code as number to API - Load existing codes when editing public events
- Auto-generate random 4-digit code when Public is checked - Remove spinner arrows from code number inputs - Add check-in code field to series creation form - Same code used for all events in a series
- Set max-h-[560px] on table container for vertical scrolling - Add sticky header to keep column titles visible while scrolling - Add border styling to the scrollable container
Support multiple cohorts per event: - Event.cohortId -> Event.cohortIds: string[] - Event.cohortName -> Event.cohortNames: string[] - CreateEventInput.cohortId -> cohortIds - UpdateEventInput.cohortId -> cohortIds
- listEvents/getEvent/getEventByCode return cohortIds array - createEvent/updateEvent accept cohortIds array - Update tests to use cohortIds arrays
- POST /api/events: Accept cohortIds array - PUT /api/events/[id]: Accept cohortIds array - GET /api/events/[id]/roster: Fetch apprentices from all cohorts - Fix events state sync warning in admin page - Rename Event import to AppEvent to avoid DOM conflict
Change cohort matching from === to .includes() so students see events where their cohort is one of the event's cohorts
- Replace multi-select with dropdown checkboxes for cohort selection - Add "Open" option to audience dropdown (controls isPublic flag) - Rename "Cohort" column to "Audience", "Public" to "Code" - Fix column width to prevent resizing based on content - Add disabled state tooltip for save button when fields missing - Show "Open" in green alongside cohort names in event list
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Major feature release adding bulk event creation with calendar picker, multi-cohort event support, and significant admin UI improvements. Events can now target multiple cohorts and/or be marked as "Open" for external attendees.
Changes
Bulk Event Creation (AP-23)
Multi-Cohort Support
cohortId→cohortIds[])Admin Events UI
Attendance Tracking