@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.
- package/CHANGELOG.md +131 -2
- package/angular.json +1 -0
- package/package.json +1 -1
- package/src/app/app.component.html +3 -1
- package/src/app/app.component.ts +72 -13
- package/src/app/chatlib/conversation-detail/message/image/image.component.html +1 -0
- package/src/app/chatlib/conversation-detail/message/image/image.component.ts +19 -0
- package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.html +14 -2
- package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.scss +39 -2
- package/src/app/chatlib/list-conversations-component/list-conversations.module.ts +14 -0
- package/src/app/components/canned-response/canned-response.component.html +26 -23
- package/src/app/components/canned-response/canned-response.component.scss +0 -2
- package/src/app/components/canned-response/canned-response.component.ts +3 -1
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +24 -1
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +30 -0
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +39 -9
- package/src/app/components/conversation-info/info-content/info-content.component.ts +2 -2
- package/src/app/components/conversation-info/info-group/info-group.component.ts +23 -21
- package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.html +1 -1
- package/src/app/components/conversations-list/header-conversations-list/header-conversations-list.component.ts +5 -1
- package/src/app/components/navbar/navbar.component.html +35 -9
- package/src/app/components/navbar/navbar.component.scss +64 -0
- package/src/app/components/navbar/navbar.component.ts +100 -42
- package/src/app/components/project-item/project-item.component.ts +79 -51
- package/src/app/components/sidebar/sidebar.component.html +65 -45
- package/src/app/components/sidebar/sidebar.component.ts +110 -117
- package/src/app/components/sidebar-user-details/sidebar-user-details.component.html +3 -3
- package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +15 -22
- package/src/app/directives/html-entities-encode.pipe.ts +20 -5
- package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
- package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
- package/src/app/pages/conversation-detail/conversation-detail.page.ts +95 -7
- package/src/app/pages/conversations-list/conversations-list.module.ts +3 -5
- package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
- package/src/app/pages/conversations-list/conversations-list.page.ts +51 -11
- package/src/app/pages/unassigned-conversations/unassigned-conversations.module.ts +16 -4
- package/src/app/pages/unassigned-conversations/unassigned-conversations.page.html +41 -17
- package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +10 -1
- package/src/app/pages/unassigned-conversations/unassigned-conversations.page.ts +114 -9
- package/src/app/services/global-settings/global-settings.service.ts +11 -3
- package/src/app/services/nav-proxy.service.ts +0 -1
- package/src/app/services/project_users/project-users.service.spec.ts +16 -0
- package/src/app/services/project_users/project-users.service.ts +63 -0
- package/src/app/services/projects/project.service.ts +2 -1
- package/src/app/services/tiledesk/tiledesk.service.ts +21 -16
- package/src/app/services/triggerEvents/triggerEvents.ts +28 -0
- package/src/app/services/websocket/websocket-js.ts +59 -534
- package/src/app/services/websocket/websocket-js_old.ts +578 -0
- package/src/app/services/websocket/websocket.service.ts +59 -10
- package/src/app/services/websocket/websocket.worker.ts +242 -0
- package/src/app/shared/shared.module.ts +11 -2
- package/src/app/utils/globals.ts +2 -0
- package/src/app/utils/permissions.constants.ts +138 -0
- package/src/app/utils/project-utils.ts +2 -2
- package/src/app/utils/utils.ts +18 -1
- package/src/assets/i18n/ar.json +11 -1
- package/src/assets/i18n/az.json +11 -1
- package/src/assets/i18n/de.json +11 -1
- package/src/assets/i18n/en.json +11 -1
- package/src/assets/i18n/es.json +11 -1
- package/src/assets/i18n/fr.json +11 -1
- package/src/assets/i18n/it.json +13 -3
- package/src/assets/i18n/kk.json +11 -1
- package/src/assets/i18n/pt.json +11 -1
- package/src/assets/i18n/ru.json +11 -1
- package/src/assets/i18n/sr.json +11 -1
- package/src/assets/i18n/sv.json +11 -1
- package/src/assets/i18n/tr.json +11 -1
- package/src/assets/i18n/uk.json +11 -1
- package/src/assets/i18n/uz.json +12 -1
- package/src/assets/img/no_data_found.png +0 -0
- package/src/assets/js/agentDesktop-sdk.js +55 -0
- package/src/assets/js/chat21client.js +36 -0
- package/src/assets/js/mqtt-keepalive-worker.js +53 -0
- package/src/assets/test.html +5 -2
- package/src/chat-config-template.json +1 -0
- package/src/chat-config.json +1 -0
- package/src/chat21-core/models/projectUsers.ts +19 -0
- package/src/chat21-core/models/project_user.ts +2 -1
- package/src/chat21-core/providers/abstract/upload.service.ts +5 -1
- package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
- package/src/chat21-core/providers/firebase/firebase-upload.service.ts +136 -9
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
- package/src/chat21-core/providers/native/native-image-repo.ts +1 -1
- package/src/chat21-core/providers/native/native-upload-service.ts +143 -45
- package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
- package/src/chat21-core/utils/constants.ts +5 -0
- package/src/chat21-core/utils/convertRequestToConversation.ts +1 -1
- package/src/chat21-core/utils/utils.ts +53 -3
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -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
|
package/src/app/utils/utils.ts
CHANGED
|
@@ -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
|
}
|
package/src/assets/i18n/ar.json
CHANGED
|
@@ -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
|
}
|
package/src/assets/i18n/az.json
CHANGED
|
@@ -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
|
}
|