Feature: Add online status to each user (#452)

* Feature: Add online status to each user
* Add OnlineStatusable, add availability status to thumbnail
This commit is contained in:
Pranav Raj S
2020-02-02 22:34:16 +05:30
committed by GitHub
parent 1f4703d25d
commit 0b31e14132
14 changed files with 106 additions and 14 deletions

View File

@@ -1,5 +1,10 @@
class RoomChannel < ApplicationCable::Channel class RoomChannel < ApplicationCable::Channel
def subscribed def subscribed
stream_from params[:pubsub_token] stream_from params[:pubsub_token]
::OnlineStatusTracker.add_subscription(params[:pubsub_token])
end
def unsubscribed
::OnlineStatusTracker.remove_subscription(params[:pubsub_token])
end end
end end

View File

@@ -4,7 +4,7 @@ class Api::V1::AgentsController < Api::BaseController
before_action :build_agent, only: [:create] before_action :build_agent, only: [:create]
def index def index
render json: agents @agents = agents
end end
def destroy def destroy

View File

@@ -16,12 +16,17 @@
:size="avatarSize" :size="avatarSize"
/> />
<img <img
v-if="badge === 'Channel::FacebookPage'" v-if="badge === 'Channel::FacebookPage' && status !== ''"
id="badge" id="badge"
class="source-badge" class="source-badge"
:style="badgeStyle" :style="badgeStyle"
src="~dashboard/assets/images/fb-badge.png" src="~dashboard/assets/images/fb-badge.png"
/> />
<div
v-else-if="status === 'online'"
class="source-badge user--online"
:style="statusStyle"
></div>
</div> </div>
</template> </template>
<script> <script>
@@ -41,6 +46,7 @@ export default {
props: { props: {
src: { src: {
type: String, type: String,
default: '',
}, },
size: { size: {
type: String, type: String,
@@ -52,6 +58,11 @@ export default {
}, },
username: { username: {
type: String, type: String,
default: '',
},
status: {
type: String,
default: '',
}, },
}, },
data() { data() {
@@ -67,6 +78,10 @@ export default {
const badgeSize = `${this.avatarSize / 3}px`; const badgeSize = `${this.avatarSize / 3}px`;
return { width: badgeSize, height: badgeSize }; return { width: badgeSize, height: badgeSize };
}, },
statusStyle() {
const statusSize = `${this.avatarSize / 4}px`;
return { width: statusSize, height: statusSize };
},
}, },
methods: { methods: {
onImgError() { onImgError() {
@@ -78,6 +93,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~dashboard/assets/scss/variables'; @import '~dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/foundation-settings';
@import '~dashboard/assets/scss/mixins'; @import '~dashboard/assets/scss/mixins';
.user-thumbnail-box { .user-thumbnail-box {
@@ -91,11 +107,21 @@ export default {
} }
.source-badge { .source-badge {
bottom: -$space-micro / 2; bottom: -$space-micro;
height: $space-slab; height: $space-slab;
position: absolute; position: absolute;
right: $zero; right: $zero;
width: $space-slab; width: $space-slab;
} }
.user--online {
background: $success-color;
border-radius: 50%;
bottom: $space-micro;
&:after {
content: ' ';
}
}
} }
</style> </style>

View File

@@ -7,6 +7,7 @@
size="56px" size="56px"
:badge="contact.channel" :badge="contact.channel"
:username="contact.name" :username="contact.name"
:status="contact.availability_status"
/> />
<div class="contact--details"> <div class="contact--details">
<div class="contact--name"> <div class="contact--name">

View File

@@ -26,10 +26,11 @@
<!-- Gravtar Image --> <!-- Gravtar Image -->
<td> <td>
<thumbnail <thumbnail
:src="gravatarUrl(agent.email)" :src="agent.thumbnail"
class="columns" class="columns"
:username="agent.name" :username="agent.name"
size="40px" size="40px"
:status="agent.availability_status"
/> />
</td> </td>
<!-- Agent Name + Email --> <!-- Agent Name + Email -->

View File

@@ -49,7 +49,6 @@ export const getters = {
Object.values(_state.conversations), Object.values(_state.conversations),
message => new DateHelper(message.created_at).format() message => new DateHelper(message.created_at).format()
); );
return Object.keys(conversationGroupedByDate).map(date => { return Object.keys(conversationGroupedByDate).map(date => {
const messages = conversationGroupedByDate[date].map((message, index) => { const messages = conversationGroupedByDate[date].map((message, index) => {
let showAvatar = false; let showAvatar = false;
@@ -59,12 +58,11 @@ export const getters = {
const nextMessage = conversationGroupedByDate[date][index + 1]; const nextMessage = conversationGroupedByDate[date][index + 1];
const currentSender = message.sender ? message.sender.name : ''; const currentSender = message.sender ? message.sender.name : '';
const nextSender = nextMessage.sender ? nextMessage.sender.name : ''; const nextSender = nextMessage.sender ? nextMessage.sender.name : '';
showAvatar = currentSender !== nextSender; showAvatar =
currentSender !== nextSender ||
message.message_type !== nextMessage.message_type;
} }
return { return { showAvatar, ...message };
showAvatar,
...message,
};
}); });
return { return {

View File

@@ -61,19 +61,27 @@ describe('#getters', () => {
id: 1, id: 1,
content: 'Thanks for the help', content: 'Thanks for the help',
created_at: 1574075964, created_at: 1574075964,
message_type: 0,
}, },
2: { 2: {
id: 2, id: 2,
content: 'Yes, It makes sense', content: 'Yes, It makes sense',
created_at: 1574092218, created_at: 1574092218,
message_type: 0,
}, },
3: { 3: {
id: 3, id: 3,
content: 'Hey', content: 'Hey',
created_at: 1576340623, created_at: 1574092218,
message_type: 1,
}, },
4: { 4: {
id: 4, id: 4,
content: 'Hey',
created_at: 1576340623,
},
5: {
id: 5,
content: 'How may I help you', content: 'How may I help you',
created_at: 1576340626, created_at: 1576340626,
}, },
@@ -88,12 +96,21 @@ describe('#getters', () => {
content: 'Thanks for the help', content: 'Thanks for the help',
created_at: 1574075964, created_at: 1574075964,
showAvatar: false, showAvatar: false,
message_type: 0,
}, },
{ {
id: 2, id: 2,
content: 'Yes, It makes sense', content: 'Yes, It makes sense',
created_at: 1574092218, created_at: 1574092218,
showAvatar: true, showAvatar: true,
message_type: 0,
},
{
id: 3,
content: 'Hey',
created_at: 1574092218,
showAvatar: true,
message_type: 1,
}, },
], ],
}, },
@@ -101,13 +118,13 @@ describe('#getters', () => {
date: 'Dec 14, 2019', date: 'Dec 14, 2019',
messages: [ messages: [
{ {
id: 3, id: 4,
content: 'Hey', content: 'Hey',
created_at: 1576340623, created_at: 1576340623,
showAvatar: false, showAvatar: false,
}, },
{ {
id: 4, id: 5,
content: 'How may I help you', content: 'How may I help you',
created_at: 1576340626, created_at: 1576340626,
showAvatar: true, showAvatar: true,

View File

@@ -0,0 +1,11 @@
module AvailabilityStatusable
extend ActiveSupport::Concern
def online?
::OnlineStatusTracker.subscription_count(pubsub_token) != 0
end
def availability_status
online? ? 'online' : 'offline'
end
end

View File

@@ -20,6 +20,7 @@
class Contact < ApplicationRecord class Contact < ApplicationRecord
include Pubsubable include Pubsubable
include Avatarable include Avatarable
include AvailabilityStatusable
validates :account_id, presence: true validates :account_id, presence: true
belongs_to :account belongs_to :account

View File

@@ -48,6 +48,7 @@ class User < ApplicationRecord
include Events::Types include Events::Types
include Pubsubable include Pubsubable
include Avatarable include Avatarable
include AvailabilityStatusable
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
devise :database_authenticatable, devise :database_authenticatable,

View File

@@ -0,0 +1,10 @@
json.array! @agents do |agent|
json.account_id agent.account_id
json.availability_status agent.availability_status
json.confirmed agent.confirmed?
json.email agent.email
json.id agent.id
json.name agent.name
json.role agent.role
json.thumbnail agent.avatar_url
end

View File

@@ -1,7 +1,8 @@
json.payload do json.payload do
json.availability_status @contact.availability_status
json.email @contact.email
json.id @contact.id json.id @contact.id
json.name @contact.name json.name @contact.name
json.email @contact.email
json.phone_number @contact.phone_number json.phone_number @contact.phone_number
json.thumbnail @contact.avatar_url json.thumbnail @contact.avatar_url
end end

View File

@@ -2,5 +2,6 @@ json.payload do
json.array! @inbox_members do |inbox_member| json.array! @inbox_members do |inbox_member|
json.name inbox_member.user.name json.name inbox_member.user.name
json.avatar_url inbox_member.user.avatar_url json.avatar_url inbox_member.user.avatar_url
json.availability_status inbox_member.user.availability_status
end end
end end

View File

@@ -0,0 +1,19 @@
module OnlineStatusTracker
def self.add_subscription(channel_id)
count = subscription_count(channel_id)
::Redis::Alfred.setex(channel_id, count + 1)
end
def self.remove_subscription(channel_id)
count = subscription_count(channel_id)
if count == 1
::Redis::Alfred.delete(channel_id)
elsif count != 0
::Redis::Alfred.setex(channel_id, count - 1)
end
end
def self.subscription_count(channel_id)
::Redis::Alfred.get(channel_id).to_i
end
end