@chat21/chat21-ionic 3.4.31 → 3.4.32-rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +133 -2
  2. package/angular.json +1 -0
  3. package/package.json +1 -1
  4. package/src/app/app.component.html +3 -1
  5. package/src/app/app.component.ts +72 -11
  6. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.html +14 -2
  7. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.scss +39 -2
  8. package/src/app/chatlib/list-conversations-component/list-conversations.module.ts +14 -0
  9. package/src/app/components/canned-response/canned-response.component.html +26 -23
  10. package/src/app/components/canned-response/canned-response.component.scss +0 -2
  11. package/src/app/components/canned-response/canned-response.component.ts +3 -1
  12. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +24 -1
  13. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +30 -0
  14. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +29 -7
  15. package/src/app/components/conversation-info/info-content/info-content.component.ts +2 -2
  16. package/src/app/components/conversation-info/info-group/info-group.component.ts +23 -21
  17. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.html +1 -1
  18. package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.ts +5 -1
  19. package/src/app/components/navbar/navbar.component.html +35 -9
  20. package/src/app/components/navbar/navbar.component.scss +64 -0
  21. package/src/app/components/navbar/navbar.component.ts +100 -42
  22. package/src/app/components/project-item/project-item.component.ts +79 -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 +3 -3
  26. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +15 -22
  27. package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
  28. package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
  29. package/src/app/pages/conversation-detail/conversation-detail.page.ts +89 -5
  30. package/src/app/pages/conversations-list/conversations-list.module.ts +3 -5
  31. package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
  32. package/src/app/pages/conversations-list/conversations-list.page.ts +51 -11
  33. package/src/app/pages/unassigned-conversations/unassigned-conversations.module.ts +16 -4
  34. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.html +43 -17
  35. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +25 -1
  36. package/src/app/pages/unassigned-conversations/unassigned-conversations.page.ts +114 -9
  37. package/src/app/services/global-settings/global-settings.service.ts +11 -3
  38. package/src/app/services/nav-proxy.service.ts +0 -1
  39. package/src/app/services/project_users/project-users.service.spec.ts +16 -0
  40. package/src/app/services/project_users/project-users.service.ts +63 -0
  41. package/src/app/services/projects/project.service.ts +2 -1
  42. package/src/app/services/tiledesk/tiledesk.service.ts +21 -16
  43. package/src/app/services/triggerEvents/triggerEvents.ts +28 -0
  44. package/src/app/services/websocket/websocket-js.ts +59 -534
  45. package/src/app/services/websocket/websocket-js_old.ts +578 -0
  46. package/src/app/services/websocket/websocket.service.ts +67 -14
  47. package/src/app/services/websocket/websocket.worker.ts +242 -0
  48. package/src/app/shared/shared.module.ts +11 -2
  49. package/src/app/utils/globals.ts +2 -0
  50. package/src/app/utils/permissions.constants.ts +138 -0
  51. package/src/app/utils/project-utils.ts +2 -2
  52. package/src/app/utils/utils.ts +18 -1
  53. package/src/assets/i18n/ar.json +11 -1
  54. package/src/assets/i18n/az.json +11 -1
  55. package/src/assets/i18n/de.json +11 -1
  56. package/src/assets/i18n/en.json +11 -1
  57. package/src/assets/i18n/es.json +11 -1
  58. package/src/assets/i18n/fr.json +11 -1
  59. package/src/assets/i18n/it.json +13 -3
  60. package/src/assets/i18n/kk.json +11 -1
  61. package/src/assets/i18n/pt.json +11 -1
  62. package/src/assets/i18n/ru.json +11 -1
  63. package/src/assets/i18n/sr.json +11 -1
  64. package/src/assets/i18n/sv.json +11 -1
  65. package/src/assets/i18n/tr.json +11 -1
  66. package/src/assets/i18n/uk.json +11 -1
  67. package/src/assets/i18n/uz.json +12 -1
  68. package/src/assets/js/agentDesktop-sdk.js +55 -0
  69. package/src/assets/js/chat21client.js +36 -0
  70. package/src/assets/js/mqtt-keepalive-worker.js +53 -0
  71. package/src/assets/test.html +5 -2
  72. package/src/chat-config-template.json +1 -0
  73. package/src/chat-config.json +1 -0
  74. package/src/chat21-core/models/projectUsers.ts +19 -0
  75. package/src/chat21-core/models/project_user.ts +2 -1
  76. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  77. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  78. package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
  79. package/src/chat21-core/utils/constants.ts +5 -0
  80. package/src/chat21-core/utils/convertRequestToConversation.ts +1 -1
  81. package/src/chat21-core/utils/utils.ts +53 -3
  82. package/src/variables.scss +3 -0
@@ -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,15 +90,24 @@ export class WebsocketService {
87
90
  }))
88
91
  }
89
92
 
90
- subscriptionToWsConversations(project_id) {
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
+ * @param project_id ID del progetto
98
+ * @param skipClear Se true, non svuota wsRequestsList (usato quando si sottoscrivono più progetti in sequenza)
99
+ */
100
+ subscriptionToWsConversations(project_id, skipClear = false) {
91
101
  // console.log("[WS-SERV] - CALLED SUBSC TO WS CONVS - PROJECT ID ", project_id);
92
102
  var self = this;
93
- this.wsRequestsList = [];
103
+ if (!skipClear) {
104
+ this.wsRequestsList = [];
105
+ }
94
106
 
95
- this.webSocketJs.ref('/' + project_id + '/requests', 'getCurrentProjectAndSubscribeTo_WsRequests',
107
+ this.webSocketJs.ref('/' + project_id + '/requests', 'getCurrentProjectAndSubscribeTo_WsRequests_' + project_id,
96
108
 
97
- function (data, notification) {
98
- // console.log("[WS-SERV] - CONVS - CREATE DATA ", data);
109
+ function (data) {
110
+ // console.log("[WS-SERV] - CONVS - CREATE DATA for project ", project_id, data);
99
111
  if (data) {
100
112
  // ------------------------------------------------
101
113
  // @ Agents - pass in data agents get from snapshot
@@ -183,7 +195,7 @@ export class WebsocketService {
183
195
  // }
184
196
  }
185
197
 
186
- }, function (data, notification) {
198
+ }, function (data) {
187
199
 
188
200
  // console.log("[WS-SERV] - CONVS - UPDATE DATA ", data);
189
201
 
@@ -201,9 +213,8 @@ export class WebsocketService {
201
213
  self.updateWsRequests(data)
202
214
 
203
215
 
204
- }, function (data, notification) {
216
+ }, function (data) {
205
217
  self.logger.log("[WS-SERV] CHAT - CONVS - ON-DATA - DATA ", data);
206
- self.logger.log("[WS-SERV] CHAT - CONVS - ON-DATA - notification ", notification);
207
218
 
208
219
  // console.log("[WS-SERV] CHAT - CONVS - ON-DATA - DATA notification > event > method ", notification.event.method);
209
220
  // if (notification.event.method === 'CREATE') {
@@ -293,6 +304,36 @@ export class WebsocketService {
293
304
  }
294
305
  }
295
306
 
307
+ /**
308
+ * Sottoscrive alle conversations di tutti i progetti con status "online" (id_project.status === 100)
309
+ * E dove l'utente ha teammateStatus "Available".
310
+ * @param projects Array di ProjectUser con teammateStatus già calcolato (getUserStatusFromProjectUser)
311
+ */
312
+ subscriptionToWsConversationsForOnlineProjects(projects: any[]) {
313
+ const onlineProjects = (projects || []).filter((p) => {
314
+ const statusOk = p?.id_project?.status === 100;
315
+ const teammateStatus = p?.teammateStatus ?? getUserStatusFromProjectUser(p);
316
+ const isAvailable = teammateStatus?.name === 'Available';
317
+ return statusOk && isAvailable;
318
+ });
319
+ if (onlineProjects.length === 0) {
320
+ this.logger.log('[WS-SERV] - No online projects to subscribe');
321
+ return [];
322
+ }
323
+ this.unsubscribeFromAllProjectConversations();
324
+ this.wsRequestsList = [];
325
+ this.subscribedConversationProjectIds = onlineProjects.map(
326
+ (p) => p.id_project._id
327
+ );
328
+ this.logger.log(
329
+ '[WS-SERV] - SUBSCR TO WS CONVS FOR PROJECTS (status 100 + Available) ',
330
+ this.subscribedConversationProjectIds
331
+ );
332
+ this.subscribedConversationProjectIds.forEach((projectId) =>
333
+ this.subscriptionToWsConversations(projectId, true)
334
+ );
335
+ return this.subscribedConversationProjectIds;
336
+ }
296
337
 
297
338
  // -----------------------------------------------
298
339
  // @ Subscribe to Requester Presence
@@ -306,17 +347,17 @@ export class WebsocketService {
306
347
 
307
348
  this.webSocketJs.ref(path, 'subscribeToWS_RequesterPresence',
308
349
 
309
- function (data, notification) {
350
+ function (data) {
310
351
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - CREATE data ", data);
311
352
 
312
353
  self.wsRequesterStatus$.next(data);
313
354
 
314
- }, function (data, notification) {
355
+ }, function (data) {
315
356
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - UPDATE data ", data);
316
357
 
317
358
  self.wsRequesterStatus$.next(data);
318
359
 
319
- }, function (data, notification) {
360
+ }, function (data) {
320
361
 
321
362
  if (data) {
322
363
  // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - ON-DATA data ", data);
@@ -343,5 +384,17 @@ export class WebsocketService {
343
384
  this.webSocketJs.unsubscribe(path);
344
385
  }
345
386
 
387
+ /**
388
+ * Rimuove tutte le sottoscrizioni alle conversations dei progetti.
389
+ */
390
+ unsubscribeFromAllProjectConversations() {
391
+ if (this.subscribedConversationProjectIds.length === 0) return;
392
+ this.subscribedConversationProjectIds.forEach((projectId) =>
393
+ this.unsubscribeToWsConversations(projectId)
394
+ );
395
+ this.subscribedConversationProjectIds = [];
396
+ this.logger.log('[WS-SERV] - UNSUBSCR FROM ALL PROJECT CONVERSATIONS');
397
+ }
398
+
346
399
 
347
400
  }
@@ -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
  }