diff --git a/packages/rocketchat-livechat/client/collections/AgentUsers.js b/packages/rocketchat-livechat/client/collections/AgentUsers.js
new file mode 100644
index 000000000000..e571fad61d2b
--- /dev/null
+++ b/packages/rocketchat-livechat/client/collections/AgentUsers.js
@@ -0,0 +1 @@
+this.AgentUsers = new Mongo.Collection('agentUsers');
diff --git a/packages/rocketchat-livechat/client/lib/LivechatDepartment.js b/packages/rocketchat-livechat/client/collections/LivechatDepartment.js
similarity index 100%
rename from packages/rocketchat-livechat/client/lib/LivechatDepartment.js
rename to packages/rocketchat-livechat/client/collections/LivechatDepartment.js
diff --git a/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js
new file mode 100644
index 000000000000..08ea1741134b
--- /dev/null
+++ b/packages/rocketchat-livechat/client/collections/LivechatDepartmentAgents.js
@@ -0,0 +1 @@
+this.LivechatDepartmentAgents = new Mongo.Collection('rocketchat_livechat_department_agents');
diff --git a/packages/rocketchat-livechat/client/lib/LivechatTrigger.js b/packages/rocketchat-livechat/client/collections/LivechatTrigger.js
similarity index 100%
rename from packages/rocketchat-livechat/client/lib/LivechatTrigger.js
rename to packages/rocketchat-livechat/client/collections/LivechatTrigger.js
diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less
index dc12fb153ec4..b389c38d398b 100644
--- a/packages/rocketchat-livechat/client/stylesheets/livechat.less
+++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less
@@ -411,3 +411,29 @@
}
}
}
+
+.department-agents {
+ list-style-type: none;
+
+ li {
+ display: inline-block;
+ background-color: #DDD;
+ border-radius: 10px;
+ padding: 2px 8px 2px 2px;
+ margin: 1px 0;
+ cursor: pointer;
+
+ .icon-plus-circled {
+ opacity: 0.5;
+ font-size: 0.8rem;
+ }
+ }
+}
+
+.agent-info {
+ input[type='text'] {
+ width: auto;
+ line-height: 24px;
+ height: 24px;
+ }
+}
diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html
index 5a82ac77c719..fccbaa7f0718 100644
--- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html
+++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.html
@@ -24,34 +24,51 @@
diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js
index d4ff6d0fcac6..6f5017e0ca2e 100644
--- a/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js
+++ b/packages/rocketchat-livechat/client/views/app/livechatDepartmentForm.js
@@ -1,10 +1,16 @@
Template.livechatDepartmentForm.helpers({
department() {
- // return Template.instance().department && !_.isEmpty(Template.instance().department.get()) ? Template.instance().department.get() : { enabled: true };
return Template.instance().department.get();
},
agents() {
return Template.instance().department && !_.isEmpty(Template.instance().department.get()) ? Template.instance().department.get().agents : []
+ },
+ selectedAgents() {
+ return _.sortBy(Template.instance().selectedAgents.get(), 'username');
+ },
+ availableAgents() {
+ var selected = _.pluck(Template.instance().selectedAgents.get(), 'username');
+ return AgentUsers.find({ username: { $nin: selected }}, { sort: { username: 1 } });
}
});
@@ -29,16 +35,22 @@ Template.livechatDepartmentForm.events({
var oldBtnValue = $btn.html();
$btn.html(t('Saving'));
- agents = instance.department && !_.isEmpty(instance.department.get()) ? instance.department.get().agents : [];
-
- departmentData = {
+ var departmentData = {
enabled: enabled === "1" ? true : false,
name: name.trim(),
- description: description.trim(),
- agents: agents
- }
+ description: description.trim()
+ };
+
+ var departmentAgents = [];
+
+ instance.selectedAgents.get().forEach((agent) => {
+ agent.count = instance.$('.count-' + agent.agentId).val();
+ agent.order = instance.$('.order-' + agent.agentId).val();
+
+ departmentAgents.push(agent);
+ });
- Meteor.call('livechat:saveDepartment', _id, departmentData, function(error, result) {
+ Meteor.call('livechat:saveDepartment', _id, departmentData, departmentAgents, function(error, result) {
$btn.html(oldBtnValue);
if (error) {
return toastr.error(t(error.reason || error.error));
@@ -54,59 +66,44 @@ Template.livechatDepartmentForm.events({
FlowRouter.go('livechat-departments');
},
- 'click button.add-agent' (e, instance) {
+ 'click .remove-agent' (e, instance) {
e.preventDefault();
- var $btn = $(e.currentTarget);
-
- var $agent = instance.$('input[name=agent]')
-
- if ($agent.val().trim() === '') {
- return toastr.error(t('Please_fill_a_username'));
- }
-
- var oldBtnValue = $btn.html();
- $btn.html(t('Saving'));
- Meteor.call('livechat:searchAgent', $agent.val(), function(error, user) {
- $btn.html(oldBtnValue);
- if (error) {
- return toastr.error(t(error.reason || error.error));
- }
- department = instance.department.get() || {};
- if (department.agents === undefined || !_.isArray(department.agents)) {
- department.agents = [];
- }
- if (!_.findWhere(department.agents, { _id: user._id })) {
- department.agents.push(user);
- }
- instance.department.set(department);
- $agent.val('');
- });
+ var selectedAgents = instance.selectedAgents.get();
+ selectedAgents = _.reject(selectedAgents, (agent) => { return agent._id === this._id });
+ instance.selectedAgents.set(selectedAgents);
},
- 'click a.remove-agent' (e, instance) {
- e.preventDefault();
- department = instance.department.get();
- department.agents = _.reject(department.agents, (agent) => { return agent._id === this._id });
- instance.department.set(department);
- },
-
- 'keydown input[name=agent]' (e, instance) {
- if (e.keyCode === 13) {
- e.preventDefault();
- $("button.add-agent").click();
- }
+ 'click .available-agents li' (e, instance) {
+ var selectedAgents = instance.selectedAgents.get();
+ var agent = _.clone(this);
+ agent.agentId = this._id;
+ delete agent._id;
+ selectedAgents.push(agent);
+ instance.selectedAgents.set(selectedAgents);
}
});
Template.livechatDepartmentForm.onCreated(function() {
this.department = new ReactiveVar({ enabled: true });
+ this.selectedAgents = new ReactiveVar([]);
+
+ this.subscribe('livechat:agents');
+
this.autorun(() => {
var sub = this.subscribe('livechat:departments', FlowRouter.getParam('_id'));
if (sub.ready()) {
department = LivechatDepartment.findOne({ _id: FlowRouter.getParam('_id') });
if (department) {
this.department.set(department);
+
+ this.subscribe('livechat:departmentAgents', department._id, () => {
+ var newSelectedAgents = [];
+ LivechatDepartmentAgents.find({ departmentId: department._id }).forEach((agent) => {
+ newSelectedAgents.push(agent);
+ });
+ this.selectedAgents.set(newSelectedAgents);
+ });
}
}
});
diff --git a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js
index eba12b82bc14..e5d0746485dc 100644
--- a/packages/rocketchat-livechat/client/views/app/livechatDepartments.js
+++ b/packages/rocketchat-livechat/client/views/app/livechatDepartments.js
@@ -1,11 +1,6 @@
Template.livechatDepartments.helpers({
"departments": () => {
return LivechatDepartment.find();
- },
- "numAgents"() {
- if (Array.isArray(this.agents)) {
- return this.agents.length;
- }
}
});
diff --git a/packages/rocketchat-livechat/client/views/app/livechatUsers.js b/packages/rocketchat-livechat/client/views/app/livechatUsers.js
index 5e29f332b938..eeb2d1dfa783 100644
--- a/packages/rocketchat-livechat/client/views/app/livechatUsers.js
+++ b/packages/rocketchat-livechat/client/views/app/livechatUsers.js
@@ -1,8 +1,6 @@
-var AgentUsers;
var ManagerUsers;
Meteor.startup(function() {
- AgentUsers = new Mongo.Collection('agentUsers');
ManagerUsers = new Mongo.Collection('managerUsers');
});
diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html
index a859f5385a50..15d3ed86810d 100644
--- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html
+++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.html
@@ -10,7 +10,7 @@
{{_ "Livechat"}}
{{_ "User_management"}}
- {{_ "Departments"}}
+ {{_ "Departments"}}
{{_ "Triggers"}}
{{_ "Installation"}}
{{_ "Appearance"}}
diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js
index 4e2578cea84e..f7a8f2f0accf 100644
--- a/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js
+++ b/packages/rocketchat-livechat/client/views/sideNav/livechatFlex.js
@@ -1,7 +1,7 @@
Template.livechatFlex.helpers({
- active (route) {
+ active (...routes) {
FlowRouter.watchPathChange();
- if (FlowRouter.current().route.name === route) {
+ if (routes.indexOf(FlowRouter.current().route.name) !== -1) {
return 'active';
}
}
diff --git a/packages/rocketchat-livechat/i18n/en.i18n.json b/packages/rocketchat-livechat/i18n/en.i18n.json
index 072aeddc3204..754decc34491 100644
--- a/packages/rocketchat-livechat/i18n/en.i18n.json
+++ b/packages/rocketchat-livechat/i18n/en.i18n.json
@@ -4,9 +4,11 @@
"Add_manager" : "Add manager",
"Agent_added" : "Agent added",
"Agent_removed" : "Agent removed",
+ "Available_agents" : "Available agents",
"Back" : "Back",
"Closed" : "Closed",
"Copy_to_clipboard" : "Copy to clipboard",
+ "Count" : "Count",
"Dashboard" : "Dashboard",
"Department_not_found" : "Department not found",
"Department_removed" : "Department removed",
@@ -32,10 +34,12 @@
"New_Department" : "New Department",
"Num_Agents" : "# Agents",
"Opened" : "Opened",
+ "Order" : "Order",
"Please_fill_a_name" : "Please fill a name",
"Please_fill_a_username" : "Please fill a username",
"Please_select_enabled_yes_or_no" : "Please select an option for Enabled",
"Saved" : "Saved",
+ "Selected_agents" : "Selected agents",
"Send_a_message" : "Send a message",
"Theme" : "Theme",
"There_are_no_agents_added_to_this_department_yet" : "There are no agents added to this department yet.",
@@ -48,4 +52,4 @@
"Username_not_found" : "Username not found",
"Visitor_page_URL" : "Visitor page URL",
"Visitor_time_on_site" : "Visitor time on site"
-}
\ No newline at end of file
+}
diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js
index b692038ae8d6..f6b14d25635b 100644
--- a/packages/rocketchat-livechat/package.js
+++ b/packages/rocketchat-livechat/package.js
@@ -38,6 +38,12 @@ Package.onUse(function(api) {
api.addFiles('client/stylesheets/livechat.less', 'client');
+ // collections
+ api.addFiles('client/collections/AgentUsers.js', 'client');
+ api.addFiles('client/collections/LivechatDepartment.js', 'client');
+ api.addFiles('client/collections/LivechatDepartmentAgents.js', 'client');
+ api.addFiles('client/collections/LivechatTrigger.js', 'client');
+
// client views
api.addFiles('client/views/app/livechatAppearance.html', 'client');
api.addFiles('client/views/app/livechatAppearance.js', 'client');
@@ -80,13 +86,14 @@ Package.onUse(function(api) {
api.addFiles('server/models/Users.js', 'server');
api.addFiles('server/models/Rooms.js', 'server');
api.addFiles('server/models/LivechatDepartment.js', 'server');
+ api.addFiles('server/models/LivechatDepartmentAgents.js', 'server');
api.addFiles('server/models/LivechatTrigger.js', 'server');
- // collections
- api.addFiles('client/lib/LivechatDepartment.js', 'client');
- api.addFiles('client/lib/LivechatTrigger.js', 'client');
+ // server lib
+ api.addFiles('server/lib/getNextAgent.js', 'server');
// publications
+ api.addFiles('server/publications/departmentAgents.js', 'server');
api.addFiles('server/publications/livechatAgents.js', 'server');
api.addFiles('server/publications/livechatManagers.js', 'server');
api.addFiles('server/publications/livechatDepartments.js', 'server');
diff --git a/packages/rocketchat-livechat/server/lib/getNextAgent.js b/packages/rocketchat-livechat/server/lib/getNextAgent.js
index 1e9aba08673c..3259ab642d93 100644
--- a/packages/rocketchat-livechat/server/lib/getNextAgent.js
+++ b/packages/rocketchat-livechat/server/lib/getNextAgent.js
@@ -1,27 +1,8 @@
this.getNextAgent = function(department) {
var agentFilter = {};
- // find agents from that department
if (department) {
- var agents = RocketChat.models.LivechatDepartment.getNextAgent(department);
-
- if (!agents) {
- return;
- }
-
- // sort = {
- // count: 1,
- // order: 1,
- // 'user.name': 1
- // }
-
- // update = {
- // $inc: {
- // count: 1
- // }
- // }
-
- // queueUser = findAndModify query, sort, update
+ return RocketChat.models.LivechatDepartment.getNextAgent(department);
} else {
return RocketChat.models.Users.getNextAgent();
}
diff --git a/packages/rocketchat-livechat/server/methods/saveDepartment.js b/packages/rocketchat-livechat/server/methods/saveDepartment.js
index de3f656817bc..2f626c395720 100644
--- a/packages/rocketchat-livechat/server/methods/saveDepartment.js
+++ b/packages/rocketchat-livechat/server/methods/saveDepartment.js
@@ -1,5 +1,5 @@
Meteor.methods({
- 'livechat:saveDepartment' (_id, departmentData) {
+ 'livechat:saveDepartment' (_id, departmentData, departmentAgents) {
if (!Meteor.userId() || !RocketChat.authz.hasPermission(Meteor.userId(), 'view-livechat-manager')) {
throw new Meteor.Error("not-authorized");
}
@@ -17,6 +17,6 @@ Meteor.methods({
}
}
- return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentData.agents);
+ return RocketChat.models.LivechatDepartment.createOrUpdateDepartment(_id, departmentData.enabled, departmentData.name, departmentData.description, departmentAgents);
}
});
diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartment.js b/packages/rocketchat-livechat/server/models/LivechatDepartment.js
index 41141b8d68ef..d474415ea963 100644
--- a/packages/rocketchat-livechat/server/models/LivechatDepartment.js
+++ b/packages/rocketchat-livechat/server/models/LivechatDepartment.js
@@ -19,23 +19,42 @@ class LivechatDepartment extends RocketChat.models._Base {
return this.find(query, options);
}
- // UPSERT
createOrUpdateDepartment(_id, enabled, name, description, agents, extraData) {
- record = {
+ var agents = [].concat(agents);
+
+ var record = {
enabled: enabled,
name: name,
description: description,
- agents: []
- }
+ numAgents: agents.length
+ };
+
+ _.extend(record, extraData);
- if (!_.isEmpty(agents)) {
- for (agent of agents) {
- record.agents.push({ _id: agent._id, username: agent.username });
- }
+ if (_id) {
+ this.update({ _id: _id }, { $set: record });
+ } else {
+ _id = this.insert(record);
}
- _.extend(record, extraData);
- this.upsert({ _id: _id }, { $set: record });
+ var savedAgents = _.pluck(RocketChat.models.LivechatDepartmentAgents.findByDepartmentId(_id).fetch(), 'agentId');
+ var agentsToSave = _.pluck(agents, 'agentId');
+
+ // remove other agents
+ _.difference(savedAgents, agentsToSave).forEach((agentId) => {
+ RocketChat.models.LivechatDepartmentAgents.removeByDepartmentIdAndAgentId(_id, agentId);
+ });
+
+ agents.forEach((agent) => {
+ RocketChat.models.LivechatDepartmentAgents.saveAgent({
+ agentId: agent.agentId,
+ departmentId: _id,
+ username: agent.username,
+ count: parseInt(agent.count),
+ order: parseInt(agent.order)
+ });
+ });
+
return _.extend(record, { _id: _id });
}
diff --git a/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js
new file mode 100644
index 000000000000..a4d56fa7ba82
--- /dev/null
+++ b/packages/rocketchat-livechat/server/models/LivechatDepartmentAgents.js
@@ -0,0 +1,71 @@
+/**
+ * Livechat Department model
+ */
+class LivechatDepartmentAgents extends RocketChat.models._Base {
+ constructor() {
+ super();
+ this._initModel('livechat_department_agents');
+ }
+
+ findByDepartmentId(departmentId) {
+ return this.find({ departmentId: departmentId });
+ }
+
+ saveAgent(agent) {
+ if (agent._id) {
+ return this.update({ _id: _id }, { $set: agent });
+ } else {
+ return this.upsert({
+ agentId: agent.agentId,
+ departmentId: agent.departmentId
+ }, {
+ $set: {
+ username: agent.username,
+ count: parseInt(agent.count),
+ order: parseInt(agent.order)
+ }
+ });
+ }
+ }
+
+ removeByDepartmentIdAndAgentId(departmentId, agentId) {
+ this.remove({ departmentId: departmentId, agentId: agentId });
+ }
+
+ getNextAgentForDepartment(departmentId) {
+ var agents = this.findByDepartmentId(departmentId).fetch();
+
+ if (agents.length === 0) {
+ return;
+ }
+
+ var onlineUsers = RocketChat.models.Users.findOnlineUserFromList(_.pluck(agents, 'username'));
+
+ var onlineUsernames = _.pluck(onlineUsers.fetch(), 'username');
+
+ var query = {
+ departmentId: departmentId,
+ username: {
+ $in: onlineUsernames
+ }
+ };
+
+ var sort = {
+ count: 1,
+ sort: 1,
+ username: 1
+ };
+ var update = {
+ $inc: {
+ count: 1
+ }
+ };
+
+ var collectionObj = this.model.rawCollection();
+ var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj);
+
+ return findAndModify(query, sort, update);
+ }
+}
+
+RocketChat.models.LivechatDepartmentAgents = new LivechatDepartmentAgents();
diff --git a/packages/rocketchat-livechat/server/publications/departmentAgents.js b/packages/rocketchat-livechat/server/publications/departmentAgents.js
new file mode 100644
index 000000000000..b09f4fe3dd9c
--- /dev/null
+++ b/packages/rocketchat-livechat/server/publications/departmentAgents.js
@@ -0,0 +1,11 @@
+Meteor.publish('livechat:departmentAgents', function(departmentId) {
+ if (!this.userId) {
+ throw new Meteor.Error('not-authorized');
+ }
+
+ if (!RocketChat.authz.hasPermission(this.userId, 'view-livechat-manager')) {
+ throw new Meteor.Error('not-authorized');
+ }
+
+ return RocketChat.models.LivechatDepartmentAgents.find({ departmentId: departmentId });
+});