Merge pull request #1130 from Retrospring/feature/mark-all-notifications-as-read
Mark all notifications as read
This commit is contained in:
commit
7a9a7e0d47
|
@ -25,6 +25,16 @@ class NotificationsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read
|
||||||
|
current_user.notifications.where(new: true).update_all(new: false) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.turbo_stream do
|
||||||
|
render "navigation/notifications", locals: { notifications: [], notification_count: nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def paginate_notifications
|
def paginate_notifications
|
||||||
|
|
|
@ -19,16 +19,19 @@
|
||||||
%a.nav-link{ href: '#', data: { bs_target: '#modal-list-memberships', bs_toggle: :modal } }
|
%a.nav-link{ href: '#', data: { bs_target: '#modal-list-memberships', bs_toggle: :modal } }
|
||||||
%i.fa.fa-list.hidden-xs
|
%i.fa.fa-list.hidden-xs
|
||||||
%span.d-none.d-sm-inline.d-md-none= t(".list")
|
%span.d-none.d-sm-inline.d-md-none= t(".list")
|
||||||
= nav_entry t("navigation.notifications"), notifications_path, badge: notification_count, class: "d-block d-sm-none", hotkey: "g n"
|
= nav_entry t("navigation.notifications"), notifications_path, class: "d-block d-sm-none", hotkey: "g n"
|
||||||
%li.nav-item.dropdown.d-none.d-sm-block
|
%li.nav-item.dropdown.d-none.d-sm-block
|
||||||
%a.nav-link.dropdown-toggle{ href: '#', data: { bs_toggle: :dropdown } }
|
%a.nav-link.dropdown-toggle{ href: '#', data: { bs_toggle: :dropdown } }
|
||||||
- if notification_count.nil?
|
%turbo-frame#notification-desktop-icon
|
||||||
%i.fa.fa-bell-o
|
- if notification_count.nil?
|
||||||
- else
|
%i.fa.fa-bell-o
|
||||||
%i.fa.fa-bell
|
- else
|
||||||
%span.visually-hidden= t("navigation.notifications")
|
%i.fa.fa-bell
|
||||||
%span.badge= notification_count
|
%span.visually-hidden= t("navigation.notifications")
|
||||||
= render 'navigation/dropdown/notifications', notifications: notifications, size: "desktop"
|
%span.badge= notification_count
|
||||||
|
.dropdown-menu.dropdown-menu-end.notification-dropdown
|
||||||
|
%turbo-frame#notifications-dropdown-list
|
||||||
|
= render "navigation/dropdown/notifications", notifications:, notification_count: nil
|
||||||
%li.nav-item.d-none.d-sm-block{ data: { bs_toggle: 'tooltip', bs_placement: 'bottom' }, title: t('.ask_question') }
|
%li.nav-item.d-none.d-sm-block{ data: { bs_toggle: 'tooltip', bs_placement: 'bottom' }, title: t('.ask_question') }
|
||||||
%a.nav-link{ href: "#", name: "toggle-all-ask", data: { bs_target: "#modal-ask-followers", bs_toggle: :modal, hotkey: "n" } }
|
%a.nav-link{ href: "#", name: "toggle-all-ask", data: { bs_target: "#modal-ask-followers", bs_toggle: :modal, hotkey: "n" } }
|
||||||
%i.fa.fa-pencil-square-o
|
%i.fa.fa-pencil-square-o
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
- if APP_CONFIG.dig(:features, :discover, :enabled) || current_user.mod?
|
- if APP_CONFIG.dig(:features, :discover, :enabled) || current_user.mod?
|
||||||
= nav_entry t("navigation.discover"), discover_path, icon: 'compass', icon_only: true
|
= nav_entry t("navigation.discover"), discover_path, icon: 'compass', icon_only: true
|
||||||
= nav_entry t("navigation.notifications"), notifications_path("all"), icon: notifications_icon,
|
= nav_entry t("navigation.notifications"), notifications_path("all"), icon: notifications_icon,
|
||||||
badge: notification_count, badge_color: "primary", icon_only: true
|
badge: notification_count, badge_color: "primary", badge_attr: { id: "notification-mobile-count" }, icon_only: true
|
||||||
%li.nav-item.profile--image-dropdown
|
%li.nav-item.profile--image-dropdown
|
||||||
%a.nav-link{ href: '#', data: { bs_toggle: 'dropdown', bs_target: '#rs-mobile-nav-profile' }, aria: { controls: 'rs-mobile-nav-profile', expanded: 'false' } }
|
%a.nav-link{ href: '#', data: { bs_toggle: 'dropdown', bs_target: '#rs-mobile-nav-profile' }, aria: { controls: 'rs-mobile-nav-profile', expanded: 'false' } }
|
||||||
%img.avatar-md.d-inline{ src: current_user.profile_picture.url(:small) }
|
%img.avatar-md.d-inline{ src: current_user.profile_picture.url(:small) }
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
.dropdown-menu.dropdown-menu-end.notification-dropdown{ id: "rs-#{size}-nav-notifications" }
|
- if notifications.count.zero?
|
||||||
- if notifications.count.zero?
|
%a.dropdown-item.text-center{ href: notifications_path('all'), data: { turbo_frame: "_top" } }
|
||||||
%a.dropdown-item.text-center{ href: notifications_path('all') }
|
%i.fa.fa-fw.fa-chevron-right
|
||||||
%i.fa.fa-fw.fa-chevron-right
|
= t(".all")
|
||||||
= t(".all")
|
.dropdown-item.text-center.p-2
|
||||||
.dropdown-item.text-center.p-2
|
%i.fa.fa-bell-o.notification__bell-icon
|
||||||
%i.fa.fa-bell-o.notification__bell-icon
|
%p= t(".none")
|
||||||
%p= t(".none")
|
- else
|
||||||
- else
|
%a.dropdown-item.text-center{ href: notifications_path, data: { turbo_frame: "_top" } }
|
||||||
%a.dropdown-item.text-center{ href: notifications_path }
|
%i.fa.fa-fw.fa-chevron-right
|
||||||
%i.fa.fa-fw.fa-chevron-right
|
= t(".new")
|
||||||
= t(".new")
|
= link_to notifications_read_path, class: "dropdown-item text-center", data: { turbo_stream: true, turbo_method: :post } do
|
||||||
- notifications.each do |notification|
|
%i.fa.fa-fw.fa-check-double
|
||||||
.dropdown-item
|
= t(".mark_as_read")
|
||||||
= render "notifications/type/#{notification.target.class.name.downcase.split('::').last}", notification: notification
|
- notifications.each do |notification|
|
||||||
|
.dropdown-item
|
||||||
|
= render "notifications/type/#{notification.target.class.name.downcase.split('::').last}", notification:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
= turbo_stream.update "notifications-dropdown-list" do
|
||||||
|
= render "navigation/dropdown/notifications", notifications:
|
||||||
|
|
||||||
|
= turbo_stream.update "notification-desktop-icon" do
|
||||||
|
- if notification_count.nil?
|
||||||
|
%i.fa.fa-bell-o
|
||||||
|
- else
|
||||||
|
%i.fa.fa-bell
|
||||||
|
%span.visually-hidden= t("navigation.notifications")
|
||||||
|
%span.badge= notification_count
|
||||||
|
|
||||||
|
= turbo_stream.update "notification-mobile-count" do
|
||||||
|
%span.badge.badge-primary= notification_count
|
|
@ -318,6 +318,7 @@ en:
|
||||||
none: :notifications.index.none
|
none: :notifications.index.none
|
||||||
all: "Show all notifications"
|
all: "Show all notifications"
|
||||||
new: "Show all new notifications"
|
new: "Show all new notifications"
|
||||||
|
mark_as_read: "Mark all as read"
|
||||||
profile:
|
profile:
|
||||||
profile: "Show profile"
|
profile: "Show profile"
|
||||||
settings: "Settings"
|
settings: "Settings"
|
||||||
|
|
|
@ -143,6 +143,7 @@ Rails.application.routes.draw do
|
||||||
get "/list/:list_name", to: "timeline#list", as: :list_timeline
|
get "/list/:list_name", to: "timeline#list", as: :list_timeline
|
||||||
|
|
||||||
get "/notifications(/:type)", to: "notifications#index", as: :notifications, defaults: { type: "new" }
|
get "/notifications(/:type)", to: "notifications#index", as: :notifications, defaults: { type: "new" }
|
||||||
|
post "/notifications", to: "notifications#read", as: :notifications_read
|
||||||
|
|
||||||
post "/inbox/create", to: "inbox#create", as: :inbox_create
|
post "/inbox/create", to: "inbox#create", as: :inbox_create
|
||||||
get "/inbox", to: "inbox#show", as: :inbox
|
get "/inbox", to: "inbox#show", as: :inbox
|
||||||
|
|
|
@ -3,39 +3,62 @@
|
||||||
require "rails_helper"
|
require "rails_helper"
|
||||||
|
|
||||||
describe NotificationsController do
|
describe NotificationsController do
|
||||||
subject { get :index, params: { type: :new } }
|
describe "#index" do
|
||||||
|
subject { get :index, params: { type: :new } }
|
||||||
|
|
||||||
let(:user) { FactoryBot.create(:user) }
|
let(:user) { FactoryBot.create(:user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "user has no notifications" do
|
context "user has no notifications" do
|
||||||
it "should show an empty list" do
|
it "should show an empty list" do
|
||||||
subject
|
subject
|
||||||
expect(response).to render_template(:index)
|
expect(response).to render_template(:index)
|
||||||
|
|
||||||
expect(controller.instance_variable_get(:@notifications)).to be_empty
|
expect(controller.instance_variable_get(:@notifications)).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "user has notifications" do
|
||||||
|
let(:other_user) { FactoryBot.create(:user) }
|
||||||
|
let(:another_user) { FactoryBot.create(:user) }
|
||||||
|
let(:question) { FactoryBot.create(:question, user:) }
|
||||||
|
let!(:answer) { FactoryBot.create(:answer, question:, user: other_user) }
|
||||||
|
let!(:subscription) { Subscription.create(user:, answer:) }
|
||||||
|
let!(:comment) { FactoryBot.create(:comment, answer:, user: other_user) }
|
||||||
|
|
||||||
|
it "should show a list of notifications" do
|
||||||
|
subject
|
||||||
|
expect(response).to render_template(:index)
|
||||||
|
expect(controller.instance_variable_get(:@notifications)).to have_attributes(size: 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "marks notifications as read" do
|
||||||
|
expect { subject }.to change { Notification.for(user).where(new: true).count }.from(2).to(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "user has notifications" do
|
describe "#read" do
|
||||||
let(:other_user) { FactoryBot.create(:user) }
|
subject { post :read, format: :turbo_stream }
|
||||||
let(:another_user) { FactoryBot.create(:user) }
|
|
||||||
let(:question) { FactoryBot.create(:question, user: user) }
|
|
||||||
let!(:answer) { FactoryBot.create(:answer, question: question, user: other_user) }
|
|
||||||
let!(:subscription) { Subscription.create(user: user, answer: answer) }
|
|
||||||
let!(:comment) { FactoryBot.create(:comment, answer: answer, user: other_user) }
|
|
||||||
|
|
||||||
it "should show a list of notifications" do
|
let(:recipient) { FactoryBot.create(:user) }
|
||||||
subject
|
let(:notification_count) { rand(8..20) }
|
||||||
expect(response).to render_template(:index)
|
|
||||||
expect(controller.instance_variable_get(:@notifications)).to have_attributes(size: 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "marks notifications as read" do
|
context "user has some unread notifications" do
|
||||||
expect { subject }.to change { Notification.for(user).where(new: true).count }.from(2).to(0)
|
before do
|
||||||
|
notification_count.times do
|
||||||
|
FactoryBot.create(:user).follow(recipient)
|
||||||
|
end
|
||||||
|
|
||||||
|
sign_in(recipient)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "marks all notifications as read" do
|
||||||
|
expect { subject }.to change { Notification.where(recipient:, new: true).count }.from(notification_count).to(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue