define(function(require){ var $ = require('jquery'), _ = require('underscore'), monster = require('monster'), toastr = require('toastr'); require([ 'datatables.net', 'datatables.net-bs', 'datatables.net-buttons', 'datatables.net-buttons-html5', 'datatables.net-buttons-bootstrap' ]); var app = { name: 'callcenter', css: [ 'app', 'icons' ], i18n: { 'en-US': { customCss: false }, 'de-DE': { customCss: false }, 'dk-DK': { customCss: false }, 'it-IT': { customCss: false }, 'fr-FR': { customCss: false }, 'nl-NL': { customCss: false }, 'ro-RO': { customCss: false }, 'ru-RU': { customCss: false }, 'pt-PT': { customCss: false }, 'zh-CN': { customCss: false }, 'es-ES': { customCss: false } }, requests: { /* move here all unstandart request 'google.getUser': { apiRoot: 'http://api.google.com/', url: 'users', verb: 'PUT' }*/ }, load: function(callback){ var self = this; self.initApp(function() { callback && callback(self); }); }, global_timer: false, current_queue_id: undefined, hide_logout: false, map_timers: { calls_waiting: {}, calls_in_progress: {} }, vars: { users: [] }, initApp: function(callback) { var self = this; monster.pub('auth.initApp', { app: self, callback: callback }); self.initHandlebarsHelpers(); }, initHandlebarsHelpers: function() { Handlebars.registerHelper('inc', function(value, options) { return parseInt(value) + 1; }); Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) { var operators, result; if (arguments.length < 3) { throw new Error('Handlerbars Helper \'compare\' needs 2 parameters'); } if (options === undefined) { options = rvalue; rvalue = operator; operator = '==='; } operators = { '==': function (l, r) { return l == r; }, '===': function (l, r) { return l === r; }, '!=': function (l, r) { return l != r; }, '!==': function (l, r) { return l !== r; }, '<': function (l, r) { return l < r; }, '>': function (l, r) { return l > r; }, '<=': function (l, r) { return l <= r; }, '>=': function (l, r) { return l >= r; }, 'typeof': function (l, r) { return typeof l == r; } }; if (!operators[operator]) { throw new Error('Handlerbars Helper \'compare\' doesn\'t know the operator ' + operator); } result = operators[operator](lvalue, rvalue); if (result) { return options.fn(this); } else { return options.inverse(this); } }); }, initHeaderSubmenu: function() { var $headerMenu = $('#cc-header-menu'); $headerMenu.on('mouseenter', function(){ $(this).find('.js-header-menu-items').show(); $(this).find('.js-header-menu-title').hide(); }).on('mouseleave', function(){ $(this).find('.js-header-menu-items').hide(); $(this).find('.js-header-menu-title').show(); }).on('click', function(e){ e.preventDefault(); }); }, queue_eavesdrop: function (callback) { var self = this; self.callApi({ resource: 'queues.queue_eavesdrop', data: { accountId: self.accountId }, success: function (queue_eavesdrop) { callback(queue_eavesdrop.data); } }); }, /* listDevices: function (callback) { var self = this; self.callApi({ resource: 'device.list', data: { accountId: self.accountId }, success: function (devices) { callback(devices.data); } }); },*/ poll_agents: function (global_data, _container) { var self = this, container = _container, polling_interval = 6, map_agents = {}, cpt = 0, current_queue, current_global_data = global_data, stop_light_polling = false, poll = function () { var data_template = $.extend(true, {}, { agents: current_global_data.agents, queues: current_global_data.queues }); //copy without reference; if (stop_light_polling === false) { monster.parallel( { queues_livestats: function (callback) { self.get_queues_livestats(function (_data_live_queues) { callback(null, _data_live_queues); }); }, agents_livestats: function (callback) { self.get_agents_livestats(function (_data_live_agents) { callback(null, _data_live_agents); }); }, agents_status: function (callback) { self.get_agents_status(function (_data_live_status) { callback(null, _data_live_status); }, function (_data_live_status) { callback(null, {}); } ); } }, function (err, results) { data_template = self.format_live_data(data_template, { agents_live_stats: results.agents_livestats, queues_live_stats: results.queues_livestats, agents_live_status: results.agents_status }); } ); } }, huge_poll = function () { if ($('#dashboard-content').size() === 0) { self.clean_timers(); } else { if (++cpt % 30 === 0) { self.fetch_all_data(function (data) { current_global_data = data; }); } else { poll(); } } }; $.each(global_data.agents, function (k, v) { map_agents[v.id] = 'logged_out'; }); self.global_timer = setInterval(huge_poll, polling_interval * 1000); }, get_queues_livestats: function (callback) { var self = this; self.callApi({ resource: 'queues.queues_livestats', data: { accountId: self.accountId }, success: function (queue_livestats) { callback(queue_livestats.data); } }); }, get_agents_status: function (callback) { var self = this; self.callApi({ resource: 'agents.agents_status', data: { accountId: self.accountId }, success: function (agents_status) { callback(agents_status.data); } }); }, get_agents_livestats: function (callback) { var self = this; self.callApi({ resource: 'agents.agents_livestats', data: { accountId: self.accountId }, success: function (agents_livestats) { callback(agents_livestats.data); } }); }, get_agents_stats: function (callback) { var self = this; self.callApi({ resource: 'agents.agents_status', data: { accountId: self.accountId }, success: function (agents_status) { callback(agents_status.data); } }); }, /*get_queues_stats: function (callback) { var self = this; self.callApi({ resource: 'queues.queues_stats', data: { accountId: self.accountId }, success: function (queues_stats) { callback(queues_stats.data); } }); },*/ get_queues: function (callback) { var self = this; self.callApi({ resource: 'queues.queues_list', data: { accountId: self.accountId }, success: function (data) { callback && callback(data.data); } }); }, get_agents: function (callback) { var self = this; self.callApi({ resource: 'agents.agents_list', data: { accountId: self.accountId }, success: function (agents) { callback(agents.data); } }); }, /*render_callwaiting_list: function (_container) { var self = this, container = _container || $('#dashboard-content'); $('#callwaiting-list', container).empty().listpanel({ label: 'Call Waiting', identifier: 'callwaiting-listview', data: [] }); $('.add_flow', container).empty().html('call_waiting_log'); },*/ get_time_seconds: function (seconds) { var seconds = Math.floor(seconds), hours = Math.floor(seconds / 3600), minutes = Math.floor(seconds / 60) % 60, remaining_seconds = seconds % 60, display_time = (hours < 10 ? '0' + hours : '' + hours) + ':' + (minutes < 10 ? '0' + minutes : '' + minutes) + ':' + (remaining_seconds < 10 ? '0' + remaining_seconds : '' + remaining_seconds); return seconds >= 0 ? display_time : '00:00:00'; }, format_live_data: function (formatted_data, data) { var self = this, current_agents_by_queue = {}; formatted_data.current_timestamp = data.queues_live_stats.current_timestamp; formatted_data.calls_waiting = {}; formatted_data.calls_in_progress = {}; formatted_data.agent_status = { busy: {}, wrapup: {}, paused: {} }; //Reinitializing previous data; $.each(formatted_data.queues, function (k, queue) { queue.abandoned_calls = 0; queue.average_hold_time = self.get_time_seconds(0); queue.current_calls = 0; queue.total_calls = 0; queue.total_wait_time = 0; }); if(data.agents_live_status) { $.each(data.agents_live_status, function(k, agent_status) { if(k in formatted_data.agents) { if(agent_status.status === 'outbound') { agent_status.status = 'busy'; } if(agent_status.status === 'connected') { agent_status.status = 'handling'; } var current_status = agent_status.status; formatted_data.agents[k].status = current_status; formatted_data.agents[k].status_started = agent_status.timestamp; if($.inArray(current_status, ['busy', 'wrapup', 'paused']) >= 0) { formatted_data.agent_status[current_status][k] = agent_status; if(current_status === 'busy') { formatted_data.agents[k].call_time = self.get_time_seconds(formatted_data.current_timestamp - agent_status.timestamp) } else if(current_status === 'paused') { if('pause_time' in agent_status) { formatted_data.agents[k].call_time = self.get_time_seconds(agent_status.pause_time - (formatted_data.current_timestamp - agent_status.timestamp)) } else { formatted_data.agents[k].call_time = self.get_time_seconds(formatted_data.current_timestamp - agent_status.timestamp) } } else { formatted_data.agents[k].call_time = self.get_time_seconds(agent_status.wait_time - (formatted_data.current_timestamp - agent_status.timestamp)); } } else if(current_status === 'connecting') { formatted_data.agents[k].current_call = { friendly_title: agent_status.caller_id_name || agent_status.caller_id_number || agent_status.call_id }; } if(current_status !== 'logged_out') { $.each(formatted_data.agents[k].queues_list, function(queue_id, queue_data) { if(!(queue_id in current_agents_by_queue)) { current_agents_by_queue[queue_id] = 1; } else { current_agents_by_queue[queue_id]++; } }); } } }); } $.each(current_agents_by_queue, function(queue_id, count) { if(queue_id in formatted_data.queues) { formatted_data.queues[queue_id].current_agents = count || 0; } }); $.each(data.agents_live_stats, function(k, agent_stats) { if(k in formatted_data.agents) { formatted_data.agents[k].missed_calls = agent_stats.missed_calls || 0; formatted_data.agents[k].total_calls = agent_stats.total_calls || 0; if('queues' in agent_stats) { $.each(agent_stats.queues, function(queue_id, queue_stat) { if(queue_id in formatted_data.agents[k].queues_list) { formatted_data.agents[k].queues_list[queue_id] = { id: queue_id || '', missed_calls: queue_stat.missed_calls || 0, total_calls: queue_stat.total_calls || 0 }; } }); } } }); if('stats' in data.queues_live_stats) { $.each(data.queues_live_stats.stats, function(index, queue_stats) { var k = queue_stats.queue_id, call_id = queue_stats.call_id; if(typeof formatted_data.queues[k] == "object") { formatted_data.queues[k].current_calls = formatted_data.queues[k].current_calls || 0; if('wait_time' in queue_stats && queue_stats.status !== 'abandoned') { formatted_data.queues[k].total_wait_time += queue_stats.wait_time; } if(queue_stats.status === 'abandoned') { formatted_data.queues[k].abandoned_calls++; formatted_data.queues[k].total_calls++; } else if(queue_stats.status === 'waiting') { formatted_data.calls_waiting[call_id] = queue_stats; formatted_data.calls_waiting[call_id].friendly_duration = self.get_time_seconds(formatted_data.current_timestamp - queue_stats.entered_timestamp); formatted_data.calls_waiting[call_id].friendly_title = queue_stats.caller_id_name || queue_stats.caller_id_number || call_id; formatted_data.queues[k].current_calls++; } else if(queue_stats.status === 'handled') { formatted_data.calls_in_progress[call_id] = queue_stats; formatted_data.agents[queue_stats.agent_id].call_time = self.get_time_seconds(formatted_data.current_timestamp - queue_stats.handled_timestamp); formatted_data.agents[queue_stats.agent_id].current_call = queue_stats; formatted_data.agents[queue_stats.agent_id].current_call.friendly_title = queue_stats.caller_id_name || queue_stats.caller_id_number || call_id; formatted_data.calls_in_progress[call_id].friendly_duration = self.get_time_seconds(formatted_data.current_timestamp - queue_stats.entered_timestamp); formatted_data.queues[k].total_calls++; formatted_data.queues[k].current_calls++; } else if(queue_stats.status === 'processed') { formatted_data.queues[k].total_calls++; }} }); } $.each(formatted_data.queues, function(k, v) { if(v.total_calls > 0) { var completed_calls = v.total_calls - v.abandoned_calls; v.average_hold_time = self.get_time_seconds(v.total_wait_time / completed_calls); } }); return formatted_data; }, format_data: function(data) { var self = this, formatted_data = {}; /* Formatting Queues */ formatted_data.queues = {}; $.each(data.queues, function(k, v) { formatted_data.queues[v.id] = $.extend(true, { current_calls: 0, total_calls: 0, current_agents: 0, max_agents: 0, average_hold_time: self.get_time_seconds(0), total_wait_time: 0, abandoned_calls: 0 }, v); }); /* Formatting Agents */ formatted_data.agents = {}; $.each(data.agents, function(k, v) { if(v.queues && v.queues.length > 0) { formatted_data.agents[v.id] = $.extend(true, { status: 'logged_out', missed_calls: 0, total_calls: 0, queues_list: {} }, v); } $.each(v.queues, function(k, queue_id) { if(queue_id in formatted_data.queues) { formatted_data.queues[queue_id].max_agents++; formatted_data.agents[v.id].queues_list[queue_id] = { missed_calls: 0, total_calls: 0 }; } }); }); formatted_data = self.format_live_data(formatted_data, data); return formatted_data; }, render: function(_container) { var self = this, container = _container || $('#monster_content'); // account switching for monster-ui self.accountId = monster.apps.auth.accountId; self.clean_timers(); self.fetch_all_data(function(data) { var queues_html = $(monster.template(self, 'queues_dashboard', {queues: data.queues})); var agents_html = $(monster.template(self, 'agents_dashboard', {agents: data.agents})); var calls_html = $(monster.template(self, 'calls_dashboard', {progress: data.calls_in_progress, waits: data.calls_waiting} )); var html = $(monster.template(self, 'dashboard', {})); container.empty().append(html); var scroll_value = $('.topbar-right .list_queues_inner', container).scrollLeft() || 0; container.find('#dashboard-view').empty().append(agents_html); container.find('.topbar-right').empty().append(queues_html); container.find('.topbar-right .list_queues_inner').animate({ scrollLeft: scroll_value }, 0); container.find('#callwaiting-list').append(calls_html); self.poll_agents(data, container); (container).empty().append(html); self.bind_live_events(container); if(typeof queue_id != 'undefined') { self.detail_stat(queue_id, container); } self.dashboardBindEvents(container); self.initHeaderSubmenu(); }); }, dashboardBindEvents: function($container) { var self = this; $container.find('.js-open-cc-settings').on('click', function(e) { e.preventDefault(); self.settingsRender($container); }); }, settingsShowMessage: function(msg, msgType, $container) { if(!$container) { $container = $('#cc-settings-content'); } var msgTypeClass; if(typeof(msgType) === 'undefined') { msgType = 'info'; } switch(msgType) { case 'warning': msgTypeClass = 'msg-warning'; break; case 'success': msgTypeClass = 'msg-success'; break; default: // 'info' msgTypeClass = 'msg-info'; } var $msg = $('
') .prependTo($container).hide().fadeIn(); $msg.animate({ backgroundColor: '#ffffff', color: '#000000' }, 1000 ); window.setTimeout(function(){ $msg.fadeOut(400, function() { $msg.remove(); }) }, 4000); }, settingsRender: function($container, callback) { var self = this; var html = $(monster.template(self, 'settings', {})); $container.empty().append(html); self.settingsInit($container, callback); self.initHeaderSubmenu(); }, settingsInit: function($container, callback) { var self = this; var $queuesListBox = $container.find('#queues-list-container'); self.settingsQueuesListRender(null, $queuesListBox, function() { monster.ui.tooltips($container, { options: { placement: 'right', container: 'body' } }); self.settingsBindEvents($container); $('#queues-list li:first-child a').click(); if(typeof(callback) === 'function') { callback(); } }); }, settingsBindEvents: function($container) { var self = this; $container.find('.js-open-cc-dashboard').on('click', function(e) { e.preventDefault(); self.render($container); }); $container.find('.js-cc-create-queue').on('click', function(e) { e.preventDefault(); self.settingsQueueNewInit($container); }); }, settingsQueueNewInit: function($container) { var self = this; var $parent = $container.find('#cc-settings-content'); var $queuesList = $('#queues-list'); $queuesList.find('.active').each(function(e, i) { $(this).removeClass('active'); }); $queuesList.find('.js-new-queue-item').remove(); $queuesList.find('#queues-list').append('