diff --git a/src/apps/common/i18n/de-DE.json b/src/apps/common/i18n/de-DE.json index ab15f2465..341428c56 100644 --- a/src/apps/common/i18n/de-DE.json +++ b/src/apps/common/i18n/de-DE.json @@ -1004,43 +1004,5 @@ "deleteConferences": "Die Konferenzen dieses Benutzers ebenfalls entfernen", "deleteConferencesHelp": "Wenn Sie diese Option deaktiviert lassen, werden Sie die Konferenznummer des Benutzers nirgends anders verwenden können, da sie weiterhin von dieser Konferenz belegt sein wird." } - }, - - "numberMessaging": { - "titles": { - "sms": "SMS", - "mms": "MMS", - "dialog": "Messaging Configuration: {{phoneNumber}}" - }, - "labels": { - "sms": "Enable SMS Services", - "mms": "Enable MMS Services", - "messaging": "Messaging" - }, - "select": { - "noOwner": "- No owner selected -", - "noMember": "- No members selected -" - }, - "info": "In order to configure MMS capabilities, SMS must be enabled first.", - "ownerInfo": "All Messaging DIDs must have an owner.", - "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}", - "messagingServicesUnavailable": "SMS and MMS services are disabled. Contact your service provider for more information.", - "mfaNotice": "Messaging requires multi-factor authentication to be enabled for all users on your account. This requirement ensures ongoing compliance and secure access to Messaging features.", - "configureSmsBox": { - "label": "Create and configure message box", - "info": "This setting applies only to messaging boxes managed through the platform's official applications and does not affect customer-supplied or third-party integrations.", - "textingCampaignRegistrationNotice": "This phone number must be approved for texting before you can send and receive text messages. Please complete the Text Campaign Registration process in the Trunking.io application.", - "owner": "Owner", - "additionalMembers": "Additional Members" - }, - "mfaNotConfiguredError": "MFA has not been configured for this account. Contact your administrator.", - "mfaEnabledDialog": { - "title": "Multi-factor authentication enabled for your account.", - "description": "Messaging requires multi-factor authentication to be enabled for all users on your account. To continue using Messaging, please ensure MFA is set up through your preferred authentication app." - }, - "buttons": { - "close": "Close", - "saveChanges": "Save changes" - } } } diff --git a/src/apps/common/i18n/en-US.json b/src/apps/common/i18n/en-US.json index 5536d32b7..d9d102154 100644 --- a/src/apps/common/i18n/en-US.json +++ b/src/apps/common/i18n/en-US.json @@ -1647,12 +1647,14 @@ "titles": { "sms": "SMS", "mms": "MMS", - "dialog": "Messaging Configuration: {{phoneNumber}}" + "dialog": "Configure Messaging" }, "labels": { "sms": "Enable SMS Services", "mms": "Enable MMS Services", - "messaging": "Messaging" + "messaging": "Messaging", + "owner": "Owner*", + "additionalMembers": "Additional Members" }, "select": { "noOwner": "- No owner selected -", @@ -1660,24 +1662,6 @@ }, "info": "In order to configure MMS capabilities, SMS must be enabled first.", "ownerInfo": "All Messaging DIDs must have an owner.", - "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}", - "messagingServicesUnavailable": "SMS and MMS services are disabled. Contact your service provider for more information.", - "mfaNotice": "Messaging requires multi-factor authentication to be enabled for all users on your account. This requirement ensures ongoing compliance and secure access to Messaging features.", - "configureSmsBox": { - "label": "Create and configure message box", - "info": "This setting applies only to messaging boxes managed through the platform's official applications and does not affect customer-supplied or third-party integrations.", - "textingCampaignRegistrationNotice": "This phone number must be approved for texting before you can send and receive text messages. Please complete the Text Campaign Registration process in the Trunking.io application.", - "owner": "Owner", - "additionalMembers": "Additional Members" - }, - "mfaNotConfiguredError": "MFA has not been configured for this account. Contact your administrator.", - "mfaEnabledDialog": { - "title": "Multi-factor authentication enabled for your account.", - "description": "Messaging requires multi-factor authentication to be enabled for all users on your account. To continue using Messaging, please ensure MFA is set up through your preferred authentication app." - }, - "buttons": { - "close": "Close", - "saveChanges": "Save changes" - } + "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}" } } diff --git a/src/apps/common/i18n/fr-FR.json b/src/apps/common/i18n/fr-FR.json index ad3cfe6fc..462fa1e4a 100644 --- a/src/apps/common/i18n/fr-FR.json +++ b/src/apps/common/i18n/fr-FR.json @@ -329,43 +329,5 @@ "usedBy": "Elle correspond au téléphone nommé {{variable}}." } } - }, - - "numberMessaging": { - "titles": { - "sms": "SMS", - "mms": "MMS", - "dialog": "Messaging Configuration: {{phoneNumber}}" - }, - "labels": { - "sms": "Enable SMS Services", - "mms": "Enable MMS Services", - "messaging": "Messaging" - }, - "select": { - "noOwner": "- No owner selected -", - "noMember": "- No members selected -" - }, - "info": "In order to configure MMS capabilities, SMS must be enabled first.", - "ownerInfo": "All Messaging DIDs must have an owner.", - "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}", - "messagingServicesUnavailable": "SMS and MMS services are disabled. Contact your service provider for more information.", - "mfaNotice": "Messaging requires multi-factor authentication to be enabled for all users on your account. This requirement ensures ongoing compliance and secure access to Messaging features.", - "configureSmsBox": { - "label": "Create and configure message box", - "info": "This setting applies only to messaging boxes managed through the platform's official applications and does not affect customer-supplied or third-party integrations.", - "textingCampaignRegistrationNotice": "This phone number must be approved for texting before you can send and receive text messages. Please complete the Text Campaign Registration process in the Trunking.io application.", - "owner": "Owner", - "additionalMembers": "Additional Members" - }, - "mfaNotConfiguredError": "MFA has not been configured for this account. Contact your administrator.", - "mfaEnabledDialog": { - "title": "Multi-factor authentication enabled for your account.", - "description": "Messaging requires multi-factor authentication to be enabled for all users on your account. To continue using Messaging, please ensure MFA is set up through your preferred authentication app." - }, - "buttons": { - "close": "Close", - "saveChanges": "Save changes" - } } } diff --git a/src/apps/common/i18n/nl-NL.json b/src/apps/common/i18n/nl-NL.json index 434d7ce2f..ab4730450 100644 --- a/src/apps/common/i18n/nl-NL.json +++ b/src/apps/common/i18n/nl-NL.json @@ -239,43 +239,5 @@ }, "saveSuccess": "De Carrier instellingen zijn succesvol verwerkt voor dit account!", "huntError": "Uw bestande instellingen voor de No_match route worden niet ondersteund door de MONSTER UI, wilt u toch doorgaan verander dan niets in dit scherm. U kunt een en ander ook aanpassen door een optie te selecteren in de dropdown!" - }, - - "numberMessaging": { - "titles": { - "sms": "SMS", - "mms": "MMS", - "dialog": "Messaging Configuration: {{phoneNumber}}" - }, - "labels": { - "sms": "Enable SMS Services", - "mms": "Enable MMS Services", - "messaging": "Messaging" - }, - "select": { - "noOwner": "- No owner selected -", - "noMember": "- No members selected -" - }, - "info": "In order to configure MMS capabilities, SMS must be enabled first.", - "ownerInfo": "All Messaging DIDs must have an owner.", - "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}", - "messagingServicesUnavailable": "SMS and MMS services are disabled. Contact your service provider for more information.", - "mfaNotice": "Messaging requires multi-factor authentication to be enabled for all users on your account. This requirement ensures ongoing compliance and secure access to Messaging features.", - "configureSmsBox": { - "label": "Create and configure message box", - "info": "This setting applies only to messaging boxes managed through the platform's official applications and does not affect customer-supplied or third-party integrations.", - "textingCampaignRegistrationNotice": "This phone number must be approved for texting before you can send and receive text messages. Please complete the Text Campaign Registration process in the Trunking.io application.", - "owner": "Owner", - "additionalMembers": "Additional Members" - }, - "mfaNotConfiguredError": "MFA has not been configured for this account. Contact your administrator.", - "mfaEnabledDialog": { - "title": "Multi-factor authentication enabled for your account.", - "description": "Messaging requires multi-factor authentication to be enabled for all users on your account. To continue using Messaging, please ensure MFA is set up through your preferred authentication app." - }, - "buttons": { - "close": "Close", - "saveChanges": "Save changes" - } } } diff --git a/src/apps/common/i18n/ru-RU.json b/src/apps/common/i18n/ru-RU.json index a85ba0896..3a8cb364a 100644 --- a/src/apps/common/i18n/ru-RU.json +++ b/src/apps/common/i18n/ru-RU.json @@ -298,43 +298,5 @@ "deleteConferences": "Также удалить конференц-комнаты пользователя из системы", "deleteConferencesHelp": "Если оставите эту опцию не выделенной, Вы не сможете использовать номер конференции пользователя где-либо еще, так как он будет использоваться данной конференцией." } - }, - - "numberMessaging": { - "titles": { - "sms": "SMS", - "mms": "MMS", - "dialog": "Messaging Configuration: {{phoneNumber}}" - }, - "labels": { - "sms": "Enable SMS Services", - "mms": "Enable MMS Services", - "messaging": "Messaging" - }, - "select": { - "noOwner": "- No owner selected -", - "noMember": "- No members selected -" - }, - "info": "In order to configure MMS capabilities, SMS must be enabled first.", - "ownerInfo": "All Messaging DIDs must have an owner.", - "successUpdate": "You successfully updated the messaging configuration for {{phoneNumber}}", - "messagingServicesUnavailable": "SMS and MMS services are disabled. Contact your service provider for more information.", - "mfaNotice": "Messaging requires multi-factor authentication to be enabled for all users on your account. This requirement ensures ongoing compliance and secure access to Messaging features.", - "configureSmsBox": { - "label": "Create and configure message box", - "info": "This setting applies only to messaging boxes managed through the platform's official applications and does not affect customer-supplied or third-party integrations.", - "textingCampaignRegistrationNotice": "This phone number must be approved for texting before you can send and receive text messages. Please complete the Text Campaign Registration process in the Trunking.io application.", - "owner": "Owner", - "additionalMembers": "Additional Members" - }, - "mfaNotConfiguredError": "MFA has not been configured for this account. Contact your administrator.", - "mfaEnabledDialog": { - "title": "Multi-factor authentication enabled for your account.", - "description": "Messaging requires multi-factor authentication to be enabled for all users on your account. To continue using Messaging, please ensure MFA is set up through your preferred authentication app." - }, - "buttons": { - "close": "Close", - "saveChanges": "Save changes" - } } } diff --git a/src/apps/common/submodules/numberMessaging/numberMessaging.js b/src/apps/common/submodules/numberMessaging/numberMessaging.js index 749ca687e..d149d61d5 100644 --- a/src/apps/common/submodules/numberMessaging/numberMessaging.js +++ b/src/apps/common/submodules/numberMessaging/numberMessaging.js @@ -10,18 +10,17 @@ define(function(require) { }, appFlags: { - users: {} + users: {}, + isCarrierTio: false, + oomaSmsBox: {} }, /** - * Render dialog to edit number messaging settings. * @param {Object} args - * @param {String} args.phoneNumber Phone number to edit. - * @param {Object} [args.accountId] ID of the account that owns the phone number. - * If not specified, the current account ID is used. - * @param {Object} [args.callbacks] Callback functions. - * @param {Function} [args.callbacks.success] Success callback. - * @param {Function} [args.callbacks.error] Error callback. + * @param {String} args.phoneNumber + * @param {Object} [args.accountId] + * @param {Function} [args.callbacks.success] + * @param {Function} [args.callbacks.error] */ numberMessagingEdit: function(args) { var self = this, @@ -33,343 +32,133 @@ define(function(require) { accountId: accountId, number: args.phoneNumber, success: function(numberData) { - callback && callback(null, { numberData: numberData }); + callback && callback(null, {numberData: numberData}); } }); }, - function(wrappedNumberData, callback) { - wrappedNumberData.isCarrierTio = _.get(wrappedNumberData, 'numberData.metadata.carrier_module') === 'trunkingio'; - - if (!wrappedNumberData.isCarrierTio) { - callback && callback(null, wrappedNumberData); - return; - } - - monster.parallel({ - users: function(callback) { - var storedUsers = self.appFlags.users[accountId]; - - if (storedUsers) { - callback && callback(null, storedUsers); - } else { - self.numberMessagingListUsers({ + function(numberData, callback) { + var isCarrierTio = _.get(numberData, 'numberData.metadata.carrier_module') === 'trunkingio'; + + self.appFlags.oomaSmsBox = {}; + self.appFlags.isCarrierTio = isCarrierTio; + + if (isCarrierTio) { + monster.parallel({ + users: function(callback) { + var storedUsers = self.appFlags.users[accountId]; + + if (storedUsers) { + callback && callback(null, storedUsers); + } else { + self.numberMessagingListUsers({ + data: { + accountId: accountId, + filters: { + paginate: 'false' + } + }, + success: function(users) { + _.each(users, function(user) { + user.name = user.first_name + ' ' + user.last_name; + }); + + self.appFlags.users[accountId] = users; + callback && callback(null, users); + } + }); + } + }, + oomaSmsBoxes: function(callback) { + self.numberMessagingListOomaSmsBoxes({ data: { accountId: accountId, filters: { paginate: 'false' - } + }, + generateError: false }, - success: function(users) { - _.each(users, function(user) { - user.name = user.first_name + ' ' + user.last_name; - }); + success: function(oomaSmsBoxes) { + var number = numberData.numberData.id; - self.appFlags.users[accountId] = users; - callback(null, users); + _.each(oomaSmsBoxes, function(oomaSmsBox) { + if (_.includes(oomaSmsBox.numbers, number)) { + self.appFlags.oomaSmsBox = oomaSmsBox; + } + }); + callback && callback(null, oomaSmsBoxes); }, error: function(dataError) { - callback(dataError); + callback && callback(null, {}); } }); } - }, - oomaSmsBox: function(callback) { - self.numberMessagingListOomaSmsBoxes({ - data: { - accountId: accountId, - filters: { - paginate: 'false' - }, - generateError: false - }, - success: function(oomaSmsBoxes) { - var number = wrappedNumberData.numberData.id, - oomaSmsBox = _.findLast(oomaSmsBoxes, function(oomaSmsBox) { - return _.includes(oomaSmsBox.numbers, number); - }); - callback(null, oomaSmsBox); - }, - error: function(_dataError) { - callback(null, {}); - } - }); - } - }, function(err, results) { - if (err) { - callback(err); - return; - } - - results.numberData = wrappedNumberData.numberData; - results.isCarrierTio = wrappedNumberData.isCarrierTio; - callback(null, results); - }); + }, function(err, results) { + results.numberData = numberData.numberData; + callback && callback(null, results); + }); + } else { + callback && callback(null, numberData); + } } ], function(err, results) { - if (err) { - _.has(args, 'callbacks.error') && args.callbacks.error(err); - return; - } - self.numberMessagingRender(_.merge({ callbacks: args.callbacks, accountId: accountId - }, results)); + }, _.omit(results, [ + 'oomaSmsBoxes' + ]))); }); }, /** - * Auxiliary function to render the dialog for number messaging settings. * @param {Object} args - * @param {Object} [args.accountId] ID of the account that owns the phone number. - * @param {Object} args.numberData Phone number data. - * @param {Object} args.oomaSmsBox SMS box data. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - * @param {Object} [args.callbacks] Callback functions. - * @param {Function} [args.callbacks.success] Success callback. - * @param {Function} [args.callbacks.error] Error callback. + * @param {Object} args.numberData + * @param {Object} [args.accountId] + * @param {Function} [args.success] + * @param {Function} [args.error] */ numberMessagingRender: function(args) { var self = this, numberData = args.numberData, users = args.users, accountId = _.get(args, 'accountId', self.accountId), - success = _.get(args, 'callbacks.success', function() {}), - error = _.get(args, 'callbacks.error', function() {}), - oomaSmsBox = _.get(args, 'oomaSmsBox', {}), - isCarrierTio = args.isCarrierTio, - smsBoxExists = !_.isEmpty(oomaSmsBox), + success = _.get(args, 'success', function() {}), + error = _.get(args, 'error', function() {}), numberMessagingFormatted = self.numberMessagingFormatData({ - numberData: numberData, - oomaSmsBox: oomaSmsBox, - isCarrierTio: isCarrierTio, - smsBoxExists: smsBoxExists + numberData: args.numberData }), - $popupForm = $(self.getTemplate({ + popup_html = $(self.getTemplate({ name: 'layout', - data: numberMessagingFormatted, - submodule: 'numberMessaging' - })), - dialogTitle = self.getTemplate({ - name: '!' + self.i18n.active().numberMessaging.titles.dialog, - data: { - phoneNumber: monster.util.formatPhoneNumber(numberData.id) - } - }); - - if (isCarrierTio || smsBoxExists) { - self.numberMessagingTioSmsBoxFormRender({ - $container: $popupForm.find('#number_messaging_tio'), - isCarrierTio: isCarrierTio, - smsBoxExists: smsBoxExists, data: _.merge({ users: users - }, numberMessagingFormatted) - }); - } - - self.numberMessagingBindEvents({ - accountId: accountId, - $form: $popupForm, - formattedData: numberMessagingFormatted, - numberData: numberData, - oomaSmsBox: oomaSmsBox, - isCarrierTio: isCarrierTio, - smsBoxExists: smsBoxExists, - users: users, - success: success, - error: error - }); - - monster.ui.dialog($popupForm, { - title: dialogTitle, - dialogClass: 'number-messaging-dialog' - }); - }, - - /** - * Binds the number message settings dialog's events. - * @param {Object} args - * @param {String} args.accountId ID of the account that owns the phone number. - * @param {jQuery} args.$form Settings form template. - * @param {Object} args.formattedData Formatted settings data for the UI. - * @param {Object} args.numberData Phone number data. - * @param {Object} args.oomaSmsBox SMS box data. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - * @param {Boolean} args.smsBoxExists Whether or not a sms box is available to configure. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. - */ - numberMessagingBindEvents: function(args) { - var self = this, - accountId = args.accountId, - $form = args.$form, - numberMessagingFormatted = args.formattedData, - numberData = args.numberData, - oomaSmsBox = args.oomaSmsBox, - success = args.success, - error = args.error, - isCarrierTio = args.isCarrierTio, - smsBoxExists = args.smsBoxExists, - $tioBoxAvailableSection = $form.find('#sms_box_available_section'), - $tioBoxEnabledSection = $tioBoxAvailableSection.find('#sms_box_enabled_section'); - - monster.ui.validate($form, { - rules: { - owner: { - required: function(_element) { - var isSmsFeatureEnabled = $form - .find('[name="sms.enabled"]') - .prop('checked'), - mustConfigureSmsBox = $form - .find('#configure_sms_box') - .prop('checked'); - - return isSmsFeatureEnabled && mustConfigureSmsBox; - } - } - } - }); - - $form.find('.feature-selection').on('click', '.sds_SelectionList_Item', function(e) { - var $this = $(this), - $input = $this.find('input'), - isChecked = $input.prop('checked'); - - e.preventDefault(); - - $input.prop('checked', !isChecked); - - // If item was checked, and now is unchecked, then uncheck and disable the following items - if (isChecked) { - $this.nextAll() - .addClass('sds_SelectionList_Item_Disabled') - .find('input') - .prop('checked', !isChecked); - } else { - // Else, enable the next item - $this.nextAll() - .removeClass('sds_SelectionList_Item_Disabled'); - } - - // If checkbox is SMS and carrier is TIO - if (!smsBoxExists && $this.data('feature-type') === 'sms' && isCarrierTio) { - if (isChecked) { - $tioBoxAvailableSection.slideUp(); - } else { - $tioBoxAvailableSection.slideDown(); - } - } - }); - - $form.find('#configure_sms_box').on('change', function(e) { - var isChecked = $(this).prop('checked'); - - if (isChecked) { - $tioBoxEnabledSection.slideDown(); - } else { - $tioBoxEnabledSection.slideUp(); - } - }); - - $form.find('.cancel-link').on('click', function(e) { - e.preventDefault(); - $form.closest('.ui-dialog-content').dialog('close'); - }); + }, numberMessagingFormatted), + submodule: 'numberMessaging' + })), + popup; - $form.on('submit', function(ev) { + self.trunkingCarrierEvents(popup_html, numberMessagingFormatted, users); + popup_html.on('submit', function(ev) { ev.preventDefault(); - self.numberMessagingSaveData({ - $form: $form, - accountId: accountId, - isCarrierTio: isCarrierTio, - number: numberData.id, - oomaSmsBox: oomaSmsBox, - nonMembers: numberMessagingFormatted.nonMembers || [], - success: success, - error: error - }); - }); - }, - - /** - * Save all the phone number messaging settings. - * @param {Object} args - * @param {String} args.accountId ID of the account that owns the phone number. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - * @param {String} args.number Phone number. - * @param {Object} args.oomaSmsBox SMS box data. - * @param {Object[]} args.nonMembers Non-user SMS box members. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. - */ - numberMessagingSaveData: function(args) { - var self = this, - $form = args.$form, - accountId = args.accountId, - isCarrierTio = args.isCarrierTio, - number = args.number, - oomaSmsBox = args.oomaSmsBox, - members = _.concat([], args.nonMembers), - success = args.success, - error = args.error; - - if (!monster.ui.valid($form)) { - return; - } + var $button = $(this).find('button[type="submit"]'), + formData = monster.ui.getFormData('form_number_messaging'), + isCarrierTio = self.appFlags.isCarrierTio, + owner, + members = numberMessagingFormatted.nonMembers || [], + oomaSmsBoxData = { + numbers: [ + numberData.id + ], + shared_box: false + }; - var $button = $form.find('button[type="submit"]'), - formData = monster.ui.getFormData('form_number_messaging'), - features = ['sms', 'mms'], - isAnyMessagingFeatureEnabled = _.some(features, function(featureName) { - return _.get(formData, [featureName, 'enabled'], false); - }), - shouldCreateSmsBox = formData.configureSmsBox && _.isEmpty(oomaSmsBox), - shouldCheckMfaConfig = isCarrierTio - && isAnyMessagingFeatureEnabled - && shouldCreateSmsBox; + $button.prop('disabled', 'disabled'); - $button.prop('disabled', true); - - monster.waterfall([ - function checkMfaConfiguration(callback) { - if (!shouldCheckMfaConfig) { - callback(null, formData, null); - return; - } - - self.numberMessagingGetOtpMultifactorConfig({ - data: { - accountId: accountId - }, - success: function(mfaConfig) { - callback(null, formData, mfaConfig); - }, - error: function(parsedError) { - callback(parsedError); - } - }); - }, - function checkMfaConfig(formData, mfaConfig, callback) { - if (shouldCheckMfaConfig && !mfaConfig.enabled && !mfaConfig.otpConfigId) { - monster.ui.alert('error', self.i18n.active().numberMessaging.mfaNotConfiguredError); - callback('MfaOtpNotConfigured'); - return; - } - - callback(null, formData, mfaConfig); - }, - function formatOomaSmsBoxData(formData, mfaConfig, callback) { - var oomaSmsBoxData; - - if (!isCarrierTio || !formData.configureSmsBox) { - callback(null, formData, mfaConfig, null); - return; - } + if (isCarrierTio) { + owner = formData.owner; _.each(formData.members, function(memberId) { - var member = _.find(self.appFlags.users[accountId], { id: memberId }); + var member = _.find( self.appFlags.users[accountId], {id: memberId }); if (member) { members.push({ @@ -380,233 +169,217 @@ define(function(require) { } }); - oomaSmsBoxData = _.assign( - { - numbers: [ - number - ], - shared_box: false, - owner: formData.owner - }, - (_.size(members) > 0) ? { - members: members, - shared_box: true - } : {} - ); - - callback(null, formData, mfaConfig, oomaSmsBoxData); - }, - function patchNumber(formData, mfaConfig, oomaSmsBoxData, callback) { - var isReseller = monster.util.isReseller(); + oomaSmsBoxData.owner = owner; - if (!isReseller) { - callback(null, mfaConfig, oomaSmsBoxData, {}); - return; + if (_.size(members) > 0) { + oomaSmsBoxData.members = members; + oomaSmsBoxData.shared_box = true; } - self.numberMessagingPatchNumber({ - data: { - accountId: accountId, - phoneNumber: number, - data: _.pick(formData, features) - }, - success: function(number) { - callback(null, mfaConfig, oomaSmsBoxData, number); - }, - error: function(dataError) { - callback(dataError || 'charges_rejected'); + delete formData.owner; + delete formData.members; + } + + monster.waterfall([ + function(callback) { + var isReseller = monster.util.isReseller(); + + + if (!isReseller && isCarrierTio) { + callback(null, {}); + return; } - }); - }, - function saveSmsBox(mfaConfig, oomaSmsBoxData, number, callback) { - if (!isCarrierTio || _.isEmpty(oomaSmsBoxData)) { - callback(null, mfaConfig, number); - return; - } - if (shouldCreateSmsBox) { - self.numberMessagingCreateOomaSmsBox({ - data: { - accountId: accountId, - data: oomaSmsBoxData - }, - success: function() { - callback(null, mfaConfig, number); - }, - error: function(parsedError) { - callback(parsedError); - } - }); - } else { - self.numberMessagingUpdateOomaSmsBox({ + self.numberMessagingPatchNumber({ data: { accountId: accountId, - boxId: oomaSmsBox.id, - data: oomaSmsBoxData + phoneNumber: numberData.id, + data: formData }, - success: function() { - callback(null, mfaConfig, number); + success: function(number) { + var phoneNumber = monster.util.formatPhoneNumber(number.id), + template = self.getTemplate({ + name: '!' + self.i18n.active().numberMessaging.successUpdate, + data: { + phoneNumber: phoneNumber + } + }); + + monster.ui.toast({ + type: 'success', + message: template + }); + + + callback(null, number); }, - error: function(parsedError) { - callback(parsedError); + error: function(dataError) { + $button.prop('disabled', false); + error(dataError); } }); - } - }, - function enableMfaOtpConfig(mfaConfig, number, callback) { - if (!shouldCheckMfaConfig || _.get(mfaConfig, 'enabled', false)) { - callback(null, number); - return; - } + }, + function(number, callback) { + var oomaSmsBox = self.appFlags.oomaSmsBox; + isUpdateOomaSmsBox = !_.isEmpty(oomaSmsBox); - self.numberMessagingEnableOtpMultifactor({ - data: { - accountId: accountId, - configurationId: mfaConfig.otpConfigId - }, - success: function() { - monster.ui.alert( - 'info', - self.i18n.active().numberMessaging.mfaEnabledDialog.description, - function() { - callback(null, number); + if (!isCarrierTio) { + callback(null, {}); + return; + } + + if (isUpdateOomaSmsBox) { + self.numberMessagingUpdateOomaSmsBox({ + data: { + accountId: accountId, + boxId: oomaSmsBox.id, + data: oomaSmsBoxData }, - { - title: self.i18n.active().numberMessaging.mfaEnabledDialog.title + success: function(oomaSmsBox) { + callback(null, oomaSmsBox); } - ); - }, - error: function(parsedError) { - callback(parsedError); + }); + } else { + self.numberMessagingCreateOomaSmsBox({ + data: { + accountId: accountId, + data: oomaSmsBoxData + }, + success: function(oomaSmsBox) { + callback(null, oomaSmsBox); + } + }); } - }); - } - ], function(errorData, numberData) { - if (errorData) { - $button.prop('disabled', false); - errorData !== 'charges_rejected' && error && error(errorData); - return; - } + } + ], function(err, results) { + popup.dialog('close'); + }); + }); - var phoneNumber = monster.util.formatPhoneNumber(number), - template = self.getTemplate({ - name: '!' + self.i18n.active().numberMessaging.successUpdate, - data: { - phoneNumber: phoneNumber - } - }); + popup_html.find('.cancel-link').on('click', function(e) { + e.preventDefault(); + popup.dialog('close'); + }); - monster.ui.toast({ - type: 'success', - message: template - }); + var featureSelectionItem = popup_html.find('.feature-selection .sds_SelectionList_Item'); + featureSelectionItem.on('click', function(e) { + var $this = $(this), + $input = $this.find('input'), + isChecked = $input.prop('checked'); - $form.closest('.ui-dialog-content').dialog('close'); + e.preventDefault(); + $input.prop('checked', !isChecked); + self.trunkingCarrierEvents(popup_html, numberMessagingFormatted, users, true); + }); - success && success({ - data: numberData - }); + popup = monster.ui.dialog(popup_html, { + title: self.i18n.active().numberMessaging.titles.dialog }); }, /** - * Render the form section corresponding to the SMS box settings. - * @param {Object} args - * @param {jQuery} args.$container Container where the form section should be rendered. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - * @param {Boolean} args.smsBoxExists Whether or not a sms box is available to configure. - * @param {Object} args.data Number messaging settings. + * @param template + * @param {Object} numberData + * @param {boolean} wasChanged */ - numberMessagingTioSmsBoxFormRender: function(args) { + trunkingCarrierEvents: function(template, numberData, users, wasChanged = false) { var self = this, - $container = args.$container, - data = args.data, - isCarrierTio = args.isCarrierTio, - smsBoxExists = args.smsBoxExists, - isSmsBoxAvailable = smsBoxExists - || _.chain(data) - .get('features', []) - .find({ feature: 'sms' }) - .get('isChecked', false) - .value(), - configureSmsBoxDisabled = !monster.util.isReseller() || smsBoxExists, - $smsBoxForm = $(self.getTemplate({ - name: 'smsBoxForm', - data: _.assign({ - isSmsBoxAvailable: isSmsBoxAvailable, - smsBoxExists: smsBoxExists, - configureSmsBoxDisabled: configureSmsBoxDisabled - }, data), - submodule: 'numberMessaging' - })); + isCarrierTio = self.appFlags.isCarrierTio, + isReseller = _.get(numberData, 'isReseller', false), + $smsSelectionItem = template.find('.feature-selection .feature-sms-item'), + $mmsSelectionItem = template.find('.feature-selection .feature-mms-item'), + isSmsChecked = $smsSelectionItem.find('input').prop('checked'); - if (configureSmsBoxDisabled) { - $smsBoxForm.find('.sms-box-switch .monster-switch').addClass('disabled'); + if (!isCarrierTio) { + return; } - self.numberMessagingTioSmsBoxFormBindEvents({ - $template: $smsBoxForm, - isCarrierTio: isCarrierTio + monster.ui.chosen(template.find('#members'), { + width: '100%' }); - $container - .append($smsBoxForm); - }, + // Dynamic positioning fix for dropdown in modal using position:fixed + template.find('#members').on('chosen:showing_dropdown', function(event) { + event.stopPropagation(); + var $select = $(this), + $chosenContainer = $select.siblings('.chosen-container'), + $dropdown = $chosenContainer.find('.chosen-drop'), + position = $chosenContainer.offset(); + + // Position dropdown using fixed positioning relative to viewport + $dropdown.css({ + 'position': 'fixed', + 'top': (position.top + $chosenContainer.outerHeight()), + 'left': position.left, + 'width': $chosenContainer.outerWidth(), + 'z-index': '25000' + }); + }); - /** - * Bind the events for the SMS box settings form section. - * @param {Object} args - * @param {jQuery} args.$template Template for the SMS box settings section. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - */ - numberMessagingTioSmsBoxFormBindEvents: function(args) { - var self = this, - $template = args.$template, - isCarrierTio = args.isCarrierTio; + template.closest('.ui-dialog-content').on('scroll', function() { + var $membersSelect = template.find('#members'), + $chosenContainer = $membersSelect.siblings('.chosen-container'), + $dropdown = $chosenContainer.find('.chosen-drop'); + + if ($dropdown.is(':visible')) { + var position = $chosenContainer.offset(); + $dropdown.css({ + 'top': (position.top + $chosenContainer.outerHeight()), + 'left': position.left, + 'width': $chosenContainer.outerWidth() + }); + } + }); - if (!isCarrierTio) { + // Hide dropdown on window resize events + $(window).on('resize', function() { + var $membersSelect = template.find('#members'), + $chosenContainer = $membersSelect.siblings('.chosen-container'), + $dropdown = $chosenContainer.find('.chosen-drop'); + + if ($dropdown.is(':visible')) { + $membersSelect.trigger('chosen:close'); + } + }); + + if (!isReseller) { + $smsSelectionItem.addClass('sds_SelectionList_Item_Disabled'); + $mmsSelectionItem.addClass('sds_SelectionList_Item_Disabled'); return; } - monster.ui.chosen($template.find('#members'), { - width: 478 - }); + if (isSmsChecked) { + $mmsSelectionItem.removeClass('sds_SelectionList_Item_Disabled'); + } else { + $mmsSelectionItem.addClass('sds_SelectionList_Item_Disabled'); + } + + if (!isSmsChecked && $mmsSelectionItem.find('input').prop('checked') && wasChanged) { + $mmsSelectionItem.find('input').prop('checked', false); + } }, /** - * Formats the phone number and SMS box data to be rendered in the UI. - * @param {Object} args - * @param {Object} args.numberData Phone number data. - * @param {Object} args.oomaSmsBox SMS box settings. - * @param {Boolean} args.isCarrierTio Whether or not the number carrier is Trunking.io. - * @param {Boolean} args.smsBoxExists Whether or not a sms box is available to configure. - * @returns Phone number settings formatted data. + * @param {Object} args.numberData */ numberMessagingFormatData: function(args) { var self = this, - isReseller = monster.util.isReseller(), - isCarrierTio = args.isCarrierTio, - smsBoxExists = args.smsBoxExists, numberData = args.numberData, settings = _.get(numberData, 'metadata.features.settings', {}), returnData = { - features: _.reduce(['sms', 'mms'], function(features, feature) { - features.push({ + features: _.map(['sms', 'mms'], function(feature) { + return { feature: feature, - isEnabled: isReseller && (features.length === 0 || _.get(features, [features.length - 1, 'isChecked'], false)), - isChecked: _.get(numberData, [feature, 'enabled'], false), + isEnabled: _.get(numberData, [feature, 'enabled'], false), isConfigured: _.get(settings, [feature, 'enabled'], false) - }); - - return features; - }, []), - isReseller: isReseller, - isCarrierTio: isCarrierTio, - editable: isReseller || smsBoxExists + }; + }), + isCarrierTio: self.appFlags.isCarrierTio, + isReseller: monster.util.isReseller() }, - oomaSmsBox = args.oomaSmsBox; + oomaSmsBox = self.appFlags.oomaSmsBox; - if (isCarrierTio && smsBoxExists) { + if (self.appFlags.isCarrierTio && !_.isEmpty(oomaSmsBox)) { var [allMembers, nonMembers] = _.partition(oomaSmsBox.members, function(member) { return member.type === 'user'; }), @@ -626,21 +399,19 @@ define(function(require) { }, /** - * Patches a phone number data. * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account that owns the phone number. - * @param {String} args.data.phoneNumber Phone number to be updated. - * @param {Object} args.data.data Phone number data to be updated. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. + * @param {Object} args.data.phoneNumber + * @param {Function} [args.success] + * @param {Function} [args.error] */ numberMessagingPatchNumber: function(args) { var self = this; self.callApi({ resource: 'numbers.patch', - data: args.data, + data: _.merge({ + accountId: self.accountId + }, args.data), success: function(data, status) { _.has(args, 'success') && args.success(data.data); }, @@ -654,198 +425,79 @@ define(function(require) { }, /** - * Gets the list of users for the account. * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {Object} [args.data.filters] Results filters. - * @param {Object} [args.data.filters.paginate] Whether or not to paginate the list of results. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. + * @param {Function} [args.success] */ numberMessagingListUsers: function(args) { var self = this; self.callApi({ resource: 'user.list', - data: args.data, + data: _.merge({ + accountId: self.accountId + }, args.data), success: function(data) { _.has(args, 'success') && args.success(data.data); - }, - error: function(parsedError) { - _.has(args, 'error') && args.error(parsedError); } }); }, /** - * Gets the multi-factor configuration for OTP. * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {Function} [args.success] Success callback, which receives the OTP configuration object. - * @param {Function} [args.error] Error callback. - */ - numberMessagingGetOtpMultifactorConfig: function(args) { - var self = this; - - monster.parallel({ - otpSettings: function(callback) { - self.callApi({ - resource: 'multifactor.list', - data: args.data, - success: function(data) { - var otpSettings = _.chain(data) - .get('data.multi_factor_providers', []) - .find({ - provider_name: 'otp', - enabled: true - }) - .value(); - - callback(null, otpSettings); - }, - error: function(parsedError) { - callback(parsedError); - } - }); - }, - securitySettings: function(callback) { - self.callApi({ - resource: 'security.get', - data: args.data, - success: function(data) { - callback(null, data.data); - }, - error: function(parsedError) { - callback(parsedError); - } - }); - } - }, function(error, results) { - if (error) { - _.has(args, 'error') && args.error(error); - return; - } - - _.has(args, 'success') && args.success({ - otpConfigId: _.get(results, 'otpSettings.id'), - enabled: _.get(results, 'securitySettings.account.auth_modules.cb_user_auth.multi_factor.enabled', false) - }); - }); - }, - - /** - * Enables the OTP multi-factor authentication for the specified account. - * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {String} args.data.configurationId Multi-factor configuration ID. - * @param {Function} [args.success] Success callback, which receives the OTP configuration object. - * @param {Function} [args.error] Error callback. - */ - numberMessagingEnableOtpMultifactor: function(args) { - var self = this, - accountId = args.data.accountId, - data = { - 'auth_modules': { - 'cb_user_auth': { - 'multi_factor': { - 'configuration_id': args.data.configurationId, - 'account_id': accountId, - 'enabled': true - } - } - }, - accountId: accountId - }; - - self.callApi({ - resource: 'security.update', - data: { - accountId: accountId, - data: data - }, - success: function(data) { - _.has(args, 'success') && args.success(data.data); - }, - error: function(parsedError) { - _.has(args, 'error') && args.error(parsedError); - } - }); - }, - - /** - * Get the list of available SMS boxes for the account. - * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {Object} [args.data.filters] Results filters. - * @param {Object} [args.data.filters.paginate] Whether or not to paginate the list of results. - * @param {Object} [args.data.generateError] Whether or not to generate error. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. + * @param {Function} [args.success] + * @param {Function} [args.error] */ numberMessagingListOomaSmsBoxes: function(args) { var self = this; self.callApi({ resource: 'oomasmsboxes.list', - data: args.data, + data: _.merge({ + accountId: self.accountId + }, args.data), success: function(data) { _.has(args, 'success') && args.success(data.data); }, - error: function(parsedError) { - _.has(args, 'error') && args.error(parsedError); + error: function(data, status) { + _.has(args, 'error') && args.error([]); } }); }, /** - * Creates a new SMS box. * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {Object} args.data.data SMS box data. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. + * @param {Object} args.data.oomaSmsBox + * @param {Function} [args.success] */ numberMessagingCreateOomaSmsBox: function(args) { var self = this; self.callApi({ resource: 'oomasmsboxes.create', - data: args.data, + data: _.merge({ + accountId: self.accountId + }, args.data), success: function(data) { - _.has(args, 'success') && args.success(data.data); - }, - error: function(parsedError) { - _.has(args, 'error') && args.error(parsedError); + _.has(args, 'success') && args.success(data); } }); }, /** - * Updates an existing SMS box. * @param {Object} args - * @param {Object} args.data - * @param {String} args.data.accountId ID of the account. - * @param {Object} args.data.boxId SMS box ID. - * @param {Object} args.data.data SMS box data. - * @param {Function} [args.success] Success callback. - * @param {Function} [args.error] Error callback. + * @param {Object} args.data.OomaSmsBox + * @param {Function} [args.success] */ numberMessagingUpdateOomaSmsBox: function(args) { var self = this; self.callApi({ resource: 'oomasmsboxes.update', - data: args.data, + data: _.merge({ + accountId: self.accountId + }, args.data), success: function(data) { _.has(args, 'success') && args.success(data.data); - }, - error: function(parsedError) { - _.has(args, 'error') && args.error(parsedError); } }); } diff --git a/src/apps/common/submodules/numberMessaging/numberMessaging.scss b/src/apps/common/submodules/numberMessaging/numberMessaging.scss index 922771d20..88d1c2306 100644 --- a/src/apps/common/submodules/numberMessaging/numberMessaging.scss +++ b/src/apps/common/submodules/numberMessaging/numberMessaging.scss @@ -1,5 +1,3 @@ -@import "../../../../css/partials/base"; - .trunkstore_popup.numberMessaging { width: 510px; margin: 0; @@ -47,40 +45,6 @@ font-size: 12px; color: #454545; } - - .sms-box-switch label { - display: inline-block; - margin-right: 1rem; - } - - .number-messaging-section-hidden { - display: none; - } - - .text-danger { - color: $danger-color; - font-weight: 600; - } - - label.monster-invalid { - position: unset; - } - - /* Position chosen popup above input field */ - .chosen-container .chosen-drop { - top: auto; - bottom: 100%; - border-top: 1px solid $primary-color; - border-bottom: 0 none; - width: 478px; - - .chosen-results { - max-height: 100px; - width: 476px; - } - } } -.number-messaging-dialog.ui-dialog .ui-dialog-title { - font-size: 22px; -} + diff --git a/src/apps/common/submodules/numberMessaging/views/layout.html b/src/apps/common/submodules/numberMessaging/views/layout.html index e55665643..3386b3ab3 100644 --- a/src/apps/common/submodules/numberMessaging/views/layout.html +++ b/src/apps/common/submodules/numberMessaging/views/layout.html @@ -1,33 +1,65 @@
{{#*inline "featureContent"}} {{#if isConfigured}} -