@chat21/chat21-ionic 3.4.31 → 3.4.32-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 (82) hide show
  1. package/CHANGELOG.md +127 -2
  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 +72 -11
  6. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.html +14 -2
  7. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.scss +39 -2
  8. package/src/app/chatlib/list-conversations-component/list-conversations.module.ts +14 -0
  9. package/src/app/components/canned-response/canned-response.component.html +26 -23
  10. package/src/app/components/canned-response/canned-response.component.scss +0 -2
  11. package/src/app/components/canned-response/canned-response.component.ts +3 -1
  12. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +24 -1
  13. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +30 -0
  14. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +29 -7
  15. package/src/app/components/conversation-info/info-content/info-content.component.ts +2 -2
  16. package/src/app/components/conversation-info/info-group/info-group.component.ts +23 -21
  17. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.html +1 -1
  18. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.ts +5 -1
  19. package/src/app/components/navbar/navbar.component.html +35 -9
  20. package/src/app/components/navbar/navbar.component.scss +64 -0
  21. package/src/app/components/navbar/navbar.component.ts +100 -42
  22. package/src/app/components/project-item/project-item.component.ts +79 -51
  23. package/src/app/components/sidebar/sidebar.component.html +65 -45
  24. package/src/app/components/sidebar/sidebar.component.ts +110 -117
  25. package/src/app/components/sidebar-user-details/sidebar-user-details.component.html +3 -3
  26. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +15 -22
  27. package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
  28. package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
  29. package/src/app/pages/conversation-detail/conversation-detail.page.ts +89 -5
  30. package/src/app/pages/conversations-list/conversations-list.module.ts +3 -5
  31. package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
  32. package/src/app/pages/conversations-list/conversations-list.page.ts +51 -11
  33. package/src/app/pages/unassigned-conversations/unassigned-conversations.module.ts +16 -4
  34. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.html +41 -17
  35. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +10 -1
  36. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.ts +114 -9
  37. package/src/app/services/global-settings/global-settings.service.ts +11 -3
  38. package/src/app/services/nav-proxy.service.ts +0 -1
  39. package/src/app/services/project_users/project-users.service.spec.ts +16 -0
  40. package/src/app/services/project_users/project-users.service.ts +63 -0
  41. package/src/app/services/projects/project.service.ts +2 -1
  42. package/src/app/services/tiledesk/tiledesk.service.ts +21 -16
  43. package/src/app/services/triggerEvents/triggerEvents.ts +28 -0
  44. package/src/app/services/websocket/websocket-js.ts +59 -534
  45. package/src/app/services/websocket/websocket-js_old.ts +578 -0
  46. package/src/app/services/websocket/websocket.service.ts +59 -10
  47. package/src/app/services/websocket/websocket.worker.ts +242 -0
  48. package/src/app/shared/shared.module.ts +11 -2
  49. package/src/app/utils/globals.ts +2 -0
  50. package/src/app/utils/permissions.constants.ts +138 -0
  51. package/src/app/utils/project-utils.ts +2 -2
  52. package/src/app/utils/utils.ts +18 -1
  53. package/src/assets/i18n/ar.json +11 -1
  54. package/src/assets/i18n/az.json +11 -1
  55. package/src/assets/i18n/de.json +11 -1
  56. package/src/assets/i18n/en.json +11 -1
  57. package/src/assets/i18n/es.json +11 -1
  58. package/src/assets/i18n/fr.json +11 -1
  59. package/src/assets/i18n/it.json +13 -3
  60. package/src/assets/i18n/kk.json +11 -1
  61. package/src/assets/i18n/pt.json +11 -1
  62. package/src/assets/i18n/ru.json +11 -1
  63. package/src/assets/i18n/sr.json +11 -1
  64. package/src/assets/i18n/sv.json +11 -1
  65. package/src/assets/i18n/tr.json +11 -1
  66. package/src/assets/i18n/uk.json +11 -1
  67. package/src/assets/i18n/uz.json +12 -1
  68. package/src/assets/js/agentDesktop-sdk.js +55 -0
  69. package/src/assets/js/chat21client.js +36 -0
  70. package/src/assets/js/mqtt-keepalive-worker.js +53 -0
  71. package/src/assets/test.html +5 -2
  72. package/src/chat-config-template.json +1 -0
  73. package/src/chat-config.json +1 -0
  74. package/src/chat21-core/models/projectUsers.ts +19 -0
  75. package/src/chat21-core/models/project_user.ts +2 -1
  76. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  77. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  78. package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
  79. package/src/chat21-core/utils/constants.ts +5 -0
  80. package/src/chat21-core/utils/convertRequestToConversation.ts +1 -1
  81. package/src/chat21-core/utils/utils.ts +53 -3
  82. package/src/variables.scss +3 -0
package/CHANGELOG.md CHANGED
@@ -8,22 +8,128 @@
8
8
  ### **Copyrigth**:
9
9
  *Tiledesk SRL*
10
10
 
11
+ # 3.4.32-rc1
12
+ - **added**: ability to change availability status for each project the logged-in user belongs to.
13
+ - **changed**: unserved-request.page refactor html and ts refactor
14
+
11
15
  # 3.4.31 in PROD
12
16
  - **changed**: enhance HTML entities encoding by normalizing line breaks and handling null/undefined inputs
13
17
  - **changed**: API for upload a file/image into chat
14
18
 
15
19
  # 3.4.30 in PROD
20
+
21
+ # 3.4.30-rc3
16
22
  - **changed**: when the app is in background, play a sound whenever a new message arrives.
17
23
 
18
24
  # 3.4.29 in PROD
19
25
  - **bug-fixed**: web (Chrome >= 144) `ion-content` stopped scrolling on some pages (conversation list / contacts directory / unassigned); removed the forced `--overflow: hidden` and handled scrolling on Ionic’s internal scroll container via `ion-content::part(scroll)`
20
26
 
27
+ # 3.4.29-rc2
28
+ - **changed**: minor updates on API to upload file/image into chat
29
+
30
+ # 3.4.29-rc1
31
+ - **changed**: API for upload a file/image into chat
32
+
33
+
21
34
  # 3.4.28 in PROD
22
35
  - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
23
36
 
24
37
  # 3.4.27 in PROD
25
38
  - **bug-fixed**: cannot find route if userFullname contains /
26
39
 
40
+ # 3.4.29-rc1
41
+ - **bug-fixed**: web (Chrome >= 144) `ion-content` stopped scrolling on some pages (conversation list / contacts directory / unassigned); removed the forced `--overflow: hidden` and handled scrolling on Ionic’s internal scroll container via `ion-content::part(scroll)`
42
+
43
+ # 3.4.28-rc1
44
+ - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
45
+
46
+ # 3.4.27-rc26
47
+ - **bug-fixed**: wss push requests twice
48
+
49
+ # 3.4.27-rc25
50
+ - **bug-fixed**: projectUserService is not initialized
51
+
52
+ # 3.4.27-rc24
53
+ - **added**: implementation of multiple message in wss onmessage
54
+
55
+ # 3.4.27-rc23
56
+ - **added**: keepAlive worker for MQTT connection
57
+
58
+ # 3.4.27-rc22
59
+ - **added**: new WsWorker to manage iframe chrome throttling while tab is in background or hidden
60
+
61
+ # 3.4.27-rc21
62
+ - **changed**: new wss reconnect and timeout keepalive
63
+ - **bug-fixed**: cannot route if senderFullaname contains /
64
+
65
+ # 3.4.27-rc20
66
+ - **added**: onOpenTicketExternally event in triggerEvents service
67
+
68
+ # 3.4.27-rc19
69
+ - **added**: window.parent['openTicketOnHDA']
70
+
71
+ # 3.4.27-rc18
72
+ - **added**: triggerOnUpdateNewConversationBadge to update conversation badge count in parent component
73
+
74
+ # 3.4.27-rc17
75
+ - **bug-fixed**: setNotification not called when click on a conversation
76
+
77
+ # 3.4.27-rc16
78
+ - **bug-fixed**: setNotification not called when resolve a conversation
79
+
80
+ # 3.4.27-rc15
81
+ - **changed**: /images with /img in assets folder
82
+
83
+ # 3.4.27-rc14
84
+ - **added**: DISPLAY_EDIT_PROFILE brand variable
85
+ - **bug-fixed**: emojii is sent also if is not allowed
86
+
87
+ # 3.4.27-rc13
88
+ - **added**: ability to mantain logout parameter when redirect to dashboard urls from sidebar component
89
+
90
+ # 3.4.27-rc12
91
+ - **added**: ability to manage logOut option in sidebar-user-detail with tiledesk_logOut url query params
92
+
93
+ # 3.4.27-rc11
94
+ - **bug-fixed**: fixed infinite loading in contact list
95
+
96
+ # 3.4.27-rc10
97
+ - **added**: ability to manage header-conversation-list with roles
98
+ - **bug-fixed**: members in group list not loaded
99
+
100
+ # 3.4.27-rc9
101
+ - **bug-fixed**: Scrolling to the last message when opening a conversation
102
+ - **bug-fixed**: Loading in the conversation list disabled when removing the last conversation
103
+
104
+ # 3.4.27-rc8
105
+ - **added**: ability to open ticket to external service
106
+ - **added**: ticketSection env var
107
+
108
+ # 3.4.27-rc7
109
+ - **bug-fixed**: Scrolling to the last message when opening a conversation
110
+ - **bug-fixed**: Loading in the conversation list disabled when removing the last conversation
111
+
112
+ # 3.4.27-rc6
113
+ - **bug-fixed**: user for dashboard app is incorrect
114
+
115
+ # 3.4.27-rc5
116
+ - **added**: managed roles in sidebar e navbar
117
+ - **bug-fixed**: projectId and supportMode url is not saved in localstorage
118
+
119
+ # 3.4.27-rc4
120
+ - **bug-fixed**: extractUrls function is not able to detect url start with www or without https/http
121
+ - **bug-fixed**: if message is sent with keydown, error on domain check is not showed
122
+
123
+ # 3.4.27-rc3
124
+ - **bug-fixed**: cannot set user availability if supportMode is enabled and tiledesk_projectID url params is set
125
+
126
+ # 3.4.27-rc2
127
+ - **bug-fixed**: cannede responses role
128
+
129
+ # 3.4.27-rc1
130
+ - **added**: managed canned responses with roles
131
+ - **changed**: name in info mesage
132
+
27
133
  # 3.4.26 in PROD
28
134
 
29
135
  # 3.4.26-rc2
@@ -32,6 +138,7 @@
32
138
  # 3.4.26-rc1
33
139
  - **added**: tiledesk_projectID query param to manage user status
34
140
  - **added**: token to managane ticket feature
141
+ - **added**: getOsCode login into utils.ts
35
142
 
36
143
  # 3.4.25 in PROD
37
144
  - **changed**: pipe marked to support malicious text input
@@ -54,6 +161,24 @@
54
161
  # 3.4.22 in PROD
55
162
  - **added**: managed allowed_upload_extentions from project settings
56
163
 
164
+ # 3.4.21-rc6
165
+ - **added**: managed allowed_upload_extentions from project settings
166
+
167
+ # 3.4.21-rc5
168
+ - **added**: setConversation as read when agent click on it
169
+
170
+ # 3.4.21-rc4
171
+ - **added**: ability to init and decrement new conversation count badge
172
+
173
+ # 3.4.21-rc3
174
+ - **changed**: badge notification for agentDesktop
175
+
176
+ # 3.4.21-rc2
177
+ - **added**: count in newConversation handler event
178
+
179
+ # 3.4.21-rc1
180
+ - **added**: implement badge notification for agentDesktop sw when new conversation is assigned to logged agent
181
+
57
182
  # 3.4.21 in PROD
58
183
 
59
184
  # 3.4.20 in PROD
@@ -67,8 +192,8 @@
67
192
  - **bug-fixed**: minor fix on ion-texarea element with allowed url domain
68
193
 
69
194
  # 3.4.19-rc1
70
- - added: ability to check for if emoji is allowd to be sent in message textarea
71
- - added: ability to check for if url domain is allowd to be sent in message textarea
195
+ - **added**: ability to check for if emoji is allowd to be sent in message textarea
196
+ - **added**: ability to check for if url domain is allowd to be sent in message textarea
72
197
 
73
198
  # 3.4.18 in PROD
74
199
 
package/angular.json CHANGED
@@ -32,6 +32,7 @@
32
32
  "src/chat-config-template.json",
33
33
  "src/chat-config.json",
34
34
  "src/chat-config-dev.json",
35
+ "src/chat-config-native-ar.json",
35
36
  {
36
37
  "glob": "**/*",
37
38
  "input": "src/assets",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-ionic",
3
3
  "author": "Tiledesk SRL",
4
- "version": "3.4.31",
4
+ "version": "3.4.32-rc1",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -21,7 +21,9 @@
21
21
  </div> -->
22
22
 
23
23
  <div class="user-details-sidebar" [ngClass]="{'hide-sidebar': IS_ONLINE === false || IS_ON_MOBILE_DEVICE || SUPPORT_MODE === false}">
24
- <app-sidebar-user-details> </app-sidebar-user-details>
24
+ <app-sidebar-user-details
25
+ [logOut]="g?.logOut">
26
+ </app-sidebar-user-details>
25
27
  </div>
26
28
 
27
29
  <ion-split-pane when="md" contentId="main" [ngClass]="{'mobile': IS_ON_MOBILE_DEVICE, 'sidebar-hidden': IS_ON_MOBILE_DEVICE || SUPPORT_MODE === false}">
@@ -44,6 +44,9 @@ import { conversationToMessage } from 'src/chat21-core/utils/utils-message';
44
44
  import { ProjectService } from './services/projects/project.service';
45
45
  import { ContactsService } from './services/contacts/contacts.service';
46
46
  import { TiledeskService } from './services/tiledesk/tiledesk.service';
47
+ import { Project } from 'src/chat21-core/models/projects';
48
+ import { BRAND_BASE_INFO } from './utils/utils-resources';
49
+ import { ProjectUsersService } from './services/project_users/project-users.service';
47
50
 
48
51
  @Component({
49
52
  selector: 'app-root',
@@ -141,6 +144,7 @@ export class AppComponent implements OnInit {
141
144
  /**TILEDESK SERVICES */
142
145
  private tiledeskService: TiledeskService,
143
146
  private projectService: ProjectService,
147
+ private projectUsersService: ProjectUsersService,
144
148
  private contactsService: ContactsService
145
149
  ) {
146
150
 
@@ -167,6 +171,7 @@ export class AppComponent implements OnInit {
167
171
  }, { capture: true });
168
172
  }
169
173
 
174
+
170
175
  listenChatAlreadyOpenWithoutParamsInMobileMode() {
171
176
  this.events.subscribe('noparams:mobile', (isAlreadyOpenInMobileMode) => {
172
177
  // console.log('[APP-COMP] Chat is Already Open In Mobile Mode ', isAlreadyOpenInMobileMode)
@@ -295,6 +300,10 @@ export class AppComponent implements OnInit {
295
300
  this.zone = new NgZone({}); // a cosa serve?
296
301
 
297
302
  this.SUPPORT_MODE = this.g.supportMode
303
+ this.logger.info('[APP-COMP] this.SUPPORT_MODE', this.SUPPORT_MODE)
304
+
305
+ BRAND_BASE_INFO['LOGOUT_ENABLED'] = this.g.logOut
306
+ this.logger.info('[APP-COMP] this.logOut', BRAND_BASE_INFO['LOGOUT_ENABLED'])
298
307
  }
299
308
 
300
309
  });
@@ -331,7 +340,7 @@ export class AppComponent implements OnInit {
331
340
 
332
341
  listenToPostMsgs() {
333
342
  window.addEventListener("message", (event) => {
334
- this.logger.log("[APP-COMP] message event ", event);
343
+ // this.logger.log("[APP-COMP] message event ", event);
335
344
 
336
345
  if (event && event.data && event.data.action && event.data.parameter) {
337
346
  if (event.data.action === 'openJoinConversationModal') {
@@ -341,7 +350,7 @@ export class AppComponent implements OnInit {
341
350
 
342
351
  if (event && event.data && event.data.action && event.data.parameter) {
343
352
  if (event.data.action === 'resolveConversation') {
344
- this.conversationsHandlerService.archiveConversation(event.data.patameter)
353
+ this.conversationsHandlerService.archiveConversation(event.data.parameter)
345
354
  }
346
355
  }
347
356
  // if (event && event.data && event.data.action && event.data.parameter) {
@@ -533,10 +542,10 @@ export class AppComponent implements OnInit {
533
542
  this.statusBar.styleLightContent();
534
543
  this.navService.init(this.sidebarNav, this.detailNav);
535
544
  this.tiledeskAuthService.initialize(this.appConfigProvider.getConfig().apiUrl);
536
- this.messagingAuthService.initialize();
537
-
545
+
538
546
  // this.currentUserService.initialize();
539
547
  this.chatManager.initialize();
548
+ this.messagingAuthService.initialize();
540
549
  this.presenceService.initialize(this.tenant);
541
550
  this.typingService.initialize(this.tenant);
542
551
 
@@ -862,7 +871,8 @@ export class AppComponent implements OnInit {
862
871
  // console.log('[APP-COMP] PLATFORM', PLATFORM_MOBILE, 'route.snapshot', this.route.snapshot);
863
872
  if (!IDConv) {
864
873
  this.logger.log('[APP-COMP] navigateByUrl -- conversations-list');
865
- this.router.navigateByUrl('conversations-list')
874
+ const queryString = window.location.search; // restituisce ad es. "?jwt=...&tiledesk_supportMode=false"
875
+ this.router.navigateByUrl('conversations-list' + queryString);
866
876
  }
867
877
  // this.router.navigateByUrl(pageUrl);
868
878
  // this.navService.setRoot(ConversationListPage, {});
@@ -1113,13 +1123,19 @@ export class AppComponent implements OnInit {
1113
1123
  if (conversation && conversation.is_new === true && this.isInitialized) {
1114
1124
  this.manageTabNotification('conv_added', conversation.sound)
1115
1125
  this.manageEventNewConversation(conversation)
1126
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1127
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1116
1128
  }
1117
1129
  if(conversation) this.updateConversationsOnStorage()
1118
1130
  });
1119
1131
 
1120
1132
  this.conversationsHandlerService.conversationChanged.subscribe((conversation: ConversationModel) => {
1121
1133
  // console.log('[APP-COMP] ***** subscribeConversationChanged conversation: ', conversation);
1122
- if(conversation) this.updateConversationsOnStorage();
1134
+ if(conversation){
1135
+ this.updateConversationsOnStorage();
1136
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1137
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1138
+ }
1123
1139
  });
1124
1140
 
1125
1141
  this.conversationsHandlerService.conversationChangedDetailed.subscribe((changes: {value: ConversationModel, previousValue: ConversationModel}) => {
@@ -1147,6 +1163,8 @@ export class AppComponent implements OnInit {
1147
1163
  if(conversation) {
1148
1164
  this.updateConversationsOnStorage();
1149
1165
  this.segmentResolved(conversation);
1166
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1167
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1150
1168
  this.router.navigateByUrl('conversation-detail/'); //redirect to basePage
1151
1169
  }
1152
1170
  });
@@ -1180,6 +1198,7 @@ export class AppComponent implements OnInit {
1180
1198
  this.chatManager.setCurrentUser(currentUser);
1181
1199
 
1182
1200
  this.tiledeskService.initialize(serverBaseURL)
1201
+ this.projectUsersService.initialize(serverBaseURL)
1183
1202
  this.projectService.initialize(serverBaseURL)
1184
1203
  this.contactsService.initialize(serverBaseURL)
1185
1204
 
@@ -1187,11 +1206,14 @@ export class AppComponent implements OnInit {
1187
1206
  this.events.publish('go:online', true);
1188
1207
  // this.chatManager.startApp();
1189
1208
 
1209
+
1210
+ //INIT WEBSOCKET
1211
+ this.connetWebsocket(tiledeskToken)
1212
+
1190
1213
  // ----------------------------------------------
1191
1214
  // PUSH NOTIFICATIONS
1192
1215
  // ----------------------------------------------
1193
1216
  const pushEngine = this.appConfigProvider.getConfig().pushEngine
1194
-
1195
1217
  if (currentUser) {
1196
1218
  if (pushEngine && pushEngine !== 'none') {
1197
1219
  this.notificationsService.getNotificationPermissionAndSaveToken(currentUser.uid);
@@ -1213,6 +1235,24 @@ export class AppComponent implements OnInit {
1213
1235
  } catch (err) {
1214
1236
  this.logger.error('[APP-COMP] -> error:', err);
1215
1237
  }
1238
+
1239
+ // ----------------------------------------------
1240
+ // LAST PROJECT FROM URL
1241
+ // ----------------------------------------------
1242
+ if(this.g.projectID){
1243
+ this.projectService.getProjects().subscribe({ next: (projects: Project[]) => {
1244
+ const project = projects.find(prjct => prjct.id_project._id === this.g.projectID)
1245
+ if(project){
1246
+ this.logger.log('[APP-COMP] - GET PROJECT - project found with this.projectID', project);
1247
+ localStorage.setItem('last_project', JSON.stringify(project))
1248
+ this.events.publish('storage:last_project', project)
1249
+ }
1250
+ }, error: (error) => {
1251
+ this.logger.log('[APP-COMP] - GET PROJECT - project NOT found with this.projectID', this.g.projectID, error);
1252
+ }, complete: () => {
1253
+
1254
+ }});
1255
+ }
1216
1256
  }
1217
1257
 
1218
1258
 
@@ -1253,9 +1293,21 @@ export class AppComponent implements OnInit {
1253
1293
  }
1254
1294
 
1255
1295
  goToDashboardLogin(){
1256
- let DASHBOARD_URL = this.appConfigProvider.getConfig().dashboardUrl + '#/login'
1257
- const myWindow = window.open(DASHBOARD_URL, '_self');
1258
- myWindow.focus();
1296
+ // let DASHBOARD_URL = this.appConfigProvider.getConfig().dashboardUrl + '#/login'
1297
+ // const myWindow = window.open(DASHBOARD_URL, '_self');
1298
+ // myWindow.focus();
1299
+ }
1300
+
1301
+ connetWebsocket(tiledeskToken) {
1302
+
1303
+ this.logger.log('[WEBSOCKET-JS] connetWebsocket called in [PROJECT-ITEM] tiledeskToken ', tiledeskToken)
1304
+ const appconfig = this.appConfigProvider.getConfig();
1305
+ this.logger.log('[WEBSOCKET-JS] connetWebsocket called in [PROJECT-ITEM] wsUrl ', appconfig.wsUrl)
1306
+ const WS_URL = appconfig.wsUrl + '?token=' + tiledeskToken
1307
+ this.logger.log('[WEBSOCKET-JS] connetWebsocket called in [PROJECT-ITEM] wsUrl ', WS_URL)
1308
+ this.webSocketJs.init(
1309
+ WS_URL
1310
+ );
1259
1311
  }
1260
1312
 
1261
1313
 
@@ -1354,7 +1406,8 @@ export class AppComponent implements OnInit {
1354
1406
 
1355
1407
  subscribeConversationSelected= (conversation: ConversationModel) => {
1356
1408
  if(conversation && conversation.is_new){
1357
- this.audio_NewConv.pause()
1409
+ this.audio_NewConv.pause();
1410
+ this.conversationsHandlerService.setConversationRead(conversation.uid)
1358
1411
  }
1359
1412
  }
1360
1413
 
@@ -1430,6 +1483,9 @@ export class AppComponent implements OnInit {
1430
1483
  this.logger.debug('[APP-COMP]-CONVS - INIT CONV CONVS 2', conversations)
1431
1484
  this.events.publish('appcompSubscribeToConvs:loadingIsActive', false);
1432
1485
  }
1486
+
1487
+ //INIT NOTIFICATION FOR NEW CONVERSATION COUNT
1488
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1433
1489
  });
1434
1490
 
1435
1491
  }
@@ -1712,6 +1768,11 @@ export class AppComponent implements OnInit {
1712
1768
  this.triggerEvents.triggerOnInit(detailOBJ)
1713
1769
  }
1714
1770
 
1771
+ private triggerOnUpdateNewConversationBadge(count: number){
1772
+ const detailOBJ = { event: 'onUpdateNewConversationBadge', count: count.toString() }
1773
+ this.triggerEvents.triggerOnUpdateNewConversationBadge(detailOBJ)
1774
+ }
1775
+
1715
1776
 
1716
1777
  // @HostListener('mouseenter', ['$event'])
1717
1778
  // onMouseEnter(event: any) {
@@ -77,6 +77,8 @@
77
77
 
78
78
  <ion-item button="true" lines="none" class="ion-no-padding" [class.ion-selected]="conversation?.uid === uidConvSelected"
79
79
  *ngFor="let conversation of listConversations; let index= index" (click)="openConversationByID(conversation)" detail=false>
80
+ <div class="conv-item-wrapper">
81
+ <div class="conv-item-top">
80
82
  <div tabindex="0"></div>
81
83
 
82
84
  <!-- <div [class.selected]="conversation.uid === uidConvSelected"></div> -->
@@ -170,9 +172,9 @@
170
172
  <div *ngIf="conversation?.recipient.startsWith('support-group')" tooltip="{{ translationsMap?.get('Archive')}}"></div> -->
171
173
  </ion-button>
172
174
 
173
- <!-- <ion-button *ngIf="conversation?.recipient.startsWith('support-group') && !conversation.archived" [tooltip]="joinTooltip" [options]="tooltip_options" placement="bottom" content-type="template"
175
+ <!-- <ion-button *ngIf="conversation?.recipient.startsWith('support-group') && !conversation.archived"
174
176
  [ngClass]="{'hide': !IS_ON_MOBILE_DEVICE, 'button-on-desktop': !IS_ON_MOBILE_DEVICE, 'button-on-mobile': IS_ON_MOBILE_DEVICE }"
175
- id="{{ 'join_conversation_button' + conversation.uid }}" class="close-conversation-button" ion-button clear
177
+ id="{{ 'join_conversation_button' + conversation.uid }}" class="join-conversation-button" ion-button clear
176
178
  item-end (click)="joinConversation(conversation);$event.stopPropagation();" padding>
177
179
  <ion-icon slot="icon-only" style="display:block;" id="{{ 'join_button_icon' + conversation.uid }}" name="link-outline" item-end></ion-icon>
178
180
 
@@ -196,5 +198,15 @@
196
198
  [ngClass]="{'notification_point-on-desktop': !IS_ON_MOBILE_DEVICE, 'notification_point-on-mobile': IS_ON_MOBILE_DEVICE }"
197
199
  *ngIf="conversation.is_new">
198
200
  </div>
201
+ </div>
202
+ <div class="conv-item-actions" *ngIf="!conversation.archived && conversation.status ===100" (click)="$event.stopPropagation()">
203
+ <ion-button size="small" class="join-button" (click)="joinConversation(conversation)">
204
+ {{ translationsMap?.get('JOIN_CONVERSATION') || 'Join' }}
205
+ </ion-button>
206
+ <ion-button size="small" class="resolve-button" (click)="closeConversation(conversation)">
207
+ {{ translationsMap?.get('Resolve') || 'Resolve' }}
208
+ </ion-button>
209
+ </div>
210
+ </div>
199
211
 
200
212
  </ion-item>
@@ -9,8 +9,9 @@
9
9
  }
10
10
  ion-item {
11
11
  cursor: pointer;
12
- height: 90px; //70px;
13
- --min-height: 90px; //70px;
12
+ min-height: 90px;
13
+ height: auto;
14
+ --min-height: auto;
14
15
  position: relative;
15
16
  display: flex;
16
17
  text-decoration: none;
@@ -23,6 +24,42 @@ ion-item {
23
24
  border-radius: var(--border-radius-item);
24
25
  margin: 4px 5px;
25
26
  transition: none;
27
+ .conv-item-wrapper {
28
+ display: flex;
29
+ flex-direction: column;
30
+ width: 100%;
31
+ padding-bottom: 8px;
32
+ }
33
+ .conv-item-top {
34
+ display: flex;
35
+ flex: 1;
36
+ position: relative;
37
+ }
38
+ .conv-item-actions {
39
+ display: flex;
40
+ justify-content: space-around;
41
+ gap: 8px;
42
+ margin-top: 4px;
43
+ ion-button {
44
+ --padding-start: 12px;
45
+ --padding-end: 12px;
46
+ font-size: 12px;
47
+ margin: 0;
48
+ --border-radius: var(--button-border-radius);
49
+ &.join-button {
50
+ --background: var(--join-button-background);
51
+ --background-hover: #e4e6eb;
52
+ --background-activated: #d8dae0;
53
+ --color: var(--bacis-white);
54
+ }
55
+ &.resolve-button {
56
+ --background: var(--resolve-button-background);
57
+ --background-hover: #e4e6eb;
58
+ --background-activated: #d8dae0;
59
+ --color: #1c1e21;
60
+ }
61
+ }
62
+ }
26
63
  .conv-container{
27
64
  width: 84%;
28
65
  height: 100%;
@@ -0,0 +1,14 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonicModule } from '@ionic/angular';
4
+ import { MomentModule } from 'ngx-moment';
5
+
6
+ import { ListConversationsComponent } from './list-conversations/list-conversations.component';
7
+ import { IonListConversationsComponent } from './ion-list-conversations/ion-list-conversations.component';
8
+
9
+ @NgModule({
10
+ imports: [CommonModule, IonicModule, MomentModule],
11
+ declarations: [ListConversationsComponent, IonListConversationsComponent],
12
+ exports: [ListConversationsComponent, IonListConversationsComponent],
13
+ })
14
+ export class ListConversationsModule {}
@@ -1,20 +1,30 @@
1
1
  <div>
2
- <div class="canned-list" *ngIf="tagsCannedFilter.length > 0">
3
- <ion-item button="true" [ngClass]="{'is_active_item': i == arrowkeyLocation}" lines="none"
4
- class="canned-item no-ripple border" id="{{'canned-item_'+ i }}"
5
- *ngFor="let canned of tagsCannedFilter; let i = index;"
6
- (click)="onClickCannedFN(canned, $event)">
7
- <div class="cannedContent">
8
- <ion-input [class.readonly]="canned?.disabled" [readonly]="canned?.disabled" type="text" [(ngModel)]="canned.title" class="title" id="{{'titleCanned_'+canned._id}}" #title></ion-input>
9
- <ion-input [class.readonly]="canned?.disabled" [readonly]="canned?.disabled" type="text" [(ngModel)]="canned.text" class="text truncate"></ion-input>
2
+ <div class="canned-list" *ngIf="!showLoading">
3
+ <span *ngIf="tagsCannedFilter.length > 0">
4
+ <ion-item button="true" [ngClass]="{'is_active_item': i == arrowkeyLocation}" lines="none"
5
+ class="canned-item no-ripple border" id="{{'canned-item_'+ i }}"
6
+ *ngFor="let canned of tagsCannedFilter; let i = index;"
7
+ (click)="onClickCannedFN(canned, $event)">
8
+ <div class="cannedContent">
9
+ <ion-input [class.readonly]="canned?.disabled" [readonly]="canned?.disabled" type="text" [(ngModel)]="canned.title" class="title" id="{{'titleCanned_'+canned._id}}" #title></ion-input>
10
+ <ion-input [class.readonly]="canned?.disabled" [readonly]="canned?.disabled" type="text" [(ngModel)]="canned.text" class="text truncate"></ion-input>
11
+ </div>
12
+ <!-- <ion-icon class="canned-item-icon" name="pin" src="assets/img/pin.svg" slot=end *ngIf="canned.pinned" (click)="onPinCanned(canned, $event)"></ion-icon>
13
+ <ion-icon class="canned-item-icon" name="pin" src="assets/img/pinned.svg" slot=end (click)="onUnPinCanned(canned, $event)"></ion-icon> -->
14
+ <ion-icon class="canned-item-icon" name="checkmark-sharp" slot=end *ngIf="(canned.createdBy === loggedUser.uid && !canned.disabled) && roles[PERMISSIONS.CANNED_RESPONSES_UPDATE]" (click)="onConfirmEditCanned(canned, $event)"></ion-icon>
15
+ <ion-icon class="canned-item-icon" name="pencil-sharp" slot=end *ngIf="(canned.createdBy === loggedUser.uid && canned.disabled) && roles[PERMISSIONS.CANNED_RESPONSES_UPDATE]" (click)="onEditCanned(canned, $event)"></ion-icon>
16
+ <ion-icon class="canned-item-icon" name="trash-bin-outline" slot=end *ngIf="(canned.createdBy === loggedUser.uid) && roles[PERMISSIONS.CANNED_RESPONSES_DELETE]" (click)="onDeleteCanned(canned, $event)"></ion-icon>
17
+ </ion-item>
18
+ </span>
19
+ <div class="no-data" *ngIf="tagsCannedFilter.length === 0">
20
+ <div class="container">
21
+ <ion-item button="false" lines="none" class="canned-item no-ripple border">
22
+ <ion-icon name="cloud-offline" slot="start"></ion-icon>
23
+ <ion-label>{{translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE')}}</ion-label>
24
+ </ion-item>
10
25
  </div>
11
- <!-- <ion-icon class="canned-item-icon" name="pin" src="assets/img/pin.svg" slot=end *ngIf="canned.pinned" (click)="onPinCanned(canned, $event)"></ion-icon>
12
- <ion-icon class="canned-item-icon" name="pin" src="assets/img/pinned.svg" slot=end (click)="onUnPinCanned(canned, $event)"></ion-icon> -->
13
- <ion-icon class="canned-item-icon" name="checkmark-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && !canned.disabled" (click)="onConfirmEditCanned(canned, $event)"></ion-icon>
14
- <ion-icon class="canned-item-icon" name="pencil-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && canned.disabled" (click)="onEditCanned(canned, $event)"></ion-icon>
15
- <ion-icon class="canned-item-icon" name="trash-bin-outline" slot=end *ngIf="canned.createdBy === loggedUser.uid" (click)="onDeleteCanned(canned, $event)"></ion-icon>
16
- </ion-item>
17
- <ion-item class="canned-item add-canned-response-wpr" button="true" lines="none" (click)="onClickAddCannedResponseFN()">
26
+ </div>
27
+ <ion-item *ngIf="roles[PERMISSIONS.CANNED_RESPONSES_CREATE]" class="canned-item add-canned-response-wpr" button="true" lines="none" (click)="onClickAddCannedResponseFN()">
18
28
  <ion-icon class="add-canned-response-icon" name="flash-outline"></ion-icon>
19
29
  <span class="add-canned-response-add-icon">+</span>
20
30
  <label class="add-canned-response-label" >{{translationMap?.get('AddNewCannedResponse')}}</label>
@@ -33,12 +43,5 @@
33
43
  <div class="label">{{translationMap.get('LABEL_LOADING')}}</div>
34
44
  </div>
35
45
  </div>
36
- <div class="no-data" *ngIf="tagsCannedFilter.length === 0 && !showLoading">
37
- <div class="container">
38
- <ion-item button="false" lines="none" class="canned-item no-ripple border">
39
- <ion-icon name="cloud-offline" slot="start"></ion-icon>
40
- <ion-label>{{translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE')}}</ion-label>
41
- </ion-item>
42
- </div>
43
- </div>
46
+
44
47
  </div>
@@ -278,7 +278,5 @@ ion-item {
278
278
  display: flex;
279
279
  justify-content: center;
280
280
  flex-direction: column;
281
- align-items: center;
282
-
283
281
  }
284
282
  }
@@ -9,6 +9,7 @@ import { TiledeskAuthService } from 'src/chat21-core/providers/tiledesk/tiledesk
9
9
  import { compareValues, htmlEntities } from 'src/chat21-core/utils/utils';
10
10
  import { getProjectIdSelectedConversation } from 'src/chat21-core/utils/utils-message';
11
11
  import { PLAN_NAME } from 'src/chat21-core/utils/constants';
12
+ import { PERMISSIONS } from 'src/app/utils/permissions.constants';
12
13
 
13
14
  @Component({
14
15
  selector: 'app-canned-response',
@@ -21,7 +22,7 @@ export class CannedResponseComponent implements OnInit {
21
22
  @Input() conversationWith: string;
22
23
  @Input() conversationWithFullname: string;
23
24
  @Input() currentString: string;
24
- @Input() canShowCanned: boolean = true;
25
+ @Input() roles: Array<string>;
25
26
  @Input() stylesMap: Map<string, string>;
26
27
  @Input() translationMap: Map<string, string>;
27
28
  @Output() onLoadedCannedResponses = new EventEmitter<[any]>();
@@ -36,6 +37,7 @@ export class CannedResponseComponent implements OnInit {
36
37
 
37
38
  public arrowkeyLocation = -1
38
39
 
40
+ PERMISSIONS = PERMISSIONS
39
41
 
40
42
  private logger: LoggerService = LoggerInstance.getInstance();
41
43
  constructor(
@@ -22,6 +22,13 @@
22
22
  {{translationMap?.get('WHATSAPP.LABEL_TEMPLATES')}}
23
23
  </ion-button>
24
24
  </div>
25
+ <!-- OPEN TICKET -->
26
+ <div *ngIf="ticketSection" class="section-option" id="template" tooltip="{{translationMap?.get('TICKET.OPEN_TICKET')}}" placement="top">
27
+ <ion-button fill="clear" [class.active]="section==='ticket'" (click)="onOpenSection('ticket')" [disabled]="channelType === 'direct'">
28
+ <ion-icon name="ticket"></ion-icon>
29
+ {{translationMap?.get('TICKET.OPEN_TICKET')}}
30
+ </ion-button>
31
+ </div>
25
32
  </div>
26
33
 
27
34
  <div class="footerContainerAlert">
@@ -50,6 +57,22 @@
50
57
  </ion-col>
51
58
  </ion-row>
52
59
 
60
+ <ion-row id="ticket" [style.display]="section==='ticket'? 'flex': 'none'">
61
+ <ion-col col-auto>
62
+ <div class="placeholder">{{translationMap.get('TICKET.DESCRIPTION')}}</div>
63
+ <div class="buttons-container">
64
+ <ion-button name="add" size="small" (click)="onClickTicket('open')">
65
+ <ion-icon name="add"></ion-icon>
66
+ {{translationMap?.get('TICKET.CONFIRM')}}
67
+ </ion-button>
68
+ <ion-button size="small" color="danger" (click)="onClickTicket('close')">
69
+ <ion-icon name="close"></ion-icon>
70
+ {{translationMap?.get('TICKET.CLOSE')}}
71
+ </ion-button>
72
+ </div>
73
+ </ion-col>
74
+ </ion-row>
75
+
53
76
  <ion-row id="message-text-area" [style.display]="section==='chat' || section ==='templates' || section ==='copilot'? 'flex': 'none'">
54
77
 
55
78
  <ion-col col-auto style="display: flex;">
@@ -57,7 +80,7 @@
57
80
  <div class="buttons-left">
58
81
 
59
82
  <!-- CANNED RESPONSES -->
60
- <ng-container *ngIf="areVisibleCAR && supportMode">
83
+ <ng-container *ngIf="areVisibleCAR && supportMode && cannedSection">
61
84
  <div class="canned-responses-btn-wpr" tooltip="{{translationMap?.get('CANNED_RESPONSES')}}" placement="top">
62
85
  <ion-button ion-button fill="clear" class="canned-responses-btn" (click)="openCannedResponses()"
63
86
  [disabled]="!conversationWith?.startsWith(CHANNEL_TYPE.SUPPORT_GROUP) || disableTextarea">