From 43147b3163d1bf4dc773979a7ee6d8ddba2c6d72 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Sat, 4 Jul 2020 20:03:16 +0530 Subject: [PATCH] Chore: Fix presence for current user (#1001) Co-authored-by: Pranav Raj Sreepuram --- app/channels/room_channel.rb | 9 +++++-- .../dashboard/helper/actionCable.js | 1 + .../dashboard/settings/profile/Index.vue | 6 +++++ app/javascript/dashboard/store/index.js | 2 -- .../dashboard/store/modules/auth.js | 16 ++++++++++++ .../dashboard/store/modules/channels.js | 14 ---------- .../store/modules/specs/auth/actions.spec.js | 26 +++++++++++++++++++ .../store/modules/specs/auth/getters.spec.js | 8 ++++++ .../dashboard/store/mutation-types.js | 2 +- .../concerns/availability_statusable.rb | 12 ++++++++- lib/online_status_tracker.rb | 2 ++ 11 files changed, 78 insertions(+), 20 deletions(-) delete mode 100644 app/javascript/dashboard/store/modules/channels.js diff --git a/app/channels/room_channel.rb b/app/channels/room_channel.rb index 1a0cbb434..ab3af0c92 100644 --- a/app/channels/room_channel.rb +++ b/app/channels/room_channel.rb @@ -4,17 +4,22 @@ class RoomChannel < ApplicationCable::Channel current_user current_account update_subscription + broadcast_presence end def update_presence update_subscription + broadcast_presence + end + + private + + def broadcast_presence data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) } data[:contacts] = ::OnlineStatusTracker.get_available_contacts(@current_account.id) if @current_user.is_a? User ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data }) end - private - def ensure_stream @pubsub_token = params[:pubsub_token] stream_from @pubsub_token diff --git a/app/javascript/dashboard/helper/actionCable.js b/app/javascript/dashboard/helper/actionCable.js index 5d6abf359..4efde4d91 100644 --- a/app/javascript/dashboard/helper/actionCable.js +++ b/app/javascript/dashboard/helper/actionCable.js @@ -33,6 +33,7 @@ class ActionCableConnector extends BaseActionCableConnector { onPresenceUpdate = data => { this.app.$store.dispatch('contacts/updatePresence', data.contacts); this.app.$store.dispatch('agents/updatePresence', data.users); + this.app.$store.dispatch('setCurrentUserAvailabilityStatus', data.users); }; onConversationContactChange = payload => { diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue index 17d7ed037..eaf40b077 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue @@ -163,6 +163,7 @@ export default { ...mapGetters({ currentUser: 'getCurrentUser', currentUserId: 'getCurrentUserID', + currentAvailabilityStatus: 'getCurrentUserAvailabilityStatus', }), }, watch: { @@ -171,6 +172,11 @@ export default { this.initializeUser(); } }, + currentAvailabilityStatus(newStatus, oldStatus) { + if (newStatus !== oldStatus) { + this.availability = newStatus; + } + }, }, mounted() { if (this.currentUserId) { diff --git a/app/javascript/dashboard/store/index.js b/app/javascript/dashboard/store/index.js index 0f9194002..3da923b76 100755 --- a/app/javascript/dashboard/store/index.js +++ b/app/javascript/dashboard/store/index.js @@ -5,7 +5,6 @@ import accounts from './modules/accounts'; import agents from './modules/agents'; import auth from './modules/auth'; import cannedResponse from './modules/cannedResponse'; -import Channel from './modules/channels'; import contactConversations from './modules/contactConversations'; import contacts from './modules/contacts'; import conversationLabels from './modules/conversationLabels'; @@ -30,7 +29,6 @@ export default new Vuex.Store({ agents, auth, cannedResponse, - Channel, contactConversations, contacts, conversationLabels, diff --git a/app/javascript/dashboard/store/modules/auth.js b/app/javascript/dashboard/store/modules/auth.js index 6486eb956..ba26ea79a 100644 --- a/app/javascript/dashboard/store/modules/auth.js +++ b/app/javascript/dashboard/store/modules/auth.js @@ -34,6 +34,10 @@ export const getters = { return _state.currentUser.id; }, + getCurrentUserAvailabilityStatus(_state) { + return _state.currentUser.availability_status; + }, + getCurrentAccountId(_state) { return _state.currentAccountId; }, @@ -104,10 +108,22 @@ export const actions = { setCurrentAccountId({ commit }, accountId) { commit(types.default.SET_CURRENT_ACCOUNT_ID, accountId); }, + + setCurrentUserAvailabilityStatus({ commit, state: $state }, data) { + if (data[$state.currentUser.id]) { + commit( + types.default.SET_CURRENT_USER_AVAILABILITY, + data[$state.currentUser.id] + ); + } + }, }; // mutations const mutations = { + [types.default.SET_CURRENT_USER_AVAILABILITY](_state, status) { + Vue.set(_state.currentUser, 'availability_status', status); + }, [types.default.CLEAR_USER](_state) { _state.currentUser.id = null; }, diff --git a/app/javascript/dashboard/store/modules/channels.js b/app/javascript/dashboard/store/modules/channels.js deleted file mode 100644 index 5104a8de5..000000000 --- a/app/javascript/dashboard/store/modules/channels.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint no-console: 0 */ -/* eslint no-param-reassign: 0 */ - -// const chatType = 'all'; -// initial state -const state = {}; - -// actions -const actions = {}; - -export default { - state, - actions, -}; diff --git a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js index 287bb1be3..1081196d6 100644 --- a/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js +++ b/app/javascript/dashboard/store/modules/specs/auth/actions.spec.js @@ -67,4 +67,30 @@ describe('#actions', () => { expect(dispatch).toHaveBeenCalledTimes(0); }); }); + + describe('#setCurrentUserAvailabilityStatus', () => { + it('sends correct mutations if user id is available', async () => { + actions.setCurrentUserAvailabilityStatus( + { + commit, + state: { currentUser: { id: 1 } }, + }, + { 1: 'online' } + ); + expect(commit.mock.calls).toEqual([ + [types.default.SET_CURRENT_USER_AVAILABILITY, 'online'], + ]); + }); + + it('does not send correct mutations if user id is not available', async () => { + actions.setCurrentUserAvailabilityStatus( + { + commit, + state: { currentUser: { id: 1 } }, + }, + {} + ); + expect(commit.mock.calls).toEqual([]); + }); + }); }); diff --git a/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js b/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js index d39f5d991..96d696085 100644 --- a/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js +++ b/app/javascript/dashboard/store/modules/specs/auth/getters.spec.js @@ -17,4 +17,12 @@ describe('#getters', () => { getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } }) ).toEqual({ id: 1, name: 'Pranav' }); }); + + it('get', () => { + expect( + getters.getCurrentUserAvailabilityStatus({ + currentUser: { id: 1, name: 'Pranav', availability_status: 'busy' }, + }) + ).toEqual('busy'); + }); }); diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js index 473304986..1a39175fa 100755 --- a/app/javascript/dashboard/store/mutation-types.js +++ b/app/javascript/dashboard/store/mutation-types.js @@ -3,7 +3,7 @@ export default { CLEAR_USER: 'LOGOUT', SET_CURRENT_USER: 'SET_CURRENT_USER', SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID', - + SET_CURRENT_USER_AVAILABILITY: 'SET_CURRENT_USER_AVAILABILITY', // Chat List RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST', SET_ALL_CONVERSATION: 'SET_ALL_CONVERSATION', diff --git a/app/models/concerns/availability_statusable.rb b/app/models/concerns/availability_statusable.rb index 2f1589bc3..11d1e438e 100644 --- a/app/models/concerns/availability_statusable.rb +++ b/app/models/concerns/availability_statusable.rb @@ -2,19 +2,29 @@ module AvailabilityStatusable extend ActiveSupport::Concern def online_presence? + return if user_profile_page_context? + ::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id) end def availability_status + return availability if user_profile_page_context? return 'offline' unless online_presence? return 'online' if is_a? Contact ::OnlineStatusTracker.get_status(availability_account_id, id) || 'online' end + def user_profile_page_context? + # at the moment profile pages aren't account scoped + # hence we will return availability attribute instead of true presence + # we will revisit this later + is_a?(User) && Current.account.blank? + end + def availability_account_id return account_id if is_a? Contact - Current.account.present? ? Current.account.id : accounts.first.id + Current.account.id end end diff --git a/lib/online_status_tracker.rb b/lib/online_status_tracker.rb index 32069dd93..c9180e96f 100644 --- a/lib/online_status_tracker.rb +++ b/lib/online_status_tracker.rb @@ -44,6 +44,8 @@ module OnlineStatusTracker def self.get_available_users(account_id) user_ids = ::Redis::Alfred.zrangebyscore(presence_key(account_id, 'User'), (Time.zone.now - PRESENCE_DURATION).to_i, Time.now.to_i) + return {} if user_ids.blank? + user_availabilities = ::Redis::Alfred.hmget(status_key(account_id), user_ids) user_ids.map.with_index { |id, index| [id, (user_availabilities[index] || 'online')] }.to_h end