diff --git a/app/model/CallForwardSourceset.js b/app/model/CallForwardSourceset.js index 98144eb9..ecc13f39 100644 --- a/app/model/CallForwardSourceset.js +++ b/app/model/CallForwardSourceset.js @@ -13,6 +13,9 @@ Ext.define('NgcpCsc.model.CallForwardSourceset', { }, { name: 'source', type: 'auto' + }, { + name: 'edit', + type: 'boolean' }] }); diff --git a/app/model/Reminder.js b/app/model/Reminder.js index 1ab156d0..e8c18673 100644 --- a/app/model/Reminder.js +++ b/app/model/Reminder.js @@ -75,7 +75,7 @@ Ext.define('NgcpCsc.model.Reminder', { proxy: { type: 'ngcp-api', route: 'reminders', - params: 'subscriber_id=' + localStorage.getItem('subscriber_id') + params: 'subscriber_id=' + localStorage.getItem('subscriber_id') // this must exist in /api/subscribers/ response } }); diff --git a/app/proxy/NgcpApi.js b/app/proxy/NgcpApi.js index 89ef4645..e25abcb2 100644 --- a/app/proxy/NgcpApi.js +++ b/app/proxy/NgcpApi.js @@ -44,6 +44,9 @@ Ext.define('NgcpCsc.proxy.NgcpApi', { }; records = request._records; + if (me.api && me.api.update) { + me.route = me.api.update; + }; url = Ext.String.format('{0}{1}/{2}', me.baseApiUrl, me.route, me.addSubscriber ? localStorage.getItem('subscriber_id') : records[0].get('id')); break; } diff --git a/app/store/CallForward.js b/app/store/CallForward.js index d4591152..f9eca466 100644 --- a/app/store/CallForward.js +++ b/app/store/CallForward.js @@ -5,9 +5,6 @@ Ext.define('NgcpCsc.store.CallForward', { model: 'NgcpCsc.model.CallForward', - // TODO: (For PUT/PATCH ticket) - // autoSync: true, - proxy: { type: 'ngcp-api', route: 'cfmappings', @@ -16,13 +13,12 @@ Ext.define('NgcpCsc.store.CallForward', { read: 'GET', update: 'PATCH' } - } + }, - // TODO: (For PUT/PATCH ticket) - // ,listeners: { - // beforesync: function(options) { - // this.fireEvent('cfStoreBeforeSync', this, options); - // } - // } + listeners: { + beforesync: function(options) { + this.fireEvent('cfStoreBeforeSync', this, options); + } + } }); diff --git a/app/store/CallForwardLocalStorage.js b/app/store/CallForwardLocalStorage.js index 60e668d0..7babc4c2 100644 --- a/app/store/CallForwardLocalStorage.js +++ b/app/store/CallForwardLocalStorage.js @@ -1,9 +1,6 @@ Ext.define('NgcpCsc.store.CallForwardLocalStorage', { extend: 'Ext.data.Store', - // TODO: Can be removed as we only have a single model, but is currently - // used with Ext.getStore() references in CallForward modules - storeId: 'CallForwardLocalStorage', model: 'NgcpCsc.model.CallForwardLocalStorage', diff --git a/app/store/CallForwardSourceset.js b/app/store/CallForwardSourceset.js index a9cae74e..518910a8 100644 --- a/app/store/CallForwardSourceset.js +++ b/app/store/CallForwardSourceset.js @@ -17,10 +17,10 @@ Ext.define('NgcpCsc.store.CallForwardSourceset', { listeners: { load: function(store, recs) { - if (recs[0] && recs[0].data && recs[0].data._embedded) { - this.fireEvent('cfSourcesetStoreLoaded', this, recs[0].data._embedded['ngcp:cfsourcesets']); - } - + this.fireEvent('cfSourcesetStoreLoaded', this, recs[0]); + }, + beforesync: function(options) { + this.fireEvent('cfSourcesetBeforeSync', this, options); } } diff --git a/app/store/CallForwardTimeset.js b/app/store/CallForwardTimeset.js index 147bbd61..b993f533 100644 --- a/app/store/CallForwardTimeset.js +++ b/app/store/CallForwardTimeset.js @@ -19,7 +19,10 @@ Ext.define('NgcpCsc.store.CallForwardTimeset', { listeners: { load: function(store, recs) { - this.fireEvent('cfTimesetStoreLoaded', this, recs[0].data._embedded['ngcp:cftimesets']); + this.fireEvent('cfTimesetStoreLoaded', this, recs[0]); + }, + beforesync: function(options) { + this.fireEvent('cfTimesetBeforeSync', this, options); } } diff --git a/app/utils/locales.js b/app/utils/locales.js index c1ff4cff..7ff1eb90 100644 --- a/app/utils/locales.js +++ b/app/utils/locales.js @@ -1036,6 +1036,34 @@ Ext.define('Ngcp.csc.locales', { en: 'From ', it: 'From ' }, + no_after_hours_set: { + de: 'You have not set your after hours calendar yet.', + fr: 'You have not set your after hours calendar yet.', + sp: 'You have not set your after hours calendar yet.', + en: 'You have not set your after hours calendar yet.', + it: 'You have not set your after hours calendar yet.' + }, + no_company_hours_set: { + de: 'You have not set your company hours calendar yet.', + fr: 'You have not set your company hours calendar yet.', + sp: 'You have not set your company hours calendar yet.', + en: 'You have not set your company hours calendar yet.', + it: 'You have not set your company hours calendar yet.' + }, + number_is_required: { + de: 'Number is required. Please retry.', + fr: 'Number is required. Please retry.', + sp: 'Number is required. Please retry.', + en: 'Number is required. Please retry.', + it: 'Number is required. Please retry.' + }, + only_numbers_allowed: { + de: 'Only numbers allowed. Please retry.', + fr: 'Only numbers allowed. Please retry.', + sp: 'Only numbers allowed. Please retry.', + en: 'Only numbers allowed. Please retry.', + it: 'Only numbers allowed. Please retry.' + }, tooltips: { change_time_from: { en: 'Change time from', diff --git a/classic/src/view/login/LoginController.js b/classic/src/view/login/LoginController.js index 97a190fa..e5c71d12 100644 --- a/classic/src/view/login/LoginController.js +++ b/classic/src/view/login/LoginController.js @@ -50,6 +50,20 @@ Ext.define('NgcpCsc.view.login.LoginController', { } }, + loadSubscriberDomain: function () { + Ext.Ajax.request({ + url: window.location.origin + '/api/subscribers/' + localStorage.getItem('subscriber_id'), + success: function(response, opts) { + var decodedResponse = Ext.decode(response.responseText); + var domain = decodedResponse.domain; + localStorage.setItem('domain', domain); + }, + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + } + }); + }, + unsuccessLogin: function(response) { localStorage.removeItem('jwt'); Ext.Msg.alert('Error', 'Username or Password not valid!'); diff --git a/classic/src/view/pages/callblocking/CallBlockingController.js b/classic/src/view/pages/callblocking/CallBlockingController.js index 8609df68..386b1488 100644 --- a/classic/src/view/pages/callblocking/CallBlockingController.js +++ b/classic/src/view/pages/callblocking/CallBlockingController.js @@ -42,7 +42,6 @@ Ext.define('NgcpCsc.view.pages.callblocking.CallBlockingController', { var vm = this.getViewModel(); var block_in_list = [], block_out_list = [], - data = [], storeType = store._type; delete options['destroy']; delete options['create']; diff --git a/classic/src/view/pages/callforward/CallForwardController.js b/classic/src/view/pages/callforward/CallForwardController.js index 3b2dfaf0..d7ec2ba8 100644 --- a/classic/src/view/pages/callforward/CallForwardController.js +++ b/classic/src/view/pages/callforward/CallForwardController.js @@ -13,33 +13,49 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { '*': { cfStoreLoaded: 'cfStoreLoaded', cfTimesetStoreLoaded: 'cfTimesetStoreLoaded', - cfSourcesetStoreLoaded: 'cfSourcesetStoreLoaded' + cfSourcesetStoreLoaded: 'cfSourcesetStoreLoaded', + cfStoreBeforeSync: 'cfStoreBeforeSync', + cfSourcesetBeforeSync: 'cfSourcesetBeforeSync', + cfTimesetBeforeSync: 'cfTimesetBeforeSync' } } }, + destinationDropped: function (node, data, overModel, dropPosition, eOpts) { + // TODO: Leaving uncommented code here for upcoming task #17654 + // var store = Ext.getStore('everybody-always-CallForwardBusy'); + // Ext.each(store.getRange(), function(record) { + // console.log(record.get('destination_cleaned')); + // }) + }, + cfTimesetStoreLoaded: function(store, data) { var me = this; var arrayOfModels = []; + var timesets; + if (data.getData()._embedded == undefined) { + return; + } else { + timesets = data.getData()._embedded['ngcp:cftimesets']; + } store.removeAll(); - Ext.each(data, function (timeset) { + Ext.each(timesets, function (timeset) { var timesetName = timeset.name; var timesetId = timeset.id; - if (timesetName == 'After Hours' || timesetName == 'Company Hours') { + me.setVmToTrue(timesetName); + if (/(After|Company)\s(Hours)/.test(timesetName)) { var times = me.getModelValuesFromTimesData(timeset.times[0]); Ext.each(times.days, function (weekday) { - var cbModel = Ext.create('NgcpCsc.model.CallForward', { + var cfModel = Ext.create('NgcpCsc.model.CallForward', { id: Ext.id(), timeset_name: timesetName, timeset_id: timesetId, time_from: times.timeFrom, time_to: times.timeTo, day: weekday, - closed: false // TODO: (For PUT/PATCH ticket) decide - // if we should keep this, or solve this - // differently, or not at all + closed: false }); - arrayOfModels.push(cbModel); + arrayOfModels.push(cfModel); }); }; }); @@ -47,26 +63,52 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { me.populateTimesetStores(arrayOfModels); }; }, + + setVmToTrue: function (name) { + var vm = this.getViewModel(); + switch (name) { + case 'After Hours': + vm.set('after_hours_exists_in_api', true); + break; + case 'Company Hours': + vm.set('company_hours_exists_in_api', true); + break; + case 'List A': + vm.set('list_a_exists_in_api', true); + break; + case 'List B': + vm.set('list_b_exists_in_api', true); + break; + }; + }, + cfSourcesetStoreLoaded: function(store, data) { var me = this; var arrayOfModels = []; - store.removeAll(); - Ext.each(data, function (sourceset) { - var sourcesetName = sourceset.name; - var sourcesetId = sourceset.id; - Ext.each(sourceset.sources, function (sourceEntry) { - var cbModel = Ext.create('NgcpCsc.model.CallForward', { - id: Ext.id(), - sourceset_name: sourcesetName, - sourceset_id: sourcesetId, - source: sourceEntry.source + if (data.getData()._embedded == undefined) { + return; + } else { + var sourcesets = data.getData()._embedded['ngcp:cfsourcesets']; + store.removeAll(); + Ext.each(sourcesets, function (sourceset) { + var sourcesetName = sourceset.name; + var sourcesetId = sourceset.id; + me.setVmToTrue(sourcesetName); + Ext.each(sourceset.sources, function (sourceEntry) { + var cfModel = Ext.create('NgcpCsc.model.CallForward', { + id: Ext.id(), + sourceset_name: sourcesetName, + sourceset_id: sourcesetId, + source: sourceEntry.source + }); + arrayOfModels.push(cfModel); }); - arrayOfModels.push(cbModel); }); - }); - if (arrayOfModels.length > 0) { - me.populateSourcesetStores(arrayOfModels); - }; + if (arrayOfModels.length > 0) { + me.populateSourcesetStores(arrayOfModels); + }; + } + }, getTimesetFromRoute: function (route) { @@ -82,6 +124,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { break; }; }, + cfStoreLoaded: function(store, data) { var me = this; var cfTypeArrayOfObjects = [data.get('cfu'), data.get('cft'), data.get('cfb'), data.get('cfna')]; @@ -90,59 +133,59 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { var arrayOfModels = []; var currentRoute = window.location.hash; var routeTimeset = this.getTimesetFromRoute(currentRoute); - if(me.getView()._preventReLoad){ - return; - } + if (me.getView()._preventReLoad) return; store.removeAll(); // TODO optimize, too many nested loops affects performance. // Ex. Where possible use break Ext.each by return false; Ext.Ajax.request({ - url: window.location.origin + '/api/cfdestinationsets/?subscriber_id=' + localStorage.getItem('subscriber_id'), + url: '/api/cfdestinationsets/?subscriber_id=' + localStorage.getItem('subscriber_id'), success: function(response, opts) { var decodedResponse = Ext.decode(response.responseText); - var destinationsets = decodedResponse._embedded['ngcp:cfdestinationsets']; - me.getView()._preventReLoad = true; // assumes there is no need to reload the store - Ext.each(cfTypeArrayOfObjects, function (cfTypeObjects, index) { - var cfType = cfTypes[index]; - Ext.each(cfTypeObjects, function(cfTypeObject) { - var destinationsetName = cfTypeObject.destinationset; - var sourcesetName = cfTypeObject.sourceset; - var timesetName = cfTypeObject.timeset; - if (timesetName == routeTimeset) { - Ext.each(destinationsets, function(destinationset) { - if (destinationset.name == destinationsetName) { - for (item in destinationset.destinations) { - var destinationToUse = me.getDestinationFromSipId(destinationset.destinations[item].destination); - var destinationAnnouncementId = destinationset.announcement_id; - var destination = destinationset.destinations[item].destination; - var priority = destinationset.destinations[item].priority; - var simpleDestination = destinationset.destinations[item].simple_destination; - var destinationId = destinationset.id; - var destinationName = destinationset.name; - var ringFor = destinationToUse == 'Voicemail' ? '' : destinationset.destinations[item].timeout; - var cbModel = Ext.create('NgcpCsc.model.CallForward', { - type: cfType, - destination_cleaned: destinationToUse, - destination_announcement_id: destinationAnnouncementId, - destination: destination, - priority: priority, - simple_destination: simpleDestination, - ring_for: ringFor, - sourceset: sourcesetName, - timeset: timesetName, - destinationset_id: destinationId, - destinationset_name: destinationName - }); - arrayOfModels.push(cbModel); + if (decodedResponse._embedded) { + var destinationsets = decodedResponse._embedded['ngcp:cfdestinationsets']; + me.getView()._preventReLoad = true; // assumes there is no need to reload the store + Ext.each(cfTypeArrayOfObjects, function (cfTypeObjects, index) { + var cfType = cfTypes[index]; + Ext.each(cfTypeObjects, function(cfTypeObject) { + var destinationsetName = cfTypeObject.destinationset; + var sourcesetName = cfTypeObject.sourceset; + var timesetName = cfTypeObject.timeset; + if (timesetName == routeTimeset) { + Ext.each(destinationsets, function(destinationset) { + if (destinationset.name == destinationsetName) { + for (item in destinationset.destinations) { + var destinationToUse = me.getDestinationFromSipId(destinationset.destinations[item].destination); + var destinationAnnouncementId = destinationset.announcement_id; + var destination = destinationset.destinations[item].destination; + var priority = destinationset.destinations[item].priority; + var simpleDestination = destinationset.destinations[item].simple_destination; + var destinationId = destinationset.id; + var destinationName = destinationset.name; + var ringFor = destinationToUse == 'Voicemail' ? '' : destinationset.destinations[item].timeout; + var cbModel = Ext.create('NgcpCsc.model.CallForward', { + type: cfType, + destination_cleaned: destinationToUse, + destination_announcement_id: destinationAnnouncementId, + destination: destination, + priority: priority, + simple_destination: simpleDestination, + ring_for: ringFor, + sourceset: sourcesetName, + timeset: timesetName, + destinationset_id: destinationId, + destinationset_name: destinationName + }); + arrayOfModels.push(cbModel); + } } - } - }); - }; + }); + }; + }); }); - }); - if (arrayOfModels.length > 0) { - me.populateDestinationStores(arrayOfModels); - } + if (arrayOfModels.length > 0) { + me.populateDestinationStores(arrayOfModels); + }; + }; }, failure: function(response, opts) { @@ -152,9 +195,124 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { }, + destinationIdExistsInArray: function (arr, id) { + return arr.some(function(arrObj) { + return id == arrObj.id; + }); + }, + cfStoreBeforeSync: function(store, options) { - console.log('cfStoreBeforeSync'); - // TODO: (For PUT/PATCH ticket) Base on on CB module implementation + // TODO: #17654 Ensure we also have ability to display and write all + // required destination types, like voicemail, fax, conference, etc + var me = this; + var recordsToSend = []; + delete options['destroy']; + delete options['create']; + Ext.each(store.getRange(), function(record) { + var data = record.getData(); + switch (recordsToSend.length === 0 || !me.destinationIdExistsInArray(recordsToSend, data.destinationset_id)) { + case true: + recordsToSend.push({id: data.destinationset_id, records: [{ "announcement_id": null, "destination": data.simple_destination, "priority": data.priority, "timeout": data.ring_for }]}); + break; + case false: + recordsToSend.forEach(function (obj, index) { + if (obj.id == data.destinationset_id) { + recordsToSend[index].records.push({ "announcement_id": null, "destination": data.simple_destination, "priority": data.priority, "timeout": data.ring_for }); + } + }) + }; + }); + Ext.each(recordsToSend, function (obj) { + Ext.Ajax.request({ + url: '/api/cfdestinationsets/' + obj.id, + method: 'PATCH', + headers: { 'Content-Type': 'application/json-patch+json' }, + jsonData: [{ + "op": "add", + "path": "/destinations", + "value": obj.records + }], + success: function(response, opts) { + store.commitChanges(); + }, + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + } + }); + }); + return false; + }, + + cfSourcesetBeforeSync: function (store, options) { + // Using Ajax request here as we are using different url + // params for PATCH compared to GET + delete options['destroy']; + delete options['create']; + delete options['update']; + var sourcesetId = store.last().get('sourceset_id'); + var recordsToSend = []; + Ext.each(store.getRange(), function (record) { + var data = record.getData(); + recordsToSend.push({ "source": data.source }); + }); + Ext.Ajax.request({ + url: '/api/cfsourcesets/' + sourcesetId, + method: 'PATCH', + headers: { 'Content-Type': 'application/json-patch+json' }, + jsonData: [{ + "op": "add", + "path": "/sources", + "value": recordsToSend + }], + success: function(response, opts) { + store.commitChanges(); + }, + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + } + }); + return false; + }, + + timesBasedOnRecords: function (store) { + // TODO: Started this, but then discovered the issue leading to creation + // of #18401. Leaving the code in place for upcoming task #18401 + var recordsToSend = []; + Ext.each(store.getRange(), function(record) { + var data = record.getData(); + // console.log(data.time_from); + // console.log(data.time_to); + // For fields of data that have been changed in the grid, data is in + // this format: + // Tue Jan 01 2008 13:00:00 GMT+0100 (CET) + }); + return recordsToSend; + }, + + cfTimesetBeforeSync: function (store, options) { + delete options['destroy']; + delete options['create']; + delete options['update']; + var timesetId = store.last().get('timeset_id'); + // var recordsToSend = this.timesBasedOnRecords(store); + // TODO: Example ajax request for #18401 + // Ext.Ajax.request({ + // url: '/api/cftimesets/' + timesetId, + // method: 'PATCH', + // headers: { 'Content-Type': 'application/json-patch+json' }, + // jsonData: [{ + // "op": "add", + // "path": "/times", + // "value": recordsToSend + // }], + // success: function(response, opts) { + // console.log('server-side success with status code ' + response.status); + // }, + // failure: function(response, opts) { + // console.log('server-side failure with status code ' + response.status); + // } + // }); + return false; }, getDestinationFromSipId: function (destination) { @@ -181,6 +339,20 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { } }, + getTypeFromTypeName: function (type) { + switch (type) { + case 'Online': + return 'cfu'; + break; + case 'Busy': + return 'cfb'; + break; + case 'Offline': + return 'cfna'; + break; + } + }, + getSourceNameFromSourceSet: function (sourceset) { switch (sourceset) { case 'List A': @@ -195,6 +367,20 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { } }, + getSourceSetFromSourceName: function (sourceset) { + switch (sourceset) { + case 'listA': + return 'List A'; + break; + case 'listB': + return 'List B'; + break; + case null: + return null; + break; + } + }, + getTimeNameFromTimeSet: function (timeset) { switch (timeset) { case 'After Hours': @@ -209,6 +395,19 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { } }, + getTimeSetFromTimeSource: function (timeset) { + switch (timeset) { + case 'afterHours': + return 'After Hours'; + break; + case 'companyHours': + return 'Company Hours'; + break; + case null: + return null; + break; + } + }, getModuleFromRoute: function(currentRoute) { switch (currentRoute) { @@ -266,26 +465,12 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { }; }, - populateSourcesetStores: function (models) { - var storeListAAlways = Ext.getStore('CallForwardListA'); - var storeListBAlways = Ext.getStore('CallForwardListB'); - storeListAAlways.removeAll(); - storeListBAlways.removeAll(); - Ext.each(models, function (model) { - if (model.get('sourceset_name') == 'List A') { - storeListAAlways.add(model); - } else if (model.get('sourceset_name') == 'List B') { - storeListBAlways.add(model); - }; - }); - storeListAAlways.commitChanges(); - storeListBAlways.commitChanges(); - }, - populateDestinationStores: function (models) { var me = this; var gridName = this.getGridCategoryFromType(models[0].get('type')); var store; + // TODO: #17654 New grid logic and styling with conditions for cft/cfu, + // and remove first ring section Ext.each(models, function (model) { var sourcename = me.getSourceNameFromSourceSet(model.get('sourceset')); var timename = me.getTimeNameFromTimeSet(model.get('timeset')); @@ -301,23 +486,29 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { } }, - cfdestinationsetsClick: function () { - console.log('cfdestinationsetsClick'); - }, - - cfsourcesetsClick: function () { - console.log('cfsourcesetsClick'); - }, - - cftimesetsClick: function () { - console.log('cftimesetsClick'); + populateSourcesetStores: function (models) { + var storeListAAlways = Ext.getStore('CallForwardListA'); + var storeListBAlways = Ext.getStore('CallForwardListB'); + storeListAAlways.removeAll(); + storeListBAlways.removeAll(); + Ext.each(models, function (model) { + if (model.get('sourceset_name') == 'List A') { + storeListAAlways.add(model); + } else if (model.get('sourceset_name') == 'List B') { + storeListBAlways.add(model); + }; + }); + storeListAAlways.commitChanges(); + storeListBAlways.commitChanges(); }, editingPhoneDone: function(editor, context) { var record = context.record; var grid = context.grid; + var store = grid.getStore(); record.set("edit", false); grid.getView().refresh(); + store.sync(); }, beforePhoneEdit: function (editor, context) { @@ -405,25 +596,104 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { return target.indexOf(string) > -1; }, - saveEmptyRowToStore: function(grid) { + writeNewSourceToStore: function(grid) { + var vm = this.getViewModel(); var store = grid.getStore(); var plugin = grid.getPlugin('celleditingSource'); var newRowIndex = store.getCount() + 1; - var record = store.getAt(store.getCount() - 1); - if (record == null || (record.data.phone !== ' ' && record.data.phone !== '')) { - // Need to add whitespace in record when using widgetcolumn - store.add({ - "phone": " ", - "edit": true - }); - }; - plugin.startEditByPosition({ - row: newRowIndex, - column: 0 + var record = store.last(); + var sourcesetName = grid.id.split('-')[0] == 'listA' ? 'List A' : 'List B'; + var listAId = null; + var listBId = null; + var listExistsInApi = false; + Ext.Ajax.request({ + url: '/api/cfsourcesets/?subscriber_id=' + localStorage.getItem('subscriber_id'), + success: function(response, opts) { + var decodedResponse = Ext.decode(response.responseText); + if (decodedResponse._embedded) { + var sourcesets = decodedResponse._embedded['ngcp:cfsourcesets']; + Ext.each(sourcesets, function (destinationset, index) { + if (destinationset.name == 'List A') { + listAId = destinationset.id; + } else if (destinationset.name == 'List B') { + listBId = destinationset.id; + } + if (sourcesetName == 'List A' && listAId !== null) { + listExistsInApi = true; + } else if (sourcesetName == 'List B' && listBId !== null) { + listExistsInApi = true; + } + }); + }; + switch (!store.last()) { + case false: + if (record == null || (record.data.source !== ' ' && record.data.source !== '')) { + var cfSourcesetModel = Ext.create('NgcpCsc.model.CallForwardSourceset', { + id: Ext.id(), + source: " ", + sourceset_name: record.get('sourceset_name'), + sourceset_id: record.get('sourceset_id'), + edit: true + }); + store.add(cfSourcesetModel); + }; + break; + case true: // if store empty we need to create new sourceset + switch (listExistsInApi) { + case true: + var cfSourcesetModel = Ext.create('NgcpCsc.model.CallForwardSourceset', { + id: Ext.id(), + source: " ", + sourceset_name: sourcesetName, + sourceset_id: listAId || listBId, + edit: true + }); + store.add(cfSourcesetModel); + break; + case false: + var subscriberId = localStorage.getItem('subscriber_id'); + Ext.Ajax.request({ + url: '/api/cfsourcesets/', + method: 'POST', + jsonData: { + name: sourcesetName, + subscriber_id: subscriberId + }, + success: function(response, opts) { + var sourcesetId = response.getResponseHeader('Location').split('/')[3]; + var cfSourcesetModel = Ext.create('NgcpCsc.model.CallForward', { + id: Ext.id(), + source: " ", + sourceset_name: sourcesetName, + sourceset_id: sourcesetId, + edit: true + }); + store.add(cfSourcesetModel); + }, + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + } + }); + break; + } + break; + } + }, + + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + }, + + callback: function () { + plugin.startEditByPosition({ + row: newRowIndex, + column: 0 + }); + } }); }, - addEmptyRow: function(button) { + addEmptySourcesetRow: function(button) { var buttonIdSplit = button.id.split('-'); var buttonPrefixOne = buttonIdSplit[0]; var buttonPrefixTwo = buttonIdSplit[1]; @@ -431,11 +701,11 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { switch (buttonSuffix) { case 'addListAButton': var grid = Ext.getCmp(buttonPrefixOne + '-' + buttonPrefixTwo + '-cf-sourceset-list-a-grid'); - this.saveEmptyRowToStore(grid); + this.writeNewSourceToStore(grid); break; case 'addListBButton': var grid = Ext.getCmp(buttonPrefixOne + '-' + buttonPrefixTwo + '-cf-sourceset-list-b-grid'); - this.saveEmptyRowToStore(grid); + this.writeNewSourceToStore(grid); break; }; }, @@ -453,6 +723,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { var store = record.store; if(store){ store.remove(record); + store.sync(); } }, @@ -596,13 +867,10 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { case true: switch (Ext.isEmpty(newNumber) && newDest === 'Number') { case true: - me.fireEvent('showmessage', false, 'Number is required. Please retry.'); + me.fireEvent('showmessage', false, Ngcp.csc.locales.callforward.number_is_required[localStorage.getItem('languageSelected')]); break; case false: - targetStore.add({ - "phone": newDest, - "ring_for": "" - }); + me.writeNewDestinationToStore(targetStore, newDest, ""); me.hideThenFieldsByStoreName(vm, storeNameStripped); break; }; @@ -611,16 +879,13 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { case false: switch (Ext.isNumber(parseInt(newNumber))) { case false: - me.fireEvent('showmessage', false, 'Only numbers allowed. Please retry.'); + me.fireEvent('showmessage', false, Ngcp.csc.locales.callforward.only_numbers_allowed[localStorage.getItem('languageSelected')]); vm.set(storeNameCategory + '_then_number', ''); break; case true: var newTimeout = newDest === 'Number' ? vm.get(storeNameCategory + '_then_timeout') : ''; var newPhone = newDest === 'Number' ? newNumber : newDest; - targetStore.add({ - "phone": newPhone, - "ring_for": newTimeout - }); + me.writeNewDestinationToStore(targetStore, newPhone, parseInt(newTimeout)); vm.set(storeNameCategory + '_then_number', ''); me.hideThenFieldsByStoreName(vm, storeNameStripped); break; @@ -629,6 +894,126 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { }; }, + + createNewStandardSet: function (url, name, subscriberId) { + var vm = this.getViewModel(); + Ext.Ajax.request({ + url: url, + method: 'POST', + jsonData: { + name: name, + subscriber_id: subscriberId + }, + success: function(response, opts) { + switch (name) { + case 'List A': + vm.set('list_a_exists_in_api', true); + break; + case 'List B': + vm.set('list_b_exists_in_api', true); + break; + case 'After Hours': + vm.set('after_hours_exists_in_api', true); + break; + case 'Company Hours': + vm.set('company_hours_exists_in_api', true); + break; + } + } + }); + }, + + createNewMapping: function (subscriberId, newType, newDestinationsetName, newSourceset, newTimeset) { + Ext.Ajax.request({ + url: '/api/cfmappings/' + subscriberId, + method: 'PATCH', + headers: { 'Content-Type': 'application/json-patch+json' }, + jsonData: [{ + "op": "add", + "path": "/" + newType, + "value": [{ "destinationset": newDestinationsetName, "sourceset": newSourceset, "timeset": newTimeset }] + }] + }); + }, + + writeNewDestinationToStore: function (store, destination, timeout) { + var me = this; + var vm = this.getViewModel(); + var simpleDestination = destination; + var priority = 1; + var storeCount = store.getCount(); + var ringFor = destination == 'Voicemail' ? '' : timeout; + var destinationCleaned = destination; + var storeIdSplit = store.storeId.split('-'); + var newSourcesetName = storeIdSplit[0] == 'everybody' ? null : storeIdSplit[0]; + var newTimesetName = storeIdSplit[1] == 'always' ? null : storeIdSplit[1]; + var newTypeName = storeIdSplit[2].slice(11); + var newSourceset = this.getSourceSetFromSourceName(newSourcesetName); + var newTimeset = this.getTimeSetFromTimeSource(newTimesetName); + var newType = this.getTypeFromTypeName(newTypeName); + var newDomain = localStorage.getItem('domain'); + // TODO: #17654 Consider the fact that one destinationset can be in + // several grids, so if you write one, update all other grids with + // that same destinationset id + if (!store.last()) { // if store empty we need to create new destset + var newDestinationsetName = 'csc_defined_' + newType; + var subscriberId = localStorage.getItem('subscriber_id'); + Ext.Ajax.request({ + url: '/api/cfdestinationsets/', + method: 'POST', + defaultHeaders: 'Prefer: return=representation', + jsonData: { + name: newDestinationsetName, + subscriber_id: subscriberId + }, + success: function(response, opts) { + var destinationsetId = response.getResponseHeader('Location').split('/')[3]; + var cfModel = Ext.create('NgcpCsc.model.CallForward', { + type: newType, + destination_cleaned: destinationCleaned, + destination_announcement_id: null, + destination: 'sip:' + destination + '@' + newDomain, + // Keeping priority 1 as default for now, as we'll handle priotity + // with grid "drag-and-drop" widget plugin in upcoming task + priority: 1, + simple_destination: destination, + ring_for: ringFor, + sourceset: newSourceset, + timeset: newTimeset, + destinationset_id: destinationsetId, + destinationset_name: newDestinationsetName + }); + store.add(cfModel); + store.sync(); + // Creates new sourceset/timeset if variable is not set to null + newSourceset && me.createNewStandardSet('/api/cfsourcesets/', newSourceset, subscriberId); + newTimeset && me.createNewStandardSet('/api/cftimesets/', newTimeset, subscriberId); + me.createNewMapping(subscriberId, newType, newDestinationsetName, newSourceset, newTimeset); + }, + failure: function(response, opts) { + console.log('server-side failure with status code ' + response.status); + } + }); + } else { + var lastRecordInStore = store.last(); + var cfModel = Ext.create('NgcpCsc.model.CallForward', { + type: lastRecordInStore.get('type'), + destination_cleaned: destinationCleaned, + destination_announcement_id: null, + destination: 'sip:' + destination + '@' + newDomain, + priority: 1, + simple_destination: destination, + ring_for: ringFor, + sourceset: lastRecordInStore.get('sourceset'), + timeset: lastRecordInStore.get('timeset'), + destinationset_id: lastRecordInStore.get('destinationset_id'), + destinationset_name: lastRecordInStore.get('destinationset_name') + }); + store.add(cfModel); + store.sync(); + } + }, + addNewDestination: function(element) { var me = this; var vm = this.getViewModel(); @@ -649,8 +1034,15 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardController', { }; }, - saveGrid: function(el) { - this.fireEvent('showmessage', true, Ngcp.csc.locales.common.save_success[localStorage.getItem('languageSelected')]); + saveTimesetGrid: function(el) { + var storeName = el.id.split('-')[0] + '-Timeset'; + var store = Ext.getStore(storeName); + store.sync(); } + // TODO #18401, maybe use a blur or change listener on editors in grid + // editingTimeDone: function () { + // + // } + }); diff --git a/classic/src/view/pages/callforward/CallForwardMainForm.js b/classic/src/view/pages/callforward/CallForwardMainForm.js index a2a4c21b..5284ff9d 100644 --- a/classic/src/view/pages/callforward/CallForwardMainForm.js +++ b/classic/src/view/pages/callforward/CallForwardMainForm.js @@ -20,7 +20,6 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { var storeListA = Ext.getStore('CallForwardListA') || Ext.create('NgcpCsc.store.CallForwardSourceset', { storeId: 'CallForwardListA' }); - var storeListB = Ext.getStore('CallForwardListB') || Ext.create('NgcpCsc.store.CallForwardSourceset', { storeId: 'CallForwardListB' }); @@ -94,20 +93,24 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { xtype: 'panel', layout: 'hbox', margin: '15 0 0 0', - items: [{ - xtype: 'button', - html: Ngcp.csc.locales.callforward.change_title[localStorage.getItem('languageSelected')], - id: this._firstprefix + this._secondprefix + 'lista_titleField-showButton', - margin: '0 0 0 500', - handler: 'toggleChangeTitle' - }, { + items: [ + // NOTE: Commenting out this now, and will tackle it as part of #17651 + // { + // xtype: 'button', + // html: Ngcp.csc.locales.callforward.change_title[localStorage.getItem('languageSelected')], + // id: this._firstprefix + this._secondprefix + 'lista_titleField-showButton', + // margin: '0 0 0 500', + // handler: 'toggleChangeTitle' + // }, + { xtype: 'button', text: Ngcp.csc.locales.callforward.add_new_source[localStorage.getItem('languageSelected')], id: this._firstprefix + this._secondprefix + 'addListAButton', + margin: '0 0 0 620', + // margin: '0 0 0 10', width: 135, - margin: '0 0 0 10', listeners: { - click: 'addEmptyRow' + click: 'addEmptySourcesetRow' } }] }] @@ -154,20 +157,24 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { bind: { hidden: '{list_b}' }, - items: [{ - xtype: 'button', - html: Ngcp.csc.locales.callforward.change_title[localStorage.getItem('languageSelected')], - id: this._firstprefix + this._secondprefix + 'listb_titleField-showButton', - margin: '0 0 0 500', - handler: 'toggleChangeTitle' - }, { + items: [ + // NOTE: Commenting out this now, and will tackle it as part of #17651 + // { + // xtype: 'button', + // html: Ngcp.csc.locales.callforward.change_title[localStorage.getItem('languageSelected')], + // id: this._firstprefix + this._secondprefix + 'listb_titleField-showButton', + // margin: '0 0 0 500', + // handler: 'toggleChangeTitle' + // }, + { xtype: 'button', text: Ngcp.csc.locales.callforward.add_new_source[localStorage.getItem('languageSelected')], id: this._firstprefix + this._secondprefix + 'addListBButton', width: 135, - margin: '0 0 0 10', + margin: '0 0 0 620', + // margin: '0 0 0 10', listeners: { - click: 'addEmptyRow' + click: 'addEmptySourcesetRow' } }] }] @@ -278,7 +285,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { hidden: '{online_then_timeout_hidden}' }, allowBlank: false, - editable: false, + editable: true, flex: 4, margin: '0 0 0 10' }, { @@ -384,7 +391,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { hidden: '{busy_then_timeout_hidden}' }, allowBlank: false, - editable: false, + editable: true, flex: 4, margin: '0 0 0 10' }, { @@ -490,7 +497,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainForm', { hidden: '{offline_then_timeout_hidden}' }, allowBlank: false, - editable: false, + editable: true, flex: 4, margin: '0 0 0 10' }, { diff --git a/classic/src/view/pages/callforward/CallForwardMainGrid.js b/classic/src/view/pages/callforward/CallForwardMainGrid.js index cf60e9cb..b61f90c9 100644 --- a/classic/src/view/pages/callforward/CallForwardMainGrid.js +++ b/classic/src/view/pages/callforward/CallForwardMainGrid.js @@ -16,7 +16,10 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardMainGrid', { markDirty: false, emptyText: Ngcp.csc.locales.callforward.nowhere[localStorage.getItem('languageSelected')], deferEmptyText: false, - stripeRows: false + stripeRows: false, + listeners: { + drop: 'destinationDropped' + } }, // TODO: Leaving this for PUT/PATCH task, as it might make sense to use diff --git a/classic/src/view/pages/callforward/CallForwardModel.js b/classic/src/view/pages/callforward/CallForwardModel.js index 8dc6b3ce..5f4582ee 100644 --- a/classic/src/view/pages/callforward/CallForwardModel.js +++ b/classic/src/view/pages/callforward/CallForwardModel.js @@ -1,6 +1,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.callforward', + // left inline as non-Api data data: { after_hours: true, @@ -37,8 +38,10 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardModel', { source_listb_title: 'List B', hide_lista_titleField: true, hide_listb_titleField: true, - afterHours_hideMessage: false, - companyHours_hideMessage: false + list_a_exists_in_api: false, + list_b_exists_in_api: false, + after_hours_exists_in_api: false, + company_hours_exists_in_api: false }, formulas: { diff --git a/classic/src/view/pages/callforward/CallForwardSourcesetGrid.js b/classic/src/view/pages/callforward/CallForwardSourcesetGrid.js index 5eb02b6e..325fab01 100644 --- a/classic/src/view/pages/callforward/CallForwardSourcesetGrid.js +++ b/classic/src/view/pages/callforward/CallForwardSourcesetGrid.js @@ -11,20 +11,15 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardSourcesetGrid', { clicksToEdit: 1 }, - hideHeaders: true, - - width: '100%', - listeners: { edit: 'editingPhoneDone', - beforeedit: 'beforePhoneEdit', - click: { - fn: 'saveGrid', - element: 'el', - delegate: 'a.edit-button' - } + beforeedit: 'beforePhoneEdit' }, + hideHeaders: true, + + width: '100%', + initComponent: function() { this.columns = { defaults: { diff --git a/classic/src/view/pages/callforward/CallForwardTimesetGrid.js b/classic/src/view/pages/callforward/CallForwardTimesetGrid.js index d64e5561..d2e6678c 100644 --- a/classic/src/view/pages/callforward/CallForwardTimesetGrid.js +++ b/classic/src/view/pages/callforward/CallForwardTimesetGrid.js @@ -7,6 +7,11 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { markDirty: false }, + // TODO: #18401 + // listeners: { + // edit: 'editingTimeDone' + // }, + initComponent: function() { this.columns = { defaults: { @@ -20,7 +25,7 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { flex: 1 }, { text: Ngcp.csc.locales.common.from[localStorage.getItem('languageSelected')], - dataIndex: 'time_from', + dataIndex: 'time_from', // TODO: #18401 Add listener xtype: 'widgetcolumn', editable: false, flex: 1, @@ -28,12 +33,13 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { xtype: 'timefield', tooltip: Ngcp.csc.locales.callforward.tooltips.change_time_from[localStorage.getItem('languageSelected')], bind: { - disabled: '{record.closed}' + disabled: '{record.closed}', + value: '{record.time_from}' } } }, { text: Ngcp.csc.locales.common.to[localStorage.getItem('languageSelected')], - dataIndex: 'time_to', + dataIndex: 'time_to', // TODO: #18401 Add listener xtype: 'widgetcolumn', editable: false, flex: 1, @@ -41,7 +47,8 @@ Ext.define('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { xtype: 'timefield', tooltip: Ngcp.csc.locales.callforward.tooltips.change_time_to[localStorage.getItem('languageSelected')], bind: { - disabled: '{record.closed}' + disabled: '{record.closed}', + value: '{record.time_to}' } } }, { diff --git a/classic/src/view/pages/callforward/afterhours/AfterHours.js b/classic/src/view/pages/callforward/afterhours/AfterHours.js index dac839a4..4e5dacb2 100644 --- a/classic/src/view/pages/callforward/afterhours/AfterHours.js +++ b/classic/src/view/pages/callforward/afterhours/AfterHours.js @@ -19,6 +19,9 @@ Ext.define('NgcpCsc.view.pages.callforward.afterhours.Afterhours', { var callForwardAfterGrid = Ext.create('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { id: 'cf-timeset-after-grid', + bind: { + hidden: '{!after_hours_exists_in_api}' + }, store: Ext.create('NgcpCsc.store.CallForwardTimeset', { storeId: 'afterHours-Timeset' }) @@ -47,9 +50,9 @@ Ext.define('NgcpCsc.view.pages.callforward.afterhours.Afterhours', { items: [{ xtype: 'panel', margin: '10 0 10 0', - html: 'You have not set your after hours calendar yet.', // TODO: Locales or icon, or both. Will wait for feedback from Andreas in next sync-up + html: Ngcp.csc.locales.callforward.no_after_hours_set[localStorage.getItem('languageSelected')], bind: { - hidden: '{afterHours_hideMessage}' + hidden: '{after_hours_exists_in_api}' } }, callForwardAfterGrid, { @@ -60,7 +63,10 @@ Ext.define('NgcpCsc.view.pages.callforward.afterhours.Afterhours', { width: 135, margin: '10 0 10 623', listeners: { - click: 'saveGrid' + click: 'saveTimesetGrid' + }, + bind: { + hidden: '{!after_hours_exists_in_api}' } } ] @@ -68,12 +74,18 @@ Ext.define('NgcpCsc.view.pages.callforward.afterhours.Afterhours', { }, { xtype: 'panel', width: '100%', - title: Ngcp.csc.locales.callforward.for_calling_parties[localStorage.getItem('languageSelected')] + title: Ngcp.csc.locales.callforward.for_calling_parties[localStorage.getItem('languageSelected')], + bind: { + hidden: '{!after_hours_exists_in_api}' + } }, { xtype: 'cftab', _tabId: 'afterhours', _firstPrefixes: ['everybody-', 'listA-', 'listB-'], - _secondprefix: 'afterHours-' + _secondprefix: 'afterHours-', + bind: { + hidden: '{!after_hours_exists_in_api}' + } }] }]; this.callParent(); diff --git a/classic/src/view/pages/callforward/companyhours/CompanyHours.js b/classic/src/view/pages/callforward/companyhours/CompanyHours.js index 24b1e615..91d48fc5 100644 --- a/classic/src/view/pages/callforward/companyhours/CompanyHours.js +++ b/classic/src/view/pages/callforward/companyhours/CompanyHours.js @@ -6,7 +6,7 @@ Ext.define('NgcpCsc.view.pages.callforward.companyhours.Companyhours', { ui: 'cf-mainform', initComponent: function() { - var cfInitialStore = Ext.create('NgcpCsc.store.CallForward',{ + var cfInitialStore = Ext.create('NgcpCsc.store.CallForward', { storeId: 'CallForwardCompanyHours', _type: 'companyHours', autoLoad: true, @@ -22,6 +22,9 @@ Ext.define('NgcpCsc.view.pages.callforward.companyhours.Companyhours', { var callForwardCompanyGrid = Ext.create('NgcpCsc.view.pages.callforward.CallForwardTimesetGrid', { id: 'cf-timeset-company-grid', + bind: { + hidden: '{!company_hours_exists_in_api}' + }, store: Ext.create('NgcpCsc.store.CallForwardTimeset', { storeId: 'companyHours-Timeset' }) @@ -48,13 +51,13 @@ Ext.define('NgcpCsc.view.pages.callforward.companyhours.Companyhours', { }, userCls: 'big-33 small-100 cf-calls-during-section', items: [{ - xtype: 'panel', - margin: '10 0 10 0', - html: 'You have not set your company hours calendar yet.', // TODO: Locales or icon, or both. Will wait for feedback from Andreas in next sync-up - bind: { - hidden: '{companyHours_hideMessage}' - } - }, + xtype: 'panel', + margin: '10 0 10 0', + html: Ngcp.csc.locales.callforward.no_company_hours_set[localStorage.getItem('languageSelected')], + bind: { + hidden: '{company_hours_exists_in_api}' + } + }, callForwardCompanyGrid, { text: Ngcp.csc.locales.common.save_caps[localStorage.getItem('languageSelected')], @@ -64,7 +67,10 @@ Ext.define('NgcpCsc.view.pages.callforward.companyhours.Companyhours', { width: 135, margin: '10 0 10 585', listeners: { - click: 'saveGrid' + click: 'saveTimesetGrid' + }, + bind: { + hidden: '{!company_hours_exists_in_api}' } } ] @@ -72,12 +78,18 @@ Ext.define('NgcpCsc.view.pages.callforward.companyhours.Companyhours', { }, { xtype: 'panel', width: '100%', - title: Ngcp.csc.locales.callforward.for_calling_parties[localStorage.getItem('languageSelected')] + title: Ngcp.csc.locales.callforward.for_calling_parties[localStorage.getItem('languageSelected')], + bind: { + hidden: '{!company_hours_exists_in_api}' + } }, { xtype: 'cftab', _tabId: 'companyhours', _firstPrefixes: ['everybody-', 'listA-', 'listB-'], - _secondprefix: 'companyHours-' + _secondprefix: 'companyHours-', + bind: { + hidden: '{!company_hours_exists_in_api}' + } }] }]; this.callParent();