@chat21/chat21-ionic 3.4.28 → 3.4.29-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 +111 -5
- package/angular.json +1 -0
- package/package.json +1 -1
- package/src/app/app.component.html +3 -1
- package/src/app/app.component.ts +71 -10
- 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 +29 -7
- 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 +3 -3
- package/src/app/components/navbar/navbar.component.ts +29 -38
- package/src/app/components/project-item/project-item.component.ts +11 -11
- 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 +2 -2
- package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +10 -7
- package/src/app/modals/create-ticket/create-ticket.page.ts +4 -2
- package/src/app/pages/contacts-directory/contacts-directory.page.scss +30 -25
- package/src/app/pages/conversation-detail/conversation-detail.page.html +7 -3
- package/src/app/pages/conversation-detail/conversation-detail.page.ts +89 -5
- package/src/app/pages/conversations-list/conversations-list.page.html +2 -0
- package/src/app/pages/conversations-list/conversations-list.page.scss +15 -4
- package/src/app/pages/conversations-list/conversations-list.page.ts +40 -2
- package/src/app/pages/unassigned-conversations/unassigned-conversations.page.scss +15 -5
- 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/tiledesk/tiledesk.service.ts +0 -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 +9 -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/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/providers/firebase/firebase-conversation-handler.ts +1 -1
- package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
- package/src/chat21-core/providers/tiledesk/tiledesk-auth.service.ts +3 -0
- package/src/chat21-core/utils/utils.ts +16 -2
|
@@ -83,7 +83,11 @@ import { WebsocketService } from 'src/app/services/websocket/websocket.service';
|
|
|
83
83
|
import { Project } from 'src/chat21-core/models/projects';
|
|
84
84
|
import { Globals } from 'src/app/utils/globals';
|
|
85
85
|
import { ProjectService } from 'src/app/services/projects/project.service';
|
|
86
|
-
import {
|
|
86
|
+
import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
|
|
87
|
+
import { ProjectUser } from 'src/chat21-core/models/projectUsers';
|
|
88
|
+
import { getOSCode, hasRole } from 'src/app/utils/utils';
|
|
89
|
+
import { PERMISSIONS } from 'src/app/utils/permissions.constants';
|
|
90
|
+
import { TriggerEvents } from 'src/app/services/triggerEvents/triggerEvents';
|
|
87
91
|
|
|
88
92
|
@Component({
|
|
89
93
|
selector: 'app-conversation-detail',
|
|
@@ -108,6 +112,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
108
112
|
private subscriptions: Array<any>
|
|
109
113
|
public tenant: string;
|
|
110
114
|
public loggedUser: UserModel
|
|
115
|
+
public projectUser: ProjectUser;
|
|
111
116
|
public conversationWith: string
|
|
112
117
|
public conversationWithFullname: string
|
|
113
118
|
public messages: Array<MessageModel> = []
|
|
@@ -137,6 +142,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
137
142
|
public tagsCannedFilter: Array<any> = [];
|
|
138
143
|
public SHOW_CANNED_RESPONSES: boolean = false
|
|
139
144
|
public canShowCanned: boolean = true
|
|
145
|
+
public rolesCanned: { [key: string]: boolean }
|
|
140
146
|
|
|
141
147
|
public SHOW_COPILOT_SUGGESTIONS: boolean = false;
|
|
142
148
|
|
|
@@ -171,6 +177,10 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
171
177
|
copilotQuestion: string = '';
|
|
172
178
|
/**COPILOT : end */
|
|
173
179
|
|
|
180
|
+
/** TICKET: start */
|
|
181
|
+
isTicketEnabled: boolean = false;
|
|
182
|
+
/** TICKET: end */
|
|
183
|
+
|
|
174
184
|
isMine = isMine
|
|
175
185
|
isInfo = isInfo
|
|
176
186
|
isFirstMessage = isFirstMessage
|
|
@@ -240,18 +250,20 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
240
250
|
public toastController: ToastController,
|
|
241
251
|
public tiledeskService: TiledeskService,
|
|
242
252
|
public projectService: ProjectService,
|
|
253
|
+
public projectUsersService: ProjectUsersService,
|
|
243
254
|
private networkService: NetworkService,
|
|
244
255
|
private events: EventsService,
|
|
245
256
|
private webSocketService: WebsocketService,
|
|
246
257
|
public projectPlanUtils: ProjectPlanUtils,
|
|
258
|
+
public triggerEvents: TriggerEvents,
|
|
247
259
|
private g: Globals,
|
|
248
260
|
) {
|
|
249
261
|
// Change list on date change
|
|
250
262
|
this.route.paramMap.subscribe((params) => {
|
|
251
263
|
this.logger.log('[CONVS-DETAIL] - constructor -> params: ', params)
|
|
252
264
|
this.conversationWith = params.get('IDConv')
|
|
253
|
-
this.conversationWithFullname = params.get('FullNameConv')
|
|
254
|
-
this.conv_type = params.get('Convtype')
|
|
265
|
+
this.conversationWithFullname = decodeURIComponent(params.get('FullNameConv'))
|
|
266
|
+
this.conv_type = decodeURIComponent(params.get('Convtype'))
|
|
255
267
|
|
|
256
268
|
this.events.publish('supportconvid:haschanged', this.conversationWith)
|
|
257
269
|
})
|
|
@@ -418,6 +430,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
418
430
|
ionViewDidEnter() {
|
|
419
431
|
this.logger.log('[CONVS-DETAIL] > ionViewDidEnter')
|
|
420
432
|
// this.info_content_child_enabled = true;
|
|
433
|
+
// Scroll to bottom to show the last message without animation
|
|
434
|
+
this.scrollToLastMessage()
|
|
421
435
|
}
|
|
422
436
|
|
|
423
437
|
// Unsubscibe when new page transition end
|
|
@@ -477,6 +491,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
477
491
|
this.messages = [] // list messages of conversation
|
|
478
492
|
this.isFileSelected = false // indicates if a file has been selected (image to upload)
|
|
479
493
|
this.isEmailEnabled = (this.appConfigProvider.getConfig().emailSection === 'true' || this.appConfigProvider.getConfig().emailSection === true) ? true : false;
|
|
494
|
+
this.isTicketEnabled = (this.appConfigProvider.getConfig().ticketSection === 'true' || this.appConfigProvider.getConfig().ticketSection === true) ? true : false;
|
|
480
495
|
this.isWhatsappTemplatesEnabled = (this.appConfigProvider.getConfig().whatsappTemplatesSection === 'true' || this.appConfigProvider.getConfig().whatsappTemplatesSection === true) ? true : false;
|
|
481
496
|
|
|
482
497
|
this.cannedResponsesService.initialize(appconfig.apiUrl)
|
|
@@ -534,7 +549,6 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
534
549
|
this.logger.log('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT * COMPLETE *',)
|
|
535
550
|
})
|
|
536
551
|
}else {
|
|
537
|
-
this.canShowCanned = false;
|
|
538
552
|
this.offlineMsgEmail = false;
|
|
539
553
|
}
|
|
540
554
|
|
|
@@ -545,10 +559,13 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
545
559
|
this.logger.log('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT RES', project)
|
|
546
560
|
if (project) {
|
|
547
561
|
const projectId = project.id_project
|
|
548
|
-
this.
|
|
562
|
+
this.projectUser = await this.projectUsersService.getProjectUserByProjectId(project._id)
|
|
549
563
|
this.offlineMsgEmail = this.checkOfflineMsgEmailIsEnabled(project)
|
|
550
564
|
this.isCopilotEnabled = this.projectPlanUtils.checkProjectProfileFeature(project, 'copilot');
|
|
551
565
|
this.fileUploadAccept = this.checkAcceptedUploadFile(project)
|
|
566
|
+
this.rolesCanned = this.checkCannedResponsesRoles()
|
|
567
|
+
this.canShowCanned = this.checkCannedResponses(project)
|
|
568
|
+
this.logger.log('[CONVS-DETAIL] this.rolesCanned ', this.canShowCanned)
|
|
552
569
|
}
|
|
553
570
|
}, (error) => {
|
|
554
571
|
this.logger.error('[CONVS-DETAIL] - GET PROJECTID BY CONV RECIPIENT - ERROR ', error)
|
|
@@ -586,6 +603,40 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
586
603
|
return this.appConfigProvider.getConfig().fileUploadAccept
|
|
587
604
|
}
|
|
588
605
|
|
|
606
|
+
checkCannedResponses(project: Project): boolean {
|
|
607
|
+
let expires = this.projectPlanUtils.checkPlanIsExpired(project)
|
|
608
|
+
this.logger.log('[CONVS-DETAIL] checkCannedResponses expires ', expires)
|
|
609
|
+
if(expires){
|
|
610
|
+
return false
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
let hasRoleToShowCanned = this.rolesCanned[PERMISSIONS.CANNED_RESPONSES_READ]
|
|
614
|
+
this.logger.log('[CONVS-DETAIL] checkCannedResponses hasRoleToShowCanned ', hasRoleToShowCanned)
|
|
615
|
+
if(!hasRoleToShowCanned){
|
|
616
|
+
return false
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return true
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
checkCannedResponsesRoles(): { [key: string]: boolean } {
|
|
623
|
+
const permissionKeys = [
|
|
624
|
+
'CANNED_RESPONSES_CREATE',
|
|
625
|
+
'CANNED_RESPONSES_READ',
|
|
626
|
+
'CANNED_RESPONSES_UPDATE',
|
|
627
|
+
'CANNED_RESPONSES_DELETE',
|
|
628
|
+
] as const;
|
|
629
|
+
|
|
630
|
+
const roles: { [key: string]: boolean } = {};
|
|
631
|
+
for (const key of permissionKeys) {
|
|
632
|
+
const permission = PERMISSIONS[key];
|
|
633
|
+
roles[permission] = hasRole(this.projectUser, permission);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return roles;
|
|
637
|
+
|
|
638
|
+
}
|
|
639
|
+
|
|
589
640
|
// getProjectIdSelectedConversation(conversationWith: string): string{
|
|
590
641
|
// const conversationWith_segments = conversationWith.split('-')
|
|
591
642
|
// // Removes the last element of the array if is = to the separator
|
|
@@ -669,6 +720,11 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
669
720
|
"WHATSAPP.ERROR_WHATSAPP_NOT_INSTALLED",
|
|
670
721
|
"WHATSAPP.ERROR_WHATSAPP_GENERIC_ERROR",
|
|
671
722
|
|
|
723
|
+
"TICKET.OPEN_TICKET",
|
|
724
|
+
"TICKET.DESCRIPTION",
|
|
725
|
+
"TICKET.CONFIRM",
|
|
726
|
+
"TICKET.CLOSE",
|
|
727
|
+
|
|
672
728
|
"COPILOT.ASK_AI",
|
|
673
729
|
"COPILOT.NO_SUGGESTIONS_PRESENT",
|
|
674
730
|
|
|
@@ -1884,6 +1940,11 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1884
1940
|
}
|
|
1885
1941
|
|
|
1886
1942
|
|
|
1943
|
+
onOpenTicket(event) {
|
|
1944
|
+
this.logger.debug('[CONVS-DETAIL] openTicketOnExternalService - conversationWith ', this.conversationWith)
|
|
1945
|
+
const detailOBJ = { event: 'onOpenTicketExternally', request_id: this.conversationWith, conversation: this.conversation }
|
|
1946
|
+
this.triggerEvents.triggerOnOpenTicketExternally(detailOBJ)
|
|
1947
|
+
}
|
|
1887
1948
|
// -------------- START SCROLL/RESIZE -------------- //
|
|
1888
1949
|
/** */
|
|
1889
1950
|
resizeTextArea() {
|
|
@@ -1927,6 +1988,29 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1927
1988
|
}
|
|
1928
1989
|
}
|
|
1929
1990
|
|
|
1991
|
+
/**
|
|
1992
|
+
* Scroll to last message without animation using requestAnimationFrame
|
|
1993
|
+
* This is a best practice alternative to setTimeout
|
|
1994
|
+
*/
|
|
1995
|
+
private scrollToLastMessage() {
|
|
1996
|
+
this.showIonContent = true
|
|
1997
|
+
if (this.ionContentChatArea) {
|
|
1998
|
+
// Use requestAnimationFrame for better performance
|
|
1999
|
+
requestAnimationFrame(() => {
|
|
2000
|
+
requestAnimationFrame(() => {
|
|
2001
|
+
// Double RAF ensures DOM is fully rendered
|
|
2002
|
+
this.ionContentChatArea.scrollToBottom(0).then(() => {
|
|
2003
|
+
this.logger.log('[CONVS-DETAIL] scroll posizionato all\'ultimo messaggio')
|
|
2004
|
+
}).catch((error) => {
|
|
2005
|
+
this.logger.error('[CONVS-DETAIL] errore durante lo scroll:', error)
|
|
2006
|
+
})
|
|
2007
|
+
})
|
|
2008
|
+
})
|
|
2009
|
+
} else {
|
|
2010
|
+
this.logger.warn('[CONVS-DETAIL] ionContentChatArea non disponibile')
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
|
|
1930
2014
|
/**
|
|
1931
2015
|
* detectBottom
|
|
1932
2016
|
*/
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
[sound_btn]="sound_btn"
|
|
8
8
|
[isMobile]="isMobile"
|
|
9
9
|
[isVisibleTKT]="isVisibleTKT"
|
|
10
|
+
[isVisibleCNT]="isVisibleCNT"
|
|
11
|
+
[roles]="rolesHeader"
|
|
10
12
|
(onSoundChange)="onSoundChange($event)"
|
|
11
13
|
(openContactsDirectory)=openContactsDirectory($event)
|
|
12
14
|
(openProfileInfo)=openProfileInfo($event)>
|
|
@@ -11,13 +11,14 @@ ion-header {
|
|
|
11
11
|
|
|
12
12
|
ion-content {
|
|
13
13
|
// overwrite inline styles
|
|
14
|
-
--offset-bottom: auto!important;
|
|
15
|
-
|
|
16
|
-
overflow:
|
|
14
|
+
// --offset-bottom: auto!important;
|
|
15
|
+
// Ionic scroll is handled by the internal scroll container (Shadow DOM).
|
|
16
|
+
// Forcing `--overflow: hidden` breaks scrolling (Chrome >= 144 is stricter here).
|
|
17
|
+
--overflow: auto;
|
|
17
18
|
|
|
18
19
|
/* For Firefox */
|
|
19
20
|
@-moz-document url-prefix() {
|
|
20
|
-
scrollbar
|
|
21
|
+
// scrollbar styling must target the internal scroll element
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
|
|
@@ -25,6 +26,16 @@ ion-content {
|
|
|
25
26
|
background: var(--list-bkg-color);
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Target Ionic internal scroll container (Shadow DOM) for overflow + scrollbar styling
|
|
32
|
+
ion-content::part(scroll) {
|
|
33
|
+
overflow-y: auto;
|
|
34
|
+
-webkit-overflow-scrolling: touch;
|
|
35
|
+
|
|
36
|
+
/* For Firefox */
|
|
37
|
+
scrollbar-width: none;
|
|
38
|
+
|
|
28
39
|
&::-webkit-scrollbar {
|
|
29
40
|
width: 6px;
|
|
30
41
|
height: 8px;
|
|
@@ -53,7 +53,10 @@ import { Globals } from 'src/app/utils/globals';
|
|
|
53
53
|
import { TriggerEvents } from 'src/app/services/triggerEvents/triggerEvents';
|
|
54
54
|
import { MessageModel } from 'src/chat21-core/models/message';
|
|
55
55
|
import { Project } from 'src/chat21-core/models/projects';
|
|
56
|
-
import { getOSCode } from 'src/app/utils/utils';
|
|
56
|
+
import { getOSCode, hasRole } from 'src/app/utils/utils';
|
|
57
|
+
import { PERMISSIONS } from 'src/app/utils/permissions.constants';
|
|
58
|
+
import { ProjectUser } from 'src/chat21-core/models/projectUsers';
|
|
59
|
+
import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
|
|
57
60
|
|
|
58
61
|
@Component({
|
|
59
62
|
selector: 'app-conversations-list',
|
|
@@ -82,6 +85,7 @@ export class ConversationListPage implements OnInit {
|
|
|
82
85
|
public archived_btn: boolean
|
|
83
86
|
public sound_btn: string
|
|
84
87
|
public isVisibleTKT: boolean = true;
|
|
88
|
+
public isVisibleCNT: boolean = true;;
|
|
85
89
|
public convertMessage = convertMessage
|
|
86
90
|
private isShowMenuPage = false
|
|
87
91
|
private logger: LoggerService = LoggerInstance.getInstance()
|
|
@@ -104,6 +108,9 @@ export class ConversationListPage implements OnInit {
|
|
|
104
108
|
public isMobile: boolean = false;
|
|
105
109
|
public isInitialized: boolean = false;
|
|
106
110
|
|
|
111
|
+
public projectUser: ProjectUser;
|
|
112
|
+
public rolesHeader: { [key: string]: boolean }
|
|
113
|
+
|
|
107
114
|
// PROJECT AVAILABILITY INFO: start
|
|
108
115
|
project: Project
|
|
109
116
|
profile_name_translated: string;
|
|
@@ -130,6 +137,7 @@ export class ConversationListPage implements OnInit {
|
|
|
130
137
|
private translateService: CustomTranslateService,
|
|
131
138
|
public tiledeskService: TiledeskService,
|
|
132
139
|
public tiledeskAuthService: TiledeskAuthService,
|
|
140
|
+
public projectUsersService: ProjectUsersService,
|
|
133
141
|
public appConfigProvider: AppConfigProvider,
|
|
134
142
|
public platform: Platform,
|
|
135
143
|
public wsService: WebsocketService,
|
|
@@ -371,6 +379,11 @@ export class ConversationListPage implements OnInit {
|
|
|
371
379
|
// save conversationHandler in chatManager
|
|
372
380
|
this.chatManager.setConversationsHandler(this.conversationsHandlerService)
|
|
373
381
|
this.showPlaceholder = false
|
|
382
|
+
|
|
383
|
+
// Hide loading spinner if there are no conversations
|
|
384
|
+
if (this.conversations.length === 0) {
|
|
385
|
+
this.loadingIsActive = false
|
|
386
|
+
}
|
|
374
387
|
}
|
|
375
388
|
|
|
376
389
|
// private manageStoredConversations() {
|
|
@@ -471,7 +484,7 @@ export class ConversationListPage implements OnInit {
|
|
|
471
484
|
}
|
|
472
485
|
|
|
473
486
|
listenToCurrentStoredProject() {
|
|
474
|
-
this.events.subscribe('storage:last_project', projectObjct => {
|
|
487
|
+
this.events.subscribe('storage:last_project', async(projectObjct) => {
|
|
475
488
|
if (projectObjct && projectObjct !== 'undefined') {
|
|
476
489
|
this.logger.log('[CONVS-LIST-PAGE] - GET STORED PROJECT ', projectObjct)
|
|
477
490
|
|
|
@@ -496,6 +509,10 @@ export class ConversationListPage implements OnInit {
|
|
|
496
509
|
} else if (this.project.profile.type === 'payment' && this.project.profile.name === 'enterprise') {
|
|
497
510
|
this.profile_name_translated = this.translationMapHeader.get('PaydPlanNameEnterprise');
|
|
498
511
|
}
|
|
512
|
+
|
|
513
|
+
this.projectUser = await this.projectUsersService.getProjectUserByProjectId(this.project._id)
|
|
514
|
+
this.rolesHeader = this.checkCannedResponsesRoles();
|
|
515
|
+
this.logger.log('[CONVS-LIST-PAGE] - GET PROJECT USER ROLES ', this.rolesHeader)
|
|
499
516
|
}
|
|
500
517
|
})
|
|
501
518
|
}
|
|
@@ -631,8 +648,24 @@ export class ConversationListPage implements OnInit {
|
|
|
631
648
|
const public_Key = this.appConfigProvider.getConfig().t2y12PruGU9wUtEGzBJfolMIgK
|
|
632
649
|
this.logger.log('[CONVS-LIST-PAGE] AppConfigService getAppConfig public_Key', public_Key)
|
|
633
650
|
this.isVisibleTKT = getOSCode("TKT", public_Key);
|
|
651
|
+
this.isVisibleCNT = getOSCode("CNT", public_Key);
|
|
634
652
|
}
|
|
635
653
|
|
|
654
|
+
checkCannedResponsesRoles(): { [key: string]: boolean } {
|
|
655
|
+
const permissionKeys = [
|
|
656
|
+
'LEADS_READ',
|
|
657
|
+
] as const;
|
|
658
|
+
|
|
659
|
+
const roles: { [key: string]: boolean } = {};
|
|
660
|
+
for (const key of permissionKeys) {
|
|
661
|
+
const permission = PERMISSIONS[key];
|
|
662
|
+
roles[permission] = hasRole(this.projectUser, permission);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return roles;
|
|
666
|
+
|
|
667
|
+
}
|
|
668
|
+
|
|
636
669
|
onBackButtonFN(event) {
|
|
637
670
|
this.conversationType = 'active'
|
|
638
671
|
|
|
@@ -883,6 +916,10 @@ export class ConversationListPage implements OnInit {
|
|
|
883
916
|
|
|
884
917
|
this.logger.log('[CONVS-LIST-PAGE] navigateByUrl this.uidConvSelected ', this.uidConvSelected)
|
|
885
918
|
|
|
919
|
+
const queryParams = this.route.snapshot.queryParams;
|
|
920
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
921
|
+
|
|
922
|
+
|
|
886
923
|
this.setUidConvSelected(uidConvSelected, converationType)
|
|
887
924
|
if (checkPlatformIsMobile()) {
|
|
888
925
|
this.logger.log('[CONVS-LIST-PAGE] checkPlatformIsMobile(): ', checkPlatformIsMobile())
|
|
@@ -900,6 +937,7 @@ export class ConversationListPage implements OnInit {
|
|
|
900
937
|
if (this.conversationSelected && this.conversationSelected.conversation_with_fullname) {
|
|
901
938
|
pageUrl = 'conversation-detail/' + this.uidConvSelected + '/' + encodeURIComponent(this.conversationSelected.conversation_with_fullname) + '/' + converationType
|
|
902
939
|
}
|
|
940
|
+
pageUrl += queryString ? `?${queryString}` : '';
|
|
903
941
|
this.logger.log('[CONVS-LIST-PAGE] setUidConvSelected navigateByUrl--->: ', pageUrl)
|
|
904
942
|
// replace(/\(/g, '%28').replace(/\)/g, '%29') -> used for the encoder of any round brackets
|
|
905
943
|
this.router.navigateByUrl(pageUrl.replace(/\(/g, '%28').replace(/\)/g, '%29'), {replaceUrl: true})
|
|
@@ -16,11 +16,21 @@ ion-toolbar {
|
|
|
16
16
|
|
|
17
17
|
ion-content {
|
|
18
18
|
// overwrite inline styles
|
|
19
|
-
|
|
20
|
-
overflow:
|
|
19
|
+
// Ionic scroll is handled by the internal scroll container (Shadow DOM).
|
|
20
|
+
// Forcing `--overflow: hidden` breaks scrolling (Chrome >= 144 is stricter here).
|
|
21
|
+
--overflow: auto;
|
|
21
22
|
&:not(.mobile){
|
|
22
23
|
--background: var(--list-bkg-color);
|
|
23
24
|
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Target Ionic internal scroll container (Shadow DOM) for overflow + scrollbar styling
|
|
28
|
+
ion-content::part(scroll) {
|
|
29
|
+
overflow-y: auto;
|
|
30
|
+
-webkit-overflow-scrolling: touch;
|
|
31
|
+
|
|
32
|
+
/* For Firefox */
|
|
33
|
+
scrollbar-width: none;
|
|
24
34
|
|
|
25
35
|
&::-webkit-scrollbar {
|
|
26
36
|
width: 6px;
|
|
@@ -32,11 +42,11 @@ ion-content {
|
|
|
32
42
|
background: #f9f9f9;
|
|
33
43
|
}
|
|
34
44
|
&::-webkit-scrollbar-thumb {
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
background-color: #b9b9b9;
|
|
46
|
+
border-radius: 0px;
|
|
37
47
|
}
|
|
38
48
|
&::-webkit-scrollbar-thumb:hover {
|
|
39
|
-
|
|
49
|
+
background-color: #727272;
|
|
40
50
|
}
|
|
41
51
|
}
|
|
42
52
|
|
|
@@ -88,14 +88,14 @@ export class GlobalSettingsService {
|
|
|
88
88
|
this.logger.debug('[GLOBAL-SET] setVariableFromStorage :::::::: SET VARIABLE ---------->', Object.keys(globals));
|
|
89
89
|
for (const key of Object.keys(globals)) {
|
|
90
90
|
const val = this.appStorageService.getItem(key);
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals KEY ---------->', key);
|
|
92
|
+
this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals VAL ---------->', val);
|
|
93
93
|
if (val && val !== null) {
|
|
94
94
|
// globals.setParameter(key, val);
|
|
95
95
|
globals[key] = stringToBoolean(val);
|
|
96
96
|
}
|
|
97
97
|
// this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals == ---------->', globals);
|
|
98
|
-
}
|
|
98
|
+
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
|
@@ -113,6 +113,7 @@ export class GlobalSettingsService {
|
|
|
113
113
|
TEMP = getParameterByName(windowContext, 'tiledesk_supportMode');
|
|
114
114
|
if (TEMP) {
|
|
115
115
|
globals.supportMode = stringToBoolean(TEMP);
|
|
116
|
+
this.appStorageService.setItem('supportMode', String(globals.supportMode))
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
TEMP = getParameterByName(windowContext, 'tiledesk_lang');
|
|
@@ -138,6 +139,13 @@ export class GlobalSettingsService {
|
|
|
138
139
|
TEMP = getParameterByName(windowContext, 'tiledesk_projectID');
|
|
139
140
|
if (TEMP) {
|
|
140
141
|
globals.projectID = TEMP;
|
|
142
|
+
this.appStorageService.setItem('projectID', TEMP)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
TEMP = getParameterByName(windowContext, 'tiledesk_logOut');
|
|
146
|
+
if (TEMP) {
|
|
147
|
+
globals.logOut = stringToBoolean(TEMP);
|
|
148
|
+
this.appStorageService.setItem('logOut', TEMP)
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
}
|
|
@@ -4,7 +4,6 @@ import { Router, NavigationExtras } from '@angular/router';
|
|
|
4
4
|
|
|
5
5
|
// utils
|
|
6
6
|
import { checkPlatformIsMobile } from '../../chat21-core/utils/utils';
|
|
7
|
-
// import { ConversationDetailPage } from '../pages/conversation-detail/conversation-detail.page';
|
|
8
7
|
|
|
9
8
|
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
10
9
|
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ProjectUsersService } from './project-users.service';
|
|
4
|
+
|
|
5
|
+
describe('ProjectUsersService', () => {
|
|
6
|
+
let service: ProjectUsersService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
TestBed.configureTestingModule({});
|
|
10
|
+
service = TestBed.inject(ProjectUsersService);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should be created', () => {
|
|
14
|
+
expect(service).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
import { map } from 'rxjs/operators';
|
|
5
|
+
import { ProjectUser } from 'src/chat21-core/models/projectUsers';
|
|
6
|
+
import { AppStorageService } from 'src/chat21-core/providers/abstract/app-storage.service';
|
|
7
|
+
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
8
|
+
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
9
|
+
|
|
10
|
+
@Injectable({
|
|
11
|
+
providedIn: 'root'
|
|
12
|
+
})
|
|
13
|
+
export class ProjectUsersService {
|
|
14
|
+
|
|
15
|
+
private SERVER_BASE_URL: string;
|
|
16
|
+
private tiledeskToken: string;
|
|
17
|
+
|
|
18
|
+
private logger: LoggerService = LoggerInstance.getInstance();
|
|
19
|
+
constructor(
|
|
20
|
+
public http: HttpClient,
|
|
21
|
+
public appStorageService: AppStorageService
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
initialize(serverBaseUrl: string) {
|
|
25
|
+
this.logger.log('[TILEDESK-PROJECT_USERS-SERV] - initialize serverBaseUrl', serverBaseUrl);
|
|
26
|
+
this.SERVER_BASE_URL = serverBaseUrl;
|
|
27
|
+
this.tiledeskToken = this.appStorageService.getItem('tiledeskToken')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public getProjectUsersByProjectId(project_id: string): Observable<ProjectUser[]> {
|
|
31
|
+
const url = this.SERVER_BASE_URL + project_id + '/project_users/';
|
|
32
|
+
this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER URL', url);
|
|
33
|
+
|
|
34
|
+
const httpOptions = {
|
|
35
|
+
headers: new HttpHeaders({
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
Authorization: this.tiledeskToken
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
return this.http.get(url, httpOptions).pipe(map((res: any) => {
|
|
41
|
+
this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
|
|
42
|
+
return res
|
|
43
|
+
}))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public getProjectUserByProjectId(project_id: string): Promise<ProjectUser> {
|
|
47
|
+
const url = this.SERVER_BASE_URL + project_id + '/project_users/me';
|
|
48
|
+
this.logger.log('[TILEDESK-SERVICE]- GET PROJECT-USER BY USER-ID - URL', url);
|
|
49
|
+
|
|
50
|
+
const httpOptions = {
|
|
51
|
+
headers: new HttpHeaders({
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
Authorization: this.tiledeskToken
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return this.http.get(url, httpOptions).pipe(map((res: any) => {
|
|
58
|
+
this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
|
|
59
|
+
return res[0]
|
|
60
|
+
})).toPromise();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
}
|
|
@@ -93,22 +93,6 @@ export class TiledeskService {
|
|
|
93
93
|
}))
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
public getProjectUsersByProjectId(project_id: string) {
|
|
97
|
-
const url = this.SERVER_BASE_URL + project_id + '/project_users/';
|
|
98
|
-
this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER URL', url);
|
|
99
|
-
|
|
100
|
-
const httpOptions = {
|
|
101
|
-
headers: new HttpHeaders({
|
|
102
|
-
'Content-Type': 'application/json',
|
|
103
|
-
Authorization: this.tiledeskToken
|
|
104
|
-
})
|
|
105
|
-
};
|
|
106
|
-
return this.http.get(url, httpOptions).pipe(map((res: any) => {
|
|
107
|
-
this.logger.log('[TILEDESK-SERVICE] - GET PROJECT-USER RES ', res);
|
|
108
|
-
return res
|
|
109
|
-
}))
|
|
110
|
-
}
|
|
111
|
-
|
|
112
96
|
public getAllLeadsActiveWithLimit(project_id: string, limit: number) {
|
|
113
97
|
const url = this.SERVER_BASE_URL + project_id + '/leads?limit=' + limit + '&with_fullname=true';
|
|
114
98
|
this.logger.log('[TILEDESK-SERVICE] - GET ALL ACTIVE LEADS (LIMIT 10000) - URL', url);
|
|
@@ -102,5 +102,33 @@ export class TriggerEvents {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
public triggerOnUpdateNewConversationBadge(detailObj: {}) {
|
|
106
|
+
this.logger.debug(' ---------------- triggerOnUpdateNewConversationBadge ---------------- ', detailObj);
|
|
107
|
+
try {
|
|
108
|
+
const onBeforeInit = new CustomEvent('onUpdateNewConversationBadge', { detail: detailObj });
|
|
109
|
+
const windowContext = this.windowContext;
|
|
110
|
+
if (windowContext){
|
|
111
|
+
// windowContext.document.dispatchEvent(onNewConversation);
|
|
112
|
+
windowContext.postMessage({type: "onUpdateNewConversationBadge", detail: detailObj }, '*')
|
|
113
|
+
}
|
|
114
|
+
} catch (e) {
|
|
115
|
+
this.logger.error('[TRIGGER-HANDLER] > Error:' + e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public triggerOnOpenTicketExternally(detailObj: {}) {
|
|
120
|
+
this.logger.debug(' ---------------- triggerOnOpenTicketExternally ---------------- ', detailObj);
|
|
121
|
+
try {
|
|
122
|
+
const onBeforeInit = new CustomEvent('onOpenTicketExternally', { detail: detailObj });
|
|
123
|
+
const windowContext = this.windowContext;
|
|
124
|
+
if (windowContext){
|
|
125
|
+
// windowContext.document.dispatchEvent(onNewConversation);
|
|
126
|
+
windowContext.postMessage({type: "onOpenTicketExternally", detail: detailObj }, '*')
|
|
127
|
+
}
|
|
128
|
+
} catch (e) {
|
|
129
|
+
this.logger.error('[TRIGGER-HANDLER] > Error:' + e);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
105
133
|
|
|
106
134
|
}
|