Add CE status column and filter to registrants index#1833
Conversation
| when "requested" then where(ce_credit_requested: true) | ||
| when "license_not_provided" then where(ce_credit_requested: true).where(ce_license_number: [ nil, "" ]) | ||
| when "hours_not_provided" then where(ce_credit_requested: true).where("COALESCE(ce_hours_requested, 0) <= 0") | ||
| when "paid" then where(ce_credit_requested: true).merge(paid_in_full) |
There was a problem hiding this comment.
🤖 From Claude: "paid" intentionally has no CE-specific payment record yet, so it falls back to the registrant being paid in full — kept in sync with ReminderRecipientFilter#matches_ce_status?.
| <% extra_cols = (payment_col ? 1 : 0) + (ce_col ? 1 : 0) %> | ||
| <% ce_index = payment_col ? 4 : 3 %> | ||
| <% date_index = 4 + extra_cols %> | ||
| <% attendance_index = 5 + extra_cols %> |
There was a problem hiding this comment.
🤖 From Claude: Sort-column indices are recomputed from extra_cols so the Date/Attendance headers stay aligned whether or not the optional Payment and CE columns are present.
| # True when at least one registrant for this event requested CE credit. Drives | ||
| # the CE status column and filter on the registrants index — there's nothing | ||
| # to show or filter when no one has asked for CE. | ||
| def any_ce_credit_requests? |
There was a problem hiding this comment.
🤖 From Claude: Column/filter visibility is gated on any registrant having requested CE, so non-CE events stay uncluttered. Easy to switch to a registration-form-field check if we'd rather surface it before anyone answers.
| # every CE surface (registrants index, onboarding matrix, bulk reminders) and | ||
| # their CSV exports, so events that don't offer CE never show empty CE | ||
| # columns/filters even if a stray registration carries CE data. | ||
| def offers_ce? |
There was a problem hiding this comment.
🤖 From Claude: Single gate for every CE surface (index column/filter, onboarding matrix + CSV, bulk-reminder filter, registrants CSV): the event offers CE only when its registration form carries the seeded ce_credit_interest field — not when a stray registration happens to hold CE data.
| static targets = ["toggle", "track", "knob"] | ||
| static values = { group: String } | ||
|
|
||
| toggle() { |
There was a problem hiding this comment.
🤖 From Claude: Generalized to multiple independent switches keyed by group value, so the same controller drives both "User confirmation" and "CE status". Columns live under a shared [data-column-toggle-root] ancestor and are matched by data-column-toggle-col="<group>".
Admins need to see and triage registrants' continuing-education credit standing at a glance — who requested CE, who is missing a license number or hours, and who has paid — without opening each registration. Surfaces this as a column and dropdown filter that only appear once an event has CE requests, so non-CE events stay uncluttered, and mirrors the column in the CSV export for parity. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CE only matters for events whose registration form actually asks the magic CE-interest question, so empty CE columns/filters were noise on every other event. Gate all CE UI — registrants index, onboarding matrix, bulk-reminder filter, and both CSV exports — on Event#offers_ce? (the form carries the ce_credit_interest field) instead of "any registrant happened to have CE data". On the registrants index the CE status column now sits behind its own slide toggle (defaulting off) alongside "User confirmation", generalizing the column-toggle controller to support multiple named groups. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Main (#1916) established Event#ce_eligible? (ce_hours_offered > 0) as the single source of truth for whether an event grants CE credit. Drop the branch's own offers_ce? (which checked the registration form for the ce_credit_interest field) and gate every CE surface on ce_eligible? so the two can't drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fd17321 to
bea6023
Compare
- Default the CE status column on (toggle on) when the event is ce_eligible; add per-column toggles (CE, Attendance off-by-default, User confirmation) by generalizing column-toggle to named groups. - Reorder columns: CE before Scholarship; Date registered moved to the far right after Edit; CE filter dropdown before Scholarship; filters wrapped in a card. - Reclaim width: compact registrant profile button (teeny avatar, smaller type), drop leading chip icons, retune column widths/truncation. - CE cell mirrors the scholarship pill and links to the registration edit (CE section); not-requested shows a "Create" chip. - Viewing a submission from the roster now navigates in the same tab and the eyebrow returns to that registrant's row (anchored + highlighted). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lish - Add Organization (on) and Scholarship (on when the event charges a fee) column toggles; Scholarship column hidden by default on free events. - Order toggles: Organization, CE, Scholarship, Attendance, User confirmation. - Rename the CE toggle and column header to "CE". - Registration-form icon: blue outline (fa-regular), shown only when a form was submitted; reserve a fixed slot otherwise so comment/warning icons stay aligned. Comments icon switched to outline. - Person column a uniform w-60 (names truncate at 30). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Requested → orange; once a license is on file show the CE amount due in orange; paid shows blue Recipient; gray Create when CE wasn't requested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CE cell now walks the ContinuingEducationRegistration lifecycle: Requested → No license # → amount due → Recipient (paid); eager-load CE records. - Comment icon: orange-filled when any comment is flagged, otherwise the new `comments` theme lilac; clickable to the registration's comments section. - Add a `comments` DomainTheme color; reuse it on the registration edit comments card. Make the shout-out field a textarea. - New filters: Comments (None/Present/Flagged) and Organization (Pending/Linked), with scopes. Filters restructured into two rows, ordered to match the columns (CE, Scholarship, Payment), wider keyword box, grey Clear button. - Reg-edit: org card narrower (even thirds) so scholarship/CE are wider. - Every "Back to registrants" eyebrow (edit, link-org, public submission, scholarships, allocations, person profile) now anchors + highlights the row. - Index row highlight recolored amber → yellow. - AI files: prefer decorators over helpers for model-specific presentation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ters Both the registrants roster and the bulk-reminder recipient filters now render their dropdowns through one events/filter_select partial (each page keeps its own text inputs, dropdown set, and options). DRYs the select markup without changing any param names, options, or filtering behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add a User-account filter (None/Invited/Has access/No access) to the registrants roster via an account_status scope (guards NULL person_ids so NOT IN works); shares the filter_select partial with the reminder page. - Align the reminder filter layout to the roster: inputs + dropdowns are flex rows of w-48 controls that wrap (so all inputs fit a row); grey Clear button. - Move the grey-placeholder behavior into the shared filter_select partial so both pages get it. - Narrow the State dropdown so Clear fits on the row. - Darken the index row highlight ring (yellow-400) so it reads yellow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t=green The row-highlight ring rendered black because ring-<color> utilities were never in the Tailwind @source safelist (only bg/border/text were), so the class fell back to currentColor. Add a ring- safelist line; the highlight now builds as a real (dark yellow) ring. Also recolor the CE chip to mirror the registration flow: Filed → blue, Recipient (paid) → green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep it a textarea (multi-line on demand) but default to one row. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r dropdowns Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…amped) The arbitrary min-w-[16rem] never compiled; min-w-0 lets the keyword flex and shrink so the dropdowns share one horizontal row on desktop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render the same dropdown filter set (attendance, payment, CE, scholarship, organization, comments, user account, state, county) on the bulk-reminder recipients page, sharing the events/filter_select partial. ReminderRecipientFilter now keeps its free-text inputs in memory but delegates the dropdowns to the same EventRegistration scopes the roster uses, so param names, options, and semantics stay identical (and filters can carry between the two pages). preview_reminder builds @dashboard for the state/county options. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…umns Completes the continuing-education cutover started by the foundation models (#1916). Reroutes registration intake, the public callout, and every read site (callouts, onboarding, reminders, CSV) off the flat EventRegistration#ce_* columns and onto ContinuingEducationRegistration / ProfessionalLicense, then drops the ce_credit_requested / ce_hours_requested / ce_license_number columns. Reconciled with #1833 (registrants-index CE column + filter), which merged to main while this branch was in flight and built the same scaffolding on the old columns: - Kept #1833's scaffolding (CE column, dropdown filter, column toggles, layout, onboarding columns, bulk-reminder filter, CSV columns, eyebrow nav) and repointed every CE data read to the new models. - EventRegistration.ce_status is now a derived scope over the CE registrations (needs_license / requested / paid / issued / not_issued), replacing the old ce_credit_requested-based buckets; the roster + reminder dropdowns follow it. - EventRegistration#ce_status_label and the aggregators (ce_requested?, ce_hours_total, ce_amount_owed_cents, ce_license_provided?, ce_paid_in_full?) read the new models; the registrants column gates on a CE record existing rather than the dropped boolean (the "requested, no record yet" state is gone now that intake creates the record). - ReminderRecipientFilter's CE matching flows through the shared ce_status scope (its per-record matchers were redundant with main's scope approach). Migration timestamped to run after the foundation migrations now in main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…umns Completes the continuing-education cutover started by the foundation models (#1916). Reroutes registration intake, the public callout, and every read site (callouts, onboarding, reminders, CSV) off the flat EventRegistration#ce_* columns and onto ContinuingEducationRegistration / ProfessionalLicense, then drops the ce_credit_requested / ce_hours_requested / ce_license_number columns. Reconciled with #1833 (registrants-index CE column + filter), which merged to main while this branch was in flight and built the same scaffolding on the old columns: - Kept #1833's scaffolding (CE column, dropdown filter, column toggles, layout, onboarding columns, bulk-reminder filter, CSV columns, eyebrow nav) and repointed every CE data read to the new models. - EventRegistration.ce_status is now a derived scope over the CE registrations (needs_license / requested / paid / issued / not_issued), replacing the old ce_credit_requested-based buckets; the roster + reminder dropdowns follow it. - EventRegistration#ce_status_label and the aggregators (ce_requested?, ce_hours_total, ce_amount_owed_cents, ce_license_provided?, ce_paid_in_full?) read the new models; the registrants column gates on a CE record existing rather than the dropped boolean (the "requested, no record yet" state is gone now that intake creates the record). - ReminderRecipientFilter's CE matching flows through the shared ce_status scope (its per-record matchers were redundant with main's scope approach). Migration timestamped to run after the foundation migrations now in main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…umns Completes the continuing-education cutover started by the foundation models (#1916). Reroutes registration intake, the public callout, and every read site (callouts, onboarding, reminders, CSV) off the flat EventRegistration#ce_* columns and onto ContinuingEducationRegistration / ProfessionalLicense, then drops the ce_credit_requested / ce_hours_requested / ce_license_number columns. Reconciled with #1833 (registrants-index CE column + filter), which merged to main while this branch was in flight and built the same scaffolding on the old columns: - Kept #1833's scaffolding (CE column, dropdown filter, column toggles, layout, onboarding columns, bulk-reminder filter, CSV columns, eyebrow nav) and repointed every CE data read to the new models. - EventRegistration.ce_status is now a derived scope over the CE registrations (needs_license / requested / paid / issued / not_issued), replacing the old ce_credit_requested-based buckets; the roster + reminder dropdowns follow it. - EventRegistration#ce_status_label and the aggregators (ce_requested?, ce_hours_total, ce_amount_owed_cents, ce_license_provided?, ce_paid_in_full?) read the new models; the registrants column gates on a CE record existing rather than the dropped boolean (the "requested, no record yet" state is gone now that intake creates the record). - ReminderRecipientFilter's CE matching flows through the shared ce_status scope (its per-record matchers were redundant with main's scope approach). Migration timestamped to run after the foundation migrations now in main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…umns Completes the continuing-education cutover started by the foundation models (#1916). Reroutes registration intake, the public callout, and every read site (callouts, onboarding, reminders, CSV) off the flat EventRegistration#ce_* columns and onto ContinuingEducationRegistration / ProfessionalLicense, then drops the ce_credit_requested / ce_hours_requested / ce_license_number columns. Reconciled with #1833 (registrants-index CE column + filter), which merged to main while this branch was in flight and built the same scaffolding on the old columns: - Kept #1833's scaffolding (CE column, dropdown filter, column toggles, layout, onboarding columns, bulk-reminder filter, CSV columns, eyebrow nav) and repointed every CE data read to the new models. - EventRegistration.ce_status is now a derived scope over the CE registrations (needs_license / requested / paid / issued / not_issued), replacing the old ce_credit_requested-based buckets; the roster + reminder dropdowns follow it. - EventRegistration#ce_status_label and the aggregators (ce_requested?, ce_hours_total, ce_amount_owed_cents, ce_license_provided?, ce_paid_in_full?) read the new models; the registrants column gates on a CE record existing rather than the dropped boolean (the "requested, no record yet" state is gone now that intake creates the record). - ReminderRecipientFilter's CE matching flows through the shared ce_status scope (its per-record matchers were redundant with main's scope approach). Migration timestamped to run after the foundation migrations now in main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 PR, suggested 👤 review level: 🔬 Inspect — substantive view/JS logic across the registrants roster plus a shared helper and the public-registration eyebrow
What is the goal of this PR and why is this important?
How did you approach the change?
EventRegistration.ce_statusscope + sharedce_status_label; a "CE status" column (scholarship-style pill linking to the registration's CE section) and dropdown filter, plus onboarding columns, bulk-reminder filter, and both CSV exports — all gated onEvent#ce_eligible?.column-toggleStimulus controller to multiple named groups. CE on by default, Attendance off by default, User confirmation off — each with its own switch.UI Testing Checklist
Anything else to add?
Event#ce_eligible?(CE foundation PR Add ProfessionalLicense and ContinuingEducationRegistration models (PR 1: foundation) #1916). Covered by model + request specs (scope, filter, CSV, toggle defaults, eyebrow).