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