@chat21/chat21-ionic 3.4.32-rc4 → 3.4.32-rc6

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,13 @@
8
8
  ### **Copyrigth**:
9
9
  *Tiledesk SRL*
10
10
 
11
+ # 3.4.32-rc6
12
+ - **bug-fixed**: convertRequestToConversation timestamp wrong unit
13
+
14
+ # 3.4.32-rc5
15
+ - **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).
16
+ - **changed**: conversations-list `onConversationLoaded` — project name and id are now resolved from the `all_projects` storage key instead of per-project localStorage entries.
17
+
11
18
  # 3.4.32-rc4
12
19
  - **changed**: unassigned conversations page — `onImageLoaded` and `onConversationLoaded` are now invoked for each conversation in the list (avatar URLs, last message formatting, project name).
13
20
  - **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.
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.32-rc4",
4
+ "version": "3.4.32-rc6",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -57,6 +57,9 @@ import { getOSCode, hasRole } from 'src/app/utils/utils';
57
57
  import { PERMISSIONS } from 'src/app/utils/permissions.constants';
58
58
  import { ProjectUser } from 'src/chat21-core/models/projectUsers';
59
59
  import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
60
+ import { ProjectService } from 'src/app/services/projects/project.service';
61
+
62
+ import { PROJECTS_STORAGE_KEY } from 'src/chat21-core/utils/constants';
60
63
 
61
64
  @Component({
62
65
  selector: 'app-conversations-list',
@@ -138,10 +141,12 @@ export class ConversationListPage implements OnInit {
138
141
  public tiledeskService: TiledeskService,
139
142
  public tiledeskAuthService: TiledeskAuthService,
140
143
  public projectUsersService: ProjectUsersService,
144
+ public projectService: ProjectService,
141
145
  public appConfigProvider: AppConfigProvider,
142
146
  public platform: Platform,
143
147
  public wsService: WebsocketService,
144
148
  public g: Globals,
149
+ public appStorageService: AppStorageService,
145
150
  ) {
146
151
  this.checkPlatform();
147
152
  this.translations();
@@ -215,8 +220,45 @@ export class ConversationListPage implements OnInit {
215
220
  // @ Lifehooks
216
221
  // -----------------------------------------------
217
222
  ngOnInit() {
218
- this.getAppConfigToHideDiplayBtns()
223
+ this.getAppConfigToHideDiplayBtns();
219
224
  this.getOSCODE();
225
+ this.loadAndStoreProjects();
226
+ }
227
+
228
+ /**
229
+ * Recupera tutti i progetti con getProjects e li salva in AppStorage.
230
+ * Prima di salvare verifica che la chiave non esista già e che non contenga già ogni singolo progetto.
231
+ */
232
+ private loadAndStoreProjects() {
233
+ const token = this.tiledeskAuthService.getTiledeskToken();
234
+ if (!token) return;
235
+ this.projectService.getProjects().subscribe((projects: Project[]) => {
236
+ if (!projects?.length) return;
237
+ let projectsMap: Record<string, Project> = {};
238
+ const stored = this.appStorageService.getItem(PROJECTS_STORAGE_KEY);
239
+ if (stored) {
240
+ try {
241
+ projectsMap = JSON.parse(stored) || {};
242
+ } catch (e) {
243
+ this.logger.warn('[CONVS-LIST-PAGE] loadAndStoreProjects - failed to parse stored projects', e);
244
+ }
245
+ }
246
+ let hasChanges = false;
247
+ projects.forEach((project) => {
248
+ const projectId = project.id_project?._id || project.id_project?.id;
249
+ if (!projectId) return;
250
+ if (!projectsMap[projectId]) {
251
+ projectsMap[projectId] = project.id_project;
252
+ hasChanges = true;
253
+ }
254
+ });
255
+ if (hasChanges) {
256
+ this.appStorageService.setItem(PROJECTS_STORAGE_KEY, JSON.stringify(projectsMap));
257
+ this.logger.log('[CONVS-LIST-PAGE] loadAndStoreProjects - saved', Object.keys(projectsMap).length, 'projects');
258
+ }
259
+ },
260
+ (err) => this.logger.error('[CONVS-LIST-PAGE] loadAndStoreProjects - error', err)
261
+ );
220
262
  }
221
263
 
222
264
  ngOnChanges() {
@@ -862,22 +904,32 @@ export class ConversationListPage implements OnInit {
862
904
  }
863
905
  }
864
906
 
865
- if(conversation.attributes && conversation.attributes['projectId']){
866
- let project = localStorage.getItem(conversation.attributes['projectId'])
867
- if(project){
868
- project = JSON.parse(project)
869
- conversation.attributes.project_name = project['name']
870
- }
871
- }else if(conversation.attributes){
872
- const projectId = getProjectIdSelectedConversation(conversation.uid)
873
- let project = localStorage.getItem(projectId)
874
- if(project){
875
- project = JSON.parse(project)
876
- conversation.attributes.projectId = project['_id']
877
- conversation.attributes.project_name = project['name']
878
- }
907
+ const project = this.getProjectFromStorage(conversation);
908
+ if (project) {
909
+ if (!conversation.attributes) conversation.attributes = {};
910
+ conversation.attributes.projectId = project._id;
911
+ conversation.attributes.project_name = project.name;
879
912
  }
913
+ }
880
914
 
915
+ /** Recupera il progetto dalla chiave di storage (all_projects) */
916
+ private getProjectFromStorage(conversation: ConversationModel): Project | null {
917
+ let projectId: string | undefined;
918
+ if (conversation.attributes?.['projectId']) {
919
+ projectId = conversation.attributes['projectId'];
920
+ } else if (conversation.attributes) {
921
+ projectId = getProjectIdSelectedConversation(conversation.uid);
922
+ }
923
+ if (!projectId) return null;
924
+ const stored = this.appStorageService.getItem(PROJECTS_STORAGE_KEY);
925
+ this.logger.log('[CONVS-LIST-PAGE] getProjectFromStorage - stored', stored);
926
+ if (!stored) return null;
927
+ try {
928
+ const projectsMap: Record<string, Project> = JSON.parse(stored);
929
+ return projectsMap[projectId] || null;
930
+ } catch {
931
+ return null;
932
+ }
881
933
  }
882
934
 
883
935
  // isMarkdownLink(last_message_text) {
@@ -13,7 +13,9 @@ import { TiledeskAuthService } from 'src/chat21-core/providers/tiledesk/tiledesk
13
13
  import { TiledeskService } from 'src/app/services/tiledesk/tiledesk.service';
14
14
  import { getProjectIdSelectedConversation, isGroup } from 'src/chat21-core/utils/utils';
15
15
  import { ImageRepoService } from 'src/chat21-core/providers/abstract/image-repo.service';
16
-
16
+ import { Project } from 'src/chat21-core/models/projects';
17
+ import { ProjectService } from 'src/app/services/projects/project.service';
18
+ import { PROJECTS_STORAGE_KEY } from 'src/chat21-core/utils/constants';
17
19
 
18
20
  @Component({
19
21
  selector: 'app-unassigned-conversations',
@@ -56,7 +58,9 @@ export class UnassignedConversationsPage implements OnInit, OnChanges {
56
58
  private events: EventsService,
57
59
  private tiledeskAuthService: TiledeskAuthService,
58
60
  private tiledeskService: TiledeskService,
59
- public imageRepoService: ImageRepoService
61
+ private projectService: ProjectService,
62
+ public imageRepoService: ImageRepoService,
63
+ public appStorageService: AppStorageService,
60
64
  ) {
61
65
  if (this.tiledeskAuthService.getCurrentUser()) {
62
66
  this.loggedUserUid = this.tiledeskAuthService.getCurrentUser().uid;
@@ -81,6 +85,7 @@ export class UnassignedConversationsPage implements OnInit, OnChanges {
81
85
  }
82
86
  this.logger.log('[UNASSIGNED-CONVS-PAGE] unassignedConversationsList', this.unassignedConversationsList);
83
87
  this.processConversationsForDisplay();
88
+ this.loadAndStoreProjects();
84
89
  // this.buildIFRAME();
85
90
  this.listenToPostMsg();
86
91
  this.hideHotjarFeedbackBtn();
@@ -107,6 +112,72 @@ export class UnassignedConversationsPage implements OnInit, OnChanges {
107
112
  });
108
113
  }
109
114
 
115
+ /**
116
+ * Recupera tutti i progetti con getProjects e li salva in AppStorage.
117
+ * Se la chiave esiste già nello storage, salta la chiamata remota e usa i dati in cache.
118
+ * Al termine richiama processConversationsForDisplay per aggiornare i project_name.
119
+ */
120
+ private loadAndStoreProjects() {
121
+ const stored = this.appStorageService.getItem(PROJECTS_STORAGE_KEY);
122
+ if (stored) {
123
+ this.processConversationsForDisplay();
124
+ return;
125
+ }
126
+ const token = this.tiledeskAuthService.getTiledeskToken();
127
+ if (!token) return;
128
+ this.projectService.getProjects().subscribe(
129
+ (projects: Project[]) => {
130
+ if (!projects?.length) return;
131
+ let projectsMap: Record<string, Project> = {};
132
+ const stored = this.appStorageService.getItem(PROJECTS_STORAGE_KEY);
133
+ if (stored) {
134
+ try {
135
+ projectsMap = JSON.parse(stored) || {};
136
+ } catch (e) {
137
+ this.logger.warn('[UNASSIGNED-CONVS-PAGE] loadAndStoreProjects - failed to parse stored projects', e);
138
+ }
139
+ }
140
+ let hasChanges = false;
141
+ projects.forEach((project) => {
142
+ const projectId = project.id_project?._id || project.id_project?.id || project._id;
143
+ if (!projectId) return;
144
+ if (!projectsMap[projectId]) {
145
+ projectsMap[projectId] = project.id_project || project;
146
+ hasChanges = true;
147
+ }
148
+ });
149
+ if (hasChanges) {
150
+ this.appStorageService.setItem(PROJECTS_STORAGE_KEY, JSON.stringify(projectsMap));
151
+ this.logger.log('[UNASSIGNED-CONVS-PAGE] loadAndStoreProjects - saved', Object.keys(projectsMap).length, 'projects');
152
+ }
153
+ this.processConversationsForDisplay();
154
+ },
155
+ (err) => {
156
+ this.logger.error('[UNASSIGNED-CONVS-PAGE] loadAndStoreProjects - error', err);
157
+ this.processConversationsForDisplay();
158
+ }
159
+ );
160
+ }
161
+
162
+ /** Recupera il progetto dalla chiave di storage (all_projects); se non trovato restituisce null */
163
+ private getProjectFromStorage(conversation: ConversationModel): Project | null {
164
+ let projectId: string | undefined;
165
+ if (conversation.attributes?.['projectId']) {
166
+ projectId = conversation.attributes['projectId'];
167
+ } else if (conversation.attributes) {
168
+ projectId = getProjectIdSelectedConversation(conversation.uid);
169
+ }
170
+ if (!projectId) return null;
171
+ const stored = this.appStorageService.getItem(PROJECTS_STORAGE_KEY);
172
+ if (!stored) return null;
173
+ try {
174
+ const projectsMap: Record<string, Project> = JSON.parse(stored);
175
+ return projectsMap[projectId] || null;
176
+ } catch {
177
+ return null;
178
+ }
179
+ }
180
+
110
181
  hideHotjarFeedbackBtn() {
111
182
  const hotjarFeedbackBtn = <HTMLElement>document.querySelector("#_hj_feedback_container > div > button")
112
183
  if (hotjarFeedbackBtn) {
@@ -370,22 +441,12 @@ export class UnassignedConversationsPage implements OnInit, OnChanges {
370
441
  }
371
442
  }
372
443
 
373
- if(conversation.attributes && conversation.attributes['projectId']){
374
- let project = localStorage.getItem(conversation.attributes['projectId'])
375
- if(project){
376
- project = JSON.parse(project)
377
- conversation.attributes.project_name = project['name']
378
- }
379
- }else if(conversation.attributes){
380
- const projectId = getProjectIdSelectedConversation(conversation.uid)
381
- let project = localStorage.getItem(projectId)
382
- if(project){
383
- project = JSON.parse(project)
384
- conversation.attributes.projectId = project['_id']
385
- conversation.attributes.project_name = project['name']
386
- }
444
+ const project = this.getProjectFromStorage(conversation);
445
+ if (project) {
446
+ if (!conversation.attributes) conversation.attributes = {};
447
+ conversation.attributes.projectId = project._id;
448
+ conversation.attributes.project_name = project.name;
387
449
  }
388
-
389
450
  }
390
451
 
391
452
  async onClose(conversation?: ConversationModel) {
@@ -7,6 +7,8 @@ import { map } from 'rxjs/operators';
7
7
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
8
8
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
9
9
  import { AppStorageService } from 'src/chat21-core/providers/abstract/app-storage.service';
10
+ import { Project } from 'src/chat21-core/models/projects';
11
+ import { Observable } from 'rxjs';
10
12
 
11
13
 
12
14
  @Injectable({
@@ -93,6 +95,23 @@ export class TiledeskService {
93
95
  }))
94
96
  }
95
97
 
98
+
99
+ public getProjectUsersByProjectId(project_id: string) {
100
+ const url = this.SERVER_BASE_URL + project_id + '/project_users/';
101
+ this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER URL', url);
102
+
103
+ const httpOptions = {
104
+ headers: new HttpHeaders({
105
+ 'Content-Type': 'application/json',
106
+ Authorization: this.tiledeskToken
107
+ })
108
+ };
109
+ return this.http.get(url, httpOptions).pipe(map((res: any) => {
110
+ this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
111
+ return res
112
+ }))
113
+ }
114
+
96
115
  public getAllLeadsActiveWithLimit(project_id: string, limit: number) {
97
116
  const url = this.SERVER_BASE_URL + project_id + '/leads?limit=' + limit + '&with_fullname=true';
98
117
  this.logger.log('[TILEDESK-SERVICE] - GET ALL ACTIVE LEADS (LIMIT 10000) - URL', url);
@@ -116,6 +116,7 @@ export const PLATFORM_DESKTOP = 'desktop';
116
116
 
117
117
  // STORAGE
118
118
  export const STORAGE_PREFIX = 'tiledesk_widget_';
119
+ export const PROJECTS_STORAGE_KEY = 'all_projects';
119
120
 
120
121
  // links
121
122
  export const FIREBASESTORAGE_BASE_URL_IMAGE = 'https://firebasestorage.googleapis.com/v0/b/' //+ 'chat-v2-dev.appspot.com/o/';
@@ -30,7 +30,7 @@ export class ConvertRequestToConversation {
30
30
  '',
31
31
  request.lead && request.lead.fullname ? request.lead.fullname: null,
32
32
  request.status || '0',
33
- moment(request.createdAt).unix(),
33
+ moment(request.createdAt).valueOf(),
34
34
  getColorBck(request.lead.fullname),
35
35
  avatarPlaceholder(request.lead.fullname),
36
36
  false,