@chat21/chat21-ionic 3.4.31 → 3.4.32-rc10

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 (88) hide show
  1. package/CHANGELOG.md +167 -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 +71 -1
  21. package/src/app/components/navbar/navbar.component.ts +100 -42
  22. package/src/app/components/project-item/project-item.component.ts +79 -52
  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 +52 -11
  26. package/src/app/components/sidebar-user-details/sidebar-user-details.component.scss +304 -17
  27. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +217 -27
  28. package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
  29. package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
  30. package/src/app/pages/conversation-detail/conversation-detail.page.ts +89 -5
  31. package/src/app/pages/conversations-list/conversations-list.module.ts +3 -5
  32. package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
  33. package/src/app/pages/conversations-list/conversations-list.page.ts +120 -26
  34. package/src/app/pages/unassigned-conversations/unassigned-conversations.module.ts +16 -4
  35. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.html +43 -17
  36. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +25 -1
  37. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.ts +279 -13
  38. package/src/app/pipe/filter.pipe.spec.ts +8 -0
  39. package/src/app/pipe/filter.pipe.ts +15 -0
  40. package/src/app/pipe/find.pipe.spec.ts +8 -0
  41. package/src/app/pipe/find.pipe.ts +15 -0
  42. package/src/app/services/global-settings/global-settings.service.ts +11 -3
  43. package/src/app/services/nav-proxy.service.ts +0 -1
  44. package/src/app/services/project_users/project-users.service.spec.ts +16 -0
  45. package/src/app/services/project_users/project-users.service.ts +63 -0
  46. package/src/app/services/projects/project.service.ts +2 -1
  47. package/src/app/services/tiledesk/tiledesk.service.ts +24 -0
  48. package/src/app/services/triggerEvents/triggerEvents.ts +40 -0
  49. package/src/app/services/websocket/websocket-js.ts +59 -534
  50. package/src/app/services/websocket/websocket-js_old.ts +578 -0
  51. package/src/app/services/websocket/websocket.service.ts +67 -14
  52. package/src/app/services/websocket/websocket.worker.ts +242 -0
  53. package/src/app/shared/shared.module.ts +26 -10
  54. package/src/app/utils/globals.ts +2 -0
  55. package/src/app/utils/permissions.constants.ts +138 -0
  56. package/src/app/utils/project-utils.ts +2 -2
  57. package/src/app/utils/utils.ts +18 -1
  58. package/src/assets/i18n/ar.json +11 -1
  59. package/src/assets/i18n/az.json +11 -1
  60. package/src/assets/i18n/de.json +11 -1
  61. package/src/assets/i18n/en.json +11 -1
  62. package/src/assets/i18n/es.json +11 -1
  63. package/src/assets/i18n/fr.json +11 -1
  64. package/src/assets/i18n/it.json +13 -3
  65. package/src/assets/i18n/kk.json +11 -1
  66. package/src/assets/i18n/pt.json +11 -1
  67. package/src/assets/i18n/ru.json +11 -1
  68. package/src/assets/i18n/sr.json +11 -1
  69. package/src/assets/i18n/sv.json +11 -1
  70. package/src/assets/i18n/tr.json +11 -1
  71. package/src/assets/i18n/uk.json +11 -1
  72. package/src/assets/i18n/uz.json +12 -1
  73. package/src/assets/js/agentDesktop-sdk.js +55 -0
  74. package/src/assets/js/chat21client.js +36 -0
  75. package/src/assets/js/mqtt-keepalive-worker.js +53 -0
  76. package/src/assets/test.html +5 -2
  77. package/src/chat-config-template.json +1 -0
  78. package/src/chat-config.json +1 -0
  79. package/src/chat21-core/models/projectUsers.ts +19 -0
  80. package/src/chat21-core/models/project_user.ts +2 -1
  81. package/src/chat21-core/models/projects.ts +1 -0
  82. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  83. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  84. package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
  85. package/src/chat21-core/utils/constants.ts +6 -0
  86. package/src/chat21-core/utils/convertRequestToConversation.ts +2 -2
  87. package/src/chat21-core/utils/utils.ts +53 -3
  88. package/src/variables.scss +3 -0
package/CHANGELOG.md CHANGED
@@ -8,22 +8,168 @@
8
8
  ### **Copyrigth**:
9
9
  *Tiledesk SRL*
10
10
 
11
+ # 3.4.32-rc10
12
+ - **bug-fixed**: minor ui fix
13
+
14
+ # 3.4.32-rc9
15
+ - **added**: sidebar-user-details — MutationObserver to close dropdowns when user details panel is hidden (watches #user-details class); cleanup in ngOnDestroy to prevent memory leaks.
16
+ - **changed**: sidebar-user-details — refined closeDropdowns for better dropdown management when panel closes.
17
+ - **added**: sidebar-user-details — hover to open status dropdown; improved status dropdown positioning logic.
18
+ - **changed**: sidebar-user-details — flexbox layout (justify-content: space-between) for improved project item spacing.
19
+ - **changed**: sidebar-user-details — HTML structure for conditional rendering of teammate status images and titles; cleaned up unused SCSS.
20
+
21
+ # 3.4.32-rc8
22
+ - **bug-fixed**: sidebar-user-details — status dropdown not visible when clicking first/last project; moved outside #user-details container to avoid overflow clipping.
23
+ - **bug-fixed**: sidebar-user-details — replaced `transform` on #user-details with `left` animation to fix `position: fixed` containing block (dropdown positioning).
24
+ - **changed**: sidebar-user-details — projects_dropdown_container and status-dropdown now use same colors as ng-select teammate-status-in-drawer.
25
+ - **changed**: sidebar-user-details — projects-dropdown-wrapper styled to match ng-select container.
26
+ - **added**: sidebar-user-details — MPA feature flag in featuresToken: if MPA is true show projects_dropdown_container, else show availability_dropdown_container.
27
+ - **bug-fixed**: RouterModule.forRoot() called twice when clicking conversation — SharedModule now imports RouterModule.forChild([]) instead of AppRoutingModule.
28
+ - **changed**: FindPipe and FilterPipe moved from AppModule to SharedModule for app-wide availability.
29
+ - **added**: conversations-list — postMessage to hosting app on conversation selection (event: `onConversationChanged`, data: full conversation object).
30
+
31
+ # 3.4.32-rc7
32
+ - **addded**: ability to change availability status for each project the logged-in user in sidebar-user-detail
33
+
34
+ # 3.4.32-rc6
35
+ - **bug-fixed**: convertRequestToConversation timestamp wrong unit
36
+
37
+ # 3.4.32-rc5
38
+ - **added**: conversations-list — on init, fetches all projects via `getProjects` and stores them in AppStorageService under `all_projects`; before saving, checks that the key does not already contain each project (avoids duplicates).
39
+ - **changed**: conversations-list `onConversationLoaded` — project name and id are now resolved from the `all_projects` storage key instead of per-project localStorage entries.
40
+
41
+ # 3.4.32-rc4
42
+ - **changed**: unassigned conversations page — `onImageLoaded` and `onConversationLoaded` are now invoked for each conversation in the list (avatar URLs, last message formatting, project name).
43
+ - **bug-fixed**: navbar project dropdown — descenders (letters like g, p, q) were being clipped; added `line-height: 1.4` and vertical padding to prevent clipping.
44
+
45
+ # 3.4.32-rc3
46
+ - **bug-fixed**: unassigned conversations list was reset on each WebSocket subscription; conversations from other projects were lost when subscribing to multiple online projects. Added `skipClear` parameter to `subscriptionToWsConversations` so the list is cleared only once when subscribing to all online projects.
47
+ - **changed**: unassigned conversations empty state — centered the "no conversations" label both vertically and horizontally within the full viewport height.
48
+
49
+ # 3.4.32-rc2
50
+
51
+ # 3.4.32-rc1
52
+ - **added**: ability to change availability status for each project the logged-in user belongs to.
53
+ - **changed**: unserved-request.page refactor html and ts refactor
54
+
11
55
  # 3.4.31 in PROD
12
56
  - **changed**: enhance HTML entities encoding by normalizing line breaks and handling null/undefined inputs
13
57
  - **changed**: API for upload a file/image into chat
14
58
 
15
59
  # 3.4.30 in PROD
60
+
61
+ # 3.4.30-rc3
16
62
  - **changed**: when the app is in background, play a sound whenever a new message arrives.
17
63
 
18
64
  # 3.4.29 in PROD
19
65
  - **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
66
 
67
+ # 3.4.29-rc2
68
+ - **changed**: minor updates on API to upload file/image into chat
69
+
70
+ # 3.4.29-rc1
71
+ - **changed**: API for upload a file/image into chat
72
+
73
+
21
74
  # 3.4.28 in PROD
22
75
  - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
23
76
 
24
77
  # 3.4.27 in PROD
25
78
  - **bug-fixed**: cannot find route if userFullname contains /
26
79
 
80
+ # 3.4.29-rc1
81
+ - **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)`
82
+
83
+ # 3.4.28-rc1
84
+ - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
85
+
86
+ # 3.4.27-rc26
87
+ - **bug-fixed**: wss push requests twice
88
+
89
+ # 3.4.27-rc25
90
+ - **bug-fixed**: projectUserService is not initialized
91
+
92
+ # 3.4.27-rc24
93
+ - **added**: implementation of multiple message in wss onmessage
94
+
95
+ # 3.4.27-rc23
96
+ - **added**: keepAlive worker for MQTT connection
97
+
98
+ # 3.4.27-rc22
99
+ - **added**: new WsWorker to manage iframe chrome throttling while tab is in background or hidden
100
+
101
+ # 3.4.27-rc21
102
+ - **changed**: new wss reconnect and timeout keepalive
103
+ - **bug-fixed**: cannot route if senderFullaname contains /
104
+
105
+ # 3.4.27-rc20
106
+ - **added**: onOpenTicketExternally event in triggerEvents service
107
+
108
+ # 3.4.27-rc19
109
+ - **added**: window.parent['openTicketOnHDA']
110
+
111
+ # 3.4.27-rc18
112
+ - **added**: triggerOnUpdateNewConversationBadge to update conversation badge count in parent component
113
+
114
+ # 3.4.27-rc17
115
+ - **bug-fixed**: setNotification not called when click on a conversation
116
+
117
+ # 3.4.27-rc16
118
+ - **bug-fixed**: setNotification not called when resolve a conversation
119
+
120
+ # 3.4.27-rc15
121
+ - **changed**: /images with /img in assets folder
122
+
123
+ # 3.4.27-rc14
124
+ - **added**: DISPLAY_EDIT_PROFILE brand variable
125
+ - **bug-fixed**: emojii is sent also if is not allowed
126
+
127
+ # 3.4.27-rc13
128
+ - **added**: ability to mantain logout parameter when redirect to dashboard urls from sidebar component
129
+
130
+ # 3.4.27-rc12
131
+ - **added**: ability to manage logOut option in sidebar-user-detail with tiledesk_logOut url query params
132
+
133
+ # 3.4.27-rc11
134
+ - **bug-fixed**: fixed infinite loading in contact list
135
+
136
+ # 3.4.27-rc10
137
+ - **added**: ability to manage header-conversation-list with roles
138
+ - **bug-fixed**: members in group list not loaded
139
+
140
+ # 3.4.27-rc9
141
+ - **bug-fixed**: Scrolling to the last message when opening a conversation
142
+ - **bug-fixed**: Loading in the conversation list disabled when removing the last conversation
143
+
144
+ # 3.4.27-rc8
145
+ - **added**: ability to open ticket to external service
146
+ - **added**: ticketSection env var
147
+
148
+ # 3.4.27-rc7
149
+ - **bug-fixed**: Scrolling to the last message when opening a conversation
150
+ - **bug-fixed**: Loading in the conversation list disabled when removing the last conversation
151
+
152
+ # 3.4.27-rc6
153
+ - **bug-fixed**: user for dashboard app is incorrect
154
+
155
+ # 3.4.27-rc5
156
+ - **added**: managed roles in sidebar e navbar
157
+ - **bug-fixed**: projectId and supportMode url is not saved in localstorage
158
+
159
+ # 3.4.27-rc4
160
+ - **bug-fixed**: extractUrls function is not able to detect url start with www or without https/http
161
+ - **bug-fixed**: if message is sent with keydown, error on domain check is not showed
162
+
163
+ # 3.4.27-rc3
164
+ - **bug-fixed**: cannot set user availability if supportMode is enabled and tiledesk_projectID url params is set
165
+
166
+ # 3.4.27-rc2
167
+ - **bug-fixed**: cannede responses role
168
+
169
+ # 3.4.27-rc1
170
+ - **added**: managed canned responses with roles
171
+ - **changed**: name in info mesage
172
+
27
173
  # 3.4.26 in PROD
28
174
 
29
175
  # 3.4.26-rc2
@@ -32,6 +178,7 @@
32
178
  # 3.4.26-rc1
33
179
  - **added**: tiledesk_projectID query param to manage user status
34
180
  - **added**: token to managane ticket feature
181
+ - **added**: getOsCode login into utils.ts
35
182
 
36
183
  # 3.4.25 in PROD
37
184
  - **changed**: pipe marked to support malicious text input
@@ -54,6 +201,24 @@
54
201
  # 3.4.22 in PROD
55
202
  - **added**: managed allowed_upload_extentions from project settings
56
203
 
204
+ # 3.4.21-rc6
205
+ - **added**: managed allowed_upload_extentions from project settings
206
+
207
+ # 3.4.21-rc5
208
+ - **added**: setConversation as read when agent click on it
209
+
210
+ # 3.4.21-rc4
211
+ - **added**: ability to init and decrement new conversation count badge
212
+
213
+ # 3.4.21-rc3
214
+ - **changed**: badge notification for agentDesktop
215
+
216
+ # 3.4.21-rc2
217
+ - **added**: count in newConversation handler event
218
+
219
+ # 3.4.21-rc1
220
+ - **added**: implement badge notification for agentDesktop sw when new conversation is assigned to logged agent
221
+
57
222
  # 3.4.21 in PROD
58
223
 
59
224
  # 3.4.20 in PROD
@@ -67,8 +232,8 @@
67
232
  - **bug-fixed**: minor fix on ion-texarea element with allowed url domain
68
233
 
69
234
  # 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
235
+ - **added**: ability to check for if emoji is allowd to be sent in message textarea
236
+ - **added**: ability to check for if url domain is allowd to be sent in message textarea
72
237
 
73
238
  # 3.4.18 in PROD
74
239
 
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-rc10",
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(