@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
@@ -6,6 +6,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
6
6
  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
+ import { getUserStatusFromProjectUser } from 'src/chat21-core/utils/utils';
9
10
 
10
11
  @Injectable({
11
12
  providedIn: 'root'
@@ -18,6 +19,8 @@ export class WebsocketService {
18
19
  public wsRequestsList$: BehaviorSubject<any[]> = new BehaviorSubject<any[]>([]);
19
20
  public currentProjectUserAvailability$: BehaviorSubject<[]> = new BehaviorSubject<[]>([])
20
21
  public wsRequesterStatus$: BehaviorSubject<any> = new BehaviorSubject<any>({});
22
+ /** Progetti attualmente sottoscritti per conversations (per gestire unsubscribe) */
23
+ private subscribedConversationProjectIds: string[] = [];
21
24
 
22
25
  private logger: LoggerService = LoggerInstance.getInstance();
23
26
 
@@ -41,18 +44,18 @@ export class WebsocketService {
41
44
  return new Promise(function (resolve, reject) {
42
45
 
43
46
  self.webSocketJs.ref(path, 'subscriptionToWsCurrentUser_allProject',
44
- function (data, notification) {
47
+ function (data) {
45
48
  // console.log("[WS-SERV] SUBSCR TO WS CURRENT PROJECT-USER AVAILABILITY - CREATE - data ", data);
46
49
  resolve(data)
47
50
  // self.currentUserWsAvailability$.next(data.user_available);
48
51
  self.currentProjectUserAvailability$.next(data)
49
52
 
50
- }, function (data, notification) {
53
+ }, function (data) {
51
54
  resolve(data)
52
55
  // console.log("[WS-SERV] SUBSCR TO WS CURRENT PROJECT-USER AVAILABILITY - UPDATE - data ", data);
53
56
  self.currentProjectUserAvailability$.next(data)
54
57
 
55
- }, function (data, notification) {
58
+ }, function (data) {
56
59
  resolve(data)
57
60
  if (data) {
58
61
  // console.log("[WS-SERV] SUBSCR TO WS CURRENT PROJECT-USER AVAILABILITY - UPDATE - data", data);
@@ -87,6 +90,11 @@ export class WebsocketService {
87
90
  }))
88
91
  }
89
92
 
93
+ /**
94
+ * Sottoscrive alle conversations di un singolo progetto.
95
+ * Mantenuto per retrocompatibilità. Preferire subscriptionToWsConversationsForOnlineProjects
96
+ * per sottoscrivere ai progetti online con status Available.
97
+ */
90
98
  subscriptionToWsConversations(project_id) {
91
99
  // console.log("[WS-SERV] - CALLED SUBSC TO WS CONVS - PROJECT ID ", project_id);
92
100
  var self = this;
@@ -94,7 +102,7 @@ export class WebsocketService {
94
102
 
95
103
  this.webSocketJs.ref('/' + project_id + '/requests', 'getCurrentProjectAndSubscribeTo_WsRequests',
96
104
 
97
- function (data, notification) {
105
+ function (data) {
98
106
  // console.log("[WS-SERV] - CONVS - CREATE DATA ", data);
99
107
  if (data) {
100
108
  // ------------------------------------------------
@@ -183,7 +191,7 @@ export class WebsocketService {
183
191
  // }
184
192
  }
185
193
 
186
- }, function (data, notification) {
194
+ }, function (data) {
187
195
 
188
196
  // console.log("[WS-SERV] - CONVS - UPDATE DATA ", data);
189
197
 
@@ -201,9 +209,8 @@ export class WebsocketService {
201
209
  self.updateWsRequests(data)
202
210
 
203
211
 
204
- }, function (data, notification) {
212
+ }, function (data) {
205
213
  self.logger.log("[WS-SERV] CHAT - CONVS - ON-DATA - DATA ", data);
206
- self.logger.log("[WS-SERV] CHAT - CONVS - ON-DATA - notification ", notification);
207
214
 
208
215
  // console.log("[WS-SERV] CHAT - CONVS - ON-DATA - DATA notification > event > method ", notification.event.method);
209
216
  // if (notification.event.method === 'CREATE') {
@@ -293,6 +300,36 @@ export class WebsocketService {
293
300
  }
294
301
  }
295
302
 
303
+ /**
304
+ * Sottoscrive alle conversations di tutti i progetti con status "online" (id_project.status === 100)
305
+ * E dove l'utente ha teammateStatus "Available".
306
+ * @param projects Array di ProjectUser con teammateStatus già calcolato (getUserStatusFromProjectUser)
307
+ */
308
+ subscriptionToWsConversationsForOnlineProjects(projects: any[]) {
309
+ const onlineProjects = (projects || []).filter((p) => {
310
+ const statusOk = p?.id_project?.status === 100;
311
+ const teammateStatus = p?.teammateStatus ?? getUserStatusFromProjectUser(p);
312
+ const isAvailable = teammateStatus?.name === 'Available';
313
+ return statusOk && isAvailable;
314
+ });
315
+ if (onlineProjects.length === 0) {
316
+ this.logger.log('[WS-SERV] - No online projects to subscribe');
317
+ return [];
318
+ }
319
+ this.unsubscribeFromAllProjectConversations();
320
+ this.wsRequestsList = [];
321
+ this.subscribedConversationProjectIds = onlineProjects.map(
322
+ (p) => p.id_project._id
323
+ );
324
+ this.logger.log(
325
+ '[WS-SERV] - SUBSCR TO WS CONVS FOR PROJECTS (status 100 + Available) ',
326
+ this.subscribedConversationProjectIds
327
+ );
328
+ this.subscribedConversationProjectIds.forEach((projectId) =>
329
+ this.subscriptionToWsConversations(projectId)
330
+ );
331
+ return this.subscribedConversationProjectIds;
332
+ }
296
333
 
297
334
  // -----------------------------------------------
298
335
  // @ Subscribe to Requester Presence
@@ -306,17 +343,17 @@ export class WebsocketService {
306
343
 
307
344
  this.webSocketJs.ref(path, 'subscribeToWS_RequesterPresence',
308
345
 
309
- function (data, notification) {
346
+ function (data) {
310
347
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - CREATE data ", data);
311
348
 
312
349
  self.wsRequesterStatus$.next(data);
313
350
 
314
- }, function (data, notification) {
351
+ }, function (data) {
315
352
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - UPDATE data ", data);
316
353
 
317
354
  self.wsRequesterStatus$.next(data);
318
355
 
319
- }, function (data, notification) {
356
+ }, function (data) {
320
357
 
321
358
  if (data) {
322
359
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - ON-DATA data ", data);
@@ -343,5 +380,17 @@ export class WebsocketService {
343
380
  this.webSocketJs.unsubscribe(path);
344
381
  }
345
382
 
383
+ /**
384
+ * Rimuove tutte le sottoscrizioni alle conversations dei progetti.
385
+ */
386
+ unsubscribeFromAllProjectConversations() {
387
+ if (this.subscribedConversationProjectIds.length === 0) return;
388
+ this.subscribedConversationProjectIds.forEach((projectId) =>
389
+ this.unsubscribeToWsConversations(projectId)
390
+ );
391
+ this.subscribedConversationProjectIds = [];
392
+ this.logger.log('[WS-SERV] - UNSUBSCR FROM ALL PROJECT CONVERSATIONS');
393
+ }
394
+
346
395
 
347
396
  }
@@ -0,0 +1,242 @@
1
+ /// websocket.worker.ts
2
+
3
+ interface WSMessage {
4
+ action?: string;
5
+ event?: { topic: string; method: string };
6
+ payload?: any;
7
+ }
8
+
9
+ interface Subscription {
10
+ topic: string;
11
+ label?: string;
12
+ onCreate?: (msg: any) => void;
13
+ onUpdate?: (msg: any) => void;
14
+ onData?: (msg: any) => void;
15
+ }
16
+
17
+ let ws: WebSocket | null = null;
18
+ let url = '';
19
+ let reconnectInterval = 5000;
20
+ let subscriptions: Subscription[] = [];
21
+ let pendingMessages: any[] = [];
22
+
23
+
24
+ let pingMsg = { action: "heartbeat", payload: { message: { text: "ping" } } }
25
+ let pongMsg = { action: "heartbeat", payload: { message: { text: "pong" } } }
26
+ const pongTimeout = 10000;
27
+ const pingTimeout = 15000;
28
+ let pingTimeoutId;
29
+ let pongTimeoutId;
30
+
31
+ let reconnectAttempts = 0;
32
+ const maxReconnectDelay = 30000;
33
+ let manuallyClosed = false;
34
+ let pageHidden = false;
35
+
36
+ onmessage = (e: MessageEvent) => {
37
+ const { action, data } = e.data;
38
+
39
+ switch (action) {
40
+ case 'init':
41
+ url = data.url;
42
+ connect();
43
+ break;
44
+ case 'subscribe':
45
+ const topic = data.topic || data.label;
46
+ subscriptions.push({ topic });
47
+ if (ws && ws.readyState === WebSocket.OPEN) {
48
+ ws.send(JSON.stringify({
49
+ action: 'subscribe',
50
+ payload: {
51
+ topic: topic,
52
+ message: undefined,
53
+ method: undefined
54
+ }
55
+ }));
56
+ }
57
+ break;
58
+ case 'unsubscribe':
59
+ subscriptions = subscriptions.filter(s => s.topic !== data.topic);
60
+ if (ws && ws.readyState === WebSocket.OPEN) {
61
+ // Unsubscribe
62
+ ws.send(JSON.stringify({
63
+ action: 'unsubscribe',
64
+ payload: {
65
+ topic: data.topic,
66
+ message: undefined,
67
+ method: undefined
68
+ }
69
+ }));
70
+ }
71
+ break;
72
+ case 'visibility': // ✅ Nuovo
73
+ pageHidden = data.hidden;
74
+ break;
75
+ case 'send':
76
+ sendMessage(data.message);
77
+ break;
78
+ case 'close': // ✅ Nuovo
79
+ closeConnection();
80
+ break;
81
+ }
82
+ };
83
+
84
+ function connect() {
85
+ ws = new WebSocket(url);
86
+ ws.onopen = () => {
87
+ console.log('[Worker] WebSocket connected',subscriptions);
88
+ // Risottiamo pending subscriptions
89
+ subscriptions.forEach(s => {
90
+ ws!.send(JSON.stringify({
91
+ action: 'subscribe',
92
+ payload: {
93
+ topic: s.topic,
94
+ message: undefined,
95
+ method: undefined
96
+ }
97
+ }));
98
+ }
99
+ );
100
+ // Invia messaggi in coda
101
+ pendingMessages.forEach(msg => ws!.send(JSON.stringify(msg)));
102
+ pendingMessages = [];
103
+
104
+ // Inizializza heartbeat
105
+ heartCheck();
106
+ reconnectAttempts = 0;
107
+ };
108
+
109
+ ws.onmessage = (event) => {
110
+ try {
111
+ const msg: WSMessage = JSON.parse(event.data);
112
+ handleMessage(msg);
113
+ } catch (err) {
114
+ console.error('[Worker] Invalid message', err);
115
+ }
116
+ };
117
+
118
+ ws.onclose = () => {
119
+ heartReset();
120
+ if(!manuallyClosed){
121
+ reconnectAttempts++;
122
+ const delay = Math.min(reconnectAttempts * 1000, maxReconnectDelay);
123
+ console.log('[Worker] WebSocket disconnected, retry in', delay, 'ms');
124
+ setTimeout(connect, delay);
125
+ }
126
+ };
127
+
128
+ ws.onerror = (err) => {
129
+ console.error('[Worker] WebSocket error', err);
130
+ ws?.close();
131
+ };
132
+ }
133
+
134
+ function handleMessage(msg: WSMessage) {
135
+ console.log('[Worker] Received message:', msg);
136
+ // --- GESTIONE PING/PONG ---
137
+ if (msg.action === 'heartbeat' && msg.payload?.message?.text === 'ping') {
138
+ console.log('[Worker] Received ping, sending pong');
139
+ if (ws && ws.readyState === WebSocket.OPEN) {
140
+ ws.send(JSON.stringify(pongMsg));
141
+ }
142
+ return; // Non processare ulteriormente il ping
143
+ }
144
+
145
+ // Solo formato "publish"
146
+ if (msg.action !== "publish") return;
147
+
148
+ const topic = msg.payload?.topic;
149
+ const method = msg.payload?.method;
150
+ const payload = msg.payload?.message;
151
+
152
+ if (!topic) return;
153
+
154
+ // --- GESTIONE ARRAY DI MESSAGGI ---
155
+ const messages = Array.isArray(msg.payload.message) ? msg.payload.message : [msg.payload.message];
156
+ // Notifica solo le subscription che matchano
157
+ subscriptions.forEach(sub => {
158
+ if (sub.topic === topic) {
159
+ messages.forEach(element => {
160
+ postMessage({
161
+ topic,
162
+ method,
163
+ payload: element, // singolo elemento
164
+ data: msg // payload completo per eventuali onData globali
165
+ }, undefined);
166
+ });
167
+ }
168
+ });
169
+
170
+ }
171
+
172
+ function sendMessage(message: any) {
173
+ if (ws && ws.readyState === WebSocket.OPEN) {
174
+ ws.send(JSON.stringify(message));
175
+ } else {
176
+ pendingMessages.push(message);
177
+ }
178
+ }
179
+
180
+
181
+ // -----------------------------------------------------------------------------------------------------
182
+ // @ HeartCheck
183
+ // -----------------------------------------------------------------------------------------------------
184
+ function heartCheck() {
185
+ heartReset();
186
+ heartStart();
187
+ }
188
+
189
+ // -----------------------------------------------------------------------------------------------------
190
+ // @ HeartStart
191
+ // -----------------------------------------------------------------------------------------------------
192
+ function heartStart() {
193
+ // this.getRemainingTime();
194
+
195
+ // usa intervallo adattivo se tab è in background (Chrome throtla i timer)
196
+ const adaptivePing = pageHidden ? pingTimeout * 3 : pingTimeout;
197
+
198
+ // // pianifica invio ping
199
+ pingTimeoutId = setTimeout(() => {
200
+ if (!ws || ws.readyState !== WebSocket.OPEN) return;
201
+ console.log("[WEBSOCKET-JS] - HEART-START - SENDING PING ");
202
+
203
+ // Qui viene inviato un battito cardiaco. Dopo averlo ricevuto, viene restituito un messaggio di battito cardiaco.
204
+ // onmessage Ottieni il battito cardiaco restituito per indicare che la connessione è normale
205
+ ws.send(JSON.stringify(pingMsg));
206
+
207
+ // Se non viene ripristinato dopo un determinato periodo di tempo, il backend viene attivamente disconnesso
208
+ pongTimeoutId = setTimeout(() => {
209
+ console.log("[WEBSOCKET-JS] - HEART-START - PONG-TIMEOUT-ID - CLOSE WS ");
210
+ // se onclose Si esibirà reconnect,Eseguiamo ws.close() Bene, se lo esegui direttamente reconnect Si innescherà onclose Causa riconnessione due volte
211
+ ws.close();
212
+ }, pongTimeout) as unknown as number;
213
+ }, adaptivePing);
214
+
215
+ }
216
+
217
+ // -----------------------------------------------------------------------------------------------------
218
+ // @ heartReset
219
+ // -----------------------------------------------------------------------------------------------------
220
+ function heartReset() {
221
+ if (pongTimeoutId !== undefined) {
222
+ clearTimeout(pongTimeoutId);
223
+ pongTimeoutId = undefined;
224
+ }
225
+
226
+ if (pingTimeoutId !== undefined) {
227
+ clearTimeout(pingTimeoutId);
228
+ pingTimeoutId = undefined;
229
+ }
230
+ }
231
+
232
+ function closeConnection() {
233
+ if (ws) {
234
+ ws.close();
235
+ ws = null;
236
+ }
237
+ heartReset();
238
+ pendingMessages = [];
239
+ subscriptions = [];
240
+ manuallyClosed = true;
241
+ console.log('[Worker] WebSocket closed manually');
242
+ }
@@ -22,8 +22,9 @@ import { MatTooltipModule } from '@angular/material/tooltip';
22
22
  import { MatSnackBarModule } from '@angular/material/snack-bar';
23
23
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
24
24
  import { SafeHtmlPipe } from '../directives/safe-html.pipe';
25
-
26
- // import { MessageTextAreaComponent } from '../components/conversation-detail/message-text-area/message-text-area.component'; // MessageTextAreaComponent is part of the declarations ConversationDetailPageModule
25
+ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
26
+ import { createTranslateLoader } from 'src/chat21-core/utils/utils';
27
+ import { HttpClient } from '@angular/common/http';
27
28
 
28
29
  @NgModule({
29
30
  declarations: [
@@ -140,6 +141,14 @@ import { SafeHtmlPipe } from '../directives/safe-html.pipe';
140
141
  NgSelectModule,
141
142
  FormsModule,
142
143
 
144
+ TranslateModule.forChild({
145
+ loader: {
146
+ provide: TranslateLoader,
147
+ useFactory: (createTranslateLoader),
148
+ deps: [HttpClient]
149
+ }
150
+ })
151
+
143
152
  ],
144
153
  schemas: [
145
154
  CUSTOM_ELEMENTS_SCHEMA,
@@ -15,6 +15,7 @@ export class Globals {
15
15
  jwt: string;
16
16
  fileUploadAccept: string;
17
17
  projectID: string;
18
+ logOut: boolean
18
19
 
19
20
  constructor(
20
21
  ) { }
@@ -36,6 +37,7 @@ export class Globals {
36
37
  this.lang = 'en'
37
38
  this.fileUploadAccept = 'image/*,.pdf,.txt'
38
39
  this.projectID = null;
40
+ this.logOut = true;
39
41
 
40
42
  }
41
43
 
@@ -0,0 +1,138 @@
1
+
2
+ export const PERMISSIONS = {
3
+ REQUEST_READ_ALL: 'request_read_all',
4
+ REQUEST_READ_GROUP: 'request_read_group',
5
+ REQUEST_READ_MY: 'request_read_my',
6
+
7
+ HOME_READ: 'home_read',
8
+
9
+ INBOX_READ: 'inbox_read',
10
+ REQUEST_UPDATE: 'request_update',
11
+ REQUEST_SEND: 'request_send',
12
+ REQUEST_CREATE_TICKET: 'request_create_ticket',
13
+ REQUEST_CLOSE: 'request_close',
14
+ REQUEST_JOIN: 'request_join',
15
+ REQUEST_REOPEN: 'request_reopen',
16
+ REQUEST_DELETE: 'request_delete',
17
+ REQUEST_UPDATE_STATUS: 'request_update_status',
18
+ REQUEST_UPDATE_PRIORITY: 'request_update_priority',
19
+ REQUEST_UPDATE_FOLLOWERS: 'request_update_followers',
20
+ REQUEST_UPDATE_SMART_ASSIGNMENT: 'request_update_smart_assignment',
21
+ REQUEST_UPDATE_TAGS: 'request_update_tags',
22
+ REQUEST_UPDATE_NOTES: 'request_update_notes',
23
+ REQUEST_REASSIGN:'request_reassign',
24
+ REQUEST_ADD:'request_add',
25
+ REQUEST_LEFT: 'request_left',
26
+ REQUEST_TRANSCRIPT_SEND: 'request_transcript_send',
27
+
28
+ HISTORY_READ: 'history_read',
29
+
30
+ RATING_READ:'rating_read',
31
+
32
+ AUTOMATIONSLOG_READ: "automationslog_read",
33
+ AUTOMATIONSLOG_CREATE: "automationslog_create",
34
+
35
+ KB_READ: 'kb_read',
36
+ KB_CONTENTS_ADD:'kb_contents_add',
37
+ KB_CONTENT_UPDATE: 'kb_content_update',
38
+ KB_CONTENT_REINDEX: 'kb_content_reindex',
39
+ KB_CONTENT_CHECK_STATUS: 'kb_content_check_status',
40
+ KB_NAMESPACE_ADD:'kb_namespace_add',
41
+ KB_SETTINGS_EDIT:'kb_settings_edit',
42
+ KB_DELETE: 'kb_delete',
43
+ KB_CONTENTS_EXPORT: 'kb_contents_export',
44
+ // KB_NAMESPACE_DELETE:'kb_namespace_delete',
45
+ // KB_CONTENTS_DELETE:'kb_contents_delete',
46
+
47
+
48
+
49
+ FLOWS_READ: 'flows_read',
50
+ FLOW_ADD: 'flow_add',
51
+ FLOW_EDIT: 'flow_edit',
52
+ FLOW_TEST: 'flow_test',
53
+ FLOW_DUPLICATE: 'flow_duplicate',
54
+ FLOW_DELETE: 'flow_delete',
55
+ FLOW_SHARE: 'flow_share',
56
+ FLOW_EXPORT: 'flow_export',
57
+ FLOW_WEBHOOK_COPY:"flow_webhook_copy",
58
+ FLOW_WEBHOOK_EDIT:"flow_webhook_edit",
59
+ FLOW_WEBHOOK_DELETE:"flow_webhook_delete",
60
+ // FLOW_VIEW_MESSAGE_GRAPH: 'flow_view_message_graph',
61
+
62
+ LEADS_READ: 'leads_read',
63
+ LEAD_UPDATE: 'lead_update',
64
+ LEAD_RESTORE: 'lead_restore',
65
+ LEAD_TRASH: 'lead_trash',
66
+ LEAD_DELETE: 'lead_delete',
67
+ LEADS_EXPORT: 'leads_export',
68
+ LEAD_BAN: 'lead_ban',
69
+ LEAD_UNBAN: 'lead_unban',
70
+
71
+ ANALYTICS_READ: 'analytics_read',
72
+ ACTIVITIES_READ: 'activities_read',
73
+
74
+ WIDGETSETUP_READ: 'widgetsetup_read',
75
+ INSTALLATION_READ: 'installation_read',
76
+ TRANSLATIONS_READ: 'translations_read',
77
+ WIDGETSETUP_UPDATE: 'widgetsetup_update',
78
+
79
+
80
+
81
+ DEPARTMENTS_LIST_READ: 'department_list_read',
82
+ DEPARTMENT_DETAIL_READ: 'department_detail_read',
83
+ DEPARTMENT_CREATE_READ: 'department_create_read',
84
+
85
+ TEAMMATES_READ: 'teammates_read',
86
+ TEAMMATE_UPDATE: 'teammate_update',
87
+ TEAMMATES_CREATE: 'teammates_create',
88
+ ROLES_READ: 'roles_read',
89
+ GROUPS_READ: 'groups_read',
90
+
91
+
92
+
93
+ EMAIL_TICKETING_READ:'email_ticketing_read',
94
+ EMAIL_TICKETING_UPDATE:'email_ticketing_update',
95
+
96
+ CANNED_RESPONSES_READ:'canned_responses_read',
97
+ CANNED_RESPONSES_UPDATE:'canned_responses_update',
98
+ CANNED_RESPONSES_CREATE:'canned_responses_create',
99
+ CANNED_RESPONSES_DELETE:'canned_responses_delete',
100
+
101
+ TAGS_READ:'tags_read',
102
+ TAG_CREATE:'tag_create',
103
+ TAG_DELETE:'tag_delete',
104
+ TAG_UPDATE:'tag_update',
105
+
106
+ HOURS_READ: 'hours_read',
107
+ HOURS_UPDATE: 'hours_update',
108
+ HOURS_DELETE: 'hours_delete',
109
+ HOURS_CREATE: 'hours_create',
110
+
111
+ INTEGRATIONS_READ: 'integrations_read',
112
+ INTEGRATIONS_UPDATE: 'integrations_update',
113
+
114
+ APPS_READ:'apps_read',
115
+ APPS_UPDATE:'apps_update',
116
+
117
+ SETTINGS_READ: 'settings_read',
118
+ PROJECTSETTINGS_GENERAL_READ: 'projectsettings_general_read',
119
+ PROJECTSETTINGS_GENERAL_UPDATE: 'projectsettings_general_update',
120
+ PROJECTSETTINGS_SUBSCRIPTION_READ: 'projectsettings_subscription_read',
121
+ PROJECTSETTINGS_DEVELOPER_READ: 'projectsettings_developer_read',
122
+ PROJECTSETTINGS_DEVELOPER_UPDATE: 'projectsettings_developer_update',
123
+ PROJECTSETTINGS_SMARTASSIGNMENT_READ: 'projectsettings_smartassignment_read',
124
+ PROJECTSETTINGS_SMARTASSIGNMENT_UPDATE: 'projectsettings_smartassignment_update',
125
+ PROJECTSETTINGS_NOTIFICATION_READ: 'projectsettings_notification_read',
126
+ PROJECTSETTINGS_SECURITY_READ: 'projectsettings_security_read',
127
+ PROJECTSETTINGS_BANNED_READ: 'projectsettings_banned_read',
128
+ PROJECTSETTINGS_ADVANCED_READ: 'projectsettings_advanced_read',
129
+
130
+ ACCESS_LISTS: 'accessLists',
131
+ PROFILE_PAGES: 'profilePages',
132
+ LEAD_DATA: 'leadData',
133
+ IMPORT_DATA: 'importData',
134
+ MANAGE_TAGS: 'manageTags',
135
+
136
+ CHANGE_PROJECT:'change_project',
137
+ SIMULATE_CONV:'simulate_conv',
138
+ };
@@ -129,9 +129,9 @@ export class ProjectPlanUtils {
129
129
 
130
130
  //case PAYMENT plan
131
131
  if(project && project.isActiveSubscription && project.profile.type=== 'payment'){
132
- check = true
133
- }else if(project && !project.isActiveSubscription && project.profile.type=== 'payment'){
134
132
  check = false
133
+ }else if(project && !project.isActiveSubscription && project.profile.type=== 'payment'){
134
+ check = true
135
135
  }
136
136
 
137
137
  return check
@@ -1,10 +1,12 @@
1
+ import { ProjectUser } from "src/chat21-core/models/projectUsers";
2
+
1
3
  export function getOSCode(key: string, token: string): boolean {
2
4
 
3
5
  if (token) {
4
6
  const keys: String[] = token.split("-");
5
7
 
6
8
  let element = keys.find(el => el.includes(key))
7
- console.log('keys', keys)
9
+ // console.log('keys', keys)
8
10
  if(element){
9
11
  element = element.split(":")[1]
10
12
  if(element && element === "F"){
@@ -21,4 +23,19 @@ export function getOSCode(key: string, token: string): boolean {
21
23
  }
22
24
 
23
25
  return false
26
+ }
27
+
28
+
29
+ export function hasRole(projectUser: ProjectUser, role: string ): boolean {
30
+ let roles = ['owner', 'admin', 'agent'];
31
+ if(roles.includes(projectUser.role)){
32
+ return true
33
+ }
34
+
35
+ if(Array.isArray(projectUser.rolePermissions) && projectUser.rolePermissions.includes(role)){
36
+ return true
37
+ }
38
+
39
+ return false
40
+
24
41
  }
@@ -225,6 +225,10 @@
225
225
  "admin": "مدير",
226
226
  "agent": "وكيل",
227
227
  "Conversations": "المحادثات",
228
+ "Monitor": "شاشة",
229
+ "Flows": "التدفّقات",
230
+ "Knowledgebases": "قواعد المعرفة",
231
+ "Whatsappbroadcasts": "نشرات WhatsApp",
228
232
  "Apps": "تطبيقات",
229
233
  "Analytics": "تحليلات",
230
234
  "Activities": "أنشطة",
@@ -306,5 +310,11 @@
306
310
  "SEND_EMAIL_SUCCESS_OFFLINE_MESSAGE":"تم إرسال الرسالة أيضًا عبر البريد الإلكتروني 📩"
307
311
  },
308
312
  "EMOJI_NOT_ELLOWED": "الرموز التعبيرية غير مسموح بها",
309
- "DOMAIN_NOT_ALLOWED": "يحتوي الرابط على نطاق غير مسموح"
313
+ "DOMAIN_NOT_ALLOWED": "يحتوي الرابط على نطاق غير مسموح",
314
+ "TICKET": {
315
+ "OPEN_TICKET": "افتح تذكرة",
316
+ "DESCRIPTION": "هل تؤكد أنك تريد فتح تذكرة لهذه المحادثة؟",
317
+ "CONFIRM": "تأكيد",
318
+ "CLOSE": "إغلاق"
319
+ }
310
320
  }
@@ -225,6 +225,10 @@
225
225
  "admin": "Administrator",
226
226
  "agent": "Agent",
227
227
  "Conversations": "Söhbətlər",
228
+ "Monitor": "Monitor",
229
+ "Flows": "Axınlar",
230
+ "Knowledgebases": "Bilik bazaları",
231
+ "Whatsappbroadcasts": "WhatsApp Yayınları",
228
232
  "Apps": "Proqramlar",
229
233
  "Analytics": "Analitika",
230
234
  "Activities": "Fəaliyyətlər",
@@ -306,5 +310,11 @@
306
310
  "SEND_EMAIL_SUCCESS_OFFLINE_MESSAGE":"Mesaj e-poçt vasitəsilə də göndərilib 📩"
307
311
  },
308
312
  "EMOJI_NOT_ELLOWED": "Emoji icazə verilmir",
309
- "DOMAIN_NOT_ALLOWED": "URL icazə verilməyən domeni ehtiva edir"
313
+ "DOMAIN_NOT_ALLOWED": "URL icazə verilməyən domeni ehtiva edir",
314
+ "TICKET": {
315
+ "OPEN_TICKET": "Bilet aç",
316
+ "DESCRIPTION": "Bu söhbət üçün bilet açmaq istədiyinizi təsdiqləyirsinizmi?",
317
+ "CONFIRM": "Təsdiqlə",
318
+ "CLOSE": "Bağla"
319
+ }
310
320
  }