diff --git a/app/controllers/events/public_registrations_controller.rb b/app/controllers/events/public_registrations_controller.rb
index a4ea0e597..42e8db55b 100644
--- a/app/controllers/events/public_registrations_controller.rb
+++ b/app/controllers/events/public_registrations_controller.rb
@@ -80,7 +80,7 @@ def create
checkout_session = create_stripe_checkout_session(registration, result.form_submission)
redirect_to checkout_session.url, allow_other_host: true, status: :see_other
else
- redirect_to registration_ticket_path(registration.slug),
+ redirect_to registration_ticket_path(registration.slug, reg: params[:reg].presence),
notice: "You have been successfully registered!"
end
else
@@ -165,8 +165,8 @@ def create_stripe_checkout_session(registration, submission = nil)
},
quantity: 1
} ],
- success_url: registration_ticket_url(registration.slug, checkout: "success"),
- cancel_url: registration_ticket_url(registration.slug, checkout: "cancelled")
+ success_url: registration_ticket_url(registration.slug, checkout: "success", reg: params[:reg].presence),
+ cancel_url: registration_ticket_url(registration.slug, checkout: "cancelled", reg: params[:reg].presence)
)
registration.update!(checkout_session_id: checkout_session.id)
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 1c6d6fe30..20adffe29 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -1,4 +1,31 @@
module EventsHelper
+ # Separates registration slugs packed into a single `?reg=` param so public
+ # (logged-out) users keep the "View registration" button lit across several
+ # events in one session. A period is used because it never appears in a
+ # urlsafe_base64 slug and stays unescaped in a URL, keeping it human-readable.
+ REG_PARAM_DELIMITER = "."
+
+ # The registration slugs carried in the current request's `?reg=` param.
+ def reg_param_slugs
+ params[:reg].to_s.split(REG_PARAM_DELIMITER)
+ end
+
+ # The registration for this event that the visitor has "unlocked" via their
+ # `?reg=` param, if any. Slugs are the authorization token, so no ownership
+ # check is needed. Returns nil when none of the param slugs belong to the event.
+ def reg_param_registration(event)
+ slugs = reg_param_slugs
+ return if slugs.empty?
+ EventRegistration.where(slug: slugs, event_id: event.id).first
+ end
+
+ # The current `?reg=` slug set with `slug` merged in, for forwarding onward
+ # links after a registration so the new event's button stays lit alongside
+ # any events registered earlier this session.
+ def reg_param_with(slug)
+ (reg_param_slugs << slug).uniq.join(REG_PARAM_DELIMITER)
+ end
+
# Stable anchor id for a registrant's row on the Onboarding matrix, so back-links
# from detail pages can scroll to (and highlight) the row they came from.
def onboarding_row_id(record_or_id)
diff --git a/app/views/events/_card.html.erb b/app/views/events/_card.html.erb
index 5d7888313..c22baa7f6 100644
--- a/app/views/events/_card.html.erb
+++ b/app/views/events/_card.html.erb
@@ -24,7 +24,7 @@
<%= link_to "Home", root_path, class: "text-sm text-gray-500 hover:text-gray-700 px-2 py-1" %>
<% if @event.event_registrations.active.exists? %>
diff --git a/spec/requests/events/registrations_spec.rb b/spec/requests/events/registrations_spec.rb
index a2b85ea59..69e6805da 100644
--- a/spec/requests/events/registrations_spec.rb
+++ b/spec/requests/events/registrations_spec.rb
@@ -18,6 +18,12 @@
get registration_ticket_path(registration.slug)
expect(response).to have_http_status(:success)
end
+
+ it "merges this slug into the reg param on the back-to-event link" do
+ prior = create(:event_registration, registrant: create(:person))
+ get registration_ticket_path(registration.slug, reg: prior.slug)
+ expect(response.body).to include("reg=#{prior.slug}.#{registration.slug}")
+ end
end
context "as an admin" do
diff --git a/spec/requests/events_spec.rb b/spec/requests/events_spec.rb
index e2854544a..07b974cf1 100644
--- a/spec/requests/events_spec.rb
+++ b/spec/requests/events_spec.rb
@@ -36,6 +36,33 @@ def offer_ce!(target_event)
expect(response).to have_http_status(:ok)
end
+ it "shows a View registration link on the card when an active reg param is present" do
+ published_event = create(:event, :published)
+ sign_in user
+ registration = create(:event_registration, event: published_event, registrant: create(:person))
+ get events_path(reg: registration.slug)
+ expect(response.body).to include("href=\"#{registration_ticket_path(registration.slug)}\"")
+ end
+
+ it "does not show a View registration link for a cancelled reg param" do
+ published_event = create(:event, :published)
+ sign_in user
+ registration = create(:event_registration, event: published_event, registrant: create(:person), status: "cancelled")
+ get events_path(reg: registration.slug)
+ expect(response.body).not_to include("href=\"#{registration_ticket_path(registration.slug)}\"")
+ end
+
+ it "shows View registration links for several events packed into one reg param" do
+ event_a = create(:event, :published)
+ event_b = create(:event, :published)
+ sign_in user
+ reg_a = create(:event_registration, event: event_a, registrant: create(:person))
+ reg_b = create(:event_registration, event: event_b, registrant: create(:person))
+ get events_path(reg: "#{reg_a.slug}.#{reg_b.slug}")
+ expect(response.body).to include("href=\"#{registration_ticket_path(reg_a.slug)}\"")
+ expect(response.body).to include("href=\"#{registration_ticket_path(reg_b.slug)}\"")
+ end
+
context "when user time_zone is set" do
# 19:00 UTC = 12:00 noon PT = 15:00 (3 pm) ET (June 15, 2031 with DST)
let(:utc_start) { Time.utc(2031, 6, 15, 19, 0, 0) }
@@ -71,6 +98,22 @@ def offer_ce!(target_event)
end
describe "GET /show" do
+ it "shows a View registration link when an active reg param is present" do
+ published_event = create(:event, :published)
+ sign_in user
+ registration = create(:event_registration, event: published_event, registrant: create(:person))
+ get event_path(published_event, reg: registration.slug)
+ expect(response.body).to include("href=\"#{registration_ticket_path(registration.slug)}\"")
+ end
+
+ it "does not show a View registration link for a cancelled reg param" do
+ published_event = create(:event, :published)
+ sign_in user
+ registration = create(:event_registration, event: published_event, registrant: create(:person), status: "cancelled")
+ get event_path(published_event, reg: registration.slug)
+ expect(response.body).not_to include("href=\"#{registration_ticket_path(registration.slug)}\"")
+ end
+
context "when event has ended" do
let(:ended_event) { create(:event, :published, :ended) }