177b62b19e2bac531ec427f927307cff3b480bb1
[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     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
376
377
378     $scope.send = function() {
379       if ($scope.text.content) {
380         var msg = {};
381         msg.body = $scope.text.content;
382
383         sendMessage(msg);
384       }
385     }
386
387     function sendMessage(msg) {
388       if (msg) {
389         msg.ChatInteractionId = $scope.interactionId;
390         msg.ChatWebsiteId = $scope.chatWebsiteId;
391         msg.ContactId = $scope.contactId;
392         msg.UserId = $scope.userId;
393         msg.direction = "out";
394         msg.secret = false;
395
396         $http.post($scope.motionUrl + "/api/chat/messages", msg, {
397           headers: {
398             'Authorization': 'Bearer ' + $scope.token
399           }
400         }).
401         then(
402           function ret(response) {
403             $scope.text.content = "";
404           }
405         );
406       }
407     }
408
409     function onInteractionSave(interaction) {
410       // NOTE: return when is not a right interaction
411       if (interaction && interaction.id != $scope.interactionId) {
412         return;
413       }
414
415       if (interaction.closed) {
416         $scope.interactionClosed = true;
417         closeReportSession(false);
418       }
419     }
420
421
422     $scope.fileAdded = function(file) {
423       if (file.size > 10240000) {
424         alert("File too big");
425         /*
426           toasty.error({
427             title: 'File too big',
428             msg: 'The max allowed size is ' + maxFileSizeMb + 'MB'
429           });
430           */
431         return false;
432       }
433
434       return true;
435     }
436
437     /**
438      * Success
439      * Automatically triggers when files added to the uploader
440      */
441     $scope.fileSuccess = function(file, message) {
442       var attachment = JSON.parse(message);
443       var body = attachment.name;
444
445
446       body =
447         '<a href="' +
448         ($location.protocol() + '://' + $location.host()) +
449         '/api/chat/interactions/' +
450         $scope.interactionId +
451         '/attachment_download?attachId=' +
452         attachment.id +
453         '&token=' +
454         $scope.token +
455         '" target="_self">' +
456         attachment.name +
457         '</a>';
458
459       sendMessage({
460         body: body,
461         AttachmentId: attachment.id
462       });
463     }
464
465     $scope.saveDisposition = function() {
466
467       var obj = {
468         closed: true,
469         closeReason: 'agent',
470         disposition: $scope.dispo.firstLevelDisposition ? $scope.dispo.firstLevelDisposition.name : null,
471         secondDisposition: $scope.dispo.secondLevelDisposition ? $scope.dispo.secondLevelDisposition.name : undefined,
472         thirdDisposition: $scope.dispo.thirdLevelDisposition ? $scope.dispo.thirdLevelDisposition.name : undefined,
473         mote: $scope.dispo.note
474       };
475
476       $http.put($scope.motionUrl + "/api/chat/interactions/" + $scope.interactionId, obj, {
477         headers: {
478           'Authorization': 'Bearer ' + $scope.token
479         }
480       }).
481       then(
482         function ret(response) {
483           if ($scope.reportMemberId > 0)
484             closeReportSession(false);
485           tvoxCloseInteraction(tvoxCallId);
486
487         }
488       );
489
490     }
491
492
493     function scrollToBottom() {
494       $timeout(function() {
495         var interactionContent = angular.element($document.find("md-content"));
496         if (interactionContent && interactionContent[0]) {
497           interactionContent[0].scrollTop = interactionContent[0].scrollHeight;
498         }
499       }, 0);
500     }
501
502
503     function onMessageSave(msg) {
504       var found = false;
505
506       if (msg.ChatWebsiteId == $scope.chatWebsiteId && msg.ChatInteractionId == $scope.interactionId) {
507         if ($scope.messages) {
508           found = _.find($scope.messages.rows, {
509             id: msg.id
510           });
511         } else {
512           $scope.messages = {
513             rows: [],
514             count: 0
515           };
516         }
517
518         if (found) {
519           _.merge(found, msg);
520         } else {
521           $scope.messages.rows.push(msg);
522           if (msg.direction == "in") {
523             $http.put($scope.motionUrl + "/api/chat/messages/" + msg.id + "/accept", {
524               id: msg.id,
525               UserId: $scope.userId
526             }, {
527               headers: {
528                 'Authorization': 'Bearer ' + $scope.token
529               }
530             }).
531             then(
532               function ret(response) {}
533             );
534           }
535
536         }
537         scrollToBottom();
538       }
539     }
540
541     $scope.accept = function(event) {}
542
543     $window.onfocus = function() {
544       createReportSession();
545     }
546     $window.onblur = function() {
547       if ($scope.reportMemberId > 0) {
548         closeReportSession(false);
549       }
550     }
551
552     function closeReportSession(openNewSession) {
553       var obj = {
554         exitAt: new Date()
555       };
556       $http.put($scope.motionUrl + "/api/members/reports/" + $scope.reportMemberId, obj, {
557         headers: {
558           'Authorization': 'Bearer ' + $scope.token
559         }
560       }).
561       then(
562         function ret(response) {
563           $scope.reportMemberId = 0;
564           if (openNewSession) {
565             openReportSession();
566           }
567         }
568       );
569
570     }
571
572   });