Built motion from commit ce9a7520.|2.5.39
[motion2.git] / public / tvox / answer.controller.js
1 // Include app dependency on ngMaterial
2 angular.module('AnswerApp', ['ngMaterial', 'ngCookies', 'motion', 'ngResource', 'flow', 'ngSanitize'])
3   .controller("AnswerController", function($rootScope, $scope, $http, $cookies, socket, $location, $timeout, $document, $window) {
4     $scope.text = {
5       content: null
6     };
7     $scope.textMessage = "";
8     $scope.messageId = 0;
9     $scope.contactId = "";
10     $scope.interactionId = 0;
11     $scope.interactionClosed = false;
12     $scope.userId = "";
13     $scope.motionUrl = "";
14     $scope.chatWebsiteId = "";
15     $scope.logo = "";
16     $scope.token = "";
17     $scope.userData = {};
18     $scope.interactionData = {};
19     $scope.error_message = "";
20     $scope.messages = {
21       count: 0,
22       rows: []
23     };
24     $scope.reportMemberId = 0;
25     $scope.contactName = "";
26     $scope.ngFlowOptions = {
27       target: '/api/attachments',
28       singleFile: true,
29       maxChunkRetries: 1,
30       chunkSize: 10240000,
31       simultaneousUploads: 1,
32       testChunks: false,
33       progressCallbacksInterval: 1000,
34       allowDuplicateUploads: true
35     };
36     $scope.ngFlow = {
37       // ng-flow will be injected into here through its directive
38       flow: {}
39     };
40
41     $scope.errors = [];
42     $scope.dispositions = [];
43
44     $scope.dispo = {};
45     $scope.dispo.firstLevelDisposition = null;
46     $scope.dispo.secondLevelDisposition = null;
47     $scope.dispo.thirdLevelDisposition = null;
48     $scope.dispo.anySecondLevelDisposition = null;
49     $scope.dispo.anyThirdLevelDisposition = null;
50     $scope.dispo.mandatoryDisposition = false;
51     $scope.dispo.mandatoryDispositionPause = '';
52     $scope.dispo.note = '';
53
54     tvoxCallId = "";
55
56
57
58
59     function parseJwt(token) {
60       var base64Url = token.split('.')[1];
61       var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
62       var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
63         return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
64       }).join(''));
65
66       return JSON.parse(jsonPayload);
67     };
68
69
70     function closeInteraction() {
71
72
73       var msg = {
74         id: $scope.interactionId,
75         closed: true,
76         closeReason: 'contact',
77         closedAt: new Date() // moment().format('YYYY-MM-DD HH:mm:ss'),
78       };
79
80       $http.put($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId + "/custom_update", msg, {
81         headers: {
82           'Authorization': 'Bearer ' + $scope.token
83         }
84       }).
85       then(
86         function ret(response) {}
87       );
88
89     }
90     $scope.close = function() {
91       closeInteraction();
92     }
93
94     $scope.keyPress = function(keyEvent) {
95       if (keyEvent.which === 13)
96         if ($scope.text.content) {
97           var msg = {};
98           msg.body = $scope.text.content;
99           sendMessage(msg);
100         }
101     }
102
103
104     this.$onInit = function() {
105       var urlParams = new URLSearchParams(window.location.search);
106       var params = urlParams.get("params");
107       var arr = params.split("|");
108       if (arr) {
109         $scope.messageId = arr[0];
110         $scope.motionUrl = arr[1];
111         $scope.chatWebsiteId = arr[2];
112         $scope.interactionId = arr[3];
113       }
114
115
116       $scope.token = $cookies.get('motion.token');
117       if (_.isNil($scope.token))
118         $scope.error_message = "XCally motion token not valid, please connect to XCally Motion, then retry";
119       else {
120
121         window.addEventListener("message", function(event) {
122
123           let message = event.data;
124           if (message == null || message.namespace == null || message.namespace != 'webclient.teleniasoftware.com') {
125             console.info("Received Unknown message", message);
126             return;
127           }
128
129           if (message.event == 'callEvent') {
130             tvoxCallId = message.data.callId;
131             if (message.data.state == "IDLE") {
132               closeInteraction();
133             }
134             /*
135             if (!_primaryCallInfo) {
136                 _primaryCallInfo = message.data;
137                 alert(_primaryCallInfo)
138                 if (_callInfoCallback !== null)
139                     _callInfoCallback(_primaryCallInfo);
140             } */
141           }
142         }, false);
143         tvoxSendReadyEvent();
144         var js = parseJwt($scope.token);
145         $scope.userId = js.id;
146         $rootScope.userId = js.id;
147         $http.get($scope.motionUrl + "/api/users/" + $scope.userId, {
148           headers: {
149             'Authorization': 'Bearer ' + $scope.token
150           }
151         }).
152         then(function(response) {
153           $scope.userData = response.data;
154
155           $http.get($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId, {
156             headers: {
157               'Authorization': 'Bearer ' + $scope.token
158             }
159           }).
160           then(function(response) {
161             $scope.interactionData = response.data;
162           });
163
164         });
165
166
167         socket.on('chatMessage:save', onMessageSave);
168         socket.on('chatInteraction:save', onInteractionSave);
169         socket.on('chatInteraction:update', onInteractionSave);
170
171
172         $http.get($scope.motionUrl + "/api/chat/websites/" + $scope.chatWebsiteId, {
173           headers: {
174             'Authorization': 'Bearer ' + $scope.token
175           }
176         }).
177         then(
178           function successCallback(response) {
179             $scope.dispo.mandatoryDisposition = response.mandatoryDisposition;
180
181             //if ($scope.mandatoryDisposition) {
182             //$scope.mandatoryDispositionPause = response.mandatoryDispositionPause.name;
183             //}
184
185             $scope.logo = $scope.motionUrl + "/api/chat/websites/" + $scope.chatWebsiteId + "/logo?token=" + response.token;
186             $http({
187                 url: $scope.motionUrl + "/api/chat/messages/" + $scope.messageId + "/accept",
188                 method: "PUT",
189                 headers: {
190                   'Authorization': 'Bearer ' + $scope.token
191                 },
192                 data: {
193                   id: $scope.messageId,
194                   UserId: $scope.userId,
195                   manual: true
196                 }
197               })
198               .then(function(message) {
199                   $scope.userId = message.data.interaction.UserId;
200                   $scope.contactId = message.data.interaction.ContactId;
201                   $http.get($scope.motionUrl + "/api/chat/interactions/" + message.data.interaction.id + "/messages", {
202                     headers: {
203                       'Authorization': 'Bearer ' + $scope.token
204                     }
205                   }).
206                   then(
207                     function ret(response) {
208                       $scope.messages.rows = response.data.rows;
209                       $http.get($scope.motionUrl + "/api/cm/contacts/" + $scope.contactId, {
210                         headers: {
211                           'Authorization': 'Bearer ' + $scope.token
212                         }
213                       }).
214                       then(
215                         function ret(contact) {
216                           var fn = "";
217                           var ln = "";
218                           $scope.contactData = contact.data;
219                           if (contact.data.firstName !== null)
220                             fn = contact.data.firstName;
221                           if (contact.data.lastName !== null)
222                             ln = contact.data.lastName;
223                           $scope.contactName = fn + " " + ln;
224                           createReportSession();
225                           loadDispositions();
226                         }
227                       );
228                     }
229                   );
230                 },
231                 function(err) {
232                   $http.get($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId + "/messages", {
233                     headers: {
234                       'Authorization': 'Bearer ' + $scope.token
235                     }
236                   }).
237                   then(
238                     function ret(response) {
239                       $scope.messages.rows = response.data.rows;
240                       $http.get($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId, {
241                         headers: {
242                           'Authorization': 'Bearer ' + $scope.token
243                         }
244                       }).
245                       then(
246                         function ret(response) {
247                           $scope.userId = response.data.UserId;
248                           $scope.contactId = response.data.ContactId;
249                           $http.get($scope.motionUrl + "/api/cm/contacts/" + $scope.contactId, {
250                             headers: {
251                               'Authorization': 'Bearer ' + $scope.token
252                             }
253                           }).
254                           then(
255                             function ret(contact) {
256                               $scope.contactData = contact.data;
257                               var fn = "";
258                               var ln = "";
259                               if (contact.data.firstName !== null)
260                                 fn = contact.data.firstName;
261                               if (contact.data.lastName !== null)
262                                 ln = contact.data.lastName;
263                               $scope.contactName = fn + " " + ln;
264                               createReportSession();
265                               loadDispositions();
266
267                             }
268                           );
269                         }
270                       );
271                     }
272                   );
273                 });
274           },
275           function errorCallback(response) {
276             console.log("Unable to perform get request", response);
277           }
278         );
279
280       }
281     }
282
283     function createReportSession() {
284       if ($scope.reportMemberId > 0) {
285         closeReportSession(true);
286       } else {
287         openReportSession();
288       }
289     }
290
291     function openReportSession() {
292       var obj = {
293         channel: "tvox",
294         membername: $scope.userData.name,
295         interface: $scope.userData.interface,
296         type: "TVOX_SESSION",
297         enterAt: new Date(),
298         role: $scope.userData.role,
299         internal: $scope.userData.internal,
300         uniqueid: $scope.interactionId
301       };
302       $http.post($scope.motionUrl + "/api/members/reports", obj, {
303         headers: {
304           'Authorization': 'Bearer ' + $scope.token
305         }
306       }).
307       then(
308         function ret(response) {
309           console.log("RMID", response.data.id);
310           $scope.reportMemberId = response.data.id;
311         }
312       );
313     }
314
315     function loadDispositions() {
316       var dispositions = [];
317       var filters = "ChatWebsiteId=null&FaxAccountId=null&ListId=null&MailAccountId=null&OpenchannelAccountId=null&SmsAccountId=null&WhatsappAccountId=null&nolimit=true";
318       $http.get($scope.motionUrl + "/api/dispositions?" + filters, {
319         headers: {
320           'Authorization': 'Bearer ' + $scope.token
321         }
322       }).
323       then(
324         function ret(res) {
325           if (res.data.rows.length) {
326             $scope.dispositions = _.concat($scope.dispositions, res.data.rows);
327           }
328           filters = "ChatWebsiteId=" + $scope.chatWebsiteId + "&nolimit=true";
329           $http.get($scope.motionUrl + "/api/dispositions?" + filters, {
330             headers: {
331               'Authorization': 'Bearer ' + $scope.token
332             }
333           }).
334           then(
335             function ret(res) {
336               if (res.data.rows.length) {
337                 $scope.dispositions = _.concat(dispositions, res.data.rows);
338
339               }
340             }
341           );
342         }
343       );
344
345     }
346
347     $scope.onDispositionChange = function(level) {
348       if (level === 'first') {
349         $scope.dispo.anySecondLevelDisposition = $scope.dispo.firstLevelDisposition ?
350           _.some($scope.dispositions, ['ParentId', $scope.dispo.firstLevelDisposition.id]) : false;
351
352         if (!$scope.dispo.firstLevelDisposition) $scope.dispo.secondLevelDisposition = undefined;
353       } else if (level === 'second') {
354         $scope.dispo.anyThirdLevelDisposition = _.some($scope.dispositions, ['ParentId', $scope.dispo.secondLevelDisposition.id]);
355       }
356     }
357
358     $scope.clearDispositionSelection = function(level) {
359       if (level === 'second') {
360         $scope.dispo.secondLevelDisposition = undefined;
361         $scope.dispo.thirdLevelDisposition = undefined;
362       } else if (level === 'third') {
363         $scope.dispo.thirdLevelDisposition = undefined;
364       }
365     }
366
367
368     $scope.upload = function() {
369       // Set headers
370       $scope.ngFlow.flow.opts.headers = {
371         'X-Requested-With': 'XMLHttpRequest',
372         Authorization: 'Bearer ' + $scope.token
373       };
374
375       $scope.ngFlow.flow.upload();
376     }
377
378
379
380
381     $scope.send = function() {
382       if ($scope.text.content) {
383         var msg = {};
384         msg.body = $scope.text.content;
385
386         sendMessage(msg);
387       }
388     }
389
390     function sendMessage(msg) {
391       if (msg) {
392         msg.ChatInteractionId = $scope.interactionId;
393         msg.ChatWebsiteId = $scope.chatWebsiteId;
394         msg.ContactId = $scope.contactId;
395         msg.UserId = $scope.userId;
396         msg.direction = "out";
397         msg.secret = false;
398
399         $http.post($scope.motionUrl + "/api/chat/messages", msg, {
400           headers: {
401             'Authorization': 'Bearer ' + $scope.token
402           }
403         }).
404         then(
405           function ret(response) {
406             $scope.text.content = "";
407           }
408         );
409       }
410     }
411
412     function onInteractionSave(interaction) {
413       // NOTE: return when is not a right interaction
414       if (interaction && interaction.id != $scope.interactionId) {
415         return;
416       }
417
418       if (interaction.closed) {
419         $scope.interactionClosed = true;
420         closeReportSession(false);
421       }
422     }
423
424
425     $scope.fileAdded = function(file) {
426       if (file.size > 10240000) {
427         alert("File too big");
428         /*
429           toasty.error({
430             title: 'File too big',
431             msg: 'The max allowed size is ' + maxFileSizeMb + 'MB'
432           });
433           */
434         return false;
435       }
436
437       return true;
438     }
439
440     /**
441      * Success
442      * Automatically triggers when files added to the uploader
443      */
444     $scope.fileSuccess = function(file, message) {
445       var attachment = JSON.parse(message);
446       var body = attachment.name;
447
448
449       body =
450         '<a href="' +
451         ($location.protocol() + '://' + $location.host()) +
452         '/api/chat/interactions/' +
453         $scope.interactionId +
454         '/attachment_download?attachId=' +
455         attachment.id +
456         '&token=' +
457         $scope.token +
458         '" target="_self">' +
459         attachment.name +
460         '</a>';
461
462       sendMessage({
463         body: body,
464         AttachmentId: attachment.id
465       });
466     }
467
468     $scope.saveDisposition = function() {
469
470       var obj = {
471         closed: true,
472         closeReason: 'agent',
473         disposition: $scope.dispo.firstLevelDisposition ? $scope.dispo.firstLevelDisposition.name : null,
474         secondDisposition: $scope.dispo.secondLevelDisposition ? $scope.dispo.secondLevelDisposition.name : undefined,
475         thirdDisposition: $scope.dispo.thirdLevelDisposition ? $scope.dispo.thirdLevelDisposition.name : undefined,
476         mote: $scope.dispo.note
477       };
478
479       $http.put($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId, obj, {
480         headers: {
481           'Authorization': 'Bearer ' + $scope.token
482         }
483       }).
484       then(
485         function ret(response) {
486           if ($scope.reportMemberId > 0)
487             closeReportSession(false);
488           tvoxCloseInteraction(tvoxCallId);
489
490         }
491       );
492
493     }
494
495
496     function scrollToBottom() {
497       $timeout(function() {
498         var interactionContent = angular.element($document.find("md-content"));
499         if (interactionContent && interactionContent[0]) {
500           interactionContent[0].scrollTop = interactionContent[0].scrollHeight;
501         }
502       }, 0);
503     }
504
505
506     function onMessageSave(msg) {
507       var found = false;
508
509       if (msg.ChatWebsiteId == $scope.chatWebsiteId && msg.ChatInteractionId == $scope.interactionId) {
510         if ($scope.messages) {
511           found = _.find($scope.messages.rows, {
512             id: msg.id
513           });
514         } else {
515           $scope.messages = {
516             rows: [],
517             count: 0
518           };
519         }
520
521         if (found) {
522           _.merge(found, msg);
523         } else {
524           $scope.messages.rows.push(msg);
525           if (msg.direction == "in") {
526             $http.put($scope.motionUrl + "/api/chat/messages/" + msg.id + "/accept", {
527               id: msg.id,
528               UserId: $scope.userId
529             }, {
530               headers: {
531                 'Authorization': 'Bearer ' + $scope.token
532               }
533             }).
534             then(
535               function ret(response) {}
536             );
537           }
538
539         }
540         scrollToBottom();
541       }
542     }
543
544     $scope.accept = function(event) {}
545
546     $window.onfocus = function() {
547       createReportSession();
548     }
549     $window.onblur = function() {
550       if ($scope.reportMemberId > 0) {
551         closeReportSession(false);
552       }
553     }
554
555     function closeReportSession(openNewSession) {
556       var obj = {
557         exitAt: new Date()
558       };
559       $http.put($scope.motionUrl + "/api/members/reports/" + $scope.reportMemberId, obj, {
560         headers: {
561           'Authorization': 'Bearer ' + $scope.token
562         }
563       }).
564       then(
565         function ret(response) {
566           $scope.reportMemberId = 0;
567           if (openNewSession) {
568             openReportSession();
569           }
570         }
571       );
572
573     }
574
575   });