diff --git a/app/controllers/concerns/event_registration_session.rb b/app/controllers/concerns/event_registration_session.rb new file mode 100644 index 000000000..833633f34 --- /dev/null +++ b/app/controllers/concerns/event_registration_session.rb @@ -0,0 +1,19 @@ +module EventRegistrationSession + extend ActiveSupport::Concern + + private + + def store_event_reg_slug(event_id, slug) + session[:event_reg_slugs] ||= {} + session[:event_reg_slugs][event_id.to_s] = slug + end + + def clear_event_reg_slug(event_id) + return unless session[:event_reg_slugs] + session[:event_reg_slugs].delete(event_id.to_s) + end + + def event_reg_slug_for(event_id) + session.dig(:event_reg_slugs, event_id.to_s) + end +end diff --git a/app/controllers/events/public_registrations_controller.rb b/app/controllers/events/public_registrations_controller.rb index ade7bfcec..96b738b77 100644 --- a/app/controllers/events/public_registrations_controller.rb +++ b/app/controllers/events/public_registrations_controller.rb @@ -1,5 +1,6 @@ module Events class PublicRegistrationsController < ApplicationController + include EventRegistrationSession skip_before_action :authenticate_user!, only: [ :new, :create, :show ] before_action :set_event before_action :ensure_registerable, only: [ :new, :create ] @@ -53,6 +54,7 @@ def create ) if result.success? + store_event_reg_slug(@event.id, result.event_registration.slug) redirect_to registration_ticket_path(result.event_registration.slug), notice: "You have been successfully registered!" else diff --git a/app/controllers/events/registrations_controller.rb b/app/controllers/events/registrations_controller.rb index a6b82c20c..d2c808a1c 100644 --- a/app/controllers/events/registrations_controller.rb +++ b/app/controllers/events/registrations_controller.rb @@ -1,5 +1,6 @@ module Events class RegistrationsController < ApplicationController + include EventRegistrationSession before_action :authenticate_user!, only: [ :create, :destroy ] before_action :set_event, only: [ :create, :destroy ] before_action :set_registrant, only: [ :create, :destroy ] @@ -7,6 +8,7 @@ class RegistrationsController < ApplicationController def show authorize! @event_registration, to: :show_public? + store_event_reg_slug(@event_registration.event_id, @event_registration.slug) if @event_registration.active? end def resend_confirmation @@ -20,6 +22,7 @@ def cancel if @event_registration.active? @event_registration.update!(status: "cancelled") + clear_event_reg_slug(@event_registration.event_id) redirect_to registration_ticket_path(@event_registration.slug), notice: "Your registration has been cancelled." else redirect_to registration_ticket_path(@event_registration.slug), alert: "Registration is already cancelled." @@ -31,6 +34,7 @@ def reactivate if @event_registration.status == "cancelled" @event_registration.update!(status: "registered") + store_event_reg_slug(@event_registration.event_id, @event_registration.slug) redirect_to registration_ticket_path(@event_registration.slug), notice: "Your registration has been reactivated." else redirect_to registration_ticket_path(@event_registration.slug), alert: "Registration is not cancelled." @@ -43,6 +47,7 @@ def create if existing&.status == "cancelled" authorize! existing existing.update!(status: "registered") + store_event_reg_slug(@event.id, existing.slug) success = "Your registration has been reactivated." respond_to do |format| format.turbo_stream { flash.now[:notice] = success } @@ -55,6 +60,7 @@ def create authorize! @event_registration if @event_registration.save + store_event_reg_slug(@event.id, @event_registration.slug) success = "You have successfully registered for this event." respond_to do |format| format.turbo_stream { flash.now[:notice] = success } diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index c043b3f52..cbb90e830 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -1,5 +1,5 @@ class EventsController < ApplicationController - include AhoyTracking, TagAssignable + include AhoyTracking, TagAssignable, EventRegistrationSession skip_before_action :authenticate_user!, only: [ :index, :show ] skip_before_action :verify_authenticity_token, only: [ :preview ] before_action :set_event, only: %i[ show edit update destroy preview manage copy_registration_form ] @@ -8,12 +8,14 @@ def index authorize! base_scope = authorized_scope(Event.all) @events = base_scope.search_by_params(params).order(start_date: :desc) + persist_reg_slug_from_params end def show authorize! @event @event = @event.decorate track_view(@event) + persist_reg_slug_from_params end def new @@ -228,6 +230,12 @@ def set_event @event = Event.find(params[:id]) end + def persist_reg_slug_from_params + return unless params[:reg].present? + reg = EventRegistration.find_by(slug: params[:reg]) + store_event_reg_slug(reg.event_id, reg.slug) if reg&.active? + end + def event_params params.require(:event).permit(:cost, :created_by_id, diff --git a/app/views/events/_card.html.erb b/app/views/events/_card.html.erb index 5ba05ace0..5c2d72150 100644 --- a/app/views/events/_card.html.erb +++ b/app/views/events/_card.html.erb @@ -30,6 +30,11 @@ <% registered = current_user && event.actively_registered?(current_user.person) %> + <% unless registered + reg_slug = session.dig(:event_reg_slugs, event.id.to_s) + slug_registration = reg_slug ? EventRegistration.find_by(slug: reg_slug, event_id: event.id) : nil + slug_registered = slug_registration&.active? + end %>
<% if event.location.present? %> @@ -55,6 +60,11 @@ data: { turbo_frame: "_top" }, class: "btn px-3 py-2 text-xs uppercase leading-tight text-white hover:bg-white event-view-registration-btn", style: "font-family: 'Telefon Bold', sans-serif; background-color: rgb(22, 101, 52); border: 2px solid rgb(22, 101, 52);" %> + <% elsif slug_registered %> + <%= link_to "View registration", registration_ticket_path(slug_registration.slug), + data: { turbo_frame: "_top" }, + class: "btn px-3 py-2 text-xs uppercase leading-tight text-white hover:bg-white event-view-registration-btn", + style: "font-family: 'Telefon Bold', sans-serif; background-color: rgb(22, 101, 52); border: 2px solid rgb(22, 101, 52);" %> <% elsif event.ended? %> Event ended <% if allowed_to?(:manage?, event) %> diff --git a/app/views/events/_registration_section.html.erb b/app/views/events/_registration_section.html.erb index 9238b97bf..e439898e5 100644 --- a/app/views/events/_registration_section.html.erb +++ b/app/views/events/_registration_section.html.erb @@ -1,7 +1,8 @@ <% instance ||= 1 %> <% button_text ||= "Register" %> <% registered = event.actively_registered?(current_user&.person) %> -<% slug_registration = params[:reg].present? ? EventRegistration.find_by(slug: params[:reg], event_id: event.id) : nil %> +<% reg_slug = params[:reg].presence || session.dig(:event_reg_slugs, event.id.to_s) %> +<% slug_registration = reg_slug ? EventRegistration.find_by(slug: reg_slug, event_id: event.id) : nil %> <% slug_registered = slug_registration&.active? %> <% slug_cancelled = slug_registration.present? && slug_registration.status == "cancelled" %> <%= tag.div id: dom_id(event.object, "registration_section_#{instance}"), class: "registration-section flex flex-col items-center gap-4 mb-6" do %> diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb index d4e32f402..d64f86e53 100644 --- a/app/views/events/show.html.erb +++ b/app/views/events/show.html.erb @@ -8,10 +8,11 @@ <% else %>
- <%= link_to "← Back to Events", events_path, class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %> + <% reg_slug = params[:reg].presence || session.dig(:event_reg_slugs, @event.id.to_s) %> + <%= link_to "← Back to Events", events_path(reg: reg_slug), class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %>
<%= link_to "Home", root_path, class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %> - <%= link_to "Events", events_path, class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %> + <%= link_to "Events", events_path(reg: reg_slug), class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %> <% if allowed_to?(:manage?, @event) && @event.object.event_forms.registration.exists? %> <%= link_to "Register (as visitor)", new_event_public_registration_path(@event), class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1 admin-only bg-blue-100" %> <% end %> diff --git a/spec/requests/events/registrations_spec.rb b/spec/requests/events/registrations_spec.rb index 3cf3d7304..30b44d351 100644 --- a/spec/requests/events/registrations_spec.rb +++ b/spec/requests/events/registrations_spec.rb @@ -18,6 +18,20 @@ get registration_ticket_path(registration.slug) expect(response).to have_http_status(:success) end + + it "stores the slug in session for active registrations" do + get registration_ticket_path(registration.slug) + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => registration.slug }) + end + end + + context "when the registration is cancelled" do + before { registration.update!(status: "cancelled") } + + it "does not store the slug in session" do + get registration_ticket_path(registration.slug) + expect(session[:event_reg_slugs]).to be_nil + end end context "as an admin" do @@ -91,6 +105,15 @@ expect(flash[:notice]).to eq("Your registration has been cancelled.") end + it "clears the slug from session" do + # First store the slug via show + get registration_ticket_path(registration.slug) + expect(session[:event_reg_slugs][event.id.to_s]).to eq(registration.slug) + + post registration_cancel_path(registration.slug) + expect(session[:event_reg_slugs][event.id.to_s]).to be_nil + end + it "does not cancel an already cancelled registration" do registration.update!(status: "cancelled") @@ -123,6 +146,11 @@ expect(flash[:notice]).to eq("Your registration has been reactivated.") end + it "stores the slug in session after reactivation" do + post registration_reactivate_path(registration.slug) + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => registration.slug }) + end + it "does not reactivate an already active registration" do registration.update!(status: "registered") @@ -193,6 +221,12 @@ expect(response.media_type).to eq("text/vnd.turbo-stream.html") expect(flash.now[:notice]).to eq("You have successfully registered for this event.") end + + it "stores the slug in session" do + post event_registrant_registration_path(event_id: event.id) + reg = EventRegistration.last + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => reg.slug }) + end end context "when a cancelled registration exists" do @@ -218,6 +252,11 @@ expect(response).to redirect_to(registration_ticket_path(cancelled_registration.slug)) expect(flash[:notice]).to eq("Your registration has been reactivated.") end + + it "stores the slug in session on reactivation" do + post event_registrant_registration_path(event_id: event.id) + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => cancelled_registration.slug }) + end end context "when creation fails" do diff --git a/spec/requests/events_spec.rb b/spec/requests/events_spec.rb index eac574b37..1309c4a9d 100644 --- a/spec/requests/events_spec.rb +++ b/spec/requests/events_spec.rb @@ -29,6 +29,13 @@ expect(response).to have_http_status(:ok) end + it "stores reg slug in session when reg param is present" do + sign_in user + registration = create(:event_registration, event: event, registrant: create(:person)) + get events_path(reg: registration.slug) + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => registration.slug }) + end + context "when user time_zone is set" do # 19:00 UTC = 12:00 noon PT = 15:00 (3 pm) ET (June 15, 2025 with DST) let(:utc_start) { Time.utc(2025, 6, 15, 19, 0, 0) } @@ -63,6 +70,22 @@ end end + describe "GET /show" do + it "stores reg slug in session when reg param is present" do + sign_in user + registration = create(:event_registration, event: event, registrant: create(:person)) + get event_path(event, reg: registration.slug) + expect(session[:event_reg_slugs]).to eq({ event.id.to_s => registration.slug }) + end + + it "does not store slug for cancelled registrations" do + sign_in user + registration = create(:event_registration, event: event, registrant: create(:person), status: "cancelled") + get event_path(event, reg: registration.slug) + expect(session[:event_reg_slugs]).to be_nil + end + end + describe "GET /new" do context "as admin" do it "renders successfully" do