define(function(require){ var $ = require('jquery'), _ = require('underscore'), monster = require('monster'), chart = require('chart'); var app = { requests: { 'voip.myOffice.getAccount': { url: 'accounts/{accountId}', verb: 'GET' }, 'voip.myOffice.updateAccount': { url: 'accounts/{accountId}', verb: 'POST' }, 'voip.myOffice.listUsers': { url: 'accounts/{accountId}/users', verb: 'GET' }, 'voip.myOffice.listDevices': { url: 'accounts/{accountId}/devices', verb: 'GET' }, 'voip.myOffice.getDevicesStatus': { url: 'accounts/{accountId}/devices/status', verb: 'GET' }, 'voip.myOffice.listNumbers': { url: 'accounts/{accountId}/phone_numbers', verb: 'GET' }, 'voip.myOffice.getNumber': { url: 'accounts/{accountId}/phone_numbers/{phoneNumber}', verb: 'GET' }, 'voip.myOffice.updateNumber': { url: 'accounts/{accountId}/phone_numbers/{phoneNumber}', verb: 'POST' }, 'voip.myOffice.listDirectories': { url: 'accounts/{accountId}/directories', verb: 'GET' }, 'voip.myOffice.listChannels': { url: 'accounts/{accountId}/channels', verb: 'GET' }, 'voip.myOffice.listTypedCallflows': { url: 'accounts/{accountId}/callflows?has_value=type', verb: 'GET' }, 'voip.myOffice.listMedia': { url: 'accounts/{accountId}/media?key_missing=type', verb: 'GET' }, 'voip.myOffice.createMedia': { url: 'accounts/{accountId}/media', verb: 'PUT' }, 'voip.myOffice.deleteMedia': { url: 'accounts/{accountId}/media/{mediaId}', verb: 'DELETE' }, 'voip.myOffice.uploadMedia': { url: 'accounts/{accountId}/media/{mediaId}/raw', verb: 'POST', type: 'application/x-base64' } }, subscribe: { 'voip.myOffice.render': 'myOfficeRender' }, chartColors: [ "#B588B9", // Purple ~ Mauve "#698BF7", // Purple ~ Dark Blue "#009AD6", // Blue "#6CC5E9", // Light Blue "#719B11", // Dark Green "#BDE55F", // Light Green "#F1E87C", // Pale Yellow "#EF8F25", // Orange "#6F7C7D" // Grey ], /* My Office */ myOfficeRender: function(args) { var self = this, parent = args.parent || $('.right-content'); self.myOfficeLoadData(function(myOfficeData) { var dataTemplate = { account: myOfficeData.account, totalUsers: myOfficeData.users.length, totalDevices: myOfficeData.devices.length, unregisteredDevices: myOfficeData.devices.length - myOfficeData.devicesStatus.length, totalNumbers: _.size(myOfficeData.numbers), totalConferences: myOfficeData.totalConferences, totalChannels: myOfficeData.totalChannels, mainNumbers: myOfficeData.mainNumbers || [], confNumbers: myOfficeData.confNumbers || [], faxNumbers: myOfficeData.faxNumbers || [], topMessage: myOfficeData.topMessage, devicesList: _.toArray(myOfficeData.devicesData).sort(function(a, b) { return b.count - a.count ; }), assignedNumbersList: _.toArray(myOfficeData.assignedNumbersData).sort(function(a, b) { return b.count - a.count ; }), // numberTypesList: _.toArray(myOfficeData.numberTypesData).sort(function(a, b) { return b.count - a.count ; }), classifiedNumbers: myOfficeData.classifiedNumbers }, template = $(monster.template(self, 'myOffice-layout', dataTemplate)), chartOptions = { animateScale: true, segmentShowStroke: false, // segmentStrokeWidth: 1, animationSteps: 50, animationEasing: "easeOutCirc", percentageInnerCutout: 60 }, devicesChart = new Chart(template.find('#dashboard_devices_chart').get(0).getContext("2d")).Doughnut( myOfficeData.devicesData.totalCount > 0 ? $.map(myOfficeData.devicesData, function(val) { return typeof val === 'object' ? { value: val.count, color: val.color } : null; }).sort(function(a, b) { return b.value - a.value ; }) : [{ value:1, color:"#DDD" }], chartOptions ), assignedNumbersChart = new Chart(template.find('#dashboard_assigned_numbers_chart').get(0).getContext("2d")).Doughnut( myOfficeData.assignedNumbersData.totalCount > 0 ? $.map(myOfficeData.assignedNumbersData, function(val) { return typeof val === 'object' ? { value: val.count, color: val.color } : null; }).sort(function(a, b) { return b.value - a.value ; }) : [{ value:1, color:"#DDD" }], chartOptions ), numberTypesChart = new Chart(template.find('#dashboard_number_types_chart').get(0).getContext("2d")).Doughnut( // $.map(myOfficeData.numberTypesData, function(val) { // return { // value: val.count, // color: val.color // }; // }).sort(function(a, b) { return b.value - a.value ; }), myOfficeData.classifiedNumbers.length > 0 ? $.map(myOfficeData.classifiedNumbers, function(val, index) { return typeof val === 'object' ? { value: val.count, color: val.color } : null; }) : [{ value:1, color:"#DDD" }], chartOptions ); // Trick to adjust the vertical positioning of the number types legend if(myOfficeData.classifiedNumbers.length <= 3) { template.find('.number-types-legend').addClass('size-'+myOfficeData.classifiedNumbers.length); } self.myOfficeBindEvents({ parent: parent, template: template, myOfficeData: myOfficeData }); parent .empty() .append(template); }); }, myOfficeLoadData: function(callback) { var self = this; monster.parallel({ account: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.getAccount', data: { accountId: self.accountId }, success: function(dataUsers) { parallelCallback && parallelCallback(null, dataUsers.data); } }); }, users: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.listUsers', data: { accountId: self.accountId }, success: function(dataUsers) { parallelCallback && parallelCallback(null, dataUsers.data); } }); }, devices: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.listDevices', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data); } }); }, devicesStatus: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.getDevicesStatus', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data); } }); }, numbers: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.listNumbers', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data.numbers); } }); }, numberFeatures: function(callback) { monster.pub('common.numbers.getListFeatures', function(features) { callback(null, features); }); }, channels: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.listChannels', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data); } }); }, callflows: function(parallelCallback) { monster.request({ resource: 'voip.myOffice.listTypedCallflows', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data); } }); }, classifiers: function(parallelCallback) { self.callApi({ resource: 'numbers.listClassifiers', data: { accountId: self.accountId }, success: function(data) { parallelCallback && parallelCallback(null, data.data); } }); } }, function(error, results) { callback && callback(self.myOfficeFormatData(results)); } ); }, myOfficeFormatData: function(data) { var self = this, devices = { "sip_device": { label: self.i18n.active().devices.types.sip_device, count: 0, color: self.chartColors[5] }, "cellphone": { label: self.i18n.active().devices.types.cellphone, count: 0, color: self.chartColors[3] }, "smartphone": { label: self.i18n.active().devices.types.smartphone, count: 0, color: self.chartColors[2] }, "mobile": { label: self.i18n.active().devices.types.mobile, count: 0, color: self.chartColors[1] }, "softphone": { label: self.i18n.active().devices.types.softphone, count: 0, color: self.chartColors[0] }, "landline": { label: self.i18n.active().devices.types.landline, count: 0, color: self.chartColors[6] }, "fax": { label: self.i18n.active().devices.types.fax, count: 0, color: self.chartColors[7] }, "ata": { label: self.i18n.active().devices.types.ata, count: 0, color: self.chartColors[8] }, "sip_uri": { label: self.i18n.active().devices.types.sip_uri, count: 0, color: self.chartColors[4] }, totalCount: 0 }, assignedNumbers = { "spare": { label: self.i18n.active().myOffice.numberChartLegend.spare, count: 0, color: self.chartColors[8] }, "assigned": { label: self.i18n.active().myOffice.numberChartLegend.assigned, count: 0, color: self.chartColors[3] }, totalCount: 0 }, // numberTypes = { // "local": { // label: self.i18n.active().myOffice.numberChartLegend.local, // count: 0, // color: "#6cc5e9" // }, // "tollfree": { // label: self.i18n.active().myOffice.numberChartLegend.tollfree, // count: 0, // color: "#bde55f" // }, // "international": { // label: self.i18n.active().myOffice.numberChartLegend.international, // count: 0, // color: "#b588b9" // } // }, totalConferences = 0, channelsArray = [], classifierRegexes = {}, classifiedNumbers = {}; _.each(data.numbers, function(numData, num) { _.find(data.classifiers, function(classifier, classifierKey) { if(!(classifierKey in classifierRegexes)) { classifierRegexes[classifierKey] = new RegExp(classifier.regex); } if(classifierRegexes[classifierKey].test(num)) { if(classifierKey in classifiedNumbers) { classifiedNumbers[classifierKey] ++; } else { classifiedNumbers[classifierKey] = 1; } return true; } else { return false; } }); }); data.classifiedNumbers = _.map(classifiedNumbers, function(val, key) { return { key: key, label: key in data.classifiers ? data.classifiers[key].friendly_name : key, count: val }; }).sort(function(a,b) { return b.count - a.count }); var maxLength = self.chartColors.length; if(data.classifiedNumbers.length > maxLength) { data.classifiedNumbers[maxLength-1].key = 'merged_others'; data.classifiedNumbers[maxLength-1].label = 'Others'; while(data.classifiedNumbers.length > maxLength) { data.classifiedNumbers[maxLength-1].count += data.classifiedNumbers.pop().count; } } _.each(data.classifiedNumbers, function(val, key) { val.color = self.chartColors[key]; }); _.each(data.devices, function(val) { if(val.device_type in devices) { devices[val.device_type].count++; devices.totalCount++; } else { console.log('Unknown device type: '+val.device_type); } }); _.each(data.numbers, function(val) { if("used_by" in val && val["used_by"].length > 0) { assignedNumbers["assigned"].count++; } else { assignedNumbers["spare"].count++; } assignedNumbers.totalCount++; //TODO: Find out the number type and increment the right category // numberTypes["local"].count++; }); _.each(data.users, function(val) { if(val.features.indexOf("conferencing") >= 0) { totalConferences++; } }); _.each(data.callflows, function(val) { var numberArrayName = ''; if(val.type === "main" && val.name === "MainCallflow") { numberArrayName = 'mainNumbers'; } else if(val.type === "conference" && val.name === "MainConference") { numberArrayName = 'confNumbers'; } if(numberArrayName.length > 0) { if(!(numberArrayName in data)) { data[numberArrayName] = []; } _.each(val.numbers, function(num) { if(num !== 'undefined' && num !== 'undefinedconf') { var number = { number: num, features: $.extend(true, {}, data.numberFeatures) }; if(num in data.numbers) { _.each(data.numbers[num].features, function(feature) { number.features[feature].active = 'active'; }); } data[numberArrayName].push(number); } }); } }); _.each(data.channels, function(val) { if(channelsArray.indexOf(val.bridge_id) < 0) { channelsArray.push(val.bridge_id); } }) if( data.mainNumbers && data.mainNumbers.length > 0 && ( !('caller_id' in data.account) || !('emergency' in data.account.caller_id) || !('number' in data.account.caller_id.emergency) || !(data.account.caller_id.emergency.number in data.numbers) || data.numbers[data.account.caller_id.emergency.number].features.indexOf('dash_e911') < 0 ) ) { data.topMessage = { class: 'btn-danger', message: self.i18n.active().myOffice.missingE911Message } } data.totalChannels = channelsArray.length; data.devicesData = devices; data.assignedNumbersData = assignedNumbers; // data.numberTypesData = numberTypes; data.totalConferences = totalConferences; return data; }, myOfficeBindEvents: function(args) { var self = this, parent = args.parent, template = args.template, myOfficeData = args.myOfficeData; template.find('.link-box').on('click', function(e) { var $this = $(this), category = $this.data('category'), subcategory = $this.data('subcategory'); $('.category#my_office').removeClass('active'); switch(category) { case "users": $('.category#users').addClass('active'); monster.pub('voip.users.render', { parent: parent }); break; case "devices": $('.category#devices').addClass('active'); monster.pub('voip.devices.render', { parent: parent }); break; case "numbers": $('.category#numbers').addClass('active'); monster.pub('voip.numbers.render', parent); break; case "strategy": $('.category#strategy').addClass('active'); monster.pub('voip.strategy.render', { parent: parent, openElement: subcategory }); break; } }); template.find('.header-link.music-on-hold').on('click', function(e) { e.preventDefault(); self.myOfficeRenderMusicOnHoldPopup({ account: myOfficeData.account }); }); template.find('.header-link.caller-id').on('click', function(e) { e.preventDefault(); self.myOfficeRenderCallerIdPopup({ parent: parent, myOfficeData: myOfficeData }); }); template.find('[data-toggle="tooltip"]').tooltip(); }, myOfficeRenderMusicOnHoldPopup: function(args) { var self = this, account = args.account, silenceMediaId = 'silence_stream://300000'; self.groupsListMedias(function(medias) { var templateData = { silenceMedia: silenceMediaId, mediaList: medias, media: 'music_on_hold' in account && 'media_id' in account.music_on_hold ? account.music_on_hold.media_id : undefined }, popupTemplate = $(monster.template(self, 'myOffice-musicOnHoldPopup', templateData)), popup = monster.ui.dialog(popupTemplate, { title: self.i18n.active().myOffice.musicOnHold.title, position: ['center', 20] }); self.myOfficeMusicOnHoldPopupBindEvents({ popupTemplate: popupTemplate, popup: popup, account: account }) }); }, myOfficeMusicOnHoldPopupBindEvents: function(args) { var self = this, popupTemplate = args.popupTemplate, popup = args.popup, account = args.account, closeUploadDiv = function(newMedia) { var uploadInput = popupTemplate.find('.upload-input'); uploadInput.wrap('