Browse Source

UI-773: Added a feature for 'Next Action' (formerly 'extra-node') on ring groups

4.3
Maxime Roux 11 years ago
parent
commit
7a98201061
5 changed files with 203 additions and 108 deletions
  1. +9
    -7
      i18n/en-US.json
  2. +9
    -7
      i18n/fr-FR.json
  3. +16
    -17
      submodules/groups/groups.css
  4. +127
    -77
      submodules/groups/groups.js
  5. +42
    -0
      views/groups-feature-next_action.html

+ 9
- 7
i18n/en-US.json View File

@ -51,13 +51,6 @@
"removeMember": "Remove Member",
"distribute": "Distribute",
"maxDurationTooltip": "Click this box to change the maximum duration for your ring group. You must enter a number between 30 and 999.",
"extraNode": {
"label": "If no one answers, forward the call to:",
"menu": "Menu",
"mainMenu": "Main Menu (Open hours)",
"voicemails": "Voicemail Boxes",
"users": "Users"
},
"title": "Groups",
"titleGrid": {
"groups": "Group Name",
@ -86,6 +79,15 @@
"defaultRingback": "Default Ringback",
"emptyUploadAlert": "Please select a file to upload",
"fileTooBigAlert": "You can not upload a file with a size exceeding 5MB"
},
"nextAction": {
"title": "Next Action",
"headline": "Add an action when no one picks up",
"label": "If no one answers, forward the call to:",
"menu": "Menu",
"mainMenu": "Main Menu (Open hours)",
"voicemails": "Voicemail Boxes",
"users": "Users"
}
},


+ 9
- 7
i18n/fr-FR.json View File

@ -51,13 +51,6 @@
"removeMember": "Supprimer ce membre",
"distribute": "Répartir",
"maxDurationTooltip": "Cliquez sur le label ci-contre pour changer la durée maximale de ce groupe d'appel. Vous devez saisir un nombre crompris entre 30 et 999.",
"extraNode": {
"label": "Si personne ne répond, transférer l'appel vers :",
"menu": "Menu",
"mainMenu": "Menu principal",
"voicemails": "Répondeurs",
"users": "Utilisateurs"
},
"title": "Groupes",
"titleGrid": {
"groups": "Nom du groupe",
@ -86,6 +79,15 @@
"defaultRingback": "Tonalité par défaut",
"emptyUploadAlert": "Veuillez sélectionner un fichier à uploader",
"fileTooBigAlert": "Vous ne pouvez pas uploader un fichier de taille excédant 5MB"
},
"nextAction": {
"title": "Action Finale",
"headline": "Sélectionner l'Action Finale",
"label": "Si personne ne répond, transférer l'appel vers :",
"menu": "Menu",
"mainMenu": "Menu principal",
"voicemails": "Répondeurs",
"users": "Utilisateurs"
}
},


+ 16
- 17
submodules/groups/groups.css View File

@ -235,22 +235,6 @@
content: "";
}
#groups_container .extra-node {
padding: 15px;
min-height: 30px;
border-top: 1px solid #fff;
line-height: 30px;
}
#groups_container .extra-node > * {
vertical-align: middle;
margin: 0;
}
#groups_container .extra-node > *:not(:first-child) {
margin-left: 10px;
}
#groups_container .groups-grid i.icon-telicon-multiple-items {
margin-left: 15px;
font-size: 14px;
@ -628,7 +612,7 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 50%;
width: 33.33%;
height: 150px;
border: 1px solid #FFF;
text-align: center;
@ -713,4 +697,19 @@
margin-left: 10px;
padding-left: 13px;
padding-right: 13px;
}
/* Next Action Feature */
.feature-popup-container[data-feature="next_action"] {
width: 540px;
}
.feature-popup-container[data-feature="next_action"] .next-action > * {
vertical-align: middle;
margin: 0;
}
.feature-popup-container[data-feature="next_action"] .next-action > *:not(:first-child) {
margin-left: 10px;
}

+ 127
- 77
submodules/groups/groups.js View File

@ -126,6 +126,11 @@ define(function(require){
icon: 'icon-music',
iconColor: 'icon-yellow',
title: self.i18n.active().groups.ringback.title
},
next_action: {
icon: 'icon-share-alt',
iconColor: 'icon-green',
title: self.i18n.active().groups.nextAction.title
}
},
hasFeatures: false
@ -443,6 +448,10 @@ define(function(require){
template.find('.feature[data-feature="ringback"]').on('click', function() {
self.groupsRenderRingback(data);
});
template.find('.feature[data-feature="next_action"]').on('click', function() {
self.groupsRenderNextAction(data);
});
},
groupsRenderCallRecording: function(data) {
@ -682,6 +691,77 @@ define(function(require){
});
},
groupsRenderNextAction: function(data) {
var self = this,
flow = data.callflow.flow,
selectedEntity = null;
while(flow.module != 'callflow') {
flow = flow.children['_'];
} //Go to the first callflow (i.e. base ring group)
if('_' in flow.children) {
selectedEntity = flow.children['_'].data.id;
} //Find the existing Next Action if there is one
var templateData = $.extend(true, {selectedEntity: selectedEntity}, data),
featureTemplate = $(monster.template(self, 'groups-feature-next_action', templateData)),
switchFeature = featureTemplate.find('.switch').bootstrapSwitch(),
popup;
featureTemplate.find('.cancel-link').on('click', function() {
popup.dialog('close').remove();
});
switchFeature.on('switch-change', function(e, data) {
data.value ? featureTemplate.find('.content').slideDown() : featureTemplate.find('.content').slideUp();
});
featureTemplate.find('.save').on('click', function() {
var selectedOption = featureTemplate.find('.next-action-select option:selected'),
enabled = switchFeature.bootstrapSwitch('status');
if(!('smartpbx' in data.group)) { data.group.smartpbx = {}; }
if(!('next_action' in data.group.smartpbx)) {
data.group.smartpbx.next_action = {
enabled: false
};
}
if(data.group.smartpbx.next_action.enabled || enabled) {
data.group.smartpbx.next_action.enabled = enabled;
var newCallflow = $.extend(true, {}, data.callflow),
newFlow = newCallflow.flow;
if(newFlow.module === 'record_call') {
newFlow = newFlow.children['_'];
}
newFlow.children = {};
if(enabled) {
newFlow.children['_'] = {
children: {},
module: selectedOption.data('module'),
data: { id: selectedOption.val() }
}
}
self.groupsUpdateCallflow(newCallflow, function(updatedCallflow) {
self.groupsUpdate(data.group, function(updatedGroup) {
popup.dialog('close').remove();
self.groupsRender({ groupId: data.group.id });
});
});
} else {
popup.dialog('close').remove();
self.groupsRender({ groupId: data.group.id });
}
});
popup = monster.ui.dialog(featureTemplate, {
title: data.group.extra.mapFeatures.next_action.title,
position: ['center', 20]
});
},
groupsBindName: function(template, data) {
var self = this,
nameForm = template.find('#form-name');
@ -1014,8 +1094,7 @@ define(function(require){
template.find('.save-groups').on('click', function() {
var endpoints = [],
groupId = data.id/*,
selectedEntity = template.find('.extra-node-select option:selected')*/;
groupId = data.id;
$.each(template.find('.group-row:not(.title)'), function() {
var $row = $(this),
@ -1031,11 +1110,6 @@ define(function(require){
endpoints.push(user);
});
// endpoints.extraNode = {
// id: selectedEntity.val(),
// module: selectedEntity.data('module')
// };
self.groupsUpdateBaseRingGroup(groupId, endpoints, function(data) {
self.groupsRender({ groupId: groupId });
});
@ -1210,16 +1284,6 @@ define(function(require){
});
},
// groupsGetFeaturesData: function(groupId, callback) {
// var self = this;
// self.groupsGetGroup(groupId, function(data) {
// if(!('extra') in data) { data.extra = {}; }
// $.extend(true, data.extra, self.groupsGetGroupFeatures(data));
// callback && callback(data);
// });
// },
groupsGetFeaturesData: function(groupId, callback) {
var self = this;
@ -1228,17 +1292,58 @@ define(function(require){
self.groupsGetGroup(groupId, function(data) {
callback(null, data);
});
},
users: function(callback) {
self.groupsListUsers(function(data) {
callback(null, data);
});
},
callflow: function(callback) {
self.groupsGetRingGroup(groupId, function(data) {
callback(null, data);
});
},
voicemails: function(callback) {
self.groupsListVMBoxes(function(data) {
callback(null, data);
});
},
mainMenu: function(callback) {
self.callApi({
resource: 'callflow.list',
data: {
accountId: self.accountId,
filters: { 'filter_type':'main' }
},
success: function(data) {
callback(null, data.data && data.data.length > 0 ? _.find(data.data, function(callflow) { return callflow.numbers[0] === "MainOpenHoursMenu" }) : null);
}
});
},
userCallflows: function(callback) {
self.callApi({
resource: 'callflow.list',
data: {
accountId: self.accountId,
filters: {
'has_key':'owner_id',
'filter_type':'mainUserCallflow'
}
},
success: function(data) {
callback(null, data.data);
}
});
}
},
function(err, results) {
results.group.extra = self.groupsGetGroupFeatures(results.group);
_.each(results.userCallflows, function(userCallflow) {
var user = _.find(results.users, function(user) { return userCallflow.owner_id === user.id });
if(user) {
userCallflow.userName = user.first_name + ' ' + user.last_name;
}
});
callback && callback(results);
}
);
@ -1360,48 +1465,11 @@ define(function(require){
callback(null, data);
});
},
// callflow: function(callback) {
// self.groupsGetRingGroup(groupId, function(data) {
// callback(null, data);
// });
// },
baseCallflow: function(callback) {
self.groupsGetBaseRingGroup(groupId, function(data) {
callback(null, data);
});
}/*,
voicemails: function(callback) {
self.groupsListVMBoxes(function(data) {
callback(null, data);
});
},
mainMenu: function(callback) {
self.callApi({
resource: 'callflow.list',
data: {
accountId: self.accountId,
filters: { 'filter_type':'main' }
},
success: function(data) {
callback(null, data.data && data.data.length > 0 ? _.find(data.data, function(callflow) { return callflow.numbers[0] === "MainOpenHoursMenu" }) : null);
}
});
},
userCallflows: function(callback) {
self.callApi({
resource: 'callflow.list',
data: {
accountId: self.accountId,
filters: {
'has_key':'owner_id',
'key_missing':'type'
}
},
success: function(data) {
callback(null, data.data);
}
});
}*/
}
},
function(err, results) {
globalCallback && globalCallback(results);
@ -1413,25 +1481,12 @@ define(function(require){
groupsFormatMembersData: function(data) {
var self = this,
mapUsers = {},
flow = data.baseCallflow.flow/*,
callEntities = {
mainMenu: data.mainMenu,
voicemails: data.voicemails.sort(function(a,b) { return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1; }),
userCallflows : []
}*/;
flow = data.baseCallflow.flow;
_.each(data.users, function(user) {
mapUsers[user.id] = user;
// var userCallflow = _.find(data.userCallflows, function(callflow) { return callflow.owner_id === user.id });
// if(userCallflow) {
// userCallflow.userName = user.first_name + ' ' + user.last_name;
// callEntities.userCallflows.push(userCallflow);
// }
});
// callEntities.userCallflows.sort(function(a,b) { return a.userName.toLowerCase() > b.userName.toLowerCase() ? 1 : -1; });
var endpoints = flow.data.endpoints;
_.each(endpoints, function(endpoint) {
@ -1449,12 +1504,7 @@ define(function(require){
data.group.extra = {
ringGroup: endpoints,
remainingUsers: mapUsers/*,
callEntities: callEntities,
selectedEntity: flow.children['_'] ? {
id: flow.children['_'].data.id,
module: flow.children['_'].module
} : null*/
remainingUsers: mapUsers
};
return data.group;


+ 42
- 0
views/groups-feature-next_action.html View File

@ -0,0 +1,42 @@
<div class="feature-popup-container" data-feature="next_action">
<div class="feature-popup-title">
<div class="feature-icon-wrapper">
<i class="{{group.extra.mapFeatures.next_action.icon}}"></i>
</div>
{{ i18n.groups.nextAction.headline }}
<div class="switch" data-on="success" data-off="default" data-on-label="{{i18n.enabled}}" data-off-label="{{i18n.disabled}}">
<input type="checkbox"{{#if group.extra.mapFeatures.next_action.active}} checked="checked"{{/if}}></input>
</div>
</div>
<div class="content{{#unless group.extra.mapFeatures.next_action.active}} disabled{{/unless}}">
<div class="next-action">
<span>{{ i18n.groups.nextAction.label }}</span>
<select class="next-action-select">
<optgroup label="{{ i18n.groups.nextAction.menu }}">
{{#if mainMenu}}
<option value="{{mainMenu.id}}" data-module="callflow" {{#compare selectedEntity '===' mainMenu.id}}selected{{/compare}}>{{ i18n.groups.nextAction.mainMenu }}</option>
{{/if}}
</optgroup>
<optgroup label="{{ i18n.groups.nextAction.voicemails }}">
{{#each voicemails}}
<option value="{{id}}" data-module="voicemail" {{#compare ../selectedEntity '===' id}}selected{{/compare}}>{{name}}</option>
{{/each}}
</optgroup>
<optgroup label="{{ i18n.groups.nextAction.users }}">
{{#each userCallflows}}
<option value="{{id}}" data-module="callflow" {{#compare ../selectedEntity '===' id}}selected{{/compare}}>{{userName}}</option>
{{/each}}
</optgroup>
</select>
</div>
</div>
<div class="actions clearfix">
<div class="pull-right">
<a class="cancel-link monster-link blue" href="javascript:void(0);">{{ i18n.cancel }}</a>
<button type="button" class="btn btn-success save">{{ i18n.saveChanges }}</button>
</div>
</div>
</div>

Loading…
Cancel
Save