From c8675fc1c0a32dbbc1f290865bf107f72ec080bd Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Fri, 8 Apr 2016 17:45:15 -0300 Subject: [PATCH 1/3] New field to track livechat agent availability --- packages/rocketchat-lib/i18n/en.i18n.json | 2 + .../client/methods/changeLivechatStatus.js | 13 +++++ .../client/stylesheets/livechat.less | 48 +++++++++---------- .../client/views/sideNav/livechat.html | 26 ++++++---- .../client/views/sideNav/livechat.js | 26 +++++++++- packages/rocketchat-livechat/package.js | 3 ++ .../server/methods/addAgent.js | 4 +- .../server/methods/changeLivechatStatus.js | 13 +++++ .../server/methods/removeAgent.js | 4 +- .../server/models/Users.js | 24 +++++++++- server/publications/userData.coffee | 1 + 11 files changed, 122 insertions(+), 42 deletions(-) create mode 100644 packages/rocketchat-livechat/client/methods/changeLivechatStatus.js create mode 100644 packages/rocketchat-livechat/server/methods/changeLivechatStatus.js diff --git a/packages/rocketchat-lib/i18n/en.i18n.json b/packages/rocketchat-lib/i18n/en.i18n.json index e4720b79ccaf..207eaeacb06b 100644 --- a/packages/rocketchat-lib/i18n/en.i18n.json +++ b/packages/rocketchat-lib/i18n/en.i18n.json @@ -149,6 +149,7 @@ "AutoLinker_Phone": "AutoLinker Phone", "AutoLinker_Phone_Description": "Automatically linked for Phone numbers. e.g. `(123)456-7890`", "Auto_Load_Images" : "Auto Load Images", + "Available" : "Available", "Available_agents" : "Available agents", "Avatar" : "Avatar", "Avatar_changed_successfully" : "Avatar changed successfully", @@ -604,6 +605,7 @@ "No_user_with_username_%s_was_found" : "No user with username \"%s\" was found!", "Not_allowed" : "Not allowed", "Not_authorized" : "Not authorized", + "Not_Available" : "Not Available", "Not_found_or_not_allowed" : "Not Found or Not Allowed", "Nothing" : "Nothing", "Nothing_found" : "Nothing found", diff --git a/packages/rocketchat-livechat/client/methods/changeLivechatStatus.js b/packages/rocketchat-livechat/client/methods/changeLivechatStatus.js new file mode 100644 index 000000000000..8114134652e0 --- /dev/null +++ b/packages/rocketchat-livechat/client/methods/changeLivechatStatus.js @@ -0,0 +1,13 @@ +Meteor.methods({ + 'livechat:changeLivechatStatus'() { + if (!Meteor.userId()) { + throw new Meteor.Error('error-not-authorized', 'Not authorized'); + } + + const user = Meteor.user(); + + let newStatus = user.statusLivechat === 'available' ? 'not-available' : 'available'; + + Meteor.users.update(user._id, { $set: { statusLivechat: newStatus }}); + } +}); diff --git a/packages/rocketchat-livechat/client/stylesheets/livechat.less b/packages/rocketchat-livechat/client/stylesheets/livechat.less index d31b90df8dab..379a29fa44b8 100644 --- a/packages/rocketchat-livechat/client/stylesheets/livechat.less +++ b/packages/rocketchat-livechat/client/stylesheets/livechat.less @@ -1,29 +1,3 @@ -.calc(...) { - @process: ~`(function(e){function t(t,r){var a=");\n",c=n.split(","),i=c[0]+":"+t+"("+(c[1].trim()||0)+a;"start"==r?e="0;\n"+i:e+=i}e=e||8121991;var r="@{state}",n=e;if(8121991==e)return e;switch(r){case"1":t("-webkit-calc","start"),t("-moz-calc"),t("calc");break;case"2":t("-webkit-calc","start"),t("-moz-calc");break;case"3":t("-webkit-calc","start"),t("calc");break;case"4":t("-webkit-calc","start");break;case"5":t("-moz-calc","start"),t("calc");break;case"6":t("-moz-calc","start");break;case"7":t("calc","start")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @state: 1; -lh-property: @process; - -} - -.transition(...) { - @process_webkit: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","border-radius","border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","box-shadow","column","transform","filter"],t="-webkit-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_moz: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process_opera: ~`(function(e){e=e||"all 0 ease 0";var r=["transform"],t="-o-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - @process: ~`(function(e){e=e||"all 0 ease 0";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));var c=e.split(/(?:,)(?![^(]*\))/g);return c.forEach(function(e,n){t.forEach(function(t){-1!==e.indexOf(t)&&(c[n]="",r.forEach(function(a,u){c[n]+=e.trim().replace(new RegExp(t,"g"),function(e){return a+e}),u10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transition: @process_webkit; - -moz-transition: @process_moz; - -o-transition: @process_opera; - transition: @process; -} - -.transform(...) { - @process: ~`(function(e){e=e||"none";var r={translate:"px",rotate:"deg",rotate3d:"deg",skew:"deg"};/^\w*\(?[a-z0-9.]*\)?/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));for(var t in r)e.indexOf(t)>=0&&(e=e.replace(new RegExp(t+"[\\w]?\\([a-z0-9, %]*\\)"),function(e){var n=/(\d+\.?\d*)(?!\w|%)/g;return"rotate3d"==t&&(n=/,\s*\d+$/),e.replace(n,function(e){return e+r[t]})}));return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`; - -webkit-transform: @process; - -moz-transform: @process; - -o-transform: @process; - -ms-transform: @process; - transform: @process; -} - .flex-list { .active { background-color: rgba(255,255,255,0.075); @@ -505,3 +479,25 @@ } } } + +.livechat-section { + opacity: 0.5; + + .transition(opacity .4s ease); + + &.available { + opacity: 1; + } +} + +.livechat-status { + float: right; + margin-right: 10px; + font-size: 20px; + &.available { + color: @status-online; + } + &.not-available { + color: @status-offline; + } +} diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.html b/packages/rocketchat-livechat/client/views/sideNav/livechat.html index c6aab41be12e..2ab2e9b3cda7 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechat.html +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.html @@ -1,12 +1,18 @@ diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.js b/packages/rocketchat-livechat/client/views/sideNav/livechat.js index ec42e0b9e651..23709894af78 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechat.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.js @@ -1,5 +1,5 @@ Template.livechat.helpers({ - isActive: function() { + isActive() { if (ChatSubscription.findOne({ t: 'l', f: { @@ -15,7 +15,7 @@ Template.livechat.helpers({ return 'active'; } }, - rooms: function() { + rooms() { var query = { t: 'l', open: true @@ -35,8 +35,30 @@ Template.livechat.helpers({ 'name': 1 } }); + }, + available() { + const user = Meteor.user(); + return { + status: user.statusLivechat, + icon: user.statusLivechat === 'available' ? 'icon-toggle-on' : 'icon-toggle-off', + hint: user.statusLivechat === 'available' ? t('Available') : t('Not_Available') + }; + }, + livechatAvailable() { + const user = Meteor.user(); + + if (user) { + return user.statusLivechat; + } } }); Template.livechat.events({ + 'click .livechat-status'() { + Meteor.call('livechat:changeLivechatStatus', (err, results) => { + if (err) { + return toastr.error(t(err.reason)); + } + }); + } }); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 4cf6c3b3d2df..e8887070521c 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -48,6 +48,8 @@ Package.onUse(function(api) { api.addFiles('client/collections/LivechatPageVisited.js', 'client'); api.addFiles('client/collections/LivechatTrigger.js', 'client'); + api.addFiles('client/methods/changeLivechatStatus.js', 'client'); + // client views api.addFiles('client/views/app/livechatAppearance.html', 'client'); api.addFiles('client/views/app/livechatAppearance.js', 'client'); @@ -79,6 +81,7 @@ Package.onUse(function(api) { // methods api.addFiles('server/methods/addAgent.js', 'server'); api.addFiles('server/methods/addManager.js', 'server'); + api.addFiles('server/methods/changeLivechatStatus.js', 'server'); api.addFiles('server/methods/pageVisited.js', 'server'); api.addFiles('server/methods/registerGuest.js', 'server'); api.addFiles('server/methods/removeAgent.js', 'server'); diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js index d71339acf638..403d1ce56a9f 100644 --- a/packages/rocketchat-livechat/server/methods/addAgent.js +++ b/packages/rocketchat-livechat/server/methods/addAgent.js @@ -15,7 +15,9 @@ Meteor.methods({ } if (RocketChat.authz.addUserRoles(user._id, 'livechat-agent')) { - return RocketChat.models.Users.setOperator(user._id, true); + RocketChat.models.Users.setOperator(user._id, true); + RocketChat.models.Users.setLivechatStatus(user._id, 'available'); + return true; } return false; diff --git a/packages/rocketchat-livechat/server/methods/changeLivechatStatus.js b/packages/rocketchat-livechat/server/methods/changeLivechatStatus.js new file mode 100644 index 000000000000..6d0f4298aafe --- /dev/null +++ b/packages/rocketchat-livechat/server/methods/changeLivechatStatus.js @@ -0,0 +1,13 @@ +Meteor.methods({ + 'livechat:changeLivechatStatus'() { + if (!Meteor.userId()) { + throw new Meteor.Error('error-not-authorized', 'Not authorized'); + } + + const user = Meteor.user(); + + let newStatus = user.statusLivechat === 'available' ? 'not-available' : 'available'; + + return RocketChat.models.Users.setLivechatStatus(user._id, newStatus); + } +}); diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js index ee77ad4af549..d9284e0f0174 100644 --- a/packages/rocketchat-livechat/server/methods/removeAgent.js +++ b/packages/rocketchat-livechat/server/methods/removeAgent.js @@ -15,7 +15,9 @@ Meteor.methods({ } if (RocketChat.authz.removeUserFromRoles(user._id, 'livechat-agent')) { - return RocketChat.models.Users.setOperator(user._id, false); + RocketChat.models.Users.setOperator(user._id, false); + RocketChat.models.Users.setLivechatStatus(user._id, 'not-available'); + return true; } return false; diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js index c67e78cf5a5e..21332f75b79c 100644 --- a/packages/rocketchat-livechat/server/models/Users.js +++ b/packages/rocketchat-livechat/server/models/Users.js @@ -33,7 +33,8 @@ RocketChat.models.Users.findOnlineAgents = function() { */ RocketChat.models.Users.findOnlineUserFromList = function(userList) { var query = { - status: 'online', + statusConnection: { $ne: 'offline' }, + statusLivechat: 'available', username: { $in: [].concat(userList) } @@ -48,7 +49,8 @@ RocketChat.models.Users.findOnlineUserFromList = function(userList) { */ RocketChat.models.Users.getNextAgent = function() { var query = { - status: 'online', + statusConnection: { $ne: 'offline' }, + statusLivechat: 'available', roles: 'livechat-agent' }; @@ -102,3 +104,21 @@ RocketChat.models.Users.findVisitorByToken = function(token) { return this.find(query); }; + +/** + * Change user's livechat status + * @param {string} token - Visitor token + */ +RocketChat.models.Users.setLivechatStatus = function(userId, status) { + let query = { + '_id': userId + }; + + let update = { + $set: { + 'statusLivechat': status + } + }; + + return this.update(query, update); +}; diff --git a/server/publications/userData.coffee b/server/publications/userData.coffee index af3db514d0fa..3f84dc2b2b84 100644 --- a/server/publications/userData.coffee +++ b/server/publications/userData.coffee @@ -19,3 +19,4 @@ Meteor.publish 'userData', -> requirePasswordChange: 1 requirePasswordChangeReason: 1 'services.password.bcrypt': 1 + statusLivechat: 1 # @TODO create an API so a package could add fields here From 3854c4b1d8f892810183cbf52fcde17302962366 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Fri, 8 Apr 2016 17:46:07 -0300 Subject: [PATCH 2/3] Fix survey UI issues --- .../app/client/stylesheets/main.less | 12 ++++++++---- .../rocketchat-livechat/app/client/views/survey.html | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-livechat/app/client/stylesheets/main.less b/packages/rocketchat-livechat/app/client/stylesheets/main.less index a321456263a6..98c9bc7447d6 100644 --- a/packages/rocketchat-livechat/app/client/stylesheets/main.less +++ b/packages/rocketchat-livechat/app/client/stylesheets/main.less @@ -447,10 +447,10 @@ input:focus { z-index: 9999; background: white; position: fixed; - height: 60vh; - width: 60vw; - top: 20vh; - left: 20vw; + height: 80%; + width: 80%; + top: 15%; + left: 10%; border-radius: 6px; display: flex; flex-direction: column; @@ -460,6 +460,10 @@ input:focus { padding: 0 15px; border-bottom: 1px solid rgba(0, 0, 0, 0.1); line-height: 40px; + + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; } .content { diff --git a/packages/rocketchat-livechat/app/client/views/survey.html b/packages/rocketchat-livechat/app/client/views/survey.html index 9c4a9b08f399..d5d2dedd9ff4 100644 --- a/packages/rocketchat-livechat/app/client/views/survey.html +++ b/packages/rocketchat-livechat/app/client/views/survey.html @@ -2,7 +2,7 @@
-
+
{{_ 'Please_answer_survey'}}
From 04c834bf44689b79b361c1be9b659dd3cc3daeda Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Fri, 8 Apr 2016 19:41:47 -0300 Subject: [PATCH 3/3] Fix for Codacy --- packages/rocketchat-livechat/client/views/sideNav/livechat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-livechat/client/views/sideNav/livechat.js b/packages/rocketchat-livechat/client/views/sideNav/livechat.js index 23709894af78..a2151f2a0592 100644 --- a/packages/rocketchat-livechat/client/views/sideNav/livechat.js +++ b/packages/rocketchat-livechat/client/views/sideNav/livechat.js @@ -55,7 +55,7 @@ Template.livechat.helpers({ Template.livechat.events({ 'click .livechat-status'() { - Meteor.call('livechat:changeLivechatStatus', (err, results) => { + Meteor.call('livechat:changeLivechatStatus', (err /*, results*/) => { if (err) { return toastr.error(t(err.reason)); }