From 913f4a08fcc466b6db78e9eed9b7237453d4aa15 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 23 Oct 2019 11:39:26 -0300 Subject: [PATCH 1/9] Initial commit. --- app/livechat/client/index.js | 1 + .../client/views/app/livechatAgents.js | 28 ++- .../views/app/tabs/livechatAgentInfo.html | 65 +++++++ .../views/app/tabs/livechatAgentInfo.js | 159 ++++++++++++++++++ 4 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 app/livechat/client/views/app/tabs/livechatAgentInfo.html create mode 100644 app/livechat/client/views/app/tabs/livechatAgentInfo.js diff --git a/app/livechat/client/index.js b/app/livechat/client/index.js index a6e31ebdb593..e6bf45814121 100644 --- a/app/livechat/client/index.js +++ b/app/livechat/client/index.js @@ -33,6 +33,7 @@ import './views/app/tabbar/visitorForward'; import './views/app/tabbar/visitorInfo'; import './views/app/tabbar/visitorHistory'; import './views/app/tabbar/visitorNavigation'; +import './views/app/tabs/livechatAgentInfo'; import './views/app/triggers/livechatTriggerAction'; import './views/app/triggers/livechatTriggerCondition'; import './views/sideNav/livechat'; diff --git a/app/livechat/client/views/app/livechatAgents.js b/app/livechat/client/views/app/livechatAgents.js index f1f515addfde..6ab0b5ef738b 100644 --- a/app/livechat/client/views/app/livechatAgents.js +++ b/app/livechat/client/views/app/livechatAgents.js @@ -1,11 +1,12 @@ import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; +import { FlowRouter } from 'meteor/kadira:flow-router'; import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveDict } from 'meteor/reactive-dict'; import s from 'underscore.string'; import _ from 'underscore'; -import { modal, call } from '../../../../ui-utils'; +import { modal, call, RocketChatTabBar } from '../../../../ui-utils'; import { t, handleError, APIClient } from '../../../../utils/client'; import './livechatAgents.html'; @@ -78,6 +79,13 @@ Template.livechatAgents.helpers({ } }; }, + flexData() { + console.log('a'); + return { + tabBar: Template.instance().tabBar, + data: Template.instance().tabBarData.get(), + }; + }, }); const DEBOUNCE_TIME_FOR_SEARCH_AGENTS_IN_MS = 300; @@ -138,23 +146,28 @@ Template.livechatAgents.events({ state.set('loading', false); } }, + 'keydown #agents-filter'(e) { if (e.which === 13) { e.stopPropagation(); e.preventDefault(); } }, + 'keyup #agents-filter': _.debounce((e, t) => { - e.stopPropagation(); e.preventDefault(); t.filter.set(e.currentTarget.value); }, DEBOUNCE_TIME_FOR_SEARCH_AGENTS_IN_MS), - /* - 'click .agent-info'(e, instance) { + + 'click .user-info'(e, instance) { + e.stopPropagation(); e.preventDefault(); - instance.tabBarData.set(FullUser.findOne(this._id)); - instance.tabBar.open('admin-user-info'); + instance.tabBarData.set(this); + instance.tabBar.setTemplate('livechatAgentInfo'); + // instance.tabBar.setData({ label: t('Agent_Info'), icon: 'info-circled' }); + instance.tabBar.open(); }, + /* 'click .info-tabs button'(e) { e.preventDefault(); $('.info-tabs button').removeClass('active'); @@ -175,6 +188,9 @@ Template.livechatAgents.onCreated(function() { this.ready = new ReactiveVar(true); this.selectedAgents = new ReactiveVar([]); this.agents = new ReactiveVar([]); + this.tabBar = new RocketChatTabBar(); + this.tabBar.showGroup(FlowRouter.current().route.name); + this.tabBarData = new ReactiveVar(); this.onSelectAgents = ({ item: agent }) => { this.selectedAgents.set([...this.selectedAgents.curValue, agent]); diff --git a/app/livechat/client/views/app/tabs/livechatAgentInfo.html b/app/livechat/client/views/app/tabs/livechatAgentInfo.html new file mode 100644 index 000000000000..2b2b7f0386e1 --- /dev/null +++ b/app/livechat/client/views/app/tabs/livechatAgentInfo.html @@ -0,0 +1,65 @@ + diff --git a/app/livechat/client/views/app/tabs/livechatAgentInfo.js b/app/livechat/client/views/app/tabs/livechatAgentInfo.js new file mode 100644 index 000000000000..20c2b45c56c4 --- /dev/null +++ b/app/livechat/client/views/app/tabs/livechatAgentInfo.js @@ -0,0 +1,159 @@ +import { ReactiveVar } from 'meteor/reactive-var'; +import { Session } from 'meteor/session'; +import { Template } from 'meteor/templating'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import _ from 'underscore'; +import s from 'underscore.string'; + +import './livechatAgentInfo.html'; + +Template.livechatAgentInfo.helpers({ + hideHeader() { + return ['Template.adminUserInfo', 'adminUserInfo'].includes(Template.parentData(2).viewName); + }, + + name() { + const user = Template.instance().user.get(); + return user && user.name ? user.name : TAPi18n.__('Unnamed'); + }, + + username() { + const user = Template.instance().user.get(); + return user && user.username; + }, + + userStatus() { + const user = Template.instance().user.get(); + const userStatus = Session.get(`user_${ user.username }_status`); + return userStatus || TAPi18n.__('offline'); + }, + + userStatusText() { + if (s.trim(this.statusText)) { + return this.statusText; + } + + const user = Template.instance().user.get(); + const userStatus = Session.get(`user_${ user.username }_status`); + return userStatus || TAPi18n.__('offline'); + }, + + email() { + const user = Template.instance().user.get(); + return user && user.emails && user.emails[0] && user.emails[0].address; + }, + + user() { + return Template.instance().user.get(); + }, + + hasEmails() { + return _.isArray(this.emails); + }, + + isLoading() { + return Template.instance().loadingUserInfo.get(); + }, + + editingUser() { + return Template.instance().editingUser.get(); + }, + + userToEdit() { + const instance = Template.instance(); + const data = Template.currentData(); + return { + user: instance.user.get(), + back(username) { + instance.editingUser.set(); + + if (username != null) { + const user = instance.user.get(); + if ((user != null ? user.username : undefined) !== username) { + data.username = username; + return instance.loadedUsername.set(username); + } + } + }, + }; + }, + + roleTags() { + const user = Template.instance().user.get(); + if (!user || !user._id) { + return; + } + + return; + /* + const userRoles = UserRoles.findOne(user._id) || {}; + const roomRoles = RoomRoles.findOne({ 'u._id': user._id, rid: Session.get('openedRoom') }) || {}; + const roles = _.union(userRoles.roles || [], roomRoles.roles || []); + return roles.length && Roles.find({ _id: { $in: roles }, description: { $exists: 1 } }, { fields: { description: 1 } }); + */ + }, +}); + +Template.livechatAgentInfo.events({ + 'click .js-close-info'(e, instance) { + return instance.clear(); + }, + 'click .js-back'(e, instance) { + return instance.clear(); + }, +}); + +Template.livechatAgentInfo.onCreated(function() { + this.user = new ReactiveVar(); + + this.autorun(() => { + const user = this.user.get(); + if (!user) { + this.actions.set([]); + } + }); + + this.editingUser = new ReactiveVar(); + this.loadingUserInfo = new ReactiveVar(true); + this.loadedUsername = new ReactiveVar(); + this.tabBar = Template.currentData().tabBar; + + this.autorun(() => { + const username = this.loadedUsername.get(); + + if (username == null) { + this.loadingUserInfo.set(false); + return; + } + + this.loadingUserInfo.set(true); + + return this.subscribe('fullUserData', username, 1, () => this.loadingUserInfo.set(false)); + }); + + this.autorun(() => { + const data = Template.currentData(); + if (data.clear != null) { + this.clear = data.clear; + } + }); + + this.autorun(() => { + const data = Template.currentData(); + const user = this.user.get(); + return this.loadedUsername.set((user != null ? user.username : undefined) || (data != null ? data.username : undefined)); + }); + + return this.autorun(() => { + let filter; + const data = Template.currentData(); + if (data && data.username != null) { + filter = { username: data.username }; + } else if (data && data._id != null) { + filter = { _id: data._id }; + } + const user = {}; //FullUser.findOne(filter); + + return this.user.set(user); + }); +}); From 55b30a1e09c733088d7418e7701acf85522f4d57 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Fri, 25 Oct 2019 15:29:31 -0300 Subject: [PATCH 2/9] Add new forms to view and edit agent data. --- app/livechat/client/index.js | 3 +- app/livechat/client/route.js | 2 +- .../client/views/app/livechatAgents.html | 172 +++++++++--------- .../client/views/app/livechatAgents.js | 30 ++- .../client/views/app/tabbar/agentEdit.html | 79 ++++++++ .../client/views/app/tabbar/agentEdit.js | 123 +++++++++++++ .../client/views/app/tabbar/agentInfo.html | 52 ++++++ .../client/views/app/tabbar/agentInfo.js | 144 +++++++++++++++ .../views/app/tabs/livechatAgentInfo.html | 65 ------- .../views/app/tabs/livechatAgentInfo.js | 159 ---------------- app/ui-utils/client/lib/AccountBox.js | 3 +- app/ui/client/index.js | 1 + .../client/views/app/pageCustomContainer.html | 3 + packages/rocketchat-i18n/i18n/en.i18n.json | 4 +- packages/rocketchat-i18n/i18n/pt-BR.i18n.json | 1 + packages/rocketchat-i18n/i18n/pt.i18n.json | 3 +- 16 files changed, 527 insertions(+), 317 deletions(-) create mode 100644 app/livechat/client/views/app/tabbar/agentEdit.html create mode 100644 app/livechat/client/views/app/tabbar/agentEdit.js create mode 100644 app/livechat/client/views/app/tabbar/agentInfo.html create mode 100644 app/livechat/client/views/app/tabbar/agentInfo.js delete mode 100644 app/livechat/client/views/app/tabs/livechatAgentInfo.html delete mode 100644 app/livechat/client/views/app/tabs/livechatAgentInfo.js create mode 100644 app/ui/client/views/app/pageCustomContainer.html diff --git a/app/livechat/client/index.js b/app/livechat/client/index.js index e6bf45814121..7c39a8c161d9 100644 --- a/app/livechat/client/index.js +++ b/app/livechat/client/index.js @@ -27,13 +27,14 @@ import './views/app/livechatNotSubscribed.html'; import './views/app/livechatRoomTagSelector.html'; import './views/app/integrations/livechatIntegrationWebhook'; import './views/app/integrations/livechatIntegrationFacebook'; +import './views/app/tabbar/agentEdit'; +import './views/app/tabbar/agentInfo'; import './views/app/tabbar/externalSearch'; import './views/app/tabbar/visitorEdit'; import './views/app/tabbar/visitorForward'; import './views/app/tabbar/visitorInfo'; import './views/app/tabbar/visitorHistory'; import './views/app/tabbar/visitorNavigation'; -import './views/app/tabs/livechatAgentInfo'; import './views/app/triggers/livechatTriggerAction'; import './views/app/triggers/livechatTriggerCondition'; import './views/sideNav/livechat'; diff --git a/app/livechat/client/route.js b/app/livechat/client/route.js index 1249422f63f4..1bfaeabceea8 100644 --- a/app/livechat/client/route.js +++ b/app/livechat/client/route.js @@ -52,8 +52,8 @@ AccountBox.addRoute({ name: 'livechat-agents', path: '/agents', sideNav: 'livechatFlex', - i18nPageTitle: 'Livechat_agents', pageTemplate: 'livechatAgents', + customContainer: true, }, livechatManagerRoutes); AccountBox.addRoute({ diff --git a/app/livechat/client/views/app/livechatAgents.html b/app/livechat/client/views/app/livechatAgents.html index 7164e017fec5..eb333a2144aa 100644 --- a/app/livechat/client/views/app/livechatAgents.html +++ b/app/livechat/client/views/app/livechatAgents.html @@ -1,89 +1,99 @@ + + {{#with flexData}} + {{> flexTabBar}} + {{/with}} + + {{/requiresPermission}} + diff --git a/app/livechat/client/views/app/livechatAgents.js b/app/livechat/client/views/app/livechatAgents.js index 6ab0b5ef738b..6364fda0b6a8 100644 --- a/app/livechat/client/views/app/livechatAgents.js +++ b/app/livechat/client/views/app/livechatAgents.js @@ -6,7 +6,7 @@ import { ReactiveDict } from 'meteor/reactive-dict'; import s from 'underscore.string'; import _ from 'underscore'; -import { modal, call, RocketChatTabBar } from '../../../../ui-utils'; +import { modal, call, TabBar, RocketChatTabBar } from '../../../../ui-utils'; import { t, handleError, APIClient } from '../../../../utils/client'; import './livechatAgents.html'; @@ -80,7 +80,6 @@ Template.livechatAgents.helpers({ }; }, flexData() { - console.log('a'); return { tabBar: Template.instance().tabBar, data: Template.instance().tabBarData.get(), @@ -112,7 +111,13 @@ Template.livechatAgents.events({ if (error) { return handleError(error); } + + if (instance.tabBar.getState() === 'opened') { + instance.tabBar.close(); + } + await loadAgents(instance); + modal.open({ title: t('Removed'), text: t('Agent_removed'), @@ -160,12 +165,14 @@ Template.livechatAgents.events({ }, DEBOUNCE_TIME_FOR_SEARCH_AGENTS_IN_MS), 'click .user-info'(e, instance) { - e.stopPropagation(); e.preventDefault(); - instance.tabBarData.set(this); - instance.tabBar.setTemplate('livechatAgentInfo'); - // instance.tabBar.setData({ label: t('Agent_Info'), icon: 'info-circled' }); - instance.tabBar.open(); + instance.tabBarData.set({ + agentId: this._id, + onRemoveAgent: () => loadAgents(instance), + }); + + instance.tabBar.setData({ label: t('Agent_Info'), icon: 'livechat' }); + instance.tabBar.open('livechat-agent-info'); }, /* 'click .info-tabs button'(e) { @@ -192,6 +199,15 @@ Template.livechatAgents.onCreated(function() { this.tabBar.showGroup(FlowRouter.current().route.name); this.tabBarData = new ReactiveVar(); + TabBar.addButton({ + groups: ['livechat-agent-users'], + id: 'livechat-agent-info', + i18nTitle: 'Agent_Info', + icon: 'livechat', + template: 'agentInfo', + order: 1, + }); + this.onSelectAgents = ({ item: agent }) => { this.selectedAgents.set([...this.selectedAgents.curValue, agent]); }; diff --git a/app/livechat/client/views/app/tabbar/agentEdit.html b/app/livechat/client/views/app/tabbar/agentEdit.html new file mode 100644 index 000000000000..e31f9f476612 --- /dev/null +++ b/app/livechat/client/views/app/tabbar/agentEdit.html @@ -0,0 +1,79 @@ + diff --git a/app/livechat/client/views/app/tabbar/agentEdit.js b/app/livechat/client/views/app/tabbar/agentEdit.js new file mode 100644 index 000000000000..067c20e96ce7 --- /dev/null +++ b/app/livechat/client/views/app/tabbar/agentEdit.js @@ -0,0 +1,123 @@ +import { Meteor } from 'meteor/meteor'; +import { ReactiveVar } from 'meteor/reactive-var'; +import { Random } from 'meteor/random'; +import { Template } from 'meteor/templating'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import toastr from 'toastr'; +import s from 'underscore.string'; + +import './agentEdit.html'; +import { AgentUsers } from '../../../collections/AgentUsers'; +import { LivechatDepartmentAgents } from '../../../collections/LivechatDepartmentAgents'; +import { LivechatDepartment } from '../../../collections/LivechatDepartment'; + +/* +import { t, handleError } from '../../../utils'; +import { Roles } from '../../../models'; +import { Notifications } from '../../../notifications'; +import { hasAtLeastOnePermission } from '../../../authorization'; +import { settings } from '../../../settings'; +import { callbacks } from '../../../callbacks'; +*/ + +Template.agentEdit.helpers({ + canEditOrAdd() { + // return (Template.instance().user && hasAtLeastOnePermission('edit-other-user-info')) || (!Template.instance().user && hasAtLeastOnePermission('create-user')); + }, + + agent() { + return Template.instance().agent.get(); + }, + + avatarPreview() { + // return Template.instance().avatar.get(); + }, + + availableDepartments() { + return Template.instance().avaliableDepartments.get(); + }, + + hasAvailableDepartments() { + const availableDepartments = Template.instance().avaliableDepartments.get(); + return availableDepartments && availableDepartments.length > 0; + }, + + agentDepartments() { + const deptIds = Template.instance().agentDepartments.get(); + return LivechatDepartment.find({ _id: { $in: deptIds } }).fetch(); + }, +}); + +Template.agentEdit.events({ + 'click .cancel'(e, instance) { + e.stopPropagation(); + e.preventDefault(); + + return this.back && this.back(); + }, + + 'submit form'(e, instance) { + e.stopPropagation(); + e.preventDefault(); + }, + + 'click .remove-department'(e, instance) { + e.stopPropagation(); + const { currentTarget: { dataset: { id } } } = e; + console.log(id); + /* + const availableDepartments = instance.availableDepartments.get(); + const hasAvailableDepartments = availableDepartments && availableDepartments.length > 0; + const availableAgentDepartments = instance.availableUserTags.get(); + + let tags = instance.tags.get(); + tags = tags.filter((el) => el !== tag); + t.tags.set(tags); + */ + }, + + 'click #addDepartment'(e, instance) { + e.stopPropagation(); + e.preventDefault(); + + if ($('#departmentSelect').find(':selected').is(':disabled')) { + return; + } + + const tags = [...instance.tags.get()]; + const tagVal = $('#tagSelect').val(); + if (tagVal === '' || tags.indexOf(tagVal) > -1) { + return; + } + + tags.push(tagVal); + instance.tags.set(tags); + $('#tagSelect').val('placeholder'); + }, +}); + +Template.agentEdit.onCreated(function() { + this.agent = new ReactiveVar(); + this.agentDepartments = new ReactiveVar([]); + this.avaliableDepartments = new ReactiveVar([]); + this.back = Template.currentData().back; + + this.subscribe('livechat:agents'); + this.subscribe('livechat:departments', () => { + this.avaliableDepartments.set(LivechatDepartment.find({ enabled: true }).fetch()); + }); + + this.autorun(() => { + const { agentId } = Template.currentData(); + + if (agentId) { + const agent = AgentUsers.findOne(agentId); + + this.subscribe('livechat:departmentAgents', null, agentId, () => { + this.agentDepartments.set(LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId)); + }); + + this.agent.set(agent); + } + }); +}); diff --git a/app/livechat/client/views/app/tabbar/agentInfo.html b/app/livechat/client/views/app/tabbar/agentInfo.html new file mode 100644 index 000000000000..fac4e63721f0 --- /dev/null +++ b/app/livechat/client/views/app/tabbar/agentInfo.html @@ -0,0 +1,52 @@ + diff --git a/app/livechat/client/views/app/tabbar/agentInfo.js b/app/livechat/client/views/app/tabbar/agentInfo.js new file mode 100644 index 000000000000..d13f44f17b9d --- /dev/null +++ b/app/livechat/client/views/app/tabbar/agentInfo.js @@ -0,0 +1,144 @@ +import { Meteor } from 'meteor/meteor'; +import { ReactiveVar } from 'meteor/reactive-var'; +import { Session } from 'meteor/session'; +import { Template } from 'meteor/templating'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import _ from 'underscore'; +import s from 'underscore.string'; + +import './agentInfo.html'; +import { modal } from '../../../../../ui-utils'; +import { t, handleError } from '../../../../../utils/client'; +import { AgentUsers } from '../../../collections/AgentUsers'; +import { LivechatDepartmentAgents } from '../../../collections/LivechatDepartmentAgents'; +import { LivechatDepartment } from '../../../collections/LivechatDepartment'; + +Template.agentInfo.helpers({ + name() { + const agent = Template.instance().agent.get(); + return agent && agent.name ? agent.name : TAPi18n.__('Unnamed'); + }, + + username() { + const agent = Template.instance().agent.get(); + return agent && agent.username; + }, + + agentStatus() { + const agent = Template.instance().agent.get(); + const userStatus = Session.get(`user_${ agent.username }_status`); + return userStatus || TAPi18n.__('offline'); + }, + + agentStatusText() { + const agent = Template.instance().agent.get(); + if (agent && s.trim(agent.statusText)) { + return agent.statusText; + } + + const agentStatus = Session.get(`user_${ agent.username }_status`); + return agentStatus || TAPi18n.__('offline'); + }, + + email() { + const agent = Template.instance().agent.get(); + return agent && agent.emails && agent.emails[0] && agent.emails[0].address; + }, + + agent() { + return Template.instance().agent.get(); + }, + + hasEmails() { + const agent = Template.instance().agent.get(); + return agent && _.isArray(agent.emails); + }, + + editingAgent() { + return Template.instance().editingAgent.get(); + }, + + agentToEdit() { + const instance = Template.instance(); + const agent = instance.agent.get(); + + return { + agentId: agent && agent._id, + back() { + instance.editingAgent.set(); + }, + }; + }, + + agentDepartments() { + return Template.instance().agentDepartments.get(); + }, +}); + +Template.agentInfo.events({ + 'click .delete-agent'(e, instance) { + e.preventDefault(); + + modal.open( + { + title: t('Are_you_sure'), + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#DD6B55', + confirmButtonText: t('Yes'), + cancelButtonText: t('Cancel'), + closeOnConfirm: false, + html: false, + }, + () => { + Meteor.call('livechat:removeAgent', this.username, (error) => { + if (error) { + return handleError(error); + } + + const { tabBar, onRemoveAgent } = instance; + tabBar.close(); + onRemoveAgent && onRemoveAgent(); + + modal.open({ + title: t('Removed'), + text: t('Agent_removed'), + type: 'success', + timer: 1000, + showConfirmButton: false, + }); + }); + } + ); + }, + 'click .edit-agent'(e, instance) { + e.preventDefault(); + instance.editingAgent.set(this._id); + }, +}); + +Template.agentInfo.onCreated(function() { + this.agent = new ReactiveVar(); + this.agentDepartments = new ReactiveVar([]); + this.editingAgent = new ReactiveVar(); + this.tabBar = Template.currentData().tabBar; + this.onRemoveAgent = Template.currentData().onRemoveAgent; + + this.subscribe('livechat:agents'); + this.subscribe('livechat:departments'); + + this.autorun(() => { + const { agentId } = Template.currentData(); + + if (agentId) { + const agent = AgentUsers.findOne(agentId); + + this.subscribe('livechat:departmentAgents', null, agentId, () => { + const deptIds = LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId); + this.agentDepartments.set(LivechatDepartment.find({ _id: { $in: deptIds } }).fetch()); + }); + + this.agent.set(agent); + } + }); +}); diff --git a/app/livechat/client/views/app/tabs/livechatAgentInfo.html b/app/livechat/client/views/app/tabs/livechatAgentInfo.html deleted file mode 100644 index 2b2b7f0386e1..000000000000 --- a/app/livechat/client/views/app/tabs/livechatAgentInfo.html +++ /dev/null @@ -1,65 +0,0 @@ - diff --git a/app/livechat/client/views/app/tabs/livechatAgentInfo.js b/app/livechat/client/views/app/tabs/livechatAgentInfo.js deleted file mode 100644 index 20c2b45c56c4..000000000000 --- a/app/livechat/client/views/app/tabs/livechatAgentInfo.js +++ /dev/null @@ -1,159 +0,0 @@ -import { ReactiveVar } from 'meteor/reactive-var'; -import { Session } from 'meteor/session'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import _ from 'underscore'; -import s from 'underscore.string'; - -import './livechatAgentInfo.html'; - -Template.livechatAgentInfo.helpers({ - hideHeader() { - return ['Template.adminUserInfo', 'adminUserInfo'].includes(Template.parentData(2).viewName); - }, - - name() { - const user = Template.instance().user.get(); - return user && user.name ? user.name : TAPi18n.__('Unnamed'); - }, - - username() { - const user = Template.instance().user.get(); - return user && user.username; - }, - - userStatus() { - const user = Template.instance().user.get(); - const userStatus = Session.get(`user_${ user.username }_status`); - return userStatus || TAPi18n.__('offline'); - }, - - userStatusText() { - if (s.trim(this.statusText)) { - return this.statusText; - } - - const user = Template.instance().user.get(); - const userStatus = Session.get(`user_${ user.username }_status`); - return userStatus || TAPi18n.__('offline'); - }, - - email() { - const user = Template.instance().user.get(); - return user && user.emails && user.emails[0] && user.emails[0].address; - }, - - user() { - return Template.instance().user.get(); - }, - - hasEmails() { - return _.isArray(this.emails); - }, - - isLoading() { - return Template.instance().loadingUserInfo.get(); - }, - - editingUser() { - return Template.instance().editingUser.get(); - }, - - userToEdit() { - const instance = Template.instance(); - const data = Template.currentData(); - return { - user: instance.user.get(), - back(username) { - instance.editingUser.set(); - - if (username != null) { - const user = instance.user.get(); - if ((user != null ? user.username : undefined) !== username) { - data.username = username; - return instance.loadedUsername.set(username); - } - } - }, - }; - }, - - roleTags() { - const user = Template.instance().user.get(); - if (!user || !user._id) { - return; - } - - return; - /* - const userRoles = UserRoles.findOne(user._id) || {}; - const roomRoles = RoomRoles.findOne({ 'u._id': user._id, rid: Session.get('openedRoom') }) || {}; - const roles = _.union(userRoles.roles || [], roomRoles.roles || []); - return roles.length && Roles.find({ _id: { $in: roles }, description: { $exists: 1 } }, { fields: { description: 1 } }); - */ - }, -}); - -Template.livechatAgentInfo.events({ - 'click .js-close-info'(e, instance) { - return instance.clear(); - }, - 'click .js-back'(e, instance) { - return instance.clear(); - }, -}); - -Template.livechatAgentInfo.onCreated(function() { - this.user = new ReactiveVar(); - - this.autorun(() => { - const user = this.user.get(); - if (!user) { - this.actions.set([]); - } - }); - - this.editingUser = new ReactiveVar(); - this.loadingUserInfo = new ReactiveVar(true); - this.loadedUsername = new ReactiveVar(); - this.tabBar = Template.currentData().tabBar; - - this.autorun(() => { - const username = this.loadedUsername.get(); - - if (username == null) { - this.loadingUserInfo.set(false); - return; - } - - this.loadingUserInfo.set(true); - - return this.subscribe('fullUserData', username, 1, () => this.loadingUserInfo.set(false)); - }); - - this.autorun(() => { - const data = Template.currentData(); - if (data.clear != null) { - this.clear = data.clear; - } - }); - - this.autorun(() => { - const data = Template.currentData(); - const user = this.user.get(); - return this.loadedUsername.set((user != null ? user.username : undefined) || (data != null ? data.username : undefined)); - }); - - return this.autorun(() => { - let filter; - const data = Template.currentData(); - if (data && data.username != null) { - filter = { username: data.username }; - } else if (data && data._id != null) { - filter = { _id: data._id }; - } - const user = {}; //FullUser.findOne(filter); - - return this.user.set(user); - }); -}); diff --git a/app/ui-utils/client/lib/AccountBox.js b/app/ui-utils/client/lib/AccountBox.js index d82f61387816..339d01d831b8 100644 --- a/app/ui-utils/client/lib/AccountBox.js +++ b/app/ui-utils/client/lib/AccountBox.js @@ -62,8 +62,9 @@ export const AccountBox = (function() { if (router == null) { router = FlowRouter; } + const container = newRoute.customContainer ? 'pageCustomContainer' : 'pageContainer'; const routeConfig = { - center: 'pageContainer', + center: container, pageTemplate: newRoute.pageTemplate, }; if (newRoute.i18nPageTitle != null) { diff --git a/app/ui/client/index.js b/app/ui/client/index.js index 39f35a953ee3..485346a1bb4e 100644 --- a/app/ui/client/index.js +++ b/app/ui/client/index.js @@ -19,6 +19,7 @@ import './views/app/fullModal.html'; import './views/app/home.html'; import './views/app/notAuthorized.html'; import './views/app/pageContainer.html'; +import './views/app/pageCustomContainer.html'; import './views/app/pageSettingsContainer.html'; import './views/app/room.html'; import './views/app/roomSearch.html'; diff --git a/app/ui/client/views/app/pageCustomContainer.html b/app/ui/client/views/app/pageCustomContainer.html new file mode 100644 index 000000000000..d4f59f354e06 --- /dev/null +++ b/app/ui/client/views/app/pageCustomContainer.html @@ -0,0 +1,3 @@ + diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index cfcb0be29670..bc88ceec62b3 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -246,6 +246,7 @@ "Advocacy": "Advocacy", "After_OAuth2_authentication_users_will_be_redirected_to_this_URL": "After OAuth2 authentication, users will be redirected to an URL on this list. You can add one URL per line.", "Agent": "Agent", + "Agent_Info": "Agent Info", "Agents": "Agents", "Agent_added": "Agent added", "Agent_removed": "Agent removed", @@ -2757,10 +2758,11 @@ "Select_a_user": "Select a user", "Select_an_avatar": "Select an avatar", "Select_an_option": "Select an option", + "Select_department": "Select a department", "Select_file": "Select file", "Select_role": "Select a Role", "Select_service_to_login": "Select a service to login to load your picture or upload one directly from your computer", - "Select_tag": "Select uma tag", + "Select_tag": "Select a tag", "Select_user": "Select user", "Select_users": "Select users", "Selected_agents": "Selected agents", diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index 598a3be2c58d..d24989d1bd04 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -2585,6 +2585,7 @@ "Select_a_user": "Selecione um usuário", "Select_an_avatar": "Selecione um avatar", "Select_an_option": "Selecione uma opção", + "Select_department": "Selecione um departmento", "Select_file": "Selecione um arquivo", "Select_role": "Selecione um papel", "Select_service_to_login": "Selecione um serviço para iniciar sessão e carregar sua imagem ou faça upload de um arquivo de seu computador", diff --git a/packages/rocketchat-i18n/i18n/pt.i18n.json b/packages/rocketchat-i18n/i18n/pt.i18n.json index 25da29296ce2..c8b8fa74e987 100644 --- a/packages/rocketchat-i18n/i18n/pt.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt.i18n.json @@ -234,6 +234,7 @@ "Advocacy": "Apoio dado", "After_OAuth2_authentication_users_will_be_redirected_to_this_URL": "Após a autenticação OAuth2, os utilizadores serão redireccionados para esta URL", "Agent": "Agente", + "Agent_Info": "Informações do Agente", "Agent_added": "Agente adicionado", "Agent_removed": "Agente removido", "Alerts": "Alertas", @@ -3211,4 +3212,4 @@ "Your_question": "A sua pergunta", "Your_server_link": "O link do seu servidor", "Your_workspace_is_ready": "O seu espaço de trabalho está pronto a usar 🎉" -} \ No newline at end of file +} From 62bc7d62bfdd471e3d2ea2fc9d8e914a1d6f7bdf Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Tue, 29 Oct 2019 12:36:33 -0300 Subject: [PATCH 3/9] Add new form to edit agent data. --- .../client/views/app/tabbar/agentEdit.html | 17 ++-- .../client/views/app/tabbar/agentEdit.js | 96 +++++++++++-------- app/livechat/server/index.js | 1 + app/livechat/server/lib/Livechat.js | 24 ++++- app/livechat/server/methods/saveAgentInfo.js | 20 ++++ app/models/server/models/Users.js | 28 ++++++ packages/rocketchat-i18n/i18n/en.i18n.json | 1 + packages/rocketchat-i18n/i18n/pt.i18n.json | 1 + 8 files changed, 141 insertions(+), 47 deletions(-) create mode 100644 app/livechat/server/methods/saveAgentInfo.js diff --git a/app/livechat/client/views/app/tabbar/agentEdit.html b/app/livechat/client/views/app/tabbar/agentEdit.html index e31f9f476612..d9f23b8af363 100644 --- a/app/livechat/client/views/app/tabbar/agentEdit.html +++ b/app/livechat/client/views/app/tabbar/agentEdit.html @@ -1,6 +1,6 @@ diff --git a/app/livechat/client/views/app/tabbar/agentInfo.js b/app/livechat/client/views/app/tabbar/agentInfo.js index 4bc9684fe15e..c57ea5faea2e 100644 --- a/app/livechat/client/views/app/tabbar/agentInfo.js +++ b/app/livechat/client/views/app/tabbar/agentInfo.js @@ -9,20 +9,17 @@ import s from 'underscore.string'; import { getCustomFormTemplate } from '../customTemplates/register'; import './agentInfo.html'; import { modal } from '../../../../../ui-utils'; -import { t, handleError } from '../../../../../utils/client'; +import { t, handleError, APIClient } from '../../../../../utils/client'; import { hasPermission } from '../../../../../authorization'; -import { AgentUsers } from '../../../collections/AgentUsers'; import { LivechatDepartmentAgents } from '../../../collections/LivechatDepartmentAgents'; -import { LivechatDepartment } from '../../../collections/LivechatDepartment'; + +const customFieldsTemplate = () => getCustomFormTemplate('livechatAgentInfoForm'); Template.agentInfo.helpers({ canEdit() { - const availableDepartments = [...Template.instance().avaliableDepartments.get()]; - return availableDepartments.length > 0 && hasPermission('add-livechat-department-agents'); - }, - - canRemove() { - return hasPermission('manage-livechat-agents'); + const availableDepartments = [...Template.instance().availableDepartments.get()]; + const hasCustomFields = customFieldsTemplate() !== null; + return (availableDepartments.length > 0 && hasPermission('add-livechat-department-agents')) || hasCustomFields; }, name() { @@ -75,25 +72,33 @@ Template.agentInfo.helpers({ return { agentId: agent && agent._id, - back() { + back(success) { instance.editingAgent.set(); + if (success) { + console.log(instance.agentDepartments.get()); + } }, }; }, agentDepartments() { - return Template.instance().agentDepartments.get(); + const deptIds = Template.instance().agentDepartments.get(); + const departments = Template.instance().departments.get(); + return departments.filter(({ _id }) => deptIds.includes(_id)); }, - customFieldsTemplate() { - return getCustomFormTemplate('livechatAgentInfoForm'); - }, + customFieldsTemplate, agentDataContext() { // To make the dynamic template reactive we need to pass a ReactiveVar through the data property // because only the dynamic template data will be reloaded return Template.instance().agent; }, + + isReady() { + const instance = Template.instance(); + return instance.ready && instance.ready.get(); + }, }); Template.agentInfo.events({ @@ -138,31 +143,33 @@ Template.agentInfo.events({ }, }); -Template.agentInfo.onCreated(function() { +Template.agentInfo.onCreated(async function() { this.agent = new ReactiveVar(); - this.avaliableDepartments = new ReactiveVar([]); + this.ready = new ReactiveVar(false); + this.departments = new ReactiveVar([]); + this.availableDepartments = new ReactiveVar([]); this.agentDepartments = new ReactiveVar([]); this.editingAgent = new ReactiveVar(); this.tabBar = Template.currentData().tabBar; this.onRemoveAgent = Template.currentData().onRemoveAgent; - this.subscribe('livechat:agents'); - this.subscribe('livechat:departments', () => { - this.avaliableDepartments.set(LivechatDepartment.find({ enabled: true }, { sort: { name: 1 } }).fetch()); - }); + const { departments } = await APIClient.v1.get('livechat/department?sort={"name": 1}'); + this.departments.set(departments); + this.availableDepartments.set(departments.filter(({ enabled }) => enabled)); - this.autorun(() => { + this.autorun(async () => { const { agentId } = Template.currentData(); if (agentId) { - const agent = AgentUsers.findOne(agentId); + const { user } = await APIClient.v1.get(`livechat/users/agent/${ agentId }`); + this.agent.set(user); + // TODO: Need to replace the following subscribe by the REST approach this.subscribe('livechat:departmentAgents', null, agentId, () => { - const deptIds = LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId); - this.agentDepartments.set(LivechatDepartment.find({ _id: { $in: deptIds } }).fetch()); + this.agentDepartments.set(LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId)); }); - - this.agent.set(agent); } + + this.ready.set(true); }); }); diff --git a/app/livechat/imports/server/rest/users.js b/app/livechat/imports/server/rest/users.js index 179cb6137925..01eee1971c95 100644 --- a/app/livechat/imports/server/rest/users.js +++ b/app/livechat/imports/server/rest/users.js @@ -101,7 +101,7 @@ API.v1.addRoute('livechat/users/:type/:_id', { authRequired: true }, { if (user.roles.indexOf(role) !== -1) { return API.v1.success({ - user: _.pick(user, '_id', 'username'), + user: _.pick(user, '_id', 'username', 'name', 'status', 'statusLivechat', 'emails', 'livechat'), }); } diff --git a/app/livechat/server/api/lib/users.js b/app/livechat/server/api/lib/users.js index 0fb8f1d307bc..c19ad0d4fe39 100644 --- a/app/livechat/server/api/lib/users.js +++ b/app/livechat/server/api/lib/users.js @@ -16,6 +16,7 @@ async function findUsers({ userId, role, pagination: { offset, count, sort } }) status: 1, statusLivechat: 1, emails: 1, + livechat: 1, }, }); diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 8063081d5124..c156508ded4b 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3160,6 +3160,7 @@ "unarchive-room": "Unarchive Room", "unarchive-room_description": "Permission to unarchive channels", "Unblock_User": "Unblock User", + "Undefined": "Undefined", "Unfavorite": "Unfavorite", "Unfollow_message": "Unfollow message", "Unignore": "Unignore", diff --git a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index d24989d1bd04..7c2edfcd9a8c 100644 --- a/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -2959,6 +2959,7 @@ "unarchive-room": "Desarquivar Sala", "unarchive-room_description": "Permissão para desarchivar canais", "Unblock_User": "Desbloquear Usuário", + "Undefined": "Não definido", "Unfavorite": "Remover dos Favoritos", "Unfollow_message": "Deixar de seguir mensagem", "Unignore": "Unignore", From 176af813192622c3cf979898e33161946faeef36 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 30 Oct 2019 17:16:04 -0300 Subject: [PATCH 6/9] Added new forms to view and edit agent info. --- .../client/views/app/tabbar/agentInfo.js | 47 +++++++++++-------- app/livechat/server/lib/Livechat.js | 11 +++-- .../server/models/LivechatDepartmentAgents.js | 4 ++ app/models/server/models/Users.js | 1 + 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/app/livechat/client/views/app/tabbar/agentInfo.js b/app/livechat/client/views/app/tabbar/agentInfo.js index c57ea5faea2e..d3a91b3e47c9 100644 --- a/app/livechat/client/views/app/tabbar/agentInfo.js +++ b/app/livechat/client/views/app/tabbar/agentInfo.js @@ -63,20 +63,17 @@ Template.agentInfo.helpers({ }, editingAgent() { - return Template.instance().editingAgent.get(); + return Template.instance().action.get() === 'edit'; }, agentToEdit() { const instance = Template.instance(); const agent = instance.agent.get(); - return { agentId: agent && agent._id, - back(success) { - instance.editingAgent.set(); - if (success) { - console.log(instance.agentDepartments.get()); - } + back(agentId) { + instance.action.set(); + instance.agentEdited.set(agentId); }, }; }, @@ -139,17 +136,18 @@ Template.agentInfo.events({ }, 'click .edit-agent'(e, instance) { e.preventDefault(); - instance.editingAgent.set(this._id); + instance.action.set('edit'); }, }); Template.agentInfo.onCreated(async function() { this.agent = new ReactiveVar(); this.ready = new ReactiveVar(false); + this.agentEdited = new ReactiveVar(); this.departments = new ReactiveVar([]); this.availableDepartments = new ReactiveVar([]); this.agentDepartments = new ReactiveVar([]); - this.editingAgent = new ReactiveVar(); + this.action = new ReactiveVar(); this.tabBar = Template.currentData().tabBar; this.onRemoveAgent = Template.currentData().onRemoveAgent; @@ -157,19 +155,30 @@ Template.agentInfo.onCreated(async function() { this.departments.set(departments); this.availableDepartments.set(departments.filter(({ enabled }) => enabled)); - this.autorun(async () => { - const { agentId } = Template.currentData(); + const loadAgentData = async (agentId) => { + const { user } = await APIClient.v1.get(`livechat/users/agent/${ agentId }`); + this.agent.set(user); - if (agentId) { - const { user } = await APIClient.v1.get(`livechat/users/agent/${ agentId }`); - this.agent.set(user); + // TODO: Need to replace the following subscribe by the REST approach + this.subscribe('livechat:departmentAgents', null, agentId, () => { + this.agentDepartments.set(LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId)); + }); + + this.ready.set(true); + }; - // TODO: Need to replace the following subscribe by the REST approach - this.subscribe('livechat:departmentAgents', null, agentId, () => { - this.agentDepartments.set(LivechatDepartmentAgents.find({ agentId }).map((deptAgent) => deptAgent.departmentId)); - }); + this.autorun(() => { + const { agentId } = Template.currentData(); + if (agentId) { + loadAgentData(agentId); } + }); - this.ready.set(true); + this.autorun(() => { + const agentEdited = this.agentEdited.get(); + if (agentEdited) { + loadAgentData(agentEdited); + this.agentEdited.set(); + } }); }); diff --git a/app/livechat/server/lib/Livechat.js b/app/livechat/server/lib/Livechat.js index 484a1fe0e041..e2f4e645b40c 100644 --- a/app/livechat/server/lib/Livechat.js +++ b/app/livechat/server/lib/Livechat.js @@ -614,10 +614,13 @@ export const Livechat = { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'livechat:removeAgent' }); } - if (removeUserFromRoles(user._id, 'livechat-agent')) { - Users.setOperator(user._id, false); - Users.removeLivechatData(user._id); - this.setUserStatusLivechat(user._id, 'not-available'); + const { _id } = user; + + if (removeUserFromRoles(_id, 'livechat-agent')) { + Users.setOperator(_id, false); + Users.removeLivechatData(_id); + this.setUserStatusLivechat(_id, 'not-available'); + LivechatDepartmentAgents.removeByAgentId(_id); return true; } diff --git a/app/models/server/models/LivechatDepartmentAgents.js b/app/models/server/models/LivechatDepartmentAgents.js index 2184478621c0..6ca6a2345428 100644 --- a/app/models/server/models/LivechatDepartmentAgents.js +++ b/app/models/server/models/LivechatDepartmentAgents.js @@ -36,6 +36,10 @@ export class LivechatDepartmentAgents extends Base { }); } + removeByAgentId(agentId) { + this.remove({ agentId }); + } + removeByDepartmentIdAndAgentId(departmentId, agentId) { this.remove({ departmentId, agentId }); } diff --git a/app/models/server/models/Users.js b/app/models/server/models/Users.js index e5b8b3018455..47287462b421 100644 --- a/app/models/server/models/Users.js +++ b/app/models/server/models/Users.js @@ -271,6 +271,7 @@ export class Users extends Base { phone: 1, customFields: 1, status: 1, + livechat: 1, }, }; From 3df238b147870636c79cd4275a09d63c0a97d183 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 30 Oct 2019 17:39:53 -0300 Subject: [PATCH 7/9] Remove unnecessary throw error. --- app/livechat/server/lib/Livechat.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/livechat/server/lib/Livechat.js b/app/livechat/server/lib/Livechat.js index e2f4e645b40c..2e27db6dca3c 100644 --- a/app/livechat/server/lib/Livechat.js +++ b/app/livechat/server/lib/Livechat.js @@ -740,12 +740,8 @@ export const Livechat = { throw new Meteor.Error('error-user-is-not-agent', 'User is not a livechat agent', { method: 'livechat:saveAgentInfo' }); } - try { - Users.setLivechatData(_id, agentData); - LivechatDepartment.saveDepartmentsByAgent(user, agentDepartments); - } catch (e) { - // throw new Meteor.Error('error-user-is-not-agent', 'User is not a livechat agent', { method: 'livechat:saveAgentInfo' }); - } + Users.setLivechatData(_id, agentData); + LivechatDepartment.saveDepartmentsByAgent(user, agentDepartments); return true; }, From 44f86042a3e05bb78608155d45a7d0c13853d2da Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Wed, 20 Nov 2019 20:42:13 -0300 Subject: [PATCH 8/9] Add new templates to import file. --- app/livechat/client/views/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/livechat/client/views/index.js b/app/livechat/client/views/index.js index d02c048d4db1..1f826262a421 100644 --- a/app/livechat/client/views/index.js +++ b/app/livechat/client/views/index.js @@ -22,6 +22,8 @@ import './app/livechatNotSubscribed.html'; import './app/livechatRoomTagSelector.html'; import './app/integrations/livechatIntegrationWebhook'; import './app/integrations/livechatIntegrationFacebook'; +import './app/tabbar/agentEdit'; +import './app/tabbar/agentInfo'; import './app/tabbar/externalSearch'; import './app/tabbar/visitorEdit'; import './app/tabbar/visitorForward'; From ee24bd3767a9bc7cd123f5e0742215a862e480bd Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 21 Nov 2019 01:01:59 -0300 Subject: [PATCH 9/9] fix review --- .../client/views/app/tabbar/agentEdit.html | 40 +++++++++---------- .../client/views/app/tabbar/agentEdit.js | 19 +++++---- .../client/views/app/tabbar/agentInfo.js | 6 ++- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/app/livechat/client/views/app/tabbar/agentEdit.html b/app/livechat/client/views/app/tabbar/agentEdit.html index 324324538c6e..2fa2438368c8 100644 --- a/app/livechat/client/views/app/tabbar/agentEdit.html +++ b/app/livechat/client/views/app/tabbar/agentEdit.html @@ -4,7 +4,7 @@ {{else}}
-
+
@@ -14,17 +14,17 @@
-
- +
+
-
+
{{#if agent.emails}} -
+
{{/if}} {{#if hasAvailableDepartments}} -
+
{{/if}} {{#if hasAgentDepartments}} -
+