@chat21/chat21-ionic 3.4.30 → 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 (90) hide show
  1. package/CHANGELOG.md +131 -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 -13
  6. package/src/app/chatlib/conversation-detail/message/image/image.component.html +1 -0
  7. package/src/app/chatlib/conversation-detail/message/image/image.component.ts +19 -0
  8. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.html +14 -2
  9. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.scss +39 -2
  10. package/src/app/chatlib/list-conversations-component/list-conversations.module.ts +14 -0
  11. package/src/app/components/canned-response/canned-response.component.html +26 -23
  12. package/src/app/components/canned-response/canned-response.component.scss +0 -2
  13. package/src/app/components/canned-response/canned-response.component.ts +3 -1
  14. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +24 -1
  15. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +30 -0
  16. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +39 -9
  17. package/src/app/components/conversation-info/info-content/info-content.component.ts +2 -2
  18. package/src/app/components/conversation-info/info-group/info-group.component.ts +23 -21
  19. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.html +1 -1
  20. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.ts +5 -1
  21. package/src/app/components/navbar/navbar.component.html +35 -9
  22. package/src/app/components/navbar/navbar.component.scss +64 -0
  23. package/src/app/components/navbar/navbar.component.ts +100 -42
  24. package/src/app/components/project-item/project-item.component.ts +79 -51
  25. package/src/app/components/sidebar/sidebar.component.html +65 -45
  26. package/src/app/components/sidebar/sidebar.component.ts +110 -117
  27. package/src/app/components/sidebar-user-details/sidebar-user-details.component.html +3 -3
  28. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +15 -22
  29. package/src/app/directives/html-entities-encode.pipe.ts +20 -5
  30. package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
  31. package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
  32. package/src/app/pages/conversation-detail/conversation-detail.page.ts +95 -7
  33. package/src/app/pages/conversations-list/conversations-list.module.ts +3 -5
  34. package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
  35. package/src/app/pages/conversations-list/conversations-list.page.ts +51 -11
  36. package/src/app/pages/unassigned-conversations/unassigned-conversations.module.ts +16 -4
  37. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.html +41 -17
  38. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +10 -1
  39. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.ts +114 -9
  40. package/src/app/services/global-settings/global-settings.service.ts +11 -3
  41. package/src/app/services/nav-proxy.service.ts +0 -1
  42. package/src/app/services/project_users/project-users.service.spec.ts +16 -0
  43. package/src/app/services/project_users/project-users.service.ts +63 -0
  44. package/src/app/services/projects/project.service.ts +2 -1
  45. package/src/app/services/tiledesk/tiledesk.service.ts +21 -16
  46. package/src/app/services/triggerEvents/triggerEvents.ts +28 -0
  47. package/src/app/services/websocket/websocket-js.ts +59 -534
  48. package/src/app/services/websocket/websocket-js_old.ts +578 -0
  49. package/src/app/services/websocket/websocket.service.ts +59 -10
  50. package/src/app/services/websocket/websocket.worker.ts +242 -0
  51. package/src/app/shared/shared.module.ts +11 -2
  52. package/src/app/utils/globals.ts +2 -0
  53. package/src/app/utils/permissions.constants.ts +138 -0
  54. package/src/app/utils/project-utils.ts +2 -2
  55. package/src/app/utils/utils.ts +18 -1
  56. package/src/assets/i18n/ar.json +11 -1
  57. package/src/assets/i18n/az.json +11 -1
  58. package/src/assets/i18n/de.json +11 -1
  59. package/src/assets/i18n/en.json +11 -1
  60. package/src/assets/i18n/es.json +11 -1
  61. package/src/assets/i18n/fr.json +11 -1
  62. package/src/assets/i18n/it.json +13 -3
  63. package/src/assets/i18n/kk.json +11 -1
  64. package/src/assets/i18n/pt.json +11 -1
  65. package/src/assets/i18n/ru.json +11 -1
  66. package/src/assets/i18n/sr.json +11 -1
  67. package/src/assets/i18n/sv.json +11 -1
  68. package/src/assets/i18n/tr.json +11 -1
  69. package/src/assets/i18n/uk.json +11 -1
  70. package/src/assets/i18n/uz.json +12 -1
  71. package/src/assets/img/no_data_found.png +0 -0
  72. package/src/assets/js/agentDesktop-sdk.js +55 -0
  73. package/src/assets/js/chat21client.js +36 -0
  74. package/src/assets/js/mqtt-keepalive-worker.js +53 -0
  75. package/src/assets/test.html +5 -2
  76. package/src/chat-config-template.json +1 -0
  77. package/src/chat-config.json +1 -0
  78. package/src/chat21-core/models/projectUsers.ts +19 -0
  79. package/src/chat21-core/models/project_user.ts +2 -1
  80. package/src/chat21-core/providers/abstract/upload.service.ts +5 -1
  81. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  82. package/src/chat21-core/providers/firebase/firebase-upload.service.ts +136 -9
  83. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  84. package/src/chat21-core/providers/native/native-image-repo.ts +1 -1
  85. package/src/chat21-core/providers/native/native-upload-service.ts +143 -45
  86. package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
  87. package/src/chat21-core/utils/constants.ts +5 -0
  88. package/src/chat21-core/utils/convertRequestToConversation.ts +1 -1
  89. package/src/chat21-core/utils/utils.ts +53 -3
  90. package/src/variables.scss +3 -0
package/CHANGELOG.md CHANGED
@@ -8,18 +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
+
15
+ # 3.4.31 in PROD
16
+ - **changed**: enhance HTML entities encoding by normalizing line breaks and handling null/undefined inputs
17
+ - **changed**: API for upload a file/image into chat
18
+
11
19
  # 3.4.30 in PROD
20
+
21
+ # 3.4.30-rc3
12
22
  - **changed**: when the app is in background, play a sound whenever a new message arrives.
13
23
 
14
24
  # 3.4.29 in PROD
15
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)`
16
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
+
17
34
  # 3.4.28 in PROD
18
35
  - **bug-fixed**: cannot do project subscription if last_project object is not a project_user obj
19
36
 
20
37
  # 3.4.27 in PROD
21
38
  - **bug-fixed**: cannot find route if userFullname contains /
22
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
+
23
133
  # 3.4.26 in PROD
24
134
 
25
135
  # 3.4.26-rc2
@@ -28,6 +138,7 @@
28
138
  # 3.4.26-rc1
29
139
  - **added**: tiledesk_projectID query param to manage user status
30
140
  - **added**: token to managane ticket feature
141
+ - **added**: getOsCode login into utils.ts
31
142
 
32
143
  # 3.4.25 in PROD
33
144
  - **changed**: pipe marked to support malicious text input
@@ -50,6 +161,24 @@
50
161
  # 3.4.22 in PROD
51
162
  - **added**: managed allowed_upload_extentions from project settings
52
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
+
53
182
  # 3.4.21 in PROD
54
183
 
55
184
  # 3.4.20 in PROD
@@ -63,8 +192,8 @@
63
192
  - **bug-fixed**: minor fix on ion-texarea element with allowed url domain
64
193
 
65
194
  # 3.4.19-rc1
66
- - added: ability to check for if emoji is allowd to be sent in message textarea
67
- - 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
68
197
 
69
198
  # 3.4.18 in PROD
70
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.30",
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',
@@ -119,7 +122,6 @@ export class AppComponent implements OnInit {
119
122
  private navService: NavProxyService,
120
123
  // public chatPresenceHandler: ChatPresenceHandler,
121
124
  public typingService: TypingService,
122
- public uploadService: UploadService,
123
125
  public appStorageService: AppStorageService,
124
126
 
125
127
  // public chatConversationsHandler: ChatConversationsHandler,
@@ -142,6 +144,7 @@ export class AppComponent implements OnInit {
142
144
  /**TILEDESK SERVICES */
143
145
  private tiledeskService: TiledeskService,
144
146
  private projectService: ProjectService,
147
+ private projectUsersService: ProjectUsersService,
145
148
  private contactsService: ContactsService
146
149
  ) {
147
150
 
@@ -168,6 +171,7 @@ export class AppComponent implements OnInit {
168
171
  }, { capture: true });
169
172
  }
170
173
 
174
+
171
175
  listenChatAlreadyOpenWithoutParamsInMobileMode() {
172
176
  this.events.subscribe('noparams:mobile', (isAlreadyOpenInMobileMode) => {
173
177
  // console.log('[APP-COMP] Chat is Already Open In Mobile Mode ', isAlreadyOpenInMobileMode)
@@ -296,6 +300,10 @@ export class AppComponent implements OnInit {
296
300
  this.zone = new NgZone({}); // a cosa serve?
297
301
 
298
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'])
299
307
  }
300
308
 
301
309
  });
@@ -332,7 +340,7 @@ export class AppComponent implements OnInit {
332
340
 
333
341
  listenToPostMsgs() {
334
342
  window.addEventListener("message", (event) => {
335
- this.logger.log("[APP-COMP] message event ", event);
343
+ // this.logger.log("[APP-COMP] message event ", event);
336
344
 
337
345
  if (event && event.data && event.data.action && event.data.parameter) {
338
346
  if (event.data.action === 'openJoinConversationModal') {
@@ -342,7 +350,7 @@ export class AppComponent implements OnInit {
342
350
 
343
351
  if (event && event.data && event.data.action && event.data.parameter) {
344
352
  if (event.data.action === 'resolveConversation') {
345
- this.conversationsHandlerService.archiveConversation(event.data.patameter)
353
+ this.conversationsHandlerService.archiveConversation(event.data.parameter)
346
354
  }
347
355
  }
348
356
  // if (event && event.data && event.data.action && event.data.parameter) {
@@ -534,10 +542,10 @@ export class AppComponent implements OnInit {
534
542
  this.statusBar.styleLightContent();
535
543
  this.navService.init(this.sidebarNav, this.detailNav);
536
544
  this.tiledeskAuthService.initialize(this.appConfigProvider.getConfig().apiUrl);
537
- this.messagingAuthService.initialize();
538
-
545
+
539
546
  // this.currentUserService.initialize();
540
547
  this.chatManager.initialize();
548
+ this.messagingAuthService.initialize();
541
549
  this.presenceService.initialize(this.tenant);
542
550
  this.typingService.initialize(this.tenant);
543
551
 
@@ -547,7 +555,6 @@ export class AppComponent implements OnInit {
547
555
  if (pushEngine && pushEngine !== 'none') {
548
556
  this.notificationsService.initialize(this.tenant, vap_id_Key, platform)
549
557
  }
550
- this.uploadService.initialize();
551
558
 
552
559
  this.setLanguage(null)
553
560
  this.initAuthentication();
@@ -864,7 +871,8 @@ export class AppComponent implements OnInit {
864
871
  // console.log('[APP-COMP] PLATFORM', PLATFORM_MOBILE, 'route.snapshot', this.route.snapshot);
865
872
  if (!IDConv) {
866
873
  this.logger.log('[APP-COMP] navigateByUrl -- conversations-list');
867
- 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);
868
876
  }
869
877
  // this.router.navigateByUrl(pageUrl);
870
878
  // this.navService.setRoot(ConversationListPage, {});
@@ -1115,13 +1123,19 @@ export class AppComponent implements OnInit {
1115
1123
  if (conversation && conversation.is_new === true && this.isInitialized) {
1116
1124
  this.manageTabNotification('conv_added', conversation.sound)
1117
1125
  this.manageEventNewConversation(conversation)
1126
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1127
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1118
1128
  }
1119
1129
  if(conversation) this.updateConversationsOnStorage()
1120
1130
  });
1121
1131
 
1122
1132
  this.conversationsHandlerService.conversationChanged.subscribe((conversation: ConversationModel) => {
1123
1133
  // console.log('[APP-COMP] ***** subscribeConversationChanged conversation: ', conversation);
1124
- if(conversation) this.updateConversationsOnStorage();
1134
+ if(conversation){
1135
+ this.updateConversationsOnStorage();
1136
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1137
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1138
+ }
1125
1139
  });
1126
1140
 
1127
1141
  this.conversationsHandlerService.conversationChangedDetailed.subscribe((changes: {value: ConversationModel, previousValue: ConversationModel}) => {
@@ -1149,6 +1163,8 @@ export class AppComponent implements OnInit {
1149
1163
  if(conversation) {
1150
1164
  this.updateConversationsOnStorage();
1151
1165
  this.segmentResolved(conversation);
1166
+ //UPDATE NOTIFICATION FOR NEW CONVERSATION COUNT
1167
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1152
1168
  this.router.navigateByUrl('conversation-detail/'); //redirect to basePage
1153
1169
  }
1154
1170
  });
@@ -1182,6 +1198,7 @@ export class AppComponent implements OnInit {
1182
1198
  this.chatManager.setCurrentUser(currentUser);
1183
1199
 
1184
1200
  this.tiledeskService.initialize(serverBaseURL)
1201
+ this.projectUsersService.initialize(serverBaseURL)
1185
1202
  this.projectService.initialize(serverBaseURL)
1186
1203
  this.contactsService.initialize(serverBaseURL)
1187
1204
 
@@ -1189,11 +1206,14 @@ export class AppComponent implements OnInit {
1189
1206
  this.events.publish('go:online', true);
1190
1207
  // this.chatManager.startApp();
1191
1208
 
1209
+
1210
+ //INIT WEBSOCKET
1211
+ this.connetWebsocket(tiledeskToken)
1212
+
1192
1213
  // ----------------------------------------------
1193
1214
  // PUSH NOTIFICATIONS
1194
1215
  // ----------------------------------------------
1195
1216
  const pushEngine = this.appConfigProvider.getConfig().pushEngine
1196
-
1197
1217
  if (currentUser) {
1198
1218
  if (pushEngine && pushEngine !== 'none') {
1199
1219
  this.notificationsService.getNotificationPermissionAndSaveToken(currentUser.uid);
@@ -1215,6 +1235,24 @@ export class AppComponent implements OnInit {
1215
1235
  } catch (err) {
1216
1236
  this.logger.error('[APP-COMP] -> error:', err);
1217
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
+ }
1218
1256
  }
1219
1257
 
1220
1258
 
@@ -1255,9 +1293,21 @@ export class AppComponent implements OnInit {
1255
1293
  }
1256
1294
 
1257
1295
  goToDashboardLogin(){
1258
- let DASHBOARD_URL = this.appConfigProvider.getConfig().dashboardUrl + '#/login'
1259
- const myWindow = window.open(DASHBOARD_URL, '_self');
1260
- 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
+ );
1261
1311
  }
1262
1312
 
1263
1313
 
@@ -1356,7 +1406,8 @@ export class AppComponent implements OnInit {
1356
1406
 
1357
1407
  subscribeConversationSelected= (conversation: ConversationModel) => {
1358
1408
  if(conversation && conversation.is_new){
1359
- this.audio_NewConv.pause()
1409
+ this.audio_NewConv.pause();
1410
+ this.conversationsHandlerService.setConversationRead(conversation.uid)
1360
1411
  }
1361
1412
  }
1362
1413
 
@@ -1432,6 +1483,9 @@ export class AppComponent implements OnInit {
1432
1483
  this.logger.debug('[APP-COMP]-CONVS - INIT CONV CONVS 2', conversations)
1433
1484
  this.events.publish('appcompSubscribeToConvs:loadingIsActive', false);
1434
1485
  }
1486
+
1487
+ //INIT NOTIFICATION FOR NEW CONVERSATION COUNT
1488
+ this.triggerOnUpdateNewConversationBadge(this.conversationsHandlerService.countIsNew());
1435
1489
  });
1436
1490
 
1437
1491
  }
@@ -1714,6 +1768,11 @@ export class AppComponent implements OnInit {
1714
1768
  this.triggerEvents.triggerOnInit(detailOBJ)
1715
1769
  }
1716
1770
 
1771
+ private triggerOnUpdateNewConversationBadge(count: number){
1772
+ const detailOBJ = { event: 'onUpdateNewConversationBadge', count: count.toString() }
1773
+ this.triggerEvents.triggerOnUpdateNewConversationBadge(detailOBJ)
1774
+ }
1775
+
1717
1776
 
1718
1777
  // @HostListener('mouseenter', ['$event'])
1719
1778
  // onMouseEnter(event: any) {
@@ -8,5 +8,6 @@
8
8
  [height]="height"
9
9
  [src]="metadata.src"
10
10
  (load)="onLoaded($event)"
11
+ (error)="onError($event)"
11
12
  (click)="openImageViewerModal(metadata.src, metadata.name)" />
12
13
  </div>
@@ -15,6 +15,7 @@ export class ImageComponent implements OnInit {
15
15
  loading: boolean = true
16
16
  modal: any
17
17
  span: any
18
+ private readonly fallbackSrc = 'assets/img/no_data_found.png'
18
19
 
19
20
  constructor() { }
20
21
 
@@ -26,6 +27,24 @@ export class ImageComponent implements OnInit {
26
27
  this.onElementRendered.emit({element: "image", status:true})
27
28
  }
28
29
 
30
+ onError(event: Event) {
31
+ this.loading = false
32
+ const img = event?.target as HTMLImageElement | null
33
+ if (!img) {
34
+ return
35
+ }
36
+ // avoid infinite loop if fallback image fails too
37
+ if (img.src && img.src.includes(this.fallbackSrc)) {
38
+ return
39
+ }
40
+ img.src = this.fallbackSrc
41
+ // also update metadata so click-to-open uses the fallback consistently
42
+ if (this.metadata) {
43
+ this.metadata.src = this.fallbackSrc
44
+ }
45
+ this.onElementRendered.emit({ element: 'image', status: true })
46
+ }
47
+
29
48
  _downloadImage(url: string, fileName: string) {
30
49
  // console.log('Image COMP - IMAGE URL ', url)
31
50
  // console.log('Image COMP - IMAGE FILENAME ', fileName)
@@ -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
  }