diff --git a/app/controllers/event_registrations_controller.rb b/app/controllers/event_registrations_controller.rb index bfb8ece42..c3f3740b2 100644 --- a/app/controllers/event_registrations_controller.rb +++ b/app/controllers/event_registrations_controller.rb @@ -2,7 +2,7 @@ class EventRegistrationsController < ApplicationController require "csv" # show redirects to slug URL; kept for backwards compatibility - before_action :set_event_registration, only: [ :show, :edit, :update, :destroy, :update_onboarding ] + before_action :set_event_registration, only: [ :show, :edit, :update, :destroy, :update_onboarding, :toggle_certificate_issued ] def index authorize! @@ -156,6 +156,17 @@ def update_onboarding end end + # Inline toggle of the "certificate issued" flag from the registrants roster. + # Replaces just the cell so the whole roster doesn't re-render on every toggle. + def toggle_certificate_issued + authorize! @event_registration, to: :toggle_certificate_issued? + @event_registration.mark_certificate_issued!(ActiveModel::Type::Boolean.new.cast(params[:value])) + respond_to do |format| + format.turbo_stream + format.html { redirect_to helpers.registrants_event_row_path(@event_registration.event, @event_registration.id) } + end + end + def confirm @event_registration = EventRegistration.includes(registrant: :user, event: :location).find(params[:id]) authorize! @event_registration, to: :confirm? diff --git a/app/models/event_registration.rb b/app/models/event_registration.rb index 5d6551da3..fbeef8ada 100644 --- a/app/models/event_registration.rb +++ b/app/models/event_registration.rb @@ -551,6 +551,23 @@ def ce_certificate_issued? continuing_education_registrations.all? { |c| c.certificate_sent_at.present? } end + # The registration's completion certificate, as shown by the registrants-roster + # toggle. For a CE-eligible registration that's the CE certificate + # (certificate_sent_at on its CE registrations, so it stays in sync with the CE + # edit page); otherwise the registration's own certificate_sent_at (Certifiable). + def certificate_issued? + ce_registered? ? ce_certificate_issued? : certificate_sent? + end + + def mark_certificate_issued!(issued) + at = issued ? Time.current : nil + if ce_registered? + continuing_education_registrations.each { |c| c.update!(certificate_sent_at: at) } + else + update!(certificate_sent_at: at) + end + end + # True when a CE registration exists and every one is fully paid. def ce_paid_in_full? return false unless ce_registered? diff --git a/app/policies/event_registration_policy.rb b/app/policies/event_registration_policy.rb index c7ba2458b..dc82897d6 100644 --- a/app/policies/event_registration_policy.rb +++ b/app/policies/event_registration_policy.rb @@ -18,6 +18,9 @@ def unlink_organization? = admin? # Editing the onboarding matrix is an admin management action; event owners # (the event's creator) manage their own events' onboarding too. def update_onboarding? = admin? || event_owner? + # Marking a certificate issued from the registrants roster is an event-management + # action, so mirror the roster's audience (admins and the event's owner). + def toggle_certificate_issued? = admin? || event_owner? relation_scope do |relation| diff --git a/app/views/event_registrations/_certificate_issued_toggle.html.erb b/app/views/event_registrations/_certificate_issued_toggle.html.erb new file mode 100644 index 000000000..fe0948a07 --- /dev/null +++ b/app/views/event_registrations/_certificate_issued_toggle.html.erb @@ -0,0 +1,15 @@ +<%# Inline "certificate issued" slider toggle, targeted by id for turbo replacement. + The track is a direct sibling of the checkbox so peer-checked applies (it only + reaches later siblings, not their descendants); the knob is the track's ::after. %> + + <%= form_with url: toggle_certificate_issued_event_registration_path(registration), method: :patch, class: "inline" do %> + <%= hidden_field_tag :value, "0" %> + + <% end %> + diff --git a/app/views/event_registrations/toggle_certificate_issued.turbo_stream.erb b/app/views/event_registrations/toggle_certificate_issued.turbo_stream.erb new file mode 100644 index 000000000..d2c8af0e0 --- /dev/null +++ b/app/views/event_registrations/toggle_certificate_issued.turbo_stream.erb @@ -0,0 +1,4 @@ +<%# Replace just the toggled cell — avoids re-rendering the whole roster. %> +<%= turbo_stream.replace dom_id(@event_registration, :certificate_issued) do %> + <%= render "event_registrations/certificate_issued_toggle", registration: @event_registration %> +<% end %> diff --git a/app/views/events/_registrants_results.html.erb b/app/views/events/_registrants_results.html.erb index 5fd73532b..214645c17 100644 --- a/app/views/events/_registrants_results.html.erb +++ b/app/views/events/_registrants_results.html.erb @@ -130,6 +130,24 @@ + + <%# Off by default — Certificate issued is hidden until the admin reveals it. %> + @@ -193,6 +211,8 @@