Add per-event dashboard with drill-in registrant filters#1565
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an admin/owner-only per-event Overview dashboard (GET /events/:id/overview) that surfaces event health metrics (registrants/orgs/sectors/states + payment/scholarship totals) and wires new payment/scholarship filters into Manage registrants, supported by seeds and automated tests.
Changes:
- Introduces
EventOverviewservice andevents#overviewroute/action + view/partials to display aggregated metrics. - Adds
payment_status+with_scholarshipfiltering to event registration management UI/controller and newEventRegistrationscopes. - Extends dev seeds and adds specs (service, model scopes, routing, request) to cover the new behavior.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
app/services/event_overview.rb |
Aggregates overview metrics (registrants, orgs, sectors, states, payment/scholarship totals). |
app/controllers/events_controller.rb |
Adds overview action and wires new manage filters. |
config/routes.rb |
Adds member route for /events/:id/overview. |
app/views/events/overview.html.erb |
New overview dashboard page UI. |
app/views/events/_overview_stat.html.erb |
Reusable stat card partial for overview money metrics. |
app/views/events/manage.html.erb |
Adds “Overview” link to manage page top actions. |
app/views/events/_manage_search.html.erb |
Adds payment/scholarship dropdown filters (paid events only). |
app/models/event_registration.rb |
Adds new scholarship/payment-related scopes used by Manage filters. |
db/seeds/dummy_dev_seeds.rb |
Seeds payments/scholarships/allocations for paid dev events + minor seed robustness tweaks. |
spec/services/event_overview_spec.rb |
Unit tests for EventOverview aggregation logic. |
spec/models/event_registration_spec.rb |
Tests for new EventRegistration scopes. |
spec/requests/events_spec.rb |
Request specs for manage filters and overview auth/rendering. |
spec/routing/events_routing_spec.rb |
Routing spec for events#overview. |
AGENTS.md |
Documents EventOverview in business logic list. |
| def scholarship_total_cents | ||
| scholarships.sum(:amount_cents) | ||
| end |
There was a problem hiding this comment.
we're going to ignore for now and fix in future pr
| scope :payment_status, ->(value) { | ||
| case value | ||
| when "paid" then paid_in_full | ||
| when "unpaid" then not_paid_in_full | ||
| end | ||
| } |
There was a problem hiding this comment.
will handle in future pr
| <%= render "overview_stat", label: "Grand total", value: number_to_currency(@overview.grand_total_cents / 100.0), | ||
| icon: "fa-coins", color: "indigo", count: @overview.registrant_count, | ||
| subtext: "Scholarships + subtotal", link: manage_event_path(@event) %> |
e564e15 to
3c4f587
Compare
3c4f587 to
124ee44
Compare
| scope :scholarship_status, ->(value) { | ||
| case value | ||
| when "yes" then with_scholarship | ||
| when "complete" then scholarship_tasks_completed | ||
| when "incomplete" then scholarship_tasks_incomplete | ||
| end | ||
| } |
There was a problem hiding this comment.
will fix in future pr
| scope :payment_status, ->(value) { | ||
| case value | ||
| when "paid" then paid_in_full | ||
| when "unpaid" then not_paid_in_full | ||
| end | ||
| } |
There was a problem hiding this comment.
will fix in future pr
| # Curated state/county pairs so the event overview's States and Counties cards | ||
| # show a recognizable spread rather than scattered random values. |
There was a problem hiding this comment.
will fix in future pr
| # Gives the paid dev events real money + scholarship records so the event | ||
| # overview dashboard (registrants / received / outstanding / scholarships) | ||
| # shows meaningful numbers. Registrations and applications (registration-form |
| <%= render "dashboard_money_row", label: "Completed", icon: "fa-circle-check", | ||
| amount_cents: @dashboard.completed_scholarship_cents, | ||
| count: @dashboard.completed_scholarship_registrants.size, registrants: @dashboard.completed_scholarship_registrants, | ||
| filter_path: manage_event_path(@event, registrant_ids: @dashboard.completed_scholarship_registrants.map(&:id).join("-")) %> |
There was a problem hiding this comment.
will fix in future pr
| icon_bg: @dashboard.outstanding_scholarship_registrants.any? ? "bg-orange-500" : nil, | ||
| amount_cents: @dashboard.outstanding_scholarship_cents, | ||
| count: @dashboard.outstanding_scholarship_registrants.size, registrants: @dashboard.outstanding_scholarship_registrants, | ||
| filter_path: manage_event_path(@event, registrant_ids: @dashboard.outstanding_scholarship_registrants.map(&:id).join("-")) %> |
There was a problem hiding this comment.
will fix in future pr
| <%= render "dashboard_money_row", label: "Paid", icon: "fa-money-bill-wave", | ||
| amount_cents: @dashboard.cont_ed_paid_cents, | ||
| count: @dashboard.cont_ed_paid_count, registrants: @dashboard.cont_ed_paid_registrants, | ||
| filter_path: manage_event_path(@event, registrant_ids: @dashboard.cont_ed_paid_registrants.map(&:id).join("-")) %> |
There was a problem hiding this comment.
will fix in future pr
| icon_bg: @dashboard.cont_ed_unpaid_count.positive? ? "bg-orange-500" : nil, | ||
| amount_cents: @dashboard.cont_ed_outstanding_cents, | ||
| count: @dashboard.cont_ed_unpaid_count, registrants: @dashboard.cont_ed_unpaid_registrants, | ||
| filter_path: manage_event_path(@event, registrant_ids: @dashboard.cont_ed_unpaid_registrants.map(&:id).join("-")) %> |
There was a problem hiding this comment.
will fix in future pr
There was a problem hiding this comment.
If this are better or more appropriate than the payment seeds I added in db/seeds/payments I'm cool with you removing mine so its not duplicating the effort and more consistent on seeding the data you want for the task at hand.
There was a problem hiding this comment.
cool. i've got a little too much in here so am going to push this through and then do sidequests after.
i've been just having one big dev seeds dump of allthethings vs the base seeds, but, it's not a bad idea to split some things out. that should prob be a bigger redux of seeds tho.
Event admins had no at-a-glance view of an event's registration and
financial health — counts, money received/outstanding, scholarships, and
who is represented all required reading the registrant table row by row.
- Dashboard at GET /events/:id/dashboard (admin/owner), backed by an
EventDashboard service that aggregates the metrics in a few queries.
- Money reads as an equation — grand total = registration fees +
scholarships + cont-ed — each addend split into paid/completed vs
outstanding, expanding to the registrants behind the figure.
- Headcounts: registrants (+ inactive), organizations, sectors, states;
each expands to its list and links to the matching filtered Manage list.
- Manage gains filters + scopes: payment status, scholarship task status,
state, state-scoped county ("CA - Los Angeles"), sector, and registrant
selection.
- Continuing-education fees are stubbed to $0 until their migration lands.
- Seed scholarships/payments/allocations for paid dev events so the
dashboard shows real numbers locally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
124ee44 to
ecafd13
Compare
PR #1565 (merged to main) added a Scholarships/Payments/Allocations section to the dummy dev seeds to give the event-overview dashboard real numbers. With dev/payments.rb now the single home for payment sample data, keeping payment-record creation in dummy split that concern across two files. - Move the scholarship/payment/allocation funding (CashPayment, CheckPayment, Allocation, Scholarship) out of dummy.rb into payments.rb, re-resolving the events/people/registrations it funds via find_by since those are still created in dummy.rb (run first by db:seed:dev) - The funding guards on missing events, so db:seed:payments on its own is a no-op for dummy events and only funds them as part of db:seed:dev - Event cost_cents, the scholarship application form, and registration scholarship flags stay in dummy.rb — they're event/registration setup, not payment records - Normalize payments.rb's leftover global indentation to top level Verified via `rake db:seed:payments`: dashboards report the expected received/outstanding/scholarship totals. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Consolidate dev payment seeds into db:seed:dev Payment seed data (test people, a sample event, and payment/allocation/ refund scenarios) was loaded from the base db/seeds.rb, so it ran on every db:seed — including production. It is sample data for exercising the payments UI, not required base data, so it does not belong in the production seed run. - Move dev-only seeds under db/seeds/dev/ to signal they never run in prod - Split seeding into rake tasks: db:seed:dummy and db:seed:payments, both orchestrated by db:seed:dev (which still runs the base db:seed first) - Drop the payment seed call (and now-unused seed helper) from db/seeds.rb - Rename the dev task db:dev:seed -> db:seed:dev to sit alongside the built-in db:seed:replant Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Clarify payment seed header comment rake db:seed:payments already runs the file on its own, so the prior 'can also be run independently' wording was confusing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Move all payment seeding from dummy into dev/payments.rb PR #1565 (merged to main) added a Scholarships/Payments/Allocations section to the dummy dev seeds to give the event-overview dashboard real numbers. With dev/payments.rb now the single home for payment sample data, keeping payment-record creation in dummy split that concern across two files. - Move the scholarship/payment/allocation funding (CashPayment, CheckPayment, Allocation, Scholarship) out of dummy.rb into payments.rb, re-resolving the events/people/registrations it funds via find_by since those are still created in dummy.rb (run first by db:seed:dev) - The funding guards on missing events, so db:seed:payments on its own is a no-op for dummy events and only funds them as part of db:seed:dev - Event cost_cents, the scholarship application form, and registration scholarship flags stay in dummy.rb — they're event/registration setup, not payment records - Normalize payments.rb's leftover global indentation to top level Verified via `rake db:seed:payments`: dashboards report the expected received/outstanding/scholarship totals. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
What is the goal of this PR and why is this important?
GET /events/:id/dashboard(admin/owner only).How did you approach the change?
EventDashboardservice aggregates every metric in a handful of queries; keeps the controller/view thin and is fully unit-tested.CA - Los Angeles), sector, and registrant-id selection. A Dashboard link is added to the manage header (alongside Group manage registrants header actions into dropdowns #1568's action dropdowns).$0until their migration lands.Notes for reviewers
main— reconciled with Custom forms with roles #1563 (Custom forms with roles) and Group manage registrants header actions into dropdowns #1568 (manage header dropdowns). The dev seed now uses Custom forms with roles #1563's role-based registration/scholarship forms, and the manage header keeps Group manage registrants header actions into dropdowns #1568's dropdowns with the Dashboard link added.EventDashboardservice spec,EventRegistrationscope specs, request specs (render + auth + Manage filters), routing + decorator specs — all green.ai/recap+ai/security(Add ai/recap and ai/security shortcuts #1570), FormBuilder seed reconciliation (Reconcile seeded FormBuilders by id and prune duplicates #1571).Anything else to add?