@chat21/chat21-ionic 3.4.28 → 3.4.29-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +111 -5
  2. package/angular.json +1 -0
  3. package/package.json +1 -1
  4. package/src/app/app.component.html +3 -1
  5. package/src/app/app.component.ts +71 -10
  6. package/src/app/components/canned-response/canned-response.component.html +26 -23
  7. package/src/app/components/canned-response/canned-response.component.scss +0 -2
  8. package/src/app/components/canned-response/canned-response.component.ts +3 -1
  9. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +24 -1
  10. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +30 -0
  11. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +29 -7
  12. package/src/app/components/conversation-info/info-content/info-content.component.ts +2 -2
  13. package/src/app/components/conversation-info/info-group/info-group.component.ts +23 -21
  14. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.html +1 -1
  15. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.ts +5 -1
  16. package/src/app/components/navbar/navbar.component.html +3 -3
  17. package/src/app/components/navbar/navbar.component.ts +29 -38
  18. package/src/app/components/project-item/project-item.component.ts +11 -11
  19. package/src/app/components/sidebar/sidebar.component.html +65 -45
  20. package/src/app/components/sidebar/sidebar.component.ts +110 -117
  21. package/src/app/components/sidebar-user-details/sidebar-user-details.component.html +2 -2
  22. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +10 -7
  23. package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
  24. package/src/app/pages/contacts-directory/contacts-directory.page.scss +30 -25
  25. package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
  26. package/src/app/pages/conversation-detail/conversation-detail.page.ts +89 -5
  27. package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
  28. package/src/app/pages/conversations-list/conversations-list.page.scss +15 -4
  29. package/src/app/pages/conversations-list/conversations-list.page.ts +40 -2
  30. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +15 -5
  31. package/src/app/services/global-settings/global-settings.service.ts +11 -3
  32. package/src/app/services/nav-proxy.service.ts +0 -1
  33. package/src/app/services/project_users/project-users.service.spec.ts +16 -0
  34. package/src/app/services/project_users/project-users.service.ts +63 -0
  35. package/src/app/services/tiledesk/tiledesk.service.ts +0 -16
  36. package/src/app/services/triggerEvents/triggerEvents.ts +28 -0
  37. package/src/app/services/websocket/websocket-js.ts +59 -534
  38. package/src/app/services/websocket/websocket-js_old.ts +578 -0
  39. package/src/app/services/websocket/websocket.service.ts +9 -10
  40. package/src/app/services/websocket/websocket.worker.ts +242 -0
  41. package/src/app/shared/shared.module.ts +11 -2
  42. package/src/app/utils/globals.ts +2 -0
  43. package/src/app/utils/permissions.constants.ts +138 -0
  44. package/src/app/utils/project-utils.ts +2 -2
  45. package/src/app/utils/utils.ts +18 -1
  46. package/src/assets/i18n/ar.json +11 -1
  47. package/src/assets/i18n/az.json +11 -1
  48. package/src/assets/i18n/de.json +11 -1
  49. package/src/assets/i18n/en.json +11 -1
  50. package/src/assets/i18n/es.json +11 -1
  51. package/src/assets/i18n/fr.json +11 -1
  52. package/src/assets/i18n/it.json +13 -3
  53. package/src/assets/i18n/kk.json +11 -1
  54. package/src/assets/i18n/pt.json +11 -1
  55. package/src/assets/i18n/ru.json +11 -1
  56. package/src/assets/i18n/sr.json +11 -1
  57. package/src/assets/i18n/sv.json +11 -1
  58. package/src/assets/i18n/tr.json +11 -1
  59. package/src/assets/i18n/uk.json +11 -1
  60. package/src/assets/i18n/uz.json +12 -1
  61. package/src/assets/js/agentDesktop-sdk.js +55 -0
  62. package/src/assets/js/chat21client.js +36 -0
  63. package/src/assets/js/mqtt-keepalive-worker.js +53 -0
  64. package/src/assets/test.html +5 -2
  65. package/src/chat-config-template.json +1 -0
  66. package/src/chat-config.json +1 -0
  67. package/src/chat21-core/models/projectUsers.ts +19 -0
  68. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  69. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  70. package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
  71. package/src/chat21-core/utils/utils.ts +16 -2
@@ -83,7 +83,11 @@ import { WebsocketService } from 'src/app/services/websocket/websocket.service';
83
83
  import { Project } from 'src/chat21-core/models/projects';
84
84
  import { Globals } from 'src/app/utils/globals';
85
85
  import { ProjectService } from 'src/app/services/projects/project.service';
86
- import { getOSCode } from 'src/app/utils/utils';
86
+ import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
87
+ import { ProjectUser } from 'src/chat21-core/models/projectUsers';
88
+ import { getOSCode, hasRole } from 'src/app/utils/utils';
89
+ import { PERMISSIONS } from 'src/app/utils/permissions.constants';
90
+ import { TriggerEvents } from 'src/app/services/triggerEvents/triggerEvents';
87
91
 
88
92
  @Component({
89
93
  selector: 'app-conversation-detail',
@@ -108,6 +112,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
108
112
  private subscriptions: Array<any>
109
113
  public tenant: string;
110
114
  public loggedUser: UserModel
115
+ public projectUser: ProjectUser;
111
116
  public conversationWith: string
112
117
  public conversationWithFullname: string
113
118
  public messages: Array<MessageModel> = []
@@ -137,6 +142,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
137
142
  public tagsCannedFilter: Array<any> = [];
138
143
  public SHOW_CANNED_RESPONSES: boolean = false
139
144
  public canShowCanned: boolean = true
145
+ public rolesCanned: { [key: string]: boolean }
140
146
 
141
147
  public SHOW_COPILOT_SUGGESTIONS: boolean = false;
142
148
 
@@ -171,6 +177,10 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
171
177
  copilotQuestion: string = '';
172
178
  /**COPILOT : end */
173
179
 
180
+ /** TICKET: start */
181
+ isTicketEnabled: boolean = false;
182
+ /** TICKET: end */
183
+
174
184
  isMine = isMine
175
185
  isInfo = isInfo
176
186
  isFirstMessage = isFirstMessage
@@ -240,18 +250,20 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
240
250
  public toastController: ToastController,
241
251
  public tiledeskService: TiledeskService,
242
252
  public projectService: ProjectService,
253
+ public projectUsersService: ProjectUsersService,
243
254
  private networkService: NetworkService,
244
255
  private events: EventsService,
245
256
  private webSocketService: WebsocketService,
246
257
  public projectPlanUtils: ProjectPlanUtils,
258
+ public triggerEvents: TriggerEvents,
247
259
  private g: Globals,
248
260
  ) {
249
261
  // Change list on date change
250
262
  this.route.paramMap.subscribe((params) => {
251
263
  this.logger.log('[CONVS-DETAIL] - constructor -> params: ', params)
252
264
  this.conversationWith = params.get('IDConv')
253
- this.conversationWithFullname = params.get('FullNameConv')
254
- this.conv_type = params.get('Convtype')
265
+ this.conversationWithFullname = decodeURIComponent(params.get('FullNameConv'))
266
+ this.conv_type = decodeURIComponent(params.get('Convtype'))
255
267
 
256
268
  this.events.publish('supportconvid:haschanged', this.conversationWith)
257
269
  })
@@ -418,6 +430,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
418
430
  ionViewDidEnter() {
419
431
  this.logger.log('[CONVS-DETAIL] > ionViewDidEnter')
420
432
  // this.info_content_child_enabled = true;
433
+ // Scroll to bottom to show the last message without animation
434
+ this.scrollToLastMessage()
421
435
  }
422
436
 
423
437
  // Unsubscibe when new page transition end
@@ -477,6 +491,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
477
491
  this.messages = [] // list messages of conversation
478
492
  this.isFileSelected = false // indicates if a file has been selected (image to upload)
479
493
  this.isEmailEnabled = (this.appConfigProvider.getConfig().emailSection === 'true' || this.appConfigProvider.getConfig().emailSection === true) ? true : false;
494
+ this.isTicketEnabled = (this.appConfigProvider.getConfig().ticketSection === 'true' || this.appConfigProvider.getConfig().ticketSection === true) ? true : false;
480
495
  this.isWhatsappTemplatesEnabled = (this.appConfigProvider.getConfig().whatsappTemplatesSection === 'true' || this.appConfigProvider.getConfig().whatsappTemplatesSection === true) ? true : false;
481
496
 
482
497
  this.cannedResponsesService.initialize(appconfig.apiUrl)
@@ -534,7 +549,6 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
534
549
  this.logger.log('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT * COMPLETE *',)
535
550
  })
536
551
  }else {
537
- this.canShowCanned = false;
538
552
  this.offlineMsgEmail = false;
539
553
  }
540
554
 
@@ -545,10 +559,13 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
545
559
  this.logger.log('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT RES', project)
546
560
  if (project) {
547
561
  const projectId = project.id_project
548
- this.canShowCanned = this.projectPlanUtils.checkPlanIsExpired(project)
562
+ this.projectUser = await this.projectUsersService.getProjectUserByProjectId(project._id)
549
563
  this.offlineMsgEmail = this.checkOfflineMsgEmailIsEnabled(project)
550
564
  this.isCopilotEnabled = this.projectPlanUtils.checkProjectProfileFeature(project, 'copilot');
551
565
  this.fileUploadAccept = this.checkAcceptedUploadFile(project)
566
+ this.rolesCanned = this.checkCannedResponsesRoles()
567
+ this.canShowCanned = this.checkCannedResponses(project)
568
+ this.logger.log('[CONVS-DETAIL] this.rolesCanned ', this.canShowCanned)
552
569
  }
553
570
  }, (error) => {
554
571
  this.logger.error('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT - ERROR ', error)
@@ -586,6 +603,40 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
586
603
  return this.appConfigProvider.getConfig().fileUploadAccept
587
604
  }
588
605
 
606
+ checkCannedResponses(project: Project): boolean {
607
+ let expires = this.projectPlanUtils.checkPlanIsExpired(project)
608
+ this.logger.log('[CONVS-DETAIL] checkCannedResponses expires ', expires)
609
+ if(expires){
610
+ return false
611
+ }
612
+
613
+ let hasRoleToShowCanned = this.rolesCanned[PERMISSIONS.CANNED_RESPONSES_READ]
614
+ this.logger.log('[CONVS-DETAIL] checkCannedResponses hasRoleToShowCanned ', hasRoleToShowCanned)
615
+ if(!hasRoleToShowCanned){
616
+ return false
617
+ }
618
+
619
+ return true
620
+ }
621
+
622
+ checkCannedResponsesRoles(): { [key: string]: boolean } {
623
+ const permissionKeys = [
624
+ 'CANNED_RESPONSES_CREATE',
625
+ 'CANNED_RESPONSES_READ',
626
+ 'CANNED_RESPONSES_UPDATE',
627
+ 'CANNED_RESPONSES_DELETE',
628
+ ] as const;
629
+
630
+ const roles: { [key: string]: boolean } = {};
631
+ for (const key of permissionKeys) {
632
+ const permission = PERMISSIONS[key];
633
+ roles[permission] = hasRole(this.projectUser, permission);
634
+ }
635
+
636
+ return roles;
637
+
638
+ }
639
+
589
640
  // getProjectIdSelectedConversation(conversationWith: string): string{
590
641
  // const conversationWith_segments = conversationWith.split('-')
591
642
  // // Removes the last element of the array if is = to the separator
@@ -669,6 +720,11 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
669
720
  "WHATSAPP.ERROR_WHATSAPP_NOT_INSTALLED",
670
721
  "WHATSAPP.ERROR_WHATSAPP_GENERIC_ERROR",
671
722
 
723
+ "TICKET.OPEN_TICKET",
724
+ "TICKET.DESCRIPTION",
725
+ "TICKET.CONFIRM",
726
+ "TICKET.CLOSE",
727
+
672
728
  "COPILOT.ASK_AI",
673
729
  "COPILOT.NO_SUGGESTIONS_PRESENT",
674
730
 
@@ -1884,6 +1940,11 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1884
1940
  }
1885
1941
 
1886
1942
 
1943
+ onOpenTicket(event) {
1944
+ this.logger.debug('[CONVS-DETAIL] openTicketOnExternalService - conversationWith ', this.conversationWith)
1945
+ const detailOBJ = { event: 'onOpenTicketExternally', request_id: this.conversationWith, conversation: this.conversation }
1946
+ this.triggerEvents.triggerOnOpenTicketExternally(detailOBJ)
1947
+ }
1887
1948
  // -------------- START SCROLL/RESIZE -------------- //
1888
1949
  /** */
1889
1950
  resizeTextArea() {
@@ -1927,6 +1988,29 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1927
1988
  }
1928
1989
  }
1929
1990
 
1991
+ /**
1992
+ * Scroll to last message without animation using requestAnimationFrame
1993
+ * This is a best practice alternative to setTimeout
1994
+ */
1995
+ private scrollToLastMessage() {
1996
+ this.showIonContent = true
1997
+ if (this.ionContentChatArea) {
1998
+ // Use requestAnimationFrame for better performance
1999
+ requestAnimationFrame(() => {
2000
+ requestAnimationFrame(() => {
2001
+ // Double RAF ensures DOM is fully rendered
2002
+ this.ionContentChatArea.scrollToBottom(0).then(() => {
2003
+ this.logger.log('[CONVS-DETAIL] scroll posizionato all\'ultimo messaggio')
2004
+ }).catch((error) => {
2005
+ this.logger.error('[CONVS-DETAIL] errore durante lo scroll:', error)
2006
+ })
2007
+ })
2008
+ })
2009
+ } else {
2010
+ this.logger.warn('[CONVS-DETAIL] ionContentChatArea non disponibile')
2011
+ }
2012
+ }
2013
+
1930
2014
  /**
1931
2015
  * detectBottom
1932
2016
  */
@@ -7,6 +7,8 @@
7
7
  [sound_btn]="sound_btn"
8
8
  [isMobile]="isMobile"
9
9
  [isVisibleTKT]="isVisibleTKT"
10
+ [isVisibleCNT]="isVisibleCNT"
11
+ [roles]="rolesHeader"
10
12
  (onSoundChange)="onSoundChange($event)"
11
13
  (openContactsDirectory)=openContactsDirectory($event)
12
14
  (openProfileInfo)=openProfileInfo($event)>
@@ -11,13 +11,14 @@ ion-header {
11
11
 
12
12
  ion-content {
13
13
  // overwrite inline styles
14
- --offset-bottom: auto!important;
15
- --overflow: hidden;
16
- overflow: scroll;
14
+ // --offset-bottom: auto!important;
15
+ // Ionic scroll is handled by the internal scroll container (Shadow DOM).
16
+ // Forcing `--overflow: hidden` breaks scrolling (Chrome >= 144 is stricter here).
17
+ --overflow: auto;
17
18
 
18
19
  /* For Firefox */
19
20
  @-moz-document url-prefix() {
20
- scrollbar-width: none;
21
+ // scrollbar styling must target the internal scroll element
21
22
  }
22
23
 
23
24
 
@@ -25,6 +26,16 @@ ion-content {
25
26
  background: var(--list-bkg-color);
26
27
  }
27
28
 
29
+ }
30
+
31
+ // Target Ionic internal scroll container (Shadow DOM) for overflow + scrollbar styling
32
+ ion-content::part(scroll) {
33
+ overflow-y: auto;
34
+ -webkit-overflow-scrolling: touch;
35
+
36
+ /* For Firefox */
37
+ scrollbar-width: none;
38
+
28
39
  &::-webkit-scrollbar {
29
40
  width: 6px;
30
41
  height: 8px;
@@ -53,7 +53,10 @@ import { Globals } from 'src/app/utils/globals';
53
53
  import { TriggerEvents } from 'src/app/services/triggerEvents/triggerEvents';
54
54
  import { MessageModel } from 'src/chat21-core/models/message';
55
55
  import { Project } from 'src/chat21-core/models/projects';
56
- import { getOSCode } from 'src/app/utils/utils';
56
+ import { getOSCode, hasRole } from 'src/app/utils/utils';
57
+ import { PERMISSIONS } from 'src/app/utils/permissions.constants';
58
+ import { ProjectUser } from 'src/chat21-core/models/projectUsers';
59
+ import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
57
60
 
58
61
  @Component({
59
62
  selector: 'app-conversations-list',
@@ -82,6 +85,7 @@ export class ConversationListPage implements OnInit {
82
85
  public archived_btn: boolean
83
86
  public sound_btn: string
84
87
  public isVisibleTKT: boolean = true;
88
+ public isVisibleCNT: boolean = true;;
85
89
  public convertMessage = convertMessage
86
90
  private isShowMenuPage = false
87
91
  private logger: LoggerService = LoggerInstance.getInstance()
@@ -104,6 +108,9 @@ export class ConversationListPage implements OnInit {
104
108
  public isMobile: boolean = false;
105
109
  public isInitialized: boolean = false;
106
110
 
111
+ public projectUser: ProjectUser;
112
+ public rolesHeader: { [key: string]: boolean }
113
+
107
114
  // PROJECT AVAILABILITY INFO: start
108
115
  project: Project
109
116
  profile_name_translated: string;
@@ -130,6 +137,7 @@ export class ConversationListPage implements OnInit {
130
137
  private translateService: CustomTranslateService,
131
138
  public tiledeskService: TiledeskService,
132
139
  public tiledeskAuthService: TiledeskAuthService,
140
+ public projectUsersService: ProjectUsersService,
133
141
  public appConfigProvider: AppConfigProvider,
134
142
  public platform: Platform,
135
143
  public wsService: WebsocketService,
@@ -371,6 +379,11 @@ export class ConversationListPage implements OnInit {
371
379
  // save conversationHandler in chatManager
372
380
  this.chatManager.setConversationsHandler(this.conversationsHandlerService)
373
381
  this.showPlaceholder = false
382
+
383
+ // Hide loading spinner if there are no conversations
384
+ if (this.conversations.length === 0) {
385
+ this.loadingIsActive = false
386
+ }
374
387
  }
375
388
 
376
389
  // private manageStoredConversations() {
@@ -471,7 +484,7 @@ export class ConversationListPage implements OnInit {
471
484
  }
472
485
 
473
486
  listenToCurrentStoredProject() {
474
- this.events.subscribe('storage:last_project', projectObjct => {
487
+ this.events.subscribe('storage:last_project', async(projectObjct) => {
475
488
  if (projectObjct && projectObjct !== 'undefined') {
476
489
  this.logger.log('[CONVS-LIST-PAGE] - GET STORED PROJECT ', projectObjct)
477
490
 
@@ -496,6 +509,10 @@ export class ConversationListPage implements OnInit {
496
509
  } else if (this.project.profile.type === 'payment' && this.project.profile.name === 'enterprise') {
497
510
  this.profile_name_translated = this.translationMapHeader.get('PaydPlanNameEnterprise');
498
511
  }
512
+
513
+ this.projectUser = await this.projectUsersService.getProjectUserByProjectId(this.project._id)
514
+ this.rolesHeader = this.checkCannedResponsesRoles();
515
+ this.logger.log('[CONVS-LIST-PAGE] - GET PROJECT USER ROLES ', this.rolesHeader)
499
516
  }
500
517
  })
501
518
  }
@@ -631,8 +648,24 @@ export class ConversationListPage implements OnInit {
631
648
  const public_Key = this.appConfigProvider.getConfig().t2y12PruGU9wUtEGzBJfolMIgK
632
649
  this.logger.log('[CONVS-LIST-PAGE] AppConfigService getAppConfig public_Key', public_Key)
633
650
  this.isVisibleTKT = getOSCode("TKT", public_Key);
651
+ this.isVisibleCNT = getOSCode("CNT", public_Key);
634
652
  }
635
653
 
654
+ checkCannedResponsesRoles(): { [key: string]: boolean } {
655
+ const permissionKeys = [
656
+ 'LEADS_READ',
657
+ ] as const;
658
+
659
+ const roles: { [key: string]: boolean } = {};
660
+ for (const key of permissionKeys) {
661
+ const permission = PERMISSIONS[key];
662
+ roles[permission] = hasRole(this.projectUser, permission);
663
+ }
664
+
665
+ return roles;
666
+
667
+ }
668
+
636
669
  onBackButtonFN(event) {
637
670
  this.conversationType = 'active'
638
671
 
@@ -883,6 +916,10 @@ export class ConversationListPage implements OnInit {
883
916
 
884
917
  this.logger.log('[CONVS-LIST-PAGE] navigateByUrl this.uidConvSelected ', this.uidConvSelected)
885
918
 
919
+ const queryParams = this.route.snapshot.queryParams;
920
+ const queryString = new URLSearchParams(queryParams).toString();
921
+
922
+
886
923
  this.setUidConvSelected(uidConvSelected, converationType)
887
924
  if (checkPlatformIsMobile()) {
888
925
  this.logger.log('[CONVS-LIST-PAGE] checkPlatformIsMobile(): ', checkPlatformIsMobile())
@@ -900,6 +937,7 @@ export class ConversationListPage implements OnInit {
900
937
  if (this.conversationSelected && this.conversationSelected.conversation_with_fullname) {
901
938
  pageUrl = 'conversation-detail/' + this.uidConvSelected + '/' + encodeURIComponent(this.conversationSelected.conversation_with_fullname) + '/' + converationType
902
939
  }
940
+ pageUrl += queryString ? `?${queryString}` : '';
903
941
  this.logger.log('[CONVS-LIST-PAGE] setUidConvSelected navigateByUrl--->: ', pageUrl)
904
942
  // replace(/\(/g, '%28').replace(/\)/g, '%29') -> used for the encoder of any round brackets
905
943
  this.router.navigateByUrl(pageUrl.replace(/\(/g, '%28').replace(/\)/g, '%29'), {replaceUrl: true})
@@ -16,11 +16,21 @@ ion-toolbar {
16
16
 
17
17
  ion-content {
18
18
  // overwrite inline styles
19
- --overflow: hidden;
20
- overflow: scroll;
19
+ // Ionic scroll is handled by the internal scroll container (Shadow DOM).
20
+ // Forcing `--overflow: hidden` breaks scrolling (Chrome >= 144 is stricter here).
21
+ --overflow: auto;
21
22
  &:not(.mobile){
22
23
  --background: var(--list-bkg-color);
23
24
  }
25
+ }
26
+
27
+ // Target Ionic internal scroll container (Shadow DOM) for overflow + scrollbar styling
28
+ ion-content::part(scroll) {
29
+ overflow-y: auto;
30
+ -webkit-overflow-scrolling: touch;
31
+
32
+ /* For Firefox */
33
+ scrollbar-width: none;
24
34
 
25
35
  &::-webkit-scrollbar {
26
36
  width: 6px;
@@ -32,11 +42,11 @@ ion-content {
32
42
  background: #f9f9f9;
33
43
  }
34
44
  &::-webkit-scrollbar-thumb {
35
- background-color: #b9b9b9;
36
- border-radius: 0px;
45
+ background-color: #b9b9b9;
46
+ border-radius: 0px;
37
47
  }
38
48
  &::-webkit-scrollbar-thumb:hover {
39
- background-color: #727272;
49
+ background-color: #727272;
40
50
  }
41
51
  }
42
52
 
@@ -88,14 +88,14 @@ export class GlobalSettingsService {
88
88
  this.logger.debug('[GLOBAL-SET] setVariableFromStorage :::::::: SET VARIABLE ---------->', Object.keys(globals));
89
89
  for (const key of Object.keys(globals)) {
90
90
  const val = this.appStorageService.getItem(key);
91
- // this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals KEY ---------->', key);
92
- // this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals VAL ---------->', val);
91
+ this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals KEY ---------->', key);
92
+ this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals VAL ---------->', val);
93
93
  if (val && val !== null) {
94
94
  // globals.setParameter(key, val);
95
95
  globals[key] = stringToBoolean(val);
96
96
  }
97
97
  // this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals == ---------->', globals);
98
- }
98
+ }
99
99
  }
100
100
 
101
101
  /**
@@ -113,6 +113,7 @@ export class GlobalSettingsService {
113
113
  TEMP = getParameterByName(windowContext, 'tiledesk_supportMode');
114
114
  if (TEMP) {
115
115
  globals.supportMode = stringToBoolean(TEMP);
116
+ this.appStorageService.setItem('supportMode', String(globals.supportMode))
116
117
  }
117
118
 
118
119
  TEMP = getParameterByName(windowContext, 'tiledesk_lang');
@@ -138,6 +139,13 @@ export class GlobalSettingsService {
138
139
  TEMP = getParameterByName(windowContext, 'tiledesk_projectID');
139
140
  if (TEMP) {
140
141
  globals.projectID = TEMP;
142
+ this.appStorageService.setItem('projectID', TEMP)
143
+ }
144
+
145
+ TEMP = getParameterByName(windowContext, 'tiledesk_logOut');
146
+ if (TEMP) {
147
+ globals.logOut = stringToBoolean(TEMP);
148
+ this.appStorageService.setItem('logOut', TEMP)
141
149
  }
142
150
 
143
151
  }
@@ -4,7 +4,6 @@ import { Router, NavigationExtras } from '@angular/router';
4
4
 
5
5
  // utils
6
6
  import { checkPlatformIsMobile } from '../../chat21-core/utils/utils';
7
- // import { ConversationDetailPage } from '../pages/conversation-detail/conversation-detail.page';
8
7
 
9
8
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
10
9
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
@@ -0,0 +1,16 @@
1
+ import { TestBed } from '@angular/core/testing';
2
+
3
+ import { ProjectUsersService } from './project-users.service';
4
+
5
+ describe('ProjectUsersService', () => {
6
+ let service: ProjectUsersService;
7
+
8
+ beforeEach(() => {
9
+ TestBed.configureTestingModule({});
10
+ service = TestBed.inject(ProjectUsersService);
11
+ });
12
+
13
+ it('should be created', () => {
14
+ expect(service).toBeTruthy();
15
+ });
16
+ });
@@ -0,0 +1,63 @@
1
+ import { HttpClient, HttpHeaders } from '@angular/common/http';
2
+ import { Injectable } from '@angular/core';
3
+ import { Observable } from 'rxjs';
4
+ import { map } from 'rxjs/operators';
5
+ import { ProjectUser } from 'src/chat21-core/models/projectUsers';
6
+ import { AppStorageService } from 'src/chat21-core/providers/abstract/app-storage.service';
7
+ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
8
+ import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
9
+
10
+ @Injectable({
11
+ providedIn: 'root'
12
+ })
13
+ export class ProjectUsersService {
14
+
15
+ private SERVER_BASE_URL: string;
16
+ private tiledeskToken: string;
17
+
18
+ private logger: LoggerService = LoggerInstance.getInstance();
19
+ constructor(
20
+ public http: HttpClient,
21
+ public appStorageService: AppStorageService
22
+ ) {}
23
+
24
+ initialize(serverBaseUrl: string) {
25
+ this.logger.log('[TILEDESK-PROJECT_USERS-SERV] - initialize serverBaseUrl', serverBaseUrl);
26
+ this.SERVER_BASE_URL = serverBaseUrl;
27
+ this.tiledeskToken = this.appStorageService.getItem('tiledeskToken')
28
+ }
29
+
30
+ public getProjectUsersByProjectId(project_id: string): Observable<ProjectUser[]> {
31
+ const url = this.SERVER_BASE_URL + project_id + '/project_users/';
32
+ this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER URL', url);
33
+
34
+ const httpOptions = {
35
+ headers: new HttpHeaders({
36
+ 'Content-Type': 'application/json',
37
+ Authorization: this.tiledeskToken
38
+ })
39
+ };
40
+ return this.http.get(url, httpOptions).pipe(map((res: any) => {
41
+ this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
42
+ return res
43
+ }))
44
+ }
45
+
46
+ public getProjectUserByProjectId(project_id: string): Promise<ProjectUser> {
47
+ const url = this.SERVER_BASE_URL + project_id + '/project_users/me';
48
+ this.logger.log('[TILEDESK-SERVICE]- GET PROJECT-USER BY USER-ID - URL', url);
49
+
50
+ const httpOptions = {
51
+ headers: new HttpHeaders({
52
+ 'Content-Type': 'application/json',
53
+ Authorization: this.tiledeskToken
54
+ })
55
+ };
56
+
57
+ return this.http.get(url, httpOptions).pipe(map((res: any) => {
58
+ this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
59
+ return res[0]
60
+ })).toPromise();
61
+ }
62
+
63
+ }
@@ -93,22 +93,6 @@ export class TiledeskService {
93
93
  }))
94
94
  }
95
95
 
96
- public getProjectUsersByProjectId(project_id: string) {
97
- const url = this.SERVER_BASE_URL + project_id + '/project_users/';
98
- this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER URL', url);
99
-
100
- const httpOptions = {
101
- headers: new HttpHeaders({
102
- 'Content-Type': 'application/json',
103
- Authorization: this.tiledeskToken
104
- })
105
- };
106
- return this.http.get(url, httpOptions).pipe(map((res: any) => {
107
- this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
108
- return res
109
- }))
110
- }
111
-
112
96
  public getAllLeadsActiveWithLimit(project_id: string, limit: number) {
113
97
  const url = this.SERVER_BASE_URL + project_id + '/leads?limit=' + limit + '&with_fullname=true';
114
98
  this.logger.log('[TILEDESK-SERVICE] - GET ALL ACTIVE LEADS (LIMIT 10000) - URL', url);
@@ -102,5 +102,33 @@ export class TriggerEvents {
102
102
  }
103
103
  }
104
104
 
105
+ public triggerOnUpdateNewConversationBadge(detailObj: {}) {
106
+ this.logger.debug(' ---------------- triggerOnUpdateNewConversationBadge ---------------- ', detailObj);
107
+ try {
108
+ const onBeforeInit = new CustomEvent('onUpdateNewConversationBadge', { detail: detailObj });
109
+ const windowContext = this.windowContext;
110
+ if (windowContext){
111
+ // windowContext.document.dispatchEvent(onNewConversation);
112
+ windowContext.postMessage({type: "onUpdateNewConversationBadge", detail: detailObj }, '*')
113
+ }
114
+ } catch (e) {
115
+ this.logger.error('[TRIGGER-HANDLER] > Error:' + e);
116
+ }
117
+ }
118
+
119
+ public triggerOnOpenTicketExternally(detailObj: {}) {
120
+ this.logger.debug(' ---------------- triggerOnOpenTicketExternally ---------------- ', detailObj);
121
+ try {
122
+ const onBeforeInit = new CustomEvent('onOpenTicketExternally', { detail: detailObj });
123
+ const windowContext = this.windowContext;
124
+ if (windowContext){
125
+ // windowContext.document.dispatchEvent(onNewConversation);
126
+ windowContext.postMessage({type: "onOpenTicketExternally", detail: detailObj }, '*')
127
+ }
128
+ } catch (e) {
129
+ this.logger.error('[TRIGGER-HANDLER] > Error:' + e);
130
+ }
131
+ }
132
+
105
133
 
106
134
  }