From c087e75808ffb6997c45eae3f3b8dafff8536d6f Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Sun, 24 Jan 2021 11:29:44 -0800 Subject: [PATCH] feat: notification center (#1612) Co-authored-by: Pranav --- .../v1/accounts/notifications_controller.rb | 12 +- app/javascript/dashboard/api/notifications.js | 33 ++++ .../dashboard/api/specs/notifications.spec.js | 13 ++ .../assets/scss/widgets/_sidemenu.scss | 24 ++- .../dashboard/components/layout/Sidebar.vue | 23 ++- .../widgets/TableFooter.vue} | 0 .../dashboard/i18n/default-sidebar.js | 9 + .../i18n/locale/en/generalSettings.json | 19 ++ .../dashboard/i18n/locale/en/settings.json | 1 + .../contacts/components/ContactsView.vue | 6 +- .../routes/dashboard/dashboard.routes.js | 8 +- .../components/NotificationTable.vue | 182 ++++++++++++++++++ .../components/NotificationsView.vue | 82 ++++++++ .../routes/dashboard/notifications/routes.js | 24 +++ app/javascript/dashboard/store/index.js | 2 + .../store/modules/notifications/actions.js | 55 ++++++ .../store/modules/notifications/getters.js | 15 ++ .../store/modules/notifications/index.js | 26 +++ .../store/modules/notifications/mutations.js | 48 +++++ .../specs/notifications/actions.spec.js | 93 +++++++++ .../specs/notifications/getters.spec.js | 46 +++++ .../specs/notifications/mutations.spec.js | 90 +++++++++ .../dashboard/store/mutation-types.js | 12 ++ 23 files changed, 811 insertions(+), 12 deletions(-) create mode 100644 app/javascript/dashboard/api/notifications.js create mode 100644 app/javascript/dashboard/api/specs/notifications.spec.js rename app/javascript/dashboard/{routes/dashboard/contacts/components/Footer.vue => components/widgets/TableFooter.vue} (100%) create mode 100644 app/javascript/dashboard/routes/dashboard/notifications/components/NotificationTable.vue create mode 100644 app/javascript/dashboard/routes/dashboard/notifications/components/NotificationsView.vue create mode 100644 app/javascript/dashboard/routes/dashboard/notifications/routes.js create mode 100644 app/javascript/dashboard/store/modules/notifications/actions.js create mode 100644 app/javascript/dashboard/store/modules/notifications/getters.js create mode 100644 app/javascript/dashboard/store/modules/notifications/index.js create mode 100644 app/javascript/dashboard/store/modules/notifications/mutations.js create mode 100644 app/javascript/dashboard/store/modules/specs/notifications/actions.spec.js create mode 100644 app/javascript/dashboard/store/modules/specs/notifications/getters.spec.js create mode 100644 app/javascript/dashboard/store/modules/specs/notifications/mutations.spec.js diff --git a/app/controllers/api/v1/accounts/notifications_controller.rb b/app/controllers/api/v1/accounts/notifications_controller.rb index 49191caad..8f63d79f5 100644 --- a/app/controllers/api/v1/accounts/notifications_controller.rb +++ b/app/controllers/api/v1/accounts/notifications_controller.rb @@ -1,6 +1,7 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseController - protect_from_forgery with: :null_session + RESULTS_PER_PAGE = 15 + protect_from_forgery with: :null_session before_action :fetch_notification, only: [:update] before_action :set_primary_actor, only: [:read_all] before_action :set_current_page, only: [:index] @@ -8,17 +9,18 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseContro def index @unread_count = current_user.notifications.where(account_id: current_account.id, read_at: nil).count @count = notifications.count - @notifications = notifications.page @current_page + @notifications = notifications.page(@current_page).per(RESULTS_PER_PAGE) end def read_all + # rubocop:disable Rails/SkipsModelValidations if @primary_actor current_user.notifications.where(account_id: current_account.id, primary_actor: @primary_actor, read_at: nil) - .update(read_at: DateTime.now.utc) + .update_all(read_at: DateTime.now.utc) else - current_user.notifications.where(account_id: current_account.id, read_at: nil).update(read_at: DateTime.now.utc) + current_user.notifications.where(account_id: current_account.id, read_at: nil).update_all(read_at: DateTime.now.utc) end - + # rubocop:enable Rails/SkipsModelValidations head :ok end diff --git a/app/javascript/dashboard/api/notifications.js b/app/javascript/dashboard/api/notifications.js new file mode 100644 index 000000000..e13bc78a6 --- /dev/null +++ b/app/javascript/dashboard/api/notifications.js @@ -0,0 +1,33 @@ +/* global axios */ +import ApiClient from './ApiClient'; + +class NotificationsAPI extends ApiClient { + constructor() { + super('notifications', { accountScoped: true }); + } + + get(page) { + return axios.get(`${this.url}?page=${page}`); + } + + getNotifications(contactId) { + return axios.get(`${this.url}/${contactId}/notifications`); + } + + getUnreadCount() { + return axios.get(`${this.url}/unread_count`); + } + + read(primaryActorType, primaryActorId) { + return axios.post(`${this.url}/read_all`, { + primary_actor_type: primaryActorType, + primary_actor_id: primaryActorId, + }); + } + + readAll() { + return axios.post(`${this.url}/read_all`); + } +} + +export default new NotificationsAPI(); diff --git a/app/javascript/dashboard/api/specs/notifications.spec.js b/app/javascript/dashboard/api/specs/notifications.spec.js new file mode 100644 index 000000000..14f472ce9 --- /dev/null +++ b/app/javascript/dashboard/api/specs/notifications.spec.js @@ -0,0 +1,13 @@ +import notifications from '../notifications'; +import ApiClient from '../ApiClient'; + +describe('#NotificationAPI', () => { + it('creates correct instance', () => { + expect(notifications).toBeInstanceOf(ApiClient); + expect(notifications).toHaveProperty('get'); + expect(notifications).toHaveProperty('getNotifications'); + expect(notifications).toHaveProperty('getUnreadCount'); + expect(notifications).toHaveProperty('read'); + expect(notifications).toHaveProperty('readAll'); + }); +}); diff --git a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss index 3971ec6fd..e56ef14d5 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss @@ -106,13 +106,13 @@ font-size: $font-size-medium; margin-top: $space-medium; - >span { + > span { margin-left: $space-one; } } } -.menu-title+ul>li>a { +.menu-title + ul > li > a { @include padding($space-micro null); color: $medium-gray; line-height: $global-lineheight; @@ -152,6 +152,26 @@ margin-left: auto; margin-top: auto; } + + .notifications { + font-size: var(--font-size-big); + margin-bottom: auto; + margin-left: auto; + margin-top: auto; + position: relative; + + .unread-badge { + background: var(--r-300); + border-radius: var(--space-small); + color: var(--white); + font-size: var(--font-size-micro); + font-weight: var(--font-weight-black); + left: var(--space-slab); + padding: 0 var(--space-smaller); + position: absolute; + top: var(--space-smaller); + } + } } .hamburger--menu { diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue index 1357ff104..b81515d3e 100644 --- a/app/javascript/dashboard/components/layout/Sidebar.vue +++ b/app/javascript/dashboard/components/layout/Sidebar.vue @@ -73,6 +73,13 @@ {{ $t(`AGENT_MGMT.AGENT_TYPES.${currentRole.toUpperCase()}`) }} + + {{ unreadCount }} + + @@ -134,7 +141,7 @@ /> -