@chat21/chat21-ionic 3.4.31 → 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 +127 -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 -11
- 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 +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 +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/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 +89 -5
- 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/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/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/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
package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss
CHANGED
|
@@ -183,6 +183,36 @@
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
#ticket{
|
|
187
|
+
text-align: center;
|
|
188
|
+
font-size: 12px;
|
|
189
|
+
|
|
190
|
+
.buttons-container{
|
|
191
|
+
display: flex;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
gap: 10px;
|
|
194
|
+
|
|
195
|
+
ion-button{
|
|
196
|
+
font-size: 12px;
|
|
197
|
+
--padding-top: 4px;
|
|
198
|
+
--padding-bottom: 4px;
|
|
199
|
+
--padding-start: 6px;
|
|
200
|
+
--padding-end: 6px;
|
|
201
|
+
--ripple-color: transparent;
|
|
202
|
+
text-transform: unset;
|
|
203
|
+
height: auto;
|
|
204
|
+
|
|
205
|
+
ion-icon{
|
|
206
|
+
margin-right: 4px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
&[name="add"]{
|
|
210
|
+
--background: var(--basic-blue);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
186
216
|
#fileInput {
|
|
187
217
|
position: absolute;
|
|
188
218
|
opacity: 0;
|
package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { CopilotService } from 'src/app/services/copilot/copilot.service';
|
|
|
26
26
|
import { BRAND_BASE_INFO } from 'src/app/utils/utils-resources';
|
|
27
27
|
import { ProjectService } from 'src/app/services/projects/project.service';
|
|
28
28
|
import { Project } from 'src/chat21-core/models/projects';
|
|
29
|
+
import { ProjectUser } from 'src/chat21-core/models/projectUsers';
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@Component({
|
|
@@ -49,6 +50,7 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
49
50
|
@ViewChild('fileInput', { static: false }) fileInput: any;
|
|
50
51
|
|
|
51
52
|
@Input() loggedUser: UserModel;
|
|
53
|
+
@Input() projectUser: ProjectUser;
|
|
52
54
|
@Input() conversationWith: string;
|
|
53
55
|
@Input() channelType: string;
|
|
54
56
|
@Input() channel: string;
|
|
@@ -61,16 +63,20 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
61
63
|
@Input() emailSection: boolean;
|
|
62
64
|
@Input() offlineMsgEmail: boolean;
|
|
63
65
|
@Input() whatsappTemplatesSection: boolean;
|
|
66
|
+
@Input() ticketSection: boolean
|
|
64
67
|
@Input() isOpenInfoConversation: boolean;
|
|
68
|
+
@Input() cannedSection: boolean;
|
|
65
69
|
@Input() stylesMap: Map<string, string>;
|
|
66
70
|
@Input() translationMap: Map<string, string>;
|
|
67
71
|
@Input() dropEvent: any;
|
|
68
72
|
@Input() disableTextarea: boolean;
|
|
73
|
+
@Input() roles: Array<string>;
|
|
69
74
|
@Output() eventChangeTextArea = new EventEmitter<{msg: string, offsetHeight: number}>();
|
|
70
75
|
@Output() eventSendMessage = new EventEmitter<{msg: string, type: string, metadata?: Object, attributes?: Object}>();
|
|
71
76
|
@Output() onClickOpenCannedResponses = new EventEmitter<boolean>();
|
|
72
77
|
@Output() onPresentModalScrollToBottom = new EventEmitter<boolean>();
|
|
73
78
|
@Output() onOpenFooterSection = new EventEmitter<string>();
|
|
79
|
+
@Output() onOpenTicket = new EventEmitter<boolean>();
|
|
74
80
|
|
|
75
81
|
public project: Project;
|
|
76
82
|
public conversationEnabled = false;
|
|
@@ -293,6 +299,17 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
293
299
|
this.prensentTemplateModal();
|
|
294
300
|
}
|
|
295
301
|
|
|
302
|
+
onClickTicket(option: "open" | "close"){
|
|
303
|
+
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] - onClickTicket', option);
|
|
304
|
+
switch(option){
|
|
305
|
+
case "open":
|
|
306
|
+
this.onOpenTicket.emit();
|
|
307
|
+
case "close":
|
|
308
|
+
this.section = 'chat'
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
}
|
|
312
|
+
|
|
296
313
|
|
|
297
314
|
/**
|
|
298
315
|
*
|
|
@@ -575,8 +592,10 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
575
592
|
if (!text.includes("/")) {
|
|
576
593
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - SEND MESSAGE 1 message: ', message);
|
|
577
594
|
this.logger.log("[CONVS-DETAIL] replaceTagInMessage onKeydown in msg-texarea SEND MESSAGE 1 message: ", message);
|
|
578
|
-
|
|
595
|
+
|
|
579
596
|
this.sendMessage(text);
|
|
597
|
+
// this.messageString = '';
|
|
598
|
+
|
|
580
599
|
this.countClicks = 0
|
|
581
600
|
} else if (text.includes("/") && pos === 0 && this.countClicks > 1 && this.tagsCannedFilter.length > 0) {
|
|
582
601
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - tagsCannedFilter.length 2: ', this.tagsCannedFilter.length);
|
|
@@ -588,9 +607,10 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
588
607
|
this.logger.log("[CONVS-DETAIL] replaceTagInMessage onKeydown in msg-texarea SEND MESSAGE 2 this.countClicks: ", this.countClicks);
|
|
589
608
|
this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown in msg-texarea SEND MESSAGE 2 this.countClicks: ", this.countClicks);
|
|
590
609
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - SEND MESSAGE 2 message: ', message);
|
|
591
|
-
|
|
592
|
-
|
|
610
|
+
|
|
593
611
|
this.sendMessage(text);
|
|
612
|
+
// this.messageString = '';
|
|
613
|
+
|
|
594
614
|
this.countClicks = 0
|
|
595
615
|
} else if (text.includes("/") && pos > 0 && this.countClicks > 1 && this.tagsCannedFilter.length > 0 && text.substr(-1) !== '/') {
|
|
596
616
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - tagsCannedFilter.length 3: ', this.tagsCannedFilter.length);
|
|
@@ -602,17 +622,19 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
602
622
|
this.logger.log("[CONVS-DETAIL] replaceTagInMessage onKeydown in msg-texarea SEND MESSAGE 2 this.countClicks: ", this.countClicks);
|
|
603
623
|
this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown in msg-texarea SEND MESSAGE 2 this.countClicks: ", this.countClicks);
|
|
604
624
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - SEND MESSAGE 2 message: ', message);
|
|
605
|
-
|
|
606
|
-
|
|
625
|
+
|
|
607
626
|
this.sendMessage(text);
|
|
627
|
+
// this.messageString = '';
|
|
628
|
+
|
|
608
629
|
this.countClicks = 0
|
|
609
630
|
} else if (text.includes("/") && this.tagsCannedFilter.length === 0) {
|
|
610
631
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - tagsCannedFilter.length 3: ', this.tagsCannedFilter.length);
|
|
611
632
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] onKeydown - SEND MESSAGE 3 message: ', message);
|
|
612
633
|
this.logger.log("[CONVS-DETAIL] replaceTagInMessage onKeydown in msg-texarea SEND MESSAGE 3 message: ", message);
|
|
613
|
-
|
|
614
|
-
|
|
634
|
+
|
|
615
635
|
this.sendMessage(text);
|
|
636
|
+
// this.messageString = '';
|
|
637
|
+
|
|
616
638
|
this.countClicks = 0
|
|
617
639
|
|
|
618
640
|
}
|
|
@@ -70,8 +70,8 @@ export class InfoContentComponent implements OnInit {
|
|
|
70
70
|
this.route.paramMap.subscribe(params => {
|
|
71
71
|
this.logger.log('[INFO-CONTENT-COMP] initialize params: ', params);
|
|
72
72
|
this.conversationWith = params.get('IDConv');
|
|
73
|
-
this.conversationWithFullname = params.get('FullNameConv');
|
|
74
|
-
this.conv_type = params.get('Convtype');
|
|
73
|
+
this.conversationWithFullname = decodeURIComponent(params.get('FullNameConv'));
|
|
74
|
+
this.conv_type = decodeURIComponent(params.get('Convtype'));
|
|
75
75
|
|
|
76
76
|
const conversationWith_segments = this.conversationWith.split('-');
|
|
77
77
|
|
|
@@ -151,27 +151,29 @@ export class InfoGroupComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
this.contactsService.loadContactDetail(key).pipe(takeUntil(this.unsubscribe$)).subscribe(user => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
154
|
+
if(user){
|
|
155
|
+
this.logger.log('InfoGroupComponent group detail loadContactDetail RES', user);
|
|
156
|
+
// this.logger.log('InfoGroupComponent group detail this.presenceService.BSIsOnline.value()', this.presenceService.BSIsOnline.getValue);
|
|
157
|
+
|
|
158
|
+
user.imageurl = this.imageRepoService.getImagePhotoUrl(key)
|
|
159
|
+
// this.member_array.push({ userid: user.uid, avatar: user.avatar, color: user.color, email: user.email, fullname: user.fullname, imageurl: user.imageurl, userOnline: isOnline })
|
|
160
|
+
var index = this.member_array.findIndex(m => m.userid === user.uid);
|
|
161
|
+
this.logger.log('InfoGroupComponent member_array first of push index', index);
|
|
162
|
+
this.logger.log('InfoGroupComponent member_array first of push', this.member_array);
|
|
163
|
+
if (index === -1) {
|
|
164
|
+
this.member_array.push(
|
|
165
|
+
{
|
|
166
|
+
userid: user.uid,
|
|
167
|
+
avatar: user.avatar,
|
|
168
|
+
color: user.color,
|
|
169
|
+
email: user.email,
|
|
170
|
+
fullname: user.fullname,
|
|
171
|
+
imageurl: user.imageurl,
|
|
172
|
+
userOnline: members_isonline_array[user.uid]['isSignin']
|
|
173
|
+
})
|
|
174
|
+
} else {
|
|
175
|
+
this.logger.log('InfoGroupComponent member already exist in member_array');
|
|
176
|
+
}
|
|
175
177
|
}
|
|
176
178
|
}, (error) => {
|
|
177
179
|
this.logger.error('InfoGroupComponent group detail loadContactDetail - ERROR ', error);
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<!-- <ion-icon name="file-tray-full-outline"></ion-icon> -->
|
|
35
35
|
</ion-button>
|
|
36
36
|
|
|
37
|
-
<ion-button *ngIf="writeto_btn" ion-button fill="clear" (click)="onOpenContactsDirectory($event)"
|
|
37
|
+
<ion-button *ngIf="writeto_btn && isVisibleCNT && roles?.[PERMISSIONS.LEADS_READ]" ion-button fill="clear" (click)="onOpenContactsDirectory($event)"
|
|
38
38
|
tooltip="{{translationMap?.get('ViewContactsList')}}" placement="bottom">
|
|
39
39
|
<ion-icon slot="icon-only" name="create-outline"></ion-icon>
|
|
40
40
|
<!-- <ion-icon slot="icon-only" name="people-outline"></ion-icon> -->
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PERMISSIONS } from 'src/app/utils/permissions.constants';
|
|
1
2
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'
|
|
2
3
|
import { ModalController } from '@ionic/angular'
|
|
3
4
|
import { EventsService } from 'src/app/services/events-service'
|
|
@@ -17,6 +18,8 @@ export class HeaderConversationsList implements OnInit {
|
|
|
17
18
|
@Input() sound_btn: string;
|
|
18
19
|
@Input() isMobile: boolean;
|
|
19
20
|
@Input() isVisibleTKT: boolean = true;
|
|
21
|
+
@Input() isVisibleCNT: boolean = true;;
|
|
22
|
+
@Input() roles: Array<string>;
|
|
20
23
|
@Output() onSoundChange = new EventEmitter<string>()
|
|
21
24
|
@Output() openContactsDirectory = new EventEmitter()
|
|
22
25
|
@Output() openProfileInfo = new EventEmitter()
|
|
@@ -24,6 +27,7 @@ export class HeaderConversationsList implements OnInit {
|
|
|
24
27
|
createTicketModal = null
|
|
25
28
|
public translationMap: Map<string, string>;
|
|
26
29
|
|
|
30
|
+
PERMISSIONS = PERMISSIONS;
|
|
27
31
|
constructor(
|
|
28
32
|
public events: EventsService,
|
|
29
33
|
public modalController: ModalController,
|
|
@@ -62,7 +66,7 @@ export class HeaderConversationsList implements OnInit {
|
|
|
62
66
|
// }
|
|
63
67
|
|
|
64
68
|
ngOnInit() {
|
|
65
|
-
|
|
69
|
+
console.log('DDP HEADER SUPPORT MODE ', this.roles)
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
// START @Output() //
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</div>
|
|
6
6
|
<div class="navbar-right">
|
|
7
7
|
<!-- test site -->
|
|
8
|
-
<ng-container *ngIf="project">
|
|
8
|
+
<ng-container *ngIf="project && roles?.[PERMISSIONS.SIMULATE_CONV]">
|
|
9
9
|
<button class="btn simulate-visitor-btn" (click)="testWidgetPage()">
|
|
10
10
|
<i class="material-icons">play_arrow</i>
|
|
11
11
|
<!-- {{translationsMap?.get('NAVBAR.SIMULATE_VISITOR')}} -->
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
</ng-container>
|
|
24
24
|
|
|
25
25
|
<!-- ------ PROJECTS DROPDOWN ------ -->
|
|
26
|
-
<ng-container *ngIf="project">
|
|
26
|
+
<ng-container *ngIf="project && roles?.[PERMISSIONS.CHANGE_PROJECT]">
|
|
27
27
|
<li>
|
|
28
|
-
<button class="btn dropdown-toggle project-dropdown" (click)="
|
|
28
|
+
<button class="btn dropdown-toggle project-dropdown" (click)="toggleProjectsDropdown()">
|
|
29
29
|
<span class="project-dropdown" style="text-transform: none"> {{ project?.id_project?.name }} </span>
|
|
30
30
|
<i class="material-icons" style="margin-right: 3px;">arrow_drop_down</i>
|
|
31
31
|
</button>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
</li>
|
|
50
50
|
|
|
51
51
|
<!-- ADD PROJECT -->
|
|
52
|
-
<li id="navbar_create_prjct" *ngIf="
|
|
52
|
+
<li id="navbar_create_prjct" *ngIf="isVisibleMT" (click)="onClickDropdownOption('addProject')" class="add-project">
|
|
53
53
|
<a>
|
|
54
54
|
<i class="material-icons">add_circle_outline </i>
|
|
55
55
|
{{translationsMap?.get('NAVBAR.ADD_PROJECT')}}
|
|
@@ -71,9 +71,22 @@
|
|
|
71
71
|
<!-- *ngFor="let prjct of projects?.slice().reverse() | slice:0:5; let i=index" -->
|
|
72
72
|
<li *ngFor="let prjct of projects?.slice() | slice:0:5; let i=index" style="cursor: pointer">
|
|
73
73
|
<a (click)="goToHome(prjct?.id_project?._id, prjct?.id_project?.name)"
|
|
74
|
-
[ngClass]="{'li-selected' : prjct?.id_project?._id === project?.id_project?.id }"
|
|
75
|
-
|
|
76
|
-
<span>
|
|
74
|
+
[ngClass]="{'li-selected' : prjct?.id_project?._id === project?.id_project?.id }"
|
|
75
|
+
class="project-item-row">
|
|
76
|
+
<span class="project-item-name">{{ prjct?.id_project?.name }}</span>
|
|
77
|
+
<span class="project-item-status project-item-status-wrapper"
|
|
78
|
+
[attr.title]="translationsMap?.get(prjct?.teammateStatus?.label) || prjct?.teammateStatus?.name"
|
|
79
|
+
(click)="toggleStatusDropdown($event, prjct)">
|
|
80
|
+
<img style="width: 15px; height: 15px; position: relative; top: 1px; cursor: pointer;" height="15" width="15" [src]="prjct?.teammateStatus?.avatar" />
|
|
81
|
+
<div class="status-dropdown status-dropdown-fixed" *ngIf="openStatusDropdownProjectId === prjct?.id_project?._id" (click)="$event.stopPropagation()"
|
|
82
|
+
[style.top.px]="statusDropdownPosition.top" [style.right.px]="statusDropdownPosition.right">
|
|
83
|
+
<div class="status-dropdown-option" *ngFor="let status of TEAMMATE_STATUS"
|
|
84
|
+
(click)="$event.stopPropagation(); onChangeProjectStatus(prjct, status.id)">
|
|
85
|
+
<img style="width: 15px; height: 15px; margin-right: 6px;" [src]="status.avatar" />
|
|
86
|
+
<span>{{ translationsMap?.get(status.label) || status.name }}</span>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</span>
|
|
77
90
|
</a>
|
|
78
91
|
</li>
|
|
79
92
|
|
|
@@ -85,8 +98,21 @@
|
|
|
85
98
|
|
|
86
99
|
<!-- *ngFor="let prjct of projects?.slice().reverse() | slice:5:10; let i=index" -->
|
|
87
100
|
<li *ngFor="let prjct of projects?.slice() | slice:5:10; let i=index" style="cursor: pointer">
|
|
88
|
-
<a (click)="goToHome(prjct?.id_project?._id, prjct?.id_project?.name)">
|
|
89
|
-
{{ prjct?.id_project?.name }}
|
|
101
|
+
<a (click)="goToHome(prjct?.id_project?._id, prjct?.id_project?.name)" class="project-item-row">
|
|
102
|
+
<span class="project-item-name">{{ prjct?.id_project?.name }}</span>
|
|
103
|
+
<span class="project-item-status project-item-status-wrapper"
|
|
104
|
+
[attr.title]="translationsMap?.get(prjct?.teammateStatus?.label) || prjct?.teammateStatus?.name"
|
|
105
|
+
(click)="toggleStatusDropdown($event, prjct)">
|
|
106
|
+
<img style="width: 15px; height: 15px; position: relative; top: 1px; cursor: pointer;" height="15" width="15" [src]="prjct?.teammateStatus?.avatar" />
|
|
107
|
+
<div class="status-dropdown status-dropdown-fixed" *ngIf="openStatusDropdownProjectId === prjct?.id_project?._id" (click)="$event.stopPropagation()"
|
|
108
|
+
[style.top.px]="statusDropdownPosition.top" [style.right.px]="statusDropdownPosition.right">
|
|
109
|
+
<div class="status-dropdown-option" *ngFor="let status of TEAMMATE_STATUS"
|
|
110
|
+
(click)="$event.stopPropagation(); onChangeProjectStatus(prjct, status.id)">
|
|
111
|
+
<img style="width: 15px; height: 15px; margin-right: 6px;" [src]="status.avatar" />
|
|
112
|
+
<span>{{ translationsMap?.get(status.label) || status.name }}</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</span>
|
|
90
116
|
</a>
|
|
91
117
|
</li>
|
|
92
118
|
</ng-container>
|
|
@@ -204,6 +204,70 @@ li{
|
|
|
204
204
|
color: var(--dropdown-menu-hover-color);
|
|
205
205
|
box-shadow: 0 12px 20px -10px rgba(var(--dropdown-menu-hover-color), 0.28), 0 4px 20px 0 rgba(0, 0, 0, 0.12), 0 7px 8px -5px rgba(var(--dropdown-menu-hover-color), 0.2);
|
|
206
206
|
}
|
|
207
|
+
|
|
208
|
+
&.project-item-row {
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
justify-content: space-between;
|
|
212
|
+
gap: 8px;
|
|
213
|
+
|
|
214
|
+
.project-item-name {
|
|
215
|
+
flex: 1;
|
|
216
|
+
min-width: 0;
|
|
217
|
+
text-align: left;
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
text-overflow: ellipsis;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.project-item-status {
|
|
223
|
+
flex: 0 0 10%;
|
|
224
|
+
display: flex;
|
|
225
|
+
justify-content: flex-end;
|
|
226
|
+
align-items: center;
|
|
227
|
+
|
|
228
|
+
&.project-item-status-wrapper {
|
|
229
|
+
position: relative;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.status-dropdown {
|
|
233
|
+
position: absolute;
|
|
234
|
+
right: 100%;
|
|
235
|
+
top: 50%;
|
|
236
|
+
transform: translateY(-50%);
|
|
237
|
+
margin-right: 4px;
|
|
238
|
+
min-width: 140px;
|
|
239
|
+
padding: 4px 0;
|
|
240
|
+
background-color: var(--dropdown-menu-background);
|
|
241
|
+
border-radius: 3px;
|
|
242
|
+
box-shadow: 0 2px 5px 0 rgb(0, 0, 0, 0.26);
|
|
243
|
+
z-index: 1001;
|
|
244
|
+
list-style: none;
|
|
245
|
+
|
|
246
|
+
&.status-dropdown-fixed {
|
|
247
|
+
position: fixed;
|
|
248
|
+
right: auto;
|
|
249
|
+
left: auto;
|
|
250
|
+
margin-right: 0;
|
|
251
|
+
transform: translateY(-50%);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.status-dropdown-option {
|
|
255
|
+
display: flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
padding: 8px 16px;
|
|
258
|
+
font-size: 13px;
|
|
259
|
+
color: var(--dropdown-menu-color);
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
white-space: nowrap;
|
|
262
|
+
|
|
263
|
+
&:hover {
|
|
264
|
+
background-color: var(--dropdown-menu-hover-background);
|
|
265
|
+
color: var(--dropdown-menu-hover-color);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
207
271
|
}
|
|
208
272
|
|
|
209
273
|
|
|
@@ -7,6 +7,13 @@ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service
|
|
|
7
7
|
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
8
8
|
import { Project } from 'src/chat21-core/models/projects';
|
|
9
9
|
import { CustomTranslateService } from 'src/chat21-core/providers/custom-translate.service';
|
|
10
|
+
import { getUserStatusFromProjectUser } from 'src/chat21-core/utils/utils';
|
|
11
|
+
import { TEAMMATE_STATUS } from 'src/chat21-core/utils/constants';
|
|
12
|
+
import { WebsocketService } from 'src/app/services/websocket/websocket.service';
|
|
13
|
+
import { ProjectUser } from 'src/chat21-core/models/project_user';
|
|
14
|
+
import { ProjectUsersService } from 'src/app/services/project_users/project-users.service';
|
|
15
|
+
import { PERMISSIONS } from 'src/app/utils/permissions.constants';
|
|
16
|
+
import { getOSCode, hasRole } from 'src/app/utils/utils';
|
|
10
17
|
|
|
11
18
|
@Component({
|
|
12
19
|
selector: 'app-navbar',
|
|
@@ -21,24 +28,31 @@ export class NavbarComponent implements OnInit {
|
|
|
21
28
|
private logger: LoggerService = LoggerInstance.getInstance();
|
|
22
29
|
private tiledeskToken: string;
|
|
23
30
|
|
|
24
|
-
public projects:
|
|
31
|
+
public projects: ProjectUser[] = [];
|
|
25
32
|
public project: any = [];
|
|
26
33
|
private USER_ROLE: string;
|
|
27
34
|
|
|
28
35
|
public translationsMap: Map<string, string> = new Map();
|
|
29
36
|
|
|
30
37
|
public openDropdownProjects: boolean = false
|
|
38
|
+
public openStatusDropdownProjectId: string | null = null
|
|
39
|
+
public TEAMMATE_STATUS = TEAMMATE_STATUS
|
|
31
40
|
private public_Key: string;
|
|
32
41
|
public isVisible: boolean;
|
|
33
|
-
public
|
|
42
|
+
public isVisibleMT: boolean;
|
|
34
43
|
|
|
44
|
+
public projectUser: ProjectUser;
|
|
45
|
+
public roles: { [key: string]: boolean }
|
|
46
|
+
PERMISSIONS = PERMISSIONS;
|
|
35
47
|
constructor(
|
|
36
48
|
private projectService: ProjectService,
|
|
49
|
+
public projectUsersService: ProjectUsersService,
|
|
37
50
|
private tiledeskAuthService: TiledeskAuthService,
|
|
38
51
|
private appConfigProvider: AppConfigProvider,
|
|
39
52
|
private translateService: CustomTranslateService,
|
|
40
53
|
private events: EventsService,
|
|
41
54
|
private cdref: ChangeDetectorRef,
|
|
55
|
+
private wsService: WebsocketService,
|
|
42
56
|
) { }
|
|
43
57
|
|
|
44
58
|
ngOnInit() {
|
|
@@ -60,7 +74,10 @@ export class NavbarComponent implements OnInit {
|
|
|
60
74
|
"NAVBAR.ADD_PROJECT",
|
|
61
75
|
"NAVBAR.RECENT_PROJECTS",
|
|
62
76
|
"NAVBAR.OTHER_PROJECTS",
|
|
63
|
-
"LABEL_CHAT"
|
|
77
|
+
"LABEL_CHAT",
|
|
78
|
+
"LABEL_AVAILABLE",
|
|
79
|
+
"LABEL_NOT_AVAILABLE",
|
|
80
|
+
"LABEL_INACTIVE"
|
|
64
81
|
]
|
|
65
82
|
|
|
66
83
|
this.translationsMap = this.translateService.translateLanguage(keys)
|
|
@@ -78,14 +95,17 @@ export class NavbarComponent implements OnInit {
|
|
|
78
95
|
|
|
79
96
|
getProjects() {
|
|
80
97
|
this.logger.log('[NAVBAR] calling getProjects ... ');
|
|
81
|
-
this.projectService.getProjects().subscribe((projects:
|
|
98
|
+
this.projectService.getProjects().subscribe((projects: ProjectUser[]) => {
|
|
82
99
|
this.logger.log('[NAVBAR] getProjects PROJECTS ', projects);
|
|
83
100
|
if (projects) {
|
|
84
101
|
// this.projects = projects;
|
|
85
|
-
this.projects = projects.filter((project:
|
|
102
|
+
this.projects = projects.filter((project: ProjectUser) => {
|
|
86
103
|
// this.logger.log('[NAVBAR] getProjects PROJECTS status ', project.id_project.status);
|
|
87
104
|
return project.id_project.status === 100;
|
|
88
105
|
});
|
|
106
|
+
this.projects.forEach((project: ProjectUser) => {
|
|
107
|
+
project.teammateStatus = getUserStatusFromProjectUser(project as any);
|
|
108
|
+
});
|
|
89
109
|
this.logger.log('[NAVBAR] getProjects this.projects ', this.projects);
|
|
90
110
|
}
|
|
91
111
|
}, (error) => {
|
|
@@ -96,11 +116,14 @@ export class NavbarComponent implements OnInit {
|
|
|
96
116
|
}
|
|
97
117
|
|
|
98
118
|
getStoredProjectAndUserRole() {
|
|
99
|
-
this.events.subscribe('storage:last_project',project =>{
|
|
119
|
+
this.events.subscribe('storage:last_project',async (project) =>{
|
|
100
120
|
this.logger.log('[NAVBAR] stored_project ', project)
|
|
101
121
|
if (project && project !== 'undefined') {
|
|
102
122
|
this.project = project;
|
|
103
123
|
this.USER_ROLE = project.role;
|
|
124
|
+
this.projectUser = await this.projectUsersService.getProjectUserByProjectId(project.id_project.id)
|
|
125
|
+
this.roles = this.checkRoles()
|
|
126
|
+
this.logger.log('[SIDEBAR] roles ', this.roles)
|
|
104
127
|
}
|
|
105
128
|
})
|
|
106
129
|
}
|
|
@@ -108,44 +131,24 @@ export class NavbarComponent implements OnInit {
|
|
|
108
131
|
getOSCODE() {
|
|
109
132
|
this.public_Key = this.appConfigProvider.getConfig().t2y12PruGU9wUtEGzBJfolMIgK;
|
|
110
133
|
this.logger.log('[NAVBAR] AppConfigService getAppConfig public_Key', this.public_Key)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - pay key&value', pay);
|
|
122
|
-
if (pay[1] === "F") {
|
|
123
|
-
this.isVisible = false;
|
|
124
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - pay isVisible', this.isVisible);
|
|
125
|
-
} else {
|
|
126
|
-
this.isVisible = true;
|
|
127
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - pay isVisible', this.isVisible);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (key.includes("MTT")) {
|
|
132
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - key', key);
|
|
133
|
-
let mt = key.split(":");
|
|
134
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - mt key&value', mt);
|
|
135
|
-
if (mt[1] === "F") {
|
|
136
|
-
this.MT = false;
|
|
137
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - mt is', this.MT);
|
|
138
|
-
} else {
|
|
139
|
-
this.MT = true;
|
|
140
|
-
// this.logger.log('PUBLIC-KEY (Navbar) - mt is', this.MT);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
});
|
|
134
|
+
|
|
135
|
+
this.isVisibleMT = getOSCode("MTT", this.public_Key);
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
checkRoles(): { [key: string]: boolean } {
|
|
140
|
+
const permissionKeys = [
|
|
141
|
+
'CHANGE_PROJECT',
|
|
142
|
+
'SIMULATE_CONV',
|
|
143
|
+
] as const;
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
const roles: { [key: string]: boolean } = {};
|
|
146
|
+
for (const key of permissionKeys) {
|
|
147
|
+
const permission = PERMISSIONS[key];
|
|
148
|
+
roles[permission] = hasRole(this.projectUser, permission);
|
|
148
149
|
}
|
|
150
|
+
|
|
151
|
+
return roles;
|
|
149
152
|
|
|
150
153
|
}
|
|
151
154
|
|
|
@@ -177,6 +180,61 @@ export class NavbarComponent implements OnInit {
|
|
|
177
180
|
window.open(url, '_blank');
|
|
178
181
|
}
|
|
179
182
|
|
|
183
|
+
toggleProjectsDropdown() {
|
|
184
|
+
this.openDropdownProjects = !this.openDropdownProjects
|
|
185
|
+
if (!this.openDropdownProjects) {
|
|
186
|
+
this.openStatusDropdownProjectId = null
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
statusDropdownPosition = { top: 0, right: 0 }
|
|
191
|
+
|
|
192
|
+
toggleStatusDropdown(event: Event, prjct: any) {
|
|
193
|
+
event.stopPropagation()
|
|
194
|
+
event.preventDefault()
|
|
195
|
+
const projectId = prjct?.id_project?._id
|
|
196
|
+
const isOpening = this.openStatusDropdownProjectId !== projectId
|
|
197
|
+
if (isOpening) {
|
|
198
|
+
const el = event.currentTarget as HTMLElement
|
|
199
|
+
const rect = el.getBoundingClientRect()
|
|
200
|
+
this.statusDropdownPosition = {
|
|
201
|
+
top: rect.top + rect.height / 2,
|
|
202
|
+
right: window.innerWidth - rect.left + 4
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
this.openStatusDropdownProjectId = this.openStatusDropdownProjectId === projectId ? null : projectId
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
onChangeProjectStatus(projectUser: ProjectUser, selectedStatusID: any) {
|
|
209
|
+
// TODO: implementare aggiornamento status progetto
|
|
210
|
+
this.logger.log('[NAVBAR] onChangeProjectStatus placeholder', projectUser, selectedStatusID)
|
|
211
|
+
this.openStatusDropdownProjectId = null
|
|
212
|
+
|
|
213
|
+
let IS_AVAILABLE = null
|
|
214
|
+
let profilestatus = ''
|
|
215
|
+
if (selectedStatusID === 1) {
|
|
216
|
+
IS_AVAILABLE = true
|
|
217
|
+
} else if (selectedStatusID === 2) {
|
|
218
|
+
IS_AVAILABLE = false
|
|
219
|
+
} else if (selectedStatusID === 3) {
|
|
220
|
+
IS_AVAILABLE = false
|
|
221
|
+
profilestatus = 'inactive'
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
this.wsService.updateCurrentUserAvailability(this.tiledeskToken, projectUser.id_project._id, IS_AVAILABLE, profilestatus).subscribe((projectUserUpdated: any) => {
|
|
225
|
+
|
|
226
|
+
this.logger.log('[NAVBAR] - PROJECT-USER UPDATED ', projectUser)
|
|
227
|
+
this.projects.find(p => p.id_project._id === projectUser.id_project._id).teammateStatus = getUserStatusFromProjectUser(projectUserUpdated as any);
|
|
228
|
+
|
|
229
|
+
}, (error) => {
|
|
230
|
+
this.logger.error('[NAVBAR] - PROJECT-USER UPDATED - ERROR ', error);
|
|
231
|
+
|
|
232
|
+
}, () => {
|
|
233
|
+
this.logger.log('[NAVBAR] - PROJECT-USER UPDATED * COMPLETE *');
|
|
234
|
+
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
180
238
|
goToHome(id_project: string, project_name: string,) {
|
|
181
239
|
// this.logger.log('!NAVBAR goToHome prjct ', prjct)
|
|
182
240
|
this.logger.log('[NAVBAR] goToHome id_project ', id_project, 'project_name', project_name)
|