Browse Source

UI-3307: Set Account External Caller ID number when adding main numbers, if not set already (#120)

* Change styles file extension from .css to .scss, to use SASS

* Set style for e911 information banner

* Show main company numbers section and E911 popup on banner click

* Refactor strategyRefreshTemplate to receive arguments via object wrapper

* Pass action from myOffice layout to strategy.strategyRefreshTemplate

* Check e911 number availability and show edit dialog or toast

* Fix typo in property name

* Extract main numbers refresh template process into separate function

* Refactor to use Lodash instead of jQuery utility functions

* Pass action to banner via topMessage object

* Refactor checkMissingE911 function

* Convert action to object, to include more parameters

* Add action callback for e911 at numbers strategy

* Fixes on flow to check if update Emergency Caller ID

* Request current account from API, when checking to update E911 caller ID

* Fix e911 phone number filter

* Use current authenticated account instead of requesting it from API

* Modify strategyNumbersBindEvents to use Lodash and reduce duplicated code

* Refactor updateCallflow to use waterfall flow, and helper functions

* Modifications to E911 functions

To prevent invoking strategyChangeEmergencyCallerId from multiple places

* Generalize popup to choose numbers + function to check if external caller ID needs to be set

* Fixes on update e911 waterfall tasks

* Set active choice on caller ID popup

* Remove log entry
4.3
Guillermo Gutiérrez 7 years ago
committed by Joris Tirado
parent
commit
9aeef9283f
6 changed files with 293 additions and 190 deletions
  1. +16
    -8
      i18n/de-DE.json
  2. +21
    -10
      i18n/en-US.json
  3. +16
    -6
      i18n/ru-RU.json
  4. +214
    -140
      submodules/strategy/strategy.js
  5. +26
    -0
      submodules/strategy/views/changeCallerIdPopup.html
  6. +0
    -26
      submodules/strategy/views/changeE911Popup.html

+ 16
- 8
i18n/de-DE.json View File

@ -1010,14 +1010,22 @@
}
},
"__comment": "UI-2629: Optionen zum Anpassen der e911-Funktion hinzugefügt",
"__version": "4.0",
"updateE911Dialog": {
"title": "Anrufer-ID des Accounts für Notfälle",
"headerNewE911": "Sie haben gerade e911 für eine Ihrer Hauptnummern aktiviert. Bitte wählen Sie eine Nummer aus, die Sie für diesen Account als Ihre Anrufer-ID für Notfälle verwenden möchten.",
"headerNoE911": "Sie haben e911 für die Nummer deaktiviert, die als Ihre Anrufer-ID für Notfälle verwendet wurde. Bitte wählen Sie eine neue Nummer aus, die für diesen Account als Anrufer-ID für Notfälle dienen soll.",
"success": "e911 wurde für den Account erfolgreich geändert und lautet nun {{ number }}.",
"current": "Aktuelle"
"updateCallerIdDialog": {
"title": {
"emergency": "Anrufer-ID des Accounts für Notfälle"
},
"headerNewNumber": {
"emergency": "Sie haben gerade e911 für eine Ihrer Hauptnummern aktiviert. Bitte wählen Sie eine Nummer aus, die Sie für diesen Account als Ihre Anrufer-ID für Notfälle verwenden möchten."
},
"headerNoNumber": {
"emergency": "Sie haben e911 für die Nummer deaktiviert, die als Ihre Anrufer-ID für Notfälle verwendet wurde. Bitte wählen Sie eine neue Nummer aus, die für diesen Account als Anrufer-ID für Notfälle dienen soll."
},
"success": {
"emergency": "e911 wurde für den Account erfolgreich geändert und lautet nun {{ number }}."
},
"current": {
"emergency": "Aktuelle"
}
}
},


+ 21
- 10
i18n/en-US.json View File

@ -1029,18 +1029,29 @@
}
},
"__comment": "UI-2629: add options to customize e911",
"__version": "4.0",
"updateE911Dialog": {
"title": "Account Emergency Caller-ID",
"headerNewE911": "You've just turned E911 on one of your main number, please select which number you would like to use for your Account Emergency Caller-ID.",
"headerNoE911": "You've disabled E911 on the number that was used for your Emergency Caller-ID, please select a new number to use as this Account Emergency Caller-ID.",
"success": "You successfully updated the E911 on the account to be {{ number }}.",
"current": "Current one"
},
"buttons": {
"reset": "Reset"
},
"updateCallerIdDialog": {
"title": {
"emergency": "Account Emergency Caller-ID",
"external": "Account External Caller-ID"
},
"headerNewNumber": {
"emergency": "You've just turned E911 on one of your main number, please select which number you would like to use for your Account Emergency Caller-ID."
},
"headerNoNumber": {
"emergency": "You've disabled E911 on the number that was used for your Emergency Caller-ID, please select a new number to use as this Account Emergency Caller-ID.",
"external": "You've not set the external number for the account yet, please select a new number to use as this Account External Caller-ID."
},
"success": {
"emergency": "You successfully updated the E911 on the account to be {{ number }}.",
"external": "You successfully updated the external caller ID on the account to be {{ number }}."
},
"current": {
"emergency": "Current one"
}
}
},


+ 16
- 6
i18n/ru-RU.json View File

@ -815,12 +815,22 @@
}
},
"updateE911Dialog": {
"title": "АОН учетной записи для экстренных служб",
"headerNewE911": "Вы только-что активировали использование E911 для одного из выших основных номеров. Пожалуйста выберете какой номер Вы желаете использовать как АОН для экстренных служб.",
"headerNoE911": "Вы отключили использование E911 для номера который ранее использовался как АОН для экстренных служб. Пожалуйста выберете новый номер для использования в качестве АОНа для экстренных служб.",
"success": "Вы успешно обновили значение E911 учетной записи. Новое значение {{ number }}.",
"current": "Один текущий"
"updateCallerIdDialog": {
"title": {
"emergency": "АОН учетной записи для экстренных служб"
},
"headerNewNumber": {
"emergency": "Вы только-что активировали использование E911 для одного из выших основных номеров. Пожалуйста выберете какой номер Вы желаете использовать как АОН для экстренных служб."
},
"headerNoNumber": {
"emergency": "Вы отключили использование E911 для номера который ранее использовался как АОН для экстренных служб. Пожалуйста выберете новый номер для использования в качестве АОНа для экстренных служб."
},
"success": {
"emergency": "Вы успешно обновили значение E911 учетной записи. Новое значение {{ number }}."
},
"current": {
"emergency": "Один текущий"
}
}
},


+ 214
- 140
submodules/strategy/strategy.js View File

@ -357,20 +357,22 @@ define(function(require) {
/**
* Show e911 number choices
* @param {Object} args
* @param {('emergency'|'external')} args.callerIdType Caller ID type: emergency, external
* @param {String} args.oldNumber Old E911 number
* @param {String[]} args.newNumbers New E911 numbers
* @param {Function} [args.success] Success callback
* @param {Function} [args.error] Error callback
* @param {Function} [args.save] Save callback
* @param {Function} [args.cancel] Cancel callback
*/
strategyShowE911Choices: function(args) {
strategyShowNumberChoices: function(args) {
var self = this,
callerIdType = args.callerIdType,
oldNumber = args.oldNumber,
template = $(self.getTemplate({
name: 'changeE911Popup',
name: 'changeCallerIdPopup',
data: {
oldNumber: oldNumber,
newNumbers: args.newNumbers
newNumbers: args.newNumbers,
callerIdType: callerIdType
},
submodule: 'strategy'
})),
@ -386,29 +388,12 @@ define(function(require) {
var number = template.find('.active').data('number');
if (number === oldNumber) {
popup.dialog('close');
_.has(args, 'cancel') && args.cancel();
} else {
self.strategyChangeEmergencyCallerId({
number: number,
success: function(number) {
monster.ui.toast({
type: 'success',
message: self.getTemplate({
name: '!' + self.i18n.active().strategy.updateE911Dialog.success,
data: {
number: monster.util.formatPhoneNumber(number)
}
})
});
popup.dialog('close');
_.has(args, 'success') && args.success(number);
},
error: function(parsedError) {
_.has(args, 'error') && args.error(parsedError);
}
});
_.has(args, 'save') && args.save(number);
}
popup.dialog('close');
});
template.find('.cancel-link').on('click', function() {
@ -418,7 +403,7 @@ define(function(require) {
});
var popup = monster.ui.dialog(template, {
title: self.i18n.active().strategy.updateE911Dialog.title
title: self.i18n.active().strategy.updateCallerIdDialog.title[callerIdType]
});
},
@ -476,7 +461,62 @@ define(function(require) {
},
/**
*
* Check if it is necessary to set the external caller ID for the account
* @param {Object} args
* @param {String[]} args.numbers Available phone numbers
*/
strategyCheckIfSetExternalCallerID: function(args) {
var self = this,
numbers = args.numbers,
currAcc = monster.apps.auth.currentAccount,
hasExternalCallerId = _.get(currAcc, 'caller_id.external.number', '') !== '';
if (hasExternalCallerId || _.isEmpty(numbers)) {
return;
}
monster.waterfall([
function(callback) {
if (numbers.length > 1) {
self.strategyShowNumberChoices({
callerIdType: 'external',
newNumbers: numbers,
save: function(number) {
callback(null, number);
},
cancel: function() {
callback(null);
}
});
} else {
callback(null, numbers[0]);
}
}
], function(err, number) {
if (err || !number) {
return;
}
self.strategyChangeCallerId({
callerIdType: 'external',
number: number,
success: function() {
monster.ui.toast({
type: 'success',
message: self.getTemplate({
name: '!' + self.i18n.active().strategy.updateCallerIdDialog.success.external,
data: {
number: monster.util.formatPhoneNumber(number)
}
})
});
}
});
});
},
/**
* Check if it is necessary to update the emergency caller ID for the account
* @param {Object} args
* @param {Object[]} args.templateNumbers Template numbers
* @param {String[]} args.features Number features
@ -504,27 +544,14 @@ define(function(require) {
hasE911Feature = _.includes(features || [], 'e911');
if (hasE911Feature && !hasEmergencyCallerId) {
self.strategyChangeEmergencyCallerId({
number: number,
success: function() {
callback({});
},
error: function(parsedError) {
callback(_.merge({
isError: true
}, parsedError));
}
});
callback('OK', number);
} else if (!hasEmergencyCallerId) {
callback('OK');
} else {
callback(null, currAcc, hasEmergencyCallerId, hasE911Feature);
callback(null, currAcc, hasE911Feature);
}
},
function(currAcc, hasEmergencyCallerId, hasE911Feature, callback) {
if (!hasEmergencyCallerId) {
callback({});
return;
}
function(currAcc, hasE911Feature, callback) {
var e911ChoicesArgs;
if (hasE911Feature) {
@ -548,25 +575,44 @@ define(function(require) {
}
if (_.isUndefined(e911ChoicesArgs)) {
callback({});
callback('OK');
} else {
callback(null, e911ChoicesArgs);
}
},
function(e911ChoicesArgs, callback) {
var executeCallback = function() {
callback();
};
self.strategyShowE911Choices(_.merge({
success: executeCallback,
cancel: executeCallback
self.strategyShowNumberChoices(_.merge({
callerIdType: 'emergency',
save: function(number) {
callback(null, number);
},
cancel: function() {
callback('OK');
}
}, e911ChoicesArgs));
}
], function(err) {
if (!err || _.isEmpty(err)) {
_.has(args, 'callbacks.success') && args.callbacks.success();
], function(err, number) {
if ((err && err !== 'OK') || !number) {
return;
}
self.strategyChangeCallerId({
callerIdType: 'emergency',
number: number,
success: function() {
monster.ui.toast({
type: 'success',
message: self.getTemplate({
name: '!' + self.i18n.active().strategy.updateCallerIdDialog.success.emergency,
data: {
number: monster.util.formatPhoneNumber(number)
}
})
});
_.has(args, 'callbacks.success') && args.callbacks.success();
}
});
});
},
@ -949,27 +995,25 @@ define(function(require) {
self.strategyListAccountNumbers(function(accountNumbers) {
var callflow = strategyData.callflows.MainCallflow,
numbers = callflow.numbers,
templateData = {
hideBuyNumbers: _.has(monster.config.whitelabel, 'hideBuyNumbers')
? monster.config.whitelabel.hideBuyNumbers
: false,
numbers: _.chain(numbers)
.filter(function(val) {
return val !== '0' && val !== 'undefinedMainNumber';
}).map(function(val) {
var ret = {
number: {
id: val
}
};
if (_.has(accountNumbers, val)) {
ret.number = _.merge(accountNumbers[val], ret.number);
numbers: _.map(self.strategyExtractMainNumbers({
mainCallflow: callflow
}), function(val) {
var ret = {
number: {
id: val
}
};
return ret;
}).value(),
if (_.has(accountNumbers, val)) {
ret.number = _.merge(accountNumbers[val], ret.number);
}
return ret;
}),
spareLinkEnabled: (_.countBy(accountNumbers, function(number) { return number.used_by ? 'assigned' : 'spare'; }).spare > 0)
},
template = $(self.getTemplate({
@ -1068,14 +1112,16 @@ define(function(require) {
},
/**
* Change the emergency caller ID for the current account
* Changes a caller ID for the current account
* @param {Object} args
* @param {('emergency'|'external')} args.callerIdType Caller ID type: emergency, external
* @param {String} args.number Number to be set for emergency calls
* @param {Function} [args.success] Success callback
* @param {Function} [args.error] Error callback
*/
strategyChangeEmergencyCallerId: function(args) {
strategyChangeCallerId: function(args) {
var self = this,
callerIdType = args.callerIdType,
number = args.number;
monster.waterfall([
@ -1091,8 +1137,8 @@ define(function(require) {
},
function(data, callback) {
data.caller_id = data.caller_id || {};
data.caller_id.emergency = data.caller_id.emergency || {};
data.caller_id.emergency.number = number;
data.caller_id[callerIdType] = data.caller_id[callerIdType] || {};
data.caller_id[callerIdType].number = number;
self.strategyUpdateAccount({
data: data,
@ -1116,30 +1162,36 @@ define(function(require) {
strategyNumbersBindEvents: function(container, strategyData) {
var self = this,
addNumbersToMainCallflow = function(numbers) {
if (numbers.length) {
var mainCallflow = strategyData.callflows.MainCallflow,
indexPlaceholder = mainCallflow.numbers.indexOf('undefinedMainNumber');
if (_.isEmpty(numbers)) {
return;
}
if (indexPlaceholder >= 0) {
mainCallflow.numbers[indexPlaceholder] = '0';
}
var mainCallflow = strategyData.callflows.MainCallflow,
indexPlaceholder = mainCallflow.numbers.indexOf('undefinedMainNumber');
mainCallflow.numbers = mainCallflow.numbers.concat(numbers);
if (indexPlaceholder >= 0) {
mainCallflow.numbers[indexPlaceholder] = '0';
}
self.strategyUpdateCallflow(mainCallflow, function(updatedCallflow) {
var parentContainer = container.parents('.element-container');
strategyData.callflows.MainCallflow = updatedCallflow;
refreshNumbersHeader(parentContainer);
self.strategyRefreshTemplate({
container: parentContainer,
strategyData: strategyData
});
mainCallflow.numbers = mainCallflow.numbers.concat(numbers);
self.strategyUpdateCallflow(mainCallflow, function(updatedCallflow) {
strategyData.callflows.MainCallflow = updatedCallflow;
refreshNumbersTemplate();
self.strategyCheckIfSetExternalCallerID({
numbers: self.strategyExtractMainNumbers({
mainCallflow: updatedCallflow
})
});
}
});
},
refreshNumbersHeader = function(parentContainer) {
refreshNumbersTemplate = function() {
var mainCallflow = strategyData.callflows.MainCallflow,
parentContainer = container.parents('.element-container'),
headerSpan = parentContainer.find('.element-header-inner .summary > span');
// Refresh headers
if (mainCallflow.numbers.length > 1) {
headerSpan.html(monster.util.formatPhoneNumber(mainCallflow.numbers[1]));
if (mainCallflow.numbers.length > 3) {
@ -1160,6 +1212,12 @@ define(function(require) {
container.parents('#strategy_container').find('.element-container.helper').show();
container.parents('#strategy_container').find('.element-container.main-number').css('margin-top', '10px');
}
// Refresh template
self.strategyRefreshTemplate({
container: parentContainer,
strategyData: strategyData
});
};
container.on('click', '.action-links .spare-link:not(.disabled)', function(e) {
@ -1169,7 +1227,7 @@ define(function(require) {
accountName: monster.apps.auth.currentAccount.name,
accountId: self.accountId,
callback: function(numberList) {
var numbers = $.map(numberList, function(val) {
var numbers = _.map(numberList, function(val) {
return val.phoneNumber;
});
addNumbersToMainCallflow(numbers);
@ -1222,55 +1280,56 @@ define(function(require) {
popupHtml,
popup,
updateCallflow = function() {
strategyData.callflows.MainCallflow.numbers.splice(indexToRemove, 1);
// We don't want the '0' to stay in the routing system if they're no longer using SmartPBX.
// If they remove their last main number, we consider they don't use SmartPBX, so we reset the "0" to be the "undefinedMainNumber"
if (strategyData.callflows.MainCallflow.numbers.length === 1 && strategyData.callflows.MainCallflow.numbers[0] === '0') {
strategyData.callflows.MainCallflow.numbers[0] = 'undefinedMainNumber';
}
monster.waterfall([
function(callback) {
strategyData.callflows.MainCallflow.numbers.splice(indexToRemove, 1);
// We don't want the '0' to stay in the routing system if they're no longer using SmartPBX.
// If they remove their last main number, we consider they don't use SmartPBX, so we reset the "0" to be the "undefinedMainNumber"
if (strategyData.callflows.MainCallflow.numbers.length === 1 && strategyData.callflows.MainCallflow.numbers[0] === '0') {
strategyData.callflows.MainCallflow.numbers[0] = 'undefinedMainNumber';
}
self.strategyUpdateCallflow(strategyData.callflows.MainCallflow, function(updatedCallflow) {
var parentContainer = container.parents('.element-container');
monster.ui.toast({
type: 'success',
message: self.i18n.active().strategy.toastrMessages.removeNumberSuccess
});
strategyData.callflows.MainCallflow = updatedCallflow;
refreshNumbersHeader(parentContainer);
self.strategyRefreshTemplate({
container: parentContainer,
strategyData: strategyData
});
self.strategyUpdateCallflow(strategyData.callflows.MainCallflow, function(updatedCallflow) {
callback(null, updatedCallflow);
});
},
function(updatedCallflow, callback) {
monster.ui.toast({
type: 'success',
message: self.i18n.active().strategy.toastrMessages.removeNumberSuccess
});
strategyData.callflows.MainCallflow = updatedCallflow;
refreshNumbersTemplate(updateCallflow);
//Updating Company Caller ID if this was the selected number
self.callApi({
resource: 'account.get',
data: {
accountId: self.accountId
},
success: function(accountData) {
var modified = false;
if ('caller_id' in accountData.data && 'external' in accountData.data.caller_id && accountData.data.caller_id.external.number === numberToRemove) {
delete accountData.data.caller_id.external;
modified = true;
}
if ('caller_id' in accountData.data && 'emergency' in accountData.data.caller_id && accountData.data.caller_id.emergency.number === numberToRemove) {
delete accountData.data.caller_id.emergency;
modified = true;
}
if (modified) {
self.callApi({
resource: 'account.update',
data: {
accountId: self.accountId,
data: accountData.data
},
success: function(data) {}
});
self.strategyGetAccount({
success: function(accountData) {
callback(null, accountData);
}
}
});
});
}
], function(err, accountData) {
if (err) {
return;
}
var modified = false;
// TODO: Maybe before unsetting external caller_id, ask user to choose another, if any other number is available
if (_.get(accountData, 'caller_id.external.number') === numberToRemove) {
delete accountData.caller_id.external;
modified = true;
}
if (_.get(accountData, 'caller_id.emergency.number') === numberToRemove) {
delete accountData.caller_id.emergency;
modified = true;
}
if (modified) {
self.strategyUpdateAccount({
data: accountData
});
}
});
};
@ -4582,6 +4641,21 @@ define(function(require) {
function(err, results) {
args.callback(err, _.reduce(results, _.assign));
});
},
/**
* Extracts the phone numbers from the main callflow
* @param {Object} args
* @param {Object} args.mainCallflow Main callflow
* @returns {String[]} Phone numbers
*/
strategyExtractMainNumbers: function(args) {
var self = this,
mainCallflow = args.mainCallflow;
return _.filter(mainCallflow.numbers, function(val) {
return val !== '0' && val !== 'undefinedMainNumber';
});
}
};


+ 26
- 0
submodules/strategy/views/changeCallerIdPopup.html View File

@ -0,0 +1,26 @@
<div class="e911-change-wrapper">
<div class="header">
{{#if oldNumber}}
{{ tryI18n i18n.strategy.updateCallerIdDialog.headerNewNumber callerIdType }}
{{else}}
{{ tryI18n i18n.strategy.updateCallerIdDialog.headerNoNumber callerIdType }}
{{/if}}
</div>
<div class="list-choices">
{{#if oldNumber}}
<div class="choice active" data-number="{{oldNumber}}">{{ formatPhoneNumber oldNumber }} <span class="current">({{ tryI18n i18n.strategy.updateCallerIdDialog.current callerIdType }})</span></div>
{{/if}}
{{#each newNumbers}}
<div class="choice{{#unless ../oldNumber}}{{#if @first}} active{{/if}}{{/unless}}" data-number="{{this}}">{{ formatPhoneNumber this }}</div>
{{/each}}
</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="monster-button monster-button-success save">{{ i18n.save }}</button>
</div>
</div>
</div>

+ 0
- 26
submodules/strategy/views/changeE911Popup.html View File

@ -1,26 +0,0 @@
<div class="e911-change-wrapper">
<div class="header">
{{#if oldNumber}}
{{ i18n.strategy.updateE911Dialog.headerNewE911 }}
{{else}}
{{ i18n.strategy.updateE911Dialog.headerNoE911 }}
{{/if}}
</div>
<div class="list-choices">
{{#if oldNumber}}
<div class="choice" data-number="{{oldNumber}}">{{ formatPhoneNumber oldNumber }} <span class="current">({{ i18n.strategy.updateE911Dialog.current }})</span></div>
{{/if}}
{{#each newNumbers}}
<div class="choice" data-number="{{this}}">{{ formatPhoneNumber this }}</div>
{{/each}}
</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="monster-button monster-button-success save">{{ i18n.save }}</button>
</div>
</div>
</div>

Loading…
Cancel
Save