Chore: Fix presence for current user (#1001)
Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
This commit is contained in:
parent
4612494923
commit
43147b3163
11 changed files with 78 additions and 20 deletions
|
@ -4,17 +4,22 @@ class RoomChannel < ApplicationCable::Channel
|
||||||
current_user
|
current_user
|
||||||
current_account
|
current_account
|
||||||
update_subscription
|
update_subscription
|
||||||
|
broadcast_presence
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_presence
|
def update_presence
|
||||||
update_subscription
|
update_subscription
|
||||||
|
broadcast_presence
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def broadcast_presence
|
||||||
data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) }
|
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
|
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 })
|
ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data })
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def ensure_stream
|
def ensure_stream
|
||||||
@pubsub_token = params[:pubsub_token]
|
@pubsub_token = params[:pubsub_token]
|
||||||
stream_from @pubsub_token
|
stream_from @pubsub_token
|
||||||
|
|
|
@ -33,6 +33,7 @@ class ActionCableConnector extends BaseActionCableConnector {
|
||||||
onPresenceUpdate = data => {
|
onPresenceUpdate = data => {
|
||||||
this.app.$store.dispatch('contacts/updatePresence', data.contacts);
|
this.app.$store.dispatch('contacts/updatePresence', data.contacts);
|
||||||
this.app.$store.dispatch('agents/updatePresence', data.users);
|
this.app.$store.dispatch('agents/updatePresence', data.users);
|
||||||
|
this.app.$store.dispatch('setCurrentUserAvailabilityStatus', data.users);
|
||||||
};
|
};
|
||||||
|
|
||||||
onConversationContactChange = payload => {
|
onConversationContactChange = payload => {
|
||||||
|
|
|
@ -163,6 +163,7 @@ export default {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
currentUser: 'getCurrentUser',
|
currentUser: 'getCurrentUser',
|
||||||
currentUserId: 'getCurrentUserID',
|
currentUserId: 'getCurrentUserID',
|
||||||
|
currentAvailabilityStatus: 'getCurrentUserAvailabilityStatus',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -171,6 +172,11 @@ export default {
|
||||||
this.initializeUser();
|
this.initializeUser();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
currentAvailabilityStatus(newStatus, oldStatus) {
|
||||||
|
if (newStatus !== oldStatus) {
|
||||||
|
this.availability = newStatus;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.currentUserId) {
|
if (this.currentUserId) {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import accounts from './modules/accounts';
|
||||||
import agents from './modules/agents';
|
import agents from './modules/agents';
|
||||||
import auth from './modules/auth';
|
import auth from './modules/auth';
|
||||||
import cannedResponse from './modules/cannedResponse';
|
import cannedResponse from './modules/cannedResponse';
|
||||||
import Channel from './modules/channels';
|
|
||||||
import contactConversations from './modules/contactConversations';
|
import contactConversations from './modules/contactConversations';
|
||||||
import contacts from './modules/contacts';
|
import contacts from './modules/contacts';
|
||||||
import conversationLabels from './modules/conversationLabels';
|
import conversationLabels from './modules/conversationLabels';
|
||||||
|
@ -30,7 +29,6 @@ export default new Vuex.Store({
|
||||||
agents,
|
agents,
|
||||||
auth,
|
auth,
|
||||||
cannedResponse,
|
cannedResponse,
|
||||||
Channel,
|
|
||||||
contactConversations,
|
contactConversations,
|
||||||
contacts,
|
contacts,
|
||||||
conversationLabels,
|
conversationLabels,
|
||||||
|
|
|
@ -34,6 +34,10 @@ export const getters = {
|
||||||
return _state.currentUser.id;
|
return _state.currentUser.id;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCurrentUserAvailabilityStatus(_state) {
|
||||||
|
return _state.currentUser.availability_status;
|
||||||
|
},
|
||||||
|
|
||||||
getCurrentAccountId(_state) {
|
getCurrentAccountId(_state) {
|
||||||
return _state.currentAccountId;
|
return _state.currentAccountId;
|
||||||
},
|
},
|
||||||
|
@ -104,10 +108,22 @@ export const actions = {
|
||||||
setCurrentAccountId({ commit }, accountId) {
|
setCurrentAccountId({ commit }, accountId) {
|
||||||
commit(types.default.SET_CURRENT_ACCOUNT_ID, 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
|
// mutations
|
||||||
const mutations = {
|
const mutations = {
|
||||||
|
[types.default.SET_CURRENT_USER_AVAILABILITY](_state, status) {
|
||||||
|
Vue.set(_state.currentUser, 'availability_status', status);
|
||||||
|
},
|
||||||
[types.default.CLEAR_USER](_state) {
|
[types.default.CLEAR_USER](_state) {
|
||||||
_state.currentUser.id = null;
|
_state.currentUser.id = 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,
|
|
||||||
};
|
|
|
@ -67,4 +67,30 @@ describe('#actions', () => {
|
||||||
expect(dispatch).toHaveBeenCalledTimes(0);
|
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([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,4 +17,12 @@ describe('#getters', () => {
|
||||||
getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } })
|
getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } })
|
||||||
).toEqual({ id: 1, name: 'Pranav' });
|
).toEqual({ id: 1, name: 'Pranav' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('get', () => {
|
||||||
|
expect(
|
||||||
|
getters.getCurrentUserAvailabilityStatus({
|
||||||
|
currentUser: { id: 1, name: 'Pranav', availability_status: 'busy' },
|
||||||
|
})
|
||||||
|
).toEqual('busy');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ export default {
|
||||||
CLEAR_USER: 'LOGOUT',
|
CLEAR_USER: 'LOGOUT',
|
||||||
SET_CURRENT_USER: 'SET_CURRENT_USER',
|
SET_CURRENT_USER: 'SET_CURRENT_USER',
|
||||||
SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID',
|
SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID',
|
||||||
|
SET_CURRENT_USER_AVAILABILITY: 'SET_CURRENT_USER_AVAILABILITY',
|
||||||
// Chat List
|
// Chat List
|
||||||
RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST',
|
RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST',
|
||||||
SET_ALL_CONVERSATION: 'SET_ALL_CONVERSATION',
|
SET_ALL_CONVERSATION: 'SET_ALL_CONVERSATION',
|
||||||
|
|
|
@ -2,19 +2,29 @@ module AvailabilityStatusable
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
def online_presence?
|
def online_presence?
|
||||||
|
return if user_profile_page_context?
|
||||||
|
|
||||||
::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id)
|
::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def availability_status
|
def availability_status
|
||||||
|
return availability if user_profile_page_context?
|
||||||
return 'offline' unless online_presence?
|
return 'offline' unless online_presence?
|
||||||
return 'online' if is_a? Contact
|
return 'online' if is_a? Contact
|
||||||
|
|
||||||
::OnlineStatusTracker.get_status(availability_account_id, id) || 'online'
|
::OnlineStatusTracker.get_status(availability_account_id, id) || 'online'
|
||||||
end
|
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
|
def availability_account_id
|
||||||
return account_id if is_a? Contact
|
return account_id if is_a? Contact
|
||||||
|
|
||||||
Current.account.present? ? Current.account.id : accounts.first.id
|
Current.account.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,6 +44,8 @@ module OnlineStatusTracker
|
||||||
|
|
||||||
def self.get_available_users(account_id)
|
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)
|
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_availabilities = ::Redis::Alfred.hmget(status_key(account_id), user_ids)
|
||||||
user_ids.map.with_index { |id, index| [id, (user_availabilities[index] || 'online')] }.to_h
|
user_ids.map.with_index { |id, index| [id, (user_availabilities[index] || 'online')] }.to_h
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue