From 3e29d7eb9492754c0923330ad6bfb66f07f666e3 Mon Sep 17 00:00:00 2001 From: Hampton Lintorn-Catlin Date: Mon, 4 May 2026 16:31:35 -0400 Subject: [PATCH] Fix "Mark all read" in inbox dropdown to not navigate The inbox dropdown's "Mark all read" button was a regular form POST with `data: { turbo: false }`, which redirected to /notifications and forced a full page navigation away from whatever page the user was on. Now the form submits via Turbo and the controller responds with a turbo_stream that: - Updates #inbox-badge to "0" - Replaces the #inbox-panel turbo frame with the refreshed panel (showing the empty state) The user stays on the current page, the dropdown stays open, and the unread count clears immediately. The HTML format on /notifications keeps its redirect behavior unchanged. Generated with Amp Amp-Thread-ID: https://ampcode.com/threads/T-019df4ad-2113-775d-bc20-300e6948aa32 Co-authored-by: Amp --- .../coplan/notifications_controller.rb | 15 ++++++++++++++- .../views/coplan/notifications/_panel.html.erb | 2 +- spec/requests/notifications_spec.rb | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/engine/app/controllers/coplan/notifications_controller.rb b/engine/app/controllers/coplan/notifications_controller.rb index 2c6886e..8efbcbe 100644 --- a/engine/app/controllers/coplan/notifications_controller.rb +++ b/engine/app/controllers/coplan/notifications_controller.rb @@ -45,7 +45,20 @@ def mark_all_read broadcast_badge_update - redirect_to notifications_path, notice: "All notifications marked as read." + respond_to do |format| + format.turbo_stream { + @notifications = current_user.notifications + .includes(:plan, :comment, comment_thread: [:created_by_user]) + .newest_first + .unread + @unread_count = 0 + render turbo_stream: [ + turbo_stream.update("inbox-badge", "0"), + turbo_stream.replace("inbox-panel", partial: "coplan/notifications/panel") + ] + } + format.html { redirect_to notifications_path, notice: "All notifications marked as read." } + end end private diff --git a/engine/app/views/coplan/notifications/_panel.html.erb b/engine/app/views/coplan/notifications/_panel.html.erb index 6690614..aa97038 100644 --- a/engine/app/views/coplan/notifications/_panel.html.erb +++ b/engine/app/views/coplan/notifications/_panel.html.erb @@ -2,7 +2,7 @@
Inbox <% if @unread_count > 0 %> - <%= button_to "Mark all read", mark_all_read_notifications_path, method: :post, class: "btn btn--secondary btn--sm", data: { turbo: false } %> + <%= button_to "Mark all read", mark_all_read_notifications_path, method: :post, class: "btn btn--secondary btn--sm", form: { data: { turbo_stream: true } } %> <% end %>
diff --git a/spec/requests/notifications_spec.rb b/spec/requests/notifications_spec.rb index 0ff432b..dd3497c 100644 --- a/spec/requests/notifications_spec.rb +++ b/spec/requests/notifications_spec.rb @@ -84,5 +84,19 @@ post mark_all_read_notifications_path expect(other_notification.reload.read_at).to be_nil end + + it "responds with a turbo_stream that updates the badge and replaces the inbox panel" do + create(:notification, user: user, plan: plan, comment_thread: thread) + + post mark_all_read_notifications_path, headers: { "Accept" => "text/vnd.turbo-stream.html" } + + expect(response).to have_http_status(:ok) + expect(response.media_type).to eq(Mime[:turbo_stream]) + expect(response.body).to include('target="inbox-badge"') + expect(response.body).to include('action="update"') + expect(response.body).to include('target="inbox-panel"') + expect(response.body).to include('action="replace"') + expect(user.notifications.unread.count).to eq(0) + end end end