Skip to content

Allow organizers to manage participants and track payments after event ends#127

Merged
michaelchu merged 12 commits intomainfrom
allow-organizer-manage-past-events
Mar 9, 2026
Merged

Allow organizers to manage participants and track payments after event ends#127
michaelchu merged 12 commits intomainfrom
allow-organizer-manage-past-events

Conversation

@michaelchu
Copy link
Copy Markdown
Owner

@michaelchu michaelchu commented Mar 9, 2026

Summary

  • Organizers can add/remove participants on past events (claim empty slots, remove participants, use the join button) — non-organizers still see "Registration Closed"
  • Past paid events with outstanding payments stay in the Organizing tab (and group Active filter) instead of moving to Archive, so organizers can track who still owes
  • Events are only fully archived once all participants have paid (or the event isn't a paid event)

Test plan

  • Unit tests for organizer controls on past events (claim buttons, join button, remove button)
  • Unit tests for non-organizer still seeing "Registration Closed" on past events
  • Unit tests for past paid events with unpaid participants staying active
  • Unit tests for past paid events with all paid participants being archived
  • Manual: as organizer, view a past paid event with unpaid participants → confirm it appears in Organizing tab, not Archive
  • Manual: mark all participants as paid → confirm event moves to Archive
  • Manual: check group detail page shows same behavior in Active/Archived filter

🤖 Generated with Claude Code

Organizers can now manage their roster on past events — claim empty
slots, remove participants, and use the join button. Non-organizers
still see "Registration Closed" as before. Also allows registered
participants (not just organizers) to claim spots for guests via
updated RLS policy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
An event is now only fully archived when it's past AND all payments
are settled. This lets organizers continue managing the roster
(add/remove participants) until the event is financially closed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
michaelchu and others added 2 commits March 9, 2026 12:50
Past paid events with pending payments now stay in the Organizing
tab so organizers can track outstanding payments. They only move
to Archive once all participants have paid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Past paid events with pending payments stay in the Active filter
on the group detail page, matching the Organizing tab behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@michaelchu michaelchu changed the title Allow organizers to manage participants after event ends Allow organizers to manage participants and track payments after event ends Mar 9, 2026
These changes belong in a separate PR for allowing registered
participants to claim spots for guests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ilter bug

Tests verify that past paid events with pending payments stay in Active/Organizing
views and only move to Archive once fully settled. Also fixes a bug where the
GroupDetailPage render filter wasn't applying unsettled payment logic (only the
empty-state check was updated).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Organizers could still add/remove participants on past events where all
payments were settled. Now the bottom button, claim spots, and remove
button all use isArchived directly — which already accounts for payment
status. No special organizer bypass needed since isArchived is false
when payments are still pending.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@michaelchu
Copy link
Copy Markdown
Owner Author

Code review

Found 1 issue:

  1. Non-organizers can join/withdraw from past paid events with unsettled payments. The join button uses isArchived as the sole guard, but isArchived is false for past paid events with pending payments. This means any user (not just the organizer) sees an active join/withdraw button on a past event that still has unsettled payments. The "Anyone can register for public events" RLS policy would allow the insert to succeed. Previously this used isEventCompleted() && !isOrganizer which correctly blocked non-organizers. The fix would be to use (isArchived || (isEventPast && !isOrganizer)) for the button disabled/onClick/label guards.

onClick={() => {
if (isArchived) return;
if (isEventFull && !userRegistration) return;
if (showRegistrationForm) {
openSignupDrawer();
} else if (userRegistration) {
setShowWithdrawDialog(true);
} else {
handleDirectJoin();
}
}}
disabled={isArchived || submitting || (isEventFull && !userRegistration)}
className={`w-full text-white shadow-lg drop-shadow-md ${
isArchived || (isEventFull && !userRegistration)
? 'bg-muted-foreground'
: userRegistration && !showRegistrationForm
? 'bg-destructive hover:bg-destructive/90'
: 'bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600'
}`}
size="default"
>
{isArchived ? (
<>

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR allows event organizers to manage participants (add/remove) on past events, and keeps past paid events with outstanding payments visible in the Organizing tab (and group Active filter) rather than immediately archiving them. Events are only moved to the archive once all participants have settled their payments.

Changes:

  • EventDetailPage.tsx: Introduces separate isEventPast and isArchived flags. A past paid event is only "archived" when all participants have paid; until then, organizers retain full participant management controls.
  • EventsPage.tsx: loadOrganizingEventsCallback now keeps unsettled past paid events in the Organizing tab; loadArchivedEventsCallback now excludes unsettled paid events from the Archive tab.
  • GroupDetailPage.tsx: Adds an _unsettled marker to past paid group events with outstanding payments, keeping them in the "Active" filter and out of "Archived."
  • New test files: EventsPage.test.tsx and GroupDetailPage.test.tsx cover the new filtering behavior; EventDetailPage.test.tsx receives an additional describe block covering organizer/non-organizer controls on past events.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/pages/EventDetailPage.tsx Replaces monolithic isArchived (based only on time) with a richer condition that requires payment settlement for paid events
src/pages/EventsPage.tsx Filters organizing/archived event lists using payment summaries so unsettled events stay in Organizing
src/pages/GroupDetailPage.tsx Marks past paid group events as _unsettled and adjusts Active/Archived filtering accordingly
src/pages/__tests__/EventDetailPage.test.tsx Adds test cases for organizer/non-organizer behavior on past events
src/pages/__tests__/EventsPage.test.tsx New test file for organizing/archive tab placement based on payment status
src/pages/__tests__/GroupDetailPage.test.tsx New test file for Active/Archived group event filtering based on payment status

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/pages/GroupDetailPage.tsx Outdated
Comment thread src/pages/EventDetailPage.tsx Outdated
Comment thread src/pages/GroupDetailPage.tsx
isArchived alone isn't sufficient since it's false for past paid events
with pending payments. Non-organizers must also be blocked when the event
is past, regardless of payment status. Only organizers should be able to
manage participants on unsettled past events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Organizers/admins: past paid events stay active while any participant
  has pending payments (existing behavior)
- Non-organizer participants: past paid events stay active only while
  their own payment is pending
- Added getMyPaymentStatusBatch to participantService for efficient
  per-user payment status lookup
- Fixed allPaid edge case: zero participants no longer counts as
  "all paid", so organizers can add participants to empty past paid events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GroupDetailPage: compute filteredEvents once instead of filtering twice
- EventDetailPage: extract isRegistrationClosed to replace 4 repeated
  instances of isArchived || (isEventPast && !isOrganizer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@michaelchu michaelchu temporarily deployed to allow-organizer-manage-past-events - Roster PR #127 March 9, 2026 18:30 — with Render Destroyed
- EventsPage Joined tab: past paid event stays when user has pending
  payment, hidden when paid, past free events always hidden
- GroupDetailPage non-admin: past paid event stays in Active when user
  has pending payment, hidden when paid

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds an amber Clock icon with "Unpaid" label on event cards in the
Joined tab and GroupDetailPage Active filter when the event is past
but kept active because the participant hasn't paid yet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@michaelchu michaelchu temporarily deployed to allow-organizer-manage-past-events - Roster PR #127 March 9, 2026 18:39 — with Render Destroyed
@michaelchu michaelchu merged commit cbd9a3f into main Mar 9, 2026
2 checks passed
@michaelchu michaelchu deleted the allow-organizer-manage-past-events branch March 9, 2026 18:47
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