Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/api/server/v1/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ API.v1.addRoute('users.removePersonalAccessToken', { authRequired: true }, {

API.v1.addRoute('users.presence', { authRequired: true }, {
get() {
const { from } = this.queryParams;
const { from, ids } = this.queryParams;

const options = {
fields: {
Expand All @@ -659,6 +659,13 @@ API.v1.addRoute('users.presence', { authRequired: true }, {
},
};

if (ids) {
return API.v1.success({
users: Users.findNotOfflineByIds(Array.isArray(ids) ? ids : ids.split(','), options).fetch(),
Comment thread
ggazzo marked this conversation as resolved.
full: false,
});
}

if (from) {
const ts = new Date(from);
const diff = (Date.now() - ts) / 1000 / 60;
Expand Down
4 changes: 2 additions & 2 deletions app/livechat/client/views/app/tabbar/agentInfo.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
</div>
<h3 title="{{name}}" class="rc-user-info__name"><i class="status-{{status}}"></i> {{name}}</h3>
{{#if username}}<p class="rc-user-info__username">@{{username}}</p>{{/if}}
<span class="rc-header__status rc-user-info__status">
{{# userPresence uid=uid}}<span class="rc-header__status rc-user-info__status">
<div class="rc-header__status-bullet rc-header__status-bullet--{{agentStatus}}" title="{{_ agentStatus}}"></div>
<div class="rc-header__visual-status">{{agentStatusText}}</div>
</span>
</span>{{/userPresence}}
</div>

<div class="rc-user-info-action">
Expand Down
4 changes: 3 additions & 1 deletion app/livechat/client/views/app/tabbar/agentInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ Template.agentInfo.helpers({
const hasCustomFields = customFieldsTemplate() !== null;
return (availableDepartments.length > 0 && hasPermission('add-livechat-department-agents')) || hasCustomFields;
},

uid() {
return Template.instance().agent.get()._id;
},
name() {
const agent = Template.instance().agent.get();
return agent && agent.name ? agent.name : TAPi18n.__('Unnamed');
Expand Down
10 changes: 10 additions & 0 deletions app/models/server/models/Users.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,16 @@ export class Users extends Base {
return this.find(query, options);
}

findNotOfflineByIds(users, options) {
const query = {
_id: { $in: users },
status: {
$in: ['online', 'away', 'busy'],
},
};
return this.find(query, options);
}

findUsersNotOffline(options) {
const query = {
username: {
Expand Down
2 changes: 1 addition & 1 deletion app/ui-flextab/client/tabs/membersList.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<li class='rc-member-list__user'>
{{> avatar username=user.username}}
<div class="rc-member-list__username">
<div class="rc-member-list__status rc-member-list__status--{{status}}"></div>
{{# userPresence uid=user._id}}<div class="rc-member-list__status rc-member-list__status--{{status}}"></div>{{/userPresence}}
{{ignored}} {{displayName}} {{utcOffset}}
</div>
{{> icon user=. block="rc-member-list__menu js-more" icon="menu" }}
Expand Down
4 changes: 2 additions & 2 deletions app/ui-flextab/client/tabs/userInfo.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ <h1 class="contextual-bar__header-title">{{_ "User_Info"}}</h1>
</div>
<h3 title="{{name}}" class="rc-user-info__name"><i class="status-{{status}}"></i> {{name}}</h3>
{{#if username}}<p class="rc-user-info__username">@{{username}}</p>{{/if}}
<span class="rc-header__status rc-user-info__status">
{{# userPresence uid=uid}}<span class="rc-header__status rc-user-info__status">
<div class="rc-header__status-bullet rc-header__status-bullet--{{userStatus}}" title="{{_ userStatus}}"></div>
<div class="rc-header__visual-status">{{userStatusText}}</div>
</span>
</span>{{/userPresence}}
</div>

<div class="rc-user-info-action">
Expand Down
5 changes: 4 additions & 1 deletion app/ui-flextab/client/tabs/userInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ Template.userInfo.helpers({
}
return customFields;
},

uid() {
const user = Template.instance().user.get();
return user._id;
},
name() {
const user = Template.instance().user.get();
return user && user.name ? user.name : TAPi18n.__('Unnamed');
Expand Down
1 change: 1 addition & 0 deletions app/ui-sidenav/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import './sideNav';
import './roomList';
import './sortlist';
import './toolbar';
import './userPresence';

export {
toolbarSearch,
Expand Down
2 changes: 1 addition & 1 deletion app/ui-sidenav/client/sidebarItem.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{{> icon block="rc-icon--default-size sidebar-item__icon sidebar-item__icon" icon=icon}}
</div>
{{else}}
<div class="sidebar-item__user-status {{#if status}}sidebar-item__user-status--{{status}}{{/if}}" aria-label="{{status}}"></div>
{{# userPresence uid=uid}}<div class="sidebar-item__user-status {{#if status}}sidebar-item__user-status--{{status}}{{/if}}" aria-label="{{status}}"></div>{{/userPresence}}
{{/if}}
</template>

Expand Down
6 changes: 6 additions & 0 deletions app/ui-sidenav/client/sidebarItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ Template.sidebarItem.events({
});

Template.sidebarItemIcon.helpers({
uid() {
if (!this.rid) {
return this._id;
}
return this.rid.replace(this.u._id, '');
Comment thread
sampaiodiego marked this conversation as resolved.
},
isRoom() {
return this.rid || this._id;
},
Expand Down
1 change: 1 addition & 0 deletions app/ui-sidenav/client/userPresence.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<template name="userPresence">{{> Template.contentBlock}}</template>
87 changes: 87 additions & 0 deletions app/ui-sidenav/client/userPresence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Meteor } from 'meteor/meteor';
// import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import { Tracker } from 'meteor/tracker';
import _ from 'underscore';
import mem from 'mem';

import { APIClient } from '../../utils/client';
import { saveUser } from '../../../imports/startup/client/listenActiveUsers';

import './userPresence.html';

const data = new Map();
const promises = new Map();
const pending = new Map();

const getAll = _.debounce(async function getAll() {
const ids = Array.from(pending.keys());

if (ids.length === 0) {
return;
}

const params = {
ids,
};

try {
const {
users,
} = await APIClient.v1.get('users.presence', params);

users.forEach((user) => saveUser(user, true));

ids.forEach((id) => {
const { resolve } = promises.get(id);
resolve();
});
} catch (e) {
ids.forEach((id) => {
const { reject } = promises.get(id);
reject();
});
}
}, 1000);

const get = mem(function get(id) {
const promise = pending.get(id) || new Promise((resolve, reject) => {
promises.set(id, { resolve, reject });
});
pending.set(id, promise);
return promise;
});

const options = {
threshold: 0.1,
};

let lastEntries = [];
const handleEntries = function(entries) {
lastEntries = entries.filter(({ isIntersecting }) => isIntersecting);
lastEntries.forEach(async (entry) => {
const { uid } = data.get(entry.target);
await get(uid);
pending.delete(uid);
});
getAll();
};

const observer = new IntersectionObserver(handleEntries, options);

Tracker.autorun(() => {
if (!Meteor.userId() || !Meteor.status().connected) {
return Meteor.users.update({}, { $unset: { status: '' } }, { multi: true });
}
mem.clear(get);

for (const node of data.keys()) {
observer.unobserve(node);
observer.observe(node);
}
});

Template.userPresence.onRendered(function() {
data.set(this.firstNode, this.data);
observer.observe(this.firstNode);
});
4 changes: 2 additions & 2 deletions app/ui/client/components/header/headerRoom.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@
{{/unless}}

{{#if isDirect}}
<span class="rc-header__status">
{{# userPresence uid=uid}}<span class="rc-header__status">
<div class="rc-header__status-bullet rc-header__status-bullet--{{userStatus}}" title="{{_ userStatus}}"></div>
<div class="rc-header__visual-status">{{userStatusText}}</div>
</span>
</span>{{/userPresence}}
{{else}}
{{#if roomTopic}}<span class="rc-header__topic">{{{roomTopic}}}</span>{{/if}}
{{/if}}
Expand Down
4 changes: 3 additions & 1 deletion app/ui/client/components/header/headerRoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ Template.headerRoom.helpers({
isToggleFavoriteButtonChecked: () => Template.instance().state.get('favorite'),
toggleFavoriteButtonIconLabel: () => (Template.instance().state.get('favorite') ? t('Unfavorite') : t('Favorite')),
toggleFavoriteButtonIcon: () => (Template.instance().state.get('favorite') ? 'star-filled' : 'star'),

uid() {
return this._id.replace(Meteor.userId(), '');
},
back() {
return Template.instance().data.back;
},
Expand Down
16 changes: 1 addition & 15 deletions imports/startup/client/listenActiveUsers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Meteor } from 'meteor/meteor';
import { Tracker } from 'meteor/tracker';
import { debounce } from 'underscore';

import { Notifications } from '../../../app/notifications/client';
Expand All @@ -13,7 +12,7 @@ const STATUS_MAP = [
'busy',
];

const saveUser = (user, force = false) => {
export const saveUser = (user, force = false) => {
// do not update my own user, my user's status will come from a subscription
if (user._id === Meteor.userId()) {
return;
Expand Down Expand Up @@ -72,19 +71,6 @@ const getUsersPresence = debounce(async (isConnected) => {
}
}, 1000);

let wasConnected = false;
Tracker.autorun(() => {
if (!Meteor.userId() || !Meteor.status().connected) {
return;
}

lastStatusChange = null;

getUsersPresence(wasConnected);

wasConnected = true;
});

Meteor.startup(function() {
Notifications.onLogged('user-status', ([_id, username, status, statusText]) => {
// only set after first request completed
Expand Down