From 2d73b30e612c143798e74b07b318f5b829082bde Mon Sep 17 00:00:00 2001 From: Maxime Roux Date: Mon, 23 Feb 2015 14:24:01 -0800 Subject: [PATCH 1/3] UI-1219: Added the prepend feature for numbers as a common control Conflicts: apps/common/app.js apps/common/i18n/en-US.json --- apps/common/app.js | 2 +- apps/common/i18n/en-US.json | 16 ++- apps/common/style/app.css | 1 + .../numberPrepend/numberPrepend.css | 26 +++++ .../submodules/numberPrepend/numberPrepend.js | 103 ++++++++++++++++++ apps/common/submodules/numbers/numbers.js | 57 +++++++--- apps/common/views/numberPrepend-layout.html | 22 ++++ apps/common/views/numbers-used.html | 5 +- 8 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 apps/common/submodules/numberPrepend/numberPrepend.css create mode 100644 apps/common/submodules/numberPrepend/numberPrepend.js create mode 100644 apps/common/views/numberPrepend-layout.html diff --git a/apps/common/app.js b/apps/common/app.js index 45b6a7b15..df2794ca8 100644 --- a/apps/common/app.js +++ b/apps/common/app.js @@ -6,7 +6,7 @@ define(function(require){ var app = { name: 'common', - subModules: ['accountBrowser', 'buyNumbers', 'callerId', 'e911', 'failover', 'numbers', 'port', 'chooseModel', 'servicePlanDetails', 'ringingDurationControl'], + subModules: ['accountBrowser', 'buyNumbers', 'callerId', 'e911', 'failover', 'numbers', 'port', 'chooseModel', 'servicePlanDetails', 'ringingDurationControl', 'numberPrepend'], css: [ 'app' ], diff --git a/apps/common/i18n/en-US.json b/apps/common/i18n/en-US.json index ab76964da..3effefe02 100644 --- a/apps/common/i18n/en-US.json +++ b/apps/common/i18n/en-US.json @@ -75,7 +75,11 @@ "questionPartThree": "?", "button": "move number(s)" } - } + }, + + "__comment": "UI-1219: Adding the prepend feature to numbers", + "__version": "v3.20_s1", + "prependIconHelp": "This icon means that this number will show up with a custom prepended text on your phone" }, "callerId": { @@ -362,5 +366,15 @@ "distribute": "Distribute", "maxDurationTooltip": "Click this box to change the maximum duration for your ring group. You must enter a number between 30 and 999.", "doNotRing": "Do not ring" + }, + + "__comment": "UI-1219: Adding the prepend feature to numbers", + "__version": "v3.20_s1", + "numberPrepend": { + "dialogTitle": "Number Prepend Setup", + "title": "Text to prepend", + "label": "Prepend", + "help": "This text will appear before your number when receiving a call. This can be used to better identify which number was called when you use more than one.", + "successUpdate": "You successfully updated the prepended text for {{phoneNumber}}" } } diff --git a/apps/common/style/app.css b/apps/common/style/app.css index 4a2f3e594..523bef5a5 100644 --- a/apps/common/style/app.css +++ b/apps/common/style/app.css @@ -8,6 +8,7 @@ @import url('../submodules/chooseModel/chooseModel.css'); @import url('../submodules/servicePlanDetails/servicePlanDetails.css'); @import url('../submodules/ringingDurationControl/ringingDurationControl.css'); +@import url('../submodules/numberPrepend/numberPrepend.css'); /* Hack because of otpimization: can't have relative paths since the folder hierarchy changes after optimization */ .trunkstore_popup.cnam .left_image { diff --git a/apps/common/submodules/numberPrepend/numberPrepend.css b/apps/common/submodules/numberPrepend/numberPrepend.css new file mode 100644 index 000000000..a456ce32a --- /dev/null +++ b/apps/common/submodules/numberPrepend/numberPrepend.css @@ -0,0 +1,26 @@ +/* NUMBER-PREPEND POPUP */ +.trunkstore_popup.number-prepend { + width: 510px; +} + +.trunkstore_popup.number-prepend form, +.trunkstore_popup.number-prepend input { + margin: 0; +} + +.trunkstore_popup.number-prepend .popup-content { + padding: 15px 25px; +} + +.trunkstore_popup.number-prepend .popup-content:not(:first-child) { + border-top: 1px solid #ccc; +} + +.trunkstore_popup.number-prepend .popup-content .popup-label { + margin: 0 10px 0 0; + display: inline-block; +} + +.trunkstore_popup.number-prepend .help-box { + margin-top: 20px; +} \ No newline at end of file diff --git a/apps/common/submodules/numberPrepend/numberPrepend.js b/apps/common/submodules/numberPrepend/numberPrepend.js new file mode 100644 index 000000000..6825ce7bc --- /dev/null +++ b/apps/common/submodules/numberPrepend/numberPrepend.js @@ -0,0 +1,103 @@ +define(function(require){ + var $ = require('jquery'), + _ = require('underscore'), + monster = require('monster'), + toastr = require('toastr'); + + var numberPrepend = { + + requests: { + }, + + subscribe: { + 'common.numberPrepend.renderPopup': 'numberPrependEdit' + }, + + numberPrependEdit: function(args) { + var self = this; + + self.numberPrependGetNumber(args.phoneNumber, function(dataNumber) { + self.numberPrependRender(dataNumber.data, args.callbacks); + }); + }, + + numberPrependRender: function(dataNumber, callbacks) { + var self = this, + popup_html = $(monster.template(self, 'numberPrepend-layout', dataNumber.prepend || {})), + popup; + + popup_html.find('.save').on('click', function(ev) { + ev.preventDefault(); + var prependFormData = monster.ui.getFormData('number_prepend'); + prependFormData.enabled = (prependFormData.name && prependFormData.name.length > 0) ? true : false; + + _.extend(true, dataNumber, { prepend: prependFormData }); + + self.numberPrependUpdateNumber(dataNumber.id, dataNumber, + function(data) { + var phoneNumber = monster.util.formatPhoneNumber(data.data.id), + template = monster.template(self, '!' + self.i18n.active().numberPrepend.successUpdate, { phoneNumber: phoneNumber }); + + toastr.success(template); + + popup.dialog('destroy').remove(); + + callbacks.success && callbacks.success(data); + }, + function(data) { + callbacks.error && callbacks.error(data); + } + ); + + }); + + popup_html.find('.cancel-link').on('click', function(e) { + e.preventDefault(); + popup.dialog('destroy').remove(); + }); + + popup = monster.ui.dialog(popup_html, { + title: self.i18n.active().numberPrepend.dialogTitle + }); + }, + + numberPrependGetNumber: function(phoneNumber, success, error) { + var self = this; + + self.callApi({ + resource: 'numbers.get', + data: { + accountId: self.accountId, + phoneNumber: encodeURIComponent(phoneNumber) + }, + success: function(_data, status) { + success && success(_data); + }, + error: function(_data, status) { + error && error(_data); + } + }); + }, + + numberPrependUpdateNumber: function(phoneNumber, data, success, error) { + var self = this; + + self.callApi({ + resource: 'numbers.update', + data: { + accountId: self.accountId, + phoneNumber: encodeURIComponent(phoneNumber), + data: data + }, + success: function(_data, status) { + success && success(_data); + }, + error: function(_data, status) { + error && error(_data); + } + }); + } + }; + + return numberPrepend; +}); diff --git a/apps/common/submodules/numbers/numbers.js b/apps/common/submodules/numbers/numbers.js index a4773f7a5..2ad1aeeec 100644 --- a/apps/common/submodules/numbers/numbers.js +++ b/apps/common/submodules/numbers/numbers.js @@ -110,7 +110,8 @@ define(function(require){ inbound_cnam: { icon: 'icon-green icon-user feature-inbound_cnam', help: self.i18n.active().numbers.cnamInboundIconHelp }, dash_e911: { icon: 'icon-red icon-ambulance feature-dash_e911', help: self.i18n.active().numbers.e911IconHelp }, local: { icon: 'icon-purple icon-rocket feature-local', help: self.i18n.active().numbers.localIconHelp }, - port: { icon: 'icon-phone icon-yellow feature-port' } + port: { icon: 'icon-phone icon-yellow feature-port' }, + prepend: { icon: 'icon-orange icon-file-text-alt feature-prepend', help: self.i18n.active().numbers.prependIconHelp } }; if(callback) { @@ -173,7 +174,7 @@ define(function(require){ var sortByDate = function(a,b) { return a.updated > b.updated ? -1 : 1; }, - sortByName = function(a,b) { + sortByName = function(a,b) { return a.phoneNumber > b.phoneNumber; }; @@ -218,7 +219,7 @@ define(function(require){ self.numbersList(accountId, function(numbers) { var spareNumbers = [], usedNumbers = [], - sortByName = function(a,b) { + sortByName = function(a,b) { return a.phoneNumber > b.phoneNumber; }; @@ -786,6 +787,28 @@ define(function(require){ } }); + parent.on('click', '.prepend-number', function() { + var prependCell = $(this).parents('.number-box').first(), + phoneNumber = prependCell.data('phonenumber'); + + if(phoneNumber) { + var args = { + phoneNumber: phoneNumber, + callbacks: { + success: function(data) { + if('prepend' in data.data && data.data.prepend.enabled) { + prependCell.find('.features i.feature-prepend').addClass('active'); + } else { + prependCell.find('.features i.feature-prepend').removeClass('active'); + } + } + } + }; + + monster.pub('common.numberPrepend.renderPopup', args); + } + }); + var searchListNumbers = function(searchString, parent) { var viewList = parent; @@ -976,26 +999,26 @@ define(function(require){ data.accountName = accountName; var formattedData = self.numbersFormatDialogSpare(data), - spareTemplate = $(monster.template(self, 'numbers-dialogSpare', formattedData)); + spareTemplate = $(monster.template(self, 'numbers-dialogSpare', formattedData)); - spareTemplate.find('.empty-search-row').hide(); + spareTemplate.find('.empty-search-row').hide(); spareTemplate.on('keyup', '.search-query', function() { - var rows = spareTemplate.find('.number-box'), - emptySearch = spareTemplate.find('.empty-search-row'), - currentRow; + var rows = spareTemplate.find('.number-box'), + emptySearch = spareTemplate.find('.empty-search-row'), + currentRow; - currentNumberSearch = $(this).val().toLowerCase(); + currentNumberSearch = $(this).val().toLowerCase(); - _.each(rows, function(row) { - currentRow = $(row); - currentRow.data('search').toLowerCase().indexOf(currentNumberSearch) < 0 ? currentRow.hide() : currentRow.show(); - }); + _.each(rows, function(row) { + currentRow = $(row); + currentRow.data('search').toLowerCase().indexOf(currentNumberSearch) < 0 ? currentRow.hide() : currentRow.show(); + }); - if(rows.size() > 0) { - rows.is(':visible') ? emptySearch.hide() : emptySearch.show(); - } - }); + if(rows.size() > 0) { + rows.is(':visible') ? emptySearch.hide() : emptySearch.show(); + } + }); spareTemplate.find('#proceed').on('click', function() { var selectedNumbersRow = spareTemplate.find('.number-box.selected'), diff --git a/apps/common/views/numberPrepend-layout.html b/apps/common/views/numberPrepend-layout.html new file mode 100644 index 000000000..2dcbf21fe --- /dev/null +++ b/apps/common/views/numberPrepend-layout.html @@ -0,0 +1,22 @@ +
+
+ + +
+
diff --git a/apps/common/views/numbers-used.html b/apps/common/views/numbers-used.html index 445ce98a8..ee0c3c0d5 100644 --- a/apps/common/views/numbers-used.html +++ b/apps/common/views/numbers-used.html @@ -23,24 +23,25 @@
{{#each usedNumbers}}
- {{#unless isLocal}}
- {{/unless}}
{{formatPhoneNumber this.phoneNumber}}
{{#if this.isoCountry }} From c94fd9e2b7a39ee8fe496dbac6008617c0a0f60a Mon Sep 17 00:00:00 2001 From: Joris Tirado Date: Tue, 24 Feb 2015 14:32:51 -0800 Subject: [PATCH 2/3] UI-1149: Update dialog charges template to new data format --- apps/core/i18n/en-US.json | 11 ++-- apps/core/i18n/fr-FR.json | 13 ++-- apps/core/i18n/ru-RU.json | 4 +- apps/core/style/app.css | 82 +++++++++++++++++-------- apps/core/views/dialog-charges.html | 92 ++++++++++++++--------------- js/lib/monster.ui.js | 12 ++-- 6 files changed, 118 insertions(+), 96 deletions(-) diff --git a/apps/core/i18n/en-US.json b/apps/core/i18n/en-US.json index f40ed2014..05e8541ac 100644 --- a/apps/core/i18n/en-US.json +++ b/apps/core/i18n/en-US.json @@ -46,6 +46,7 @@ "delete": "Delete", "dialog" : { "showError": "Show Error", + "confirm": "Confirm", "confirmOk": "OK", "confirmCancel" : "Cancel", "confirmTitle" : "Confirmation" @@ -123,17 +124,13 @@ "warning": "Warning!", "confirmCharges": { "title": "Charges Confirmation", - "withChargesPartOne": "You will pay a ${{variable}}", - "withChargesPartTwo": " on-time {{variable}}. ", - "withoutCharges": "There is no {{variable}}.", - "detail": "Here is the detail of the monthly charges attached to your account for this service:", - "service": "Service", + "oneTimeFee": "One-time fee", + "detail": "Here are the updated details of the monthly charges that will be made to your account for this service:", "rate": "Rate", "quantity": "Quantity", "discount": "Discount", "monthlyCharges": "Monthly Charges", - "amount": "${{variable}}", - "actions": "Press OK to confirm or Cancel to abort the process." + "amount": "${{variable}}" }, "languages": { "auto": "Default", diff --git a/apps/core/i18n/fr-FR.json b/apps/core/i18n/fr-FR.json index 617b63b07..1eeed4d74 100644 --- a/apps/core/i18n/fr-FR.json +++ b/apps/core/i18n/fr-FR.json @@ -47,6 +47,7 @@ "delete": "Supprimer", "dialog":{ "showError":"Détails erreur", + "confirm": "Confirmer", "confirmOk":"OK", "confirmCancel":"Annuler", "confirmTitle":"Confirmation" @@ -125,17 +126,13 @@ "confirmCharges": { "title":"Confirmation de frais", - "withChargesPartOne": "You will pay a {{variable}}€", - "withChargesPartTwo": " on-time {{variable}}. ", - "withoutCharges": "There is no {{variable}}.", - "detail":"Voici les détails des frais mensuels de ce compte pour ce service:", - "service": "Service", + "oneTimeFee": "Frais unique", + "detail":"Voici les détails mis à jour des frais mensuels de ce compte pour ce service:", "rate":"Taux", "quantity":"Quantité", - "discount": "Discount", + "discount": "Réduction", "monthlyCharges":"Frais mensuels", - "amount": "{{variable}}€", - "actions":"Pressez OK pour confirmer ou Annuler pour revenir en arrière." + "amount": "${{variable}}" }, "languages":{ "auto":"Par Défaut", diff --git a/apps/core/i18n/ru-RU.json b/apps/core/i18n/ru-RU.json index 4d4b85edf..3651466cb 100644 --- a/apps/core/i18n/ru-RU.json +++ b/apps/core/i18n/ru-RU.json @@ -125,13 +125,11 @@ "withChargesPartTwo": " on-time {{variable}}. ", "withoutCharges": "Не существует {{variable}}.", "detail": "Детализация ежемесячных платежей по вашим услугам:", - "service": "Услуга", "rate": "Ставка", "quantity": "Количество", "discount": "Скидка", "monthlyCharges": "Ежемесячный платёж", - "amount": "{{variable}}", - "actions": "Нажмите OK для подтверждения или Отменить для отказа." + "amount": "{{variable}}" }, "languages": { "auto": "Автоматически", diff --git a/apps/core/style/app.css b/apps/core/style/app.css index 35a3593cb..76ad64fe2 100644 --- a/apps/core/style/app.css +++ b/apps/core/style/app.css @@ -915,45 +915,79 @@ label.monster-invalid { } /* Confirm Charges popup */ -.charges-dialog { - max-width: 800px; - width: auto; +.dialog-charges { + width: 520px; + padding: 30px; } -.charges-dialog .help-box .text-wrapper { - padding: 25px 30px 15px; +.dialog-charges .content > div { + padding: 10px; + border: solid 1px #c0c0c9; + border-radius: 2px; + background-color: #f0f0f9; } -.charges-dialog .help-box .text-wrapper p { - text-align: justify; +.dialog-charges .content > .section:not(:first-child) { + margin-top: 20px; } -.charges-dialog .help-box .text-wrapper table { - margin: 15px 0; - min-width: 400px; +.dialog-charges .content .title-block { + line-height: 47px; } -.charges-dialog .help-box .text-wrapper table thead th:nth-child(2), -.charges-dialog .help-box .text-wrapper table thead th:nth-child(5), -.charges-dialog .help-box .text-wrapper table thead th:nth-child(6), -.charges-dialog .help-box .text-wrapper table tbody td:nth-child(2), -.charges-dialog .help-box .text-wrapper table tbody td:nth-child(5), -.charges-dialog .help-box .text-wrapper table tbody td:nth-child(6) { - text-align: right; +.dialog-charges .charges-info .icon-warning-sign { + font-size: 39px; + color: #c0c0c9; } -.charges-dialog .help-box .text-wrapper table thead th:nth-child(4), -.charges-dialog .help-box .text-wrapper table tbody td:nth-child(4) { - text-align: left; +.dialog-charges .charges-list { + margin-top: 20px } -.charges-dialog .help-box .text-wrapper table tbody td:nth-child(3), -.charges-dialog .help-box .text-wrapper p:last-child { +.dialog-charges .charges-element { + padding: 10px; text-align: center; + border: 1px solid #c0c0c9; + border-radius: 2px; + background-color: #fff; +} + +.dialog-charges .charges-element:not(:first-child) { + margin-top: 5px; +} + +.dialog-charges .charges-element table { + width: 100%; +} + +.dialog-charges .charges-element tr:first-child { + height: 40px; +} + +.dialog-charges .charges-element td { + font-size: 20px; +} + +.dialog-charges .charges-element td:nth-child(odd) { + font-weight: bold; + min-width: 100px; + color: #22a5ff; +} + +.dialog-charges .charges-element th { + font-weight: normal; +} + +.dialog-charges .actions { + margin-top: 30px; + padding-top: 20px; + text-align: right; + border-top: 1px solid #c0c0c9; } -.charges-dialog .help-box .text-wrapper table tbody tr { - background: #fdfdfd; +.dialog-charges .actions button:last-child { + width: 130px; + margin-left: 20px; } /* Left Menu */ diff --git a/apps/core/views/dialog-charges.html b/apps/core/views/dialog-charges.html index c4d731b02..3f8c45143 100644 --- a/apps/core/views/dialog-charges.html +++ b/apps/core/views/dialog-charges.html @@ -1,52 +1,50 @@ -
-
-
- +
+
+ {{#if activation_charges}} +
+
+
{{replaceVar i18n.confirmCharges.amount activation_charges}}
+
+
{{i18n/confirmCharges.oneTimeFee}}
-
-

- {{#if activation_charges_description}} - {{#if activation_charges}} - {{replaceVar i18n.confirmCharges.withChargesPartOne activation_charges}}{{replaceVar i18n.confirmCharges.withChargesPartTwo activation_charges_description}} - {{else}} - {{replaceVar i18n.confirmCharges.withoutCharges activation_charges_description}} - {{/if}} - {{/if}} - {{#if charges}} - {{i18n.confirmCharges.detail}} - {{/if}} -

- {{#if charges}} - - - - - - - - - - - - - {{#each charges}} - - - - - - - - - {{/each}} - -
{{i18n.confirmCharges.service}}{{i18n.confirmCharges.rate}}{{i18n.confirmCharges.quantity}}{{i18n.confirmCharges.discount}}{{i18n.confirmCharges.monthlyCharges}}
{{service}}{{replaceVar ../i18n.confirmCharges.amount rate}}x{{quantity}}{{#if discount}}-{{replaceVar ../../i18n.confirmCharges.amount discount}}{{else}}0{{/if}}{{replaceVar ../i18n.confirmCharges.amount monthlyCharges}}
- {{/if}} -

{{i18n.confirmCharges.actions}}

+ {{/if}} + {{#if charges}} +
+
+ + {{i18n/confirmCharges.detail}} +
+
+ {{#each charges}} +
+ + + + + + + + + + + + + + + + + + + +
{{quantity}}x{{replaceVar ../i18n.confirmCharges.amount rate}}-{{#if discount}}{{replaceVar ../i18n.confirmCharges.amount discount}}{{else}}{{discount}}{{/if}}={{replaceVar ../i18n.confirmCharges.amount monthlyCharges}}
{{service}}{{../i18n.confirmCharges.rate}}{{../i18n.confirmCharges.discount}}{{../i18n.confirmCharges.monthlyCharges}}
+
+ {{/each}} +
+ {{/if}}
-
- - +
+ +
\ No newline at end of file diff --git a/js/lib/monster.ui.js b/js/lib/monster.ui.js index b0e78ee57..7aa58f582 100644 --- a/js/lib/monster.ui.js +++ b/js/lib/monster.ui.js @@ -281,16 +281,16 @@ define(function(require){ renderData = []; $.each(data, function(categoryName, category) { - if (categoryName != 'activation_charges' && categoryName != 'activation_charges_description') { + if (categoryName != 'activation_charges') { $.each(category, function(itemName, item) { var discount = item.single_discount_rate + (item.cumulative_discount_rate * item.cumulative_discount), monthlyCharges = parseFloat(((item.rate * item.quantity) - discount) || 0).toFixed(2); if(monthlyCharges > 0) { renderData.push({ - service: i18n.services[itemName], - rate: item.rate || 0, + service: i18n.services.hasOwnProperty(itemName) ? i18n.services[itemName] : itemName.replace(/_/, ' '), + rate: item.rate.toFixed(2) || 0, quantity: item.quantity || 0, - discount: discount > 0 ? parseFloat(discount).toFixed(2) : '', + discount: discount > 0 ? parseFloat(discount).toFixed(2) : 0, monthlyCharges: monthlyCharges }); @@ -302,11 +302,9 @@ define(function(require){ return renderData; }, - charges = data.hasOwnProperty('activation_charges') ? data.activation_charges : false, - description = typeof data.activation_charges_description === 'string' ? data.activation_charges_description : false, + charges = data.activation_charges ? data.activation_charges.toFixed(2) : 0, template = $(monster.template(coreApp, 'dialog-charges', { activation_charges: charges, - activation_charges_description: description, charges: formatData(data) } )), From 764ea08b0abf63efecfb0b68794718e10e75ade0 Mon Sep 17 00:00:00 2001 From: Joris Tirado Date: Tue, 24 Feb 2015 15:03:46 -0800 Subject: [PATCH 3/3] UI-1151: Don't show error on 402 and let monster.request handle it --- apps/common/submodules/port/port.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/common/submodules/port/port.js b/apps/common/submodules/port/port.js index c6284f742..9f0cb21be 100644 --- a/apps/common/submodules/port/port.js +++ b/apps/common/submodules/port/port.js @@ -1384,7 +1384,9 @@ define(function(require){ callbackSuccess && callbackSuccess(); }, error: function(data, status) { - callbackError && callbackError(); + if (parseInt(data.error, 10) !== 402) { + callbackError && callbackError(); + } } }); },