@chat21/chat21-ionic 3.0.76-rc.1 → 3.0.76-rc.2
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 +5 -0
- package/package.json +1 -1
- package/src/app/chatlib/conversation-detail/conversation-content/conversation-content.component.html +1 -1
- package/src/app/chatlib/conversation-detail/conversation-content/conversation-content.component.ts +15 -1
- package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.html +1 -1
- package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.scss +9 -2
- package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.html +8 -1
- package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.scss +5 -3
- package/src/app/components/canned-response/canned-response.component.html +26 -0
- package/src/app/components/canned-response/canned-response.component.scss +141 -0
- package/src/app/components/canned-response/canned-response.component.spec.ts +24 -0
- package/src/app/components/canned-response/canned-response.component.ts +281 -0
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +9 -8
- package/src/app/pages/conversation-detail/conversation-detail.module.ts +2 -0
- package/src/app/pages/conversation-detail/conversation-detail.page.html +25 -12
- package/src/app/pages/conversation-detail/conversation-detail.page.scss +14 -29
- package/src/app/pages/conversation-detail/conversation-detail.page.ts +80 -357
- package/src/global.scss +0 -137
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# chat21-ionic ver 3.0
|
|
2
2
|
|
|
3
|
+
### 3.0.76-rc.2
|
|
4
|
+
- added: canned component to manage canned responses
|
|
5
|
+
- bug-fixed: if more than oe '/' is present in message-text-area and a canned is selected, replace canned text on the last '/' character in the message string
|
|
6
|
+
- bug-fixed: close canned component if user click again on canned-icon-button
|
|
7
|
+
|
|
3
8
|
### 3.0.76-rc.1
|
|
4
9
|
- changed: senderFullName in list conversation for guest users with guest#uuid[0..5]
|
|
5
10
|
- added: multi-language to MEMBER_LEFT_GROUP and LEAD_UPDATED info messages
|
package/package.json
CHANGED
package/src/app/chatlib/conversation-detail/conversation-content/conversation-content.component.ts
CHANGED
|
@@ -256,7 +256,21 @@ export class ConversationContentComponent implements OnInit {
|
|
|
256
256
|
return false;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
isSameSender(senderId, index):boolean{
|
|
260
|
+
if(senderId && this.messages[index - 1] && (senderId === this.messages[index - 1].sender)){
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
isFirstMessage(senderId, index):boolean{
|
|
267
|
+
if(senderId && index == 0 && this.messages[index] && (this.messages[index] !== senderId)){
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
hideOutsideElements() {
|
|
260
274
|
this.onMenuOptionShow.emit(false)
|
|
261
275
|
}
|
|
262
276
|
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
</div>
|
|
103
103
|
|
|
104
104
|
<!-- message RECIPIENT:: -->
|
|
105
|
-
<div role="messaggio" *ngIf="messageType(MESSAGE_TYPE_OTHERS, message) && isChannelTypeGroup(channelType)"
|
|
105
|
+
<div role="messaggio" *ngIf="messageType(MESSAGE_TYPE_OTHERS, message) && isChannelTypeGroup(channelType) && !isSameSender(message?.sender, i)"
|
|
106
106
|
class="message_sender_fullname">
|
|
107
107
|
{{message.sender_fullname}}
|
|
108
108
|
</div>
|
|
@@ -245,15 +245,22 @@ ion-item {
|
|
|
245
245
|
// left: -26px;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
:host .base_receive .msg_receive ::ng-deep div > div > ion-button {
|
|
248
|
+
:host .base_receive .msg_receive ::ng-deep div > div > div > ion-button.canned {
|
|
249
249
|
display: none;
|
|
250
250
|
position: absolute;
|
|
251
251
|
top: -3px;
|
|
252
252
|
right: -31px;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
:host .base_receive .msg_receive ::ng-deep div > div > div >ion-button.emoji {
|
|
256
|
+
display: none;
|
|
257
|
+
position: absolute;
|
|
258
|
+
top: -3px;
|
|
259
|
+
right: -51px;
|
|
260
|
+
}
|
|
261
|
+
|
|
255
262
|
// :host .base_receive .msg_receive:hover ::ng-deep div > div > ion-button {
|
|
256
|
-
:host .base_receive:hover .msg_receive ::ng-deep div > div > ion-button {
|
|
263
|
+
:host .base_receive:hover .msg_receive ::ng-deep div > div > div > ion-button {
|
|
257
264
|
display: block;
|
|
258
265
|
// position: absolute;
|
|
259
266
|
// top: -11px;
|
package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.html
CHANGED
|
@@ -61,12 +61,19 @@
|
|
|
61
61
|
</chat-html>
|
|
62
62
|
|
|
63
63
|
<ng-container *ngIf="areVisibleCAR && supportMode">
|
|
64
|
-
<ion-button shape="round" size="small" class="btn-add-msg
|
|
64
|
+
<ion-button shape="round" size="small" class="btn-add-msg canned" ion-button fill="clear"
|
|
65
65
|
(click)="presentCreateCannedResponseModal()" tooltip="{{addAsCannedResponseTooltipText}}"
|
|
66
66
|
[options]="tooltipOptions" placement="bottom">
|
|
67
67
|
<ion-icon slot="icon-only" name="flash-outline" style="font-size: 1em;"> </ion-icon>
|
|
68
68
|
</ion-button>
|
|
69
69
|
</ng-container>
|
|
70
|
+
<!-- <ng-container *ngIf="supportMode">
|
|
71
|
+
<ion-button shape="round" size="small" class="btn-add-msg emoji" ion-button fill="clear"
|
|
72
|
+
(click)="presentEmojiiModal()" tooltip="{{addAsCannedResponseTooltipText}}"
|
|
73
|
+
[options]="tooltipOptions" placement="bottom">
|
|
74
|
+
<ion-icon slot="icon-only" name="happy-outline" style="font-size: 1em;"> </ion-icon>
|
|
75
|
+
</ion-button>
|
|
76
|
+
</ng-container> -->
|
|
70
77
|
</div>
|
|
71
78
|
</div>
|
|
72
79
|
|
package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.scss
CHANGED
|
@@ -48,13 +48,15 @@
|
|
|
48
48
|
|
|
49
49
|
}
|
|
50
50
|
// > .button-native
|
|
51
|
-
.btn-add-msg
|
|
52
|
-
// padding-left: 5px ;
|
|
53
|
-
// padding-right: 5px ;
|
|
51
|
+
.btn-add-msg {
|
|
54
52
|
border-radius: 50%;
|
|
55
53
|
--padding-end: 7px;
|
|
56
54
|
--padding-start: 7px;
|
|
57
55
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.6);
|
|
56
|
+
|
|
57
|
+
ion-icon{
|
|
58
|
+
font-size: 1.2em;
|
|
59
|
+
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<div id="canned">
|
|
2
|
+
<ion-list class="canned-list" *ngIf="tagsCannedFilter.length > 0">
|
|
3
|
+
<ion-item button="true" [ngClass]="{'is_active_item': i == arrowkeyLocation}" lines="none"
|
|
4
|
+
class="canned-item no-ripple border" id="{{'canned-item_'+ i }}"
|
|
5
|
+
*ngFor="let canned of tagsCannedFilter; let i = index;"
|
|
6
|
+
(click)="onClickCannedFN(canned, $event)">
|
|
7
|
+
<div class="cannedContent">
|
|
8
|
+
<ion-input [(ngModel)]="canned.title" class="title" id="{{'titleCanned_'+canned._id}}" [disabled]="canned.disabled"></ion-input>
|
|
9
|
+
<ion-input [(ngModel)]="canned.text" *ngIf="canned.text" class="text" [disabled]="canned.disabled"></ion-input>
|
|
10
|
+
</div>
|
|
11
|
+
<ion-icon class="canned-item-icon" name="checkmark-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && !canned.disabled" (click)="onConfirmEditCanned(canned, $event)"></ion-icon>
|
|
12
|
+
<ion-icon class="canned-item-icon" name="pencil-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && canned.disabled" (click)="onEditCanned(canned, $event)"></ion-icon>
|
|
13
|
+
<ion-icon class="canned-item-icon" name="trash-bin-outline" slot=end *ngIf="canned.createdBy === loggedUser.uid" (click)="onDeleteCanned(canned, $event)"></ion-icon>
|
|
14
|
+
</ion-item>
|
|
15
|
+
<ion-item class="canned-item add-canned-response-wpr" button="true" lines="none" (click)="onClickAddCannedResponseFN()">
|
|
16
|
+
<ion-icon class="add-canned-response-icon" name="flash-outline"></ion-icon>
|
|
17
|
+
<span class="add-canned-response-add-icon">+</span>
|
|
18
|
+
<label class="add-canned-response-label" >{{translationMap?.get('AddNewCannedResponse')}}</label>
|
|
19
|
+
</ion-item>
|
|
20
|
+
</ion-list>
|
|
21
|
+
<!-- <ion-list class="canned-list" *ngIf="tagsCannedFilter.length === 0 && HIDE_CANNED_RESPONSES === false">
|
|
22
|
+
<ion-item button="true" >
|
|
23
|
+
There are no canned responses available
|
|
24
|
+
</ion-item>
|
|
25
|
+
</ion-list> -->
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
.canned-item.add-canned-response-wpr:hover > span {
|
|
2
|
+
color: #1877f2;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.canned-item.add-canned-response-wpr:hover > ion-icon {
|
|
6
|
+
color: #1877f2;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.canned-item.add-canned-response-wpr:hover > label {
|
|
10
|
+
color: #1877f2;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.is_active_item {
|
|
14
|
+
// background-color: #eaf1fd!important;
|
|
15
|
+
--background: #eaf1fd !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
.header {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: row;
|
|
23
|
+
-webkit-box-pack: start;
|
|
24
|
+
justify-content: flex-end;
|
|
25
|
+
-webkit-box-align: center;
|
|
26
|
+
align-items: center;
|
|
27
|
+
border-bottom: 1px solid rgb(239, 242, 246);
|
|
28
|
+
padding: 0px 10px;
|
|
29
|
+
background: white;
|
|
30
|
+
width: 100%;
|
|
31
|
+
box-shadow: rgb(0, 27, 71, .24) 0px 8px 20px;
|
|
32
|
+
.canned-response-icon-header{
|
|
33
|
+
color: #3880ff !important;
|
|
34
|
+
font-size: 1.4em;
|
|
35
|
+
margin: 8px 5px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.add-canned-response-icon {
|
|
41
|
+
color: #b3bfd0;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
font-size: 18px;
|
|
44
|
+
}
|
|
45
|
+
.add-canned-response-label {
|
|
46
|
+
color: #b3bfd0;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
}
|
|
49
|
+
.add-canned-response-add-icon {
|
|
50
|
+
color: #b3bfd0;
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
position: relative;
|
|
53
|
+
top: 4px;
|
|
54
|
+
left: -6px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.canned-list {
|
|
58
|
+
// position: absolute;
|
|
59
|
+
// bottom: 0;
|
|
60
|
+
background-color: white !important;
|
|
61
|
+
width: 100%;
|
|
62
|
+
max-height: 310px;
|
|
63
|
+
overflow-y: auto;
|
|
64
|
+
// padding: 10px 0;
|
|
65
|
+
// margin: 0;
|
|
66
|
+
margin-bottom: 1px;
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
line-height: 1.42857143;
|
|
69
|
+
color: #080f1a;
|
|
70
|
+
box-sizing: border-box;
|
|
71
|
+
-webkit-font-smoothing: antialiased;
|
|
72
|
+
// list-style: none;
|
|
73
|
+
z-index: 999999;
|
|
74
|
+
|
|
75
|
+
.cannedContent{
|
|
76
|
+
width: 100%;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
ion-input {
|
|
80
|
+
--padding-bottom: 0px;
|
|
81
|
+
--padding-top: 0px;
|
|
82
|
+
&.text{
|
|
83
|
+
font-style: italic;
|
|
84
|
+
}
|
|
85
|
+
&.title {
|
|
86
|
+
font-weight: 500;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
.native-input[disabled] {
|
|
90
|
+
opacity: 10 !important;
|
|
91
|
+
}
|
|
92
|
+
ion-icon {
|
|
93
|
+
zoom: 0.7;
|
|
94
|
+
}
|
|
95
|
+
.no-ripple {
|
|
96
|
+
--ripple-color: transparent;
|
|
97
|
+
--background-activated: transparent;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.border{
|
|
101
|
+
border-bottom: 1px dashed rgb(211, 219, 229) !important;
|
|
102
|
+
margin: 0px 4px
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.canned-item {
|
|
109
|
+
-webkit-tap-highlight-color: transparent;
|
|
110
|
+
font-family: Lato, sans-serif;
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
line-height: 1.42857143;
|
|
113
|
+
list-style: none;
|
|
114
|
+
box-sizing: border-box;
|
|
115
|
+
-webkit-font-smoothing: antialiased;
|
|
116
|
+
// margin: 0 10px;
|
|
117
|
+
position: relative;
|
|
118
|
+
outline: none;
|
|
119
|
+
color: #434a54;
|
|
120
|
+
// padding: 10px;
|
|
121
|
+
padding: 5px;
|
|
122
|
+
width: auto;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
// .item-inner{
|
|
125
|
+
// border: none!important;
|
|
126
|
+
// }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ion-item {
|
|
130
|
+
--background-hover: #1877f2 !important;
|
|
131
|
+
|
|
132
|
+
.nocannedTitle {
|
|
133
|
+
color: #f44336;
|
|
134
|
+
}
|
|
135
|
+
.no-canned-available-text {
|
|
136
|
+
color: #1877f2 !important;
|
|
137
|
+
}
|
|
138
|
+
.no-canned-available-text:hover {
|
|
139
|
+
text-decoration: underline;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { IonicModule } from '@ionic/angular';
|
|
3
|
+
|
|
4
|
+
import { CannedResponseComponent } from './canned-response.component';
|
|
5
|
+
|
|
6
|
+
describe('CannedResponseComponent', () => {
|
|
7
|
+
let component: CannedResponseComponent;
|
|
8
|
+
let fixture: ComponentFixture<CannedResponseComponent>;
|
|
9
|
+
|
|
10
|
+
beforeEach(async(() => {
|
|
11
|
+
TestBed.configureTestingModule({
|
|
12
|
+
declarations: [ CannedResponseComponent ],
|
|
13
|
+
imports: [IonicModule.forRoot()]
|
|
14
|
+
}).compileComponents();
|
|
15
|
+
|
|
16
|
+
fixture = TestBed.createComponent(CannedResponseComponent);
|
|
17
|
+
component = fixture.componentInstance;
|
|
18
|
+
fixture.detectChanges();
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
it('should create', () => {
|
|
22
|
+
expect(component).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { Component, Input, OnInit, SimpleChange, ElementRef, Output, EventEmitter, HostListener } from '@angular/core';
|
|
2
|
+
import { CreateCannedResponsePage } from 'src/app/pages/create-canned-response/create-canned-response.page';
|
|
3
|
+
import { CannedResponsesService } from 'src/app/services/canned-responses/canned-responses.service';
|
|
4
|
+
import { TiledeskService } from 'src/app/services/tiledesk/tiledesk.service';
|
|
5
|
+
import { UserModel } from 'src/chat21-core/models/user';
|
|
6
|
+
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
7
|
+
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
8
|
+
import { TiledeskAuthService } from 'src/chat21-core/providers/tiledesk/tiledesk-auth.service';
|
|
9
|
+
import { compareValues, htmlEntities } from 'src/chat21-core/utils/utils';
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'app-canned-response',
|
|
13
|
+
templateUrl: './canned-response.component.html',
|
|
14
|
+
styleUrls: ['./canned-response.component.scss'],
|
|
15
|
+
})
|
|
16
|
+
export class CannedResponseComponent implements OnInit {
|
|
17
|
+
|
|
18
|
+
// @Input() tagsCannedFilter: any = []
|
|
19
|
+
@Input() conversationWith: string;
|
|
20
|
+
@Input() conversationWithFullname: string;
|
|
21
|
+
@Input() currentString: string;
|
|
22
|
+
@Input() translationMap: Map<string, string>;
|
|
23
|
+
@Output() onLoadedCannedResponses = new EventEmitter<[any]>();
|
|
24
|
+
@Output() onClickCanned = new EventEmitter<any>();
|
|
25
|
+
@Output() onClickAddCannedResponse = new EventEmitter();
|
|
26
|
+
public loggedUser: UserModel
|
|
27
|
+
|
|
28
|
+
public tagsCanned: any = []
|
|
29
|
+
public tagsCannedCount: number
|
|
30
|
+
public tagsCannedFilter: any = []
|
|
31
|
+
|
|
32
|
+
public arrowkeyLocation = -1
|
|
33
|
+
|
|
34
|
+
private logger: LoggerService = LoggerInstance.getInstance();
|
|
35
|
+
constructor(
|
|
36
|
+
public tiledeskAuthService: TiledeskAuthService,
|
|
37
|
+
public tiledeskService: TiledeskService,
|
|
38
|
+
public cannedResponsesService: CannedResponsesService,
|
|
39
|
+
public el: ElementRef
|
|
40
|
+
) { }
|
|
41
|
+
|
|
42
|
+
ngOnInit() {
|
|
43
|
+
this.loggedUser = this.tiledeskAuthService.getCurrentUser()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
ngOnChanges(changes: SimpleChange){
|
|
47
|
+
this.logger.debug('[CANNED] - loadTagsCanned strSearch ', this.currentString)
|
|
48
|
+
if(this.currentString !== undefined){
|
|
49
|
+
this.loadTagsCanned(this.currentString, this.conversationWith)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ----------------------------------------------------------
|
|
54
|
+
// @ CANNED RESPONSES methods
|
|
55
|
+
// ----------------------------------------------------------
|
|
56
|
+
loadTagsCanned(strSearch, conversationWith) {
|
|
57
|
+
this.logger.log('[CANNED] - loadTagsCanned strSearch ', strSearch)
|
|
58
|
+
this.logger.log('[CANNED] - loadTagsCanned conversationWith ', conversationWith)
|
|
59
|
+
|
|
60
|
+
const conversationWith_segments = conversationWith.split('-')
|
|
61
|
+
// Removes the last element of the array if is = to the separator
|
|
62
|
+
if (conversationWith_segments[conversationWith_segments.length - 1] === '') {
|
|
63
|
+
conversationWith_segments.pop()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.logger.log('[CANNED] - loadTagsCanned conversationWith_segments ', conversationWith_segments)
|
|
67
|
+
let projectId = ''
|
|
68
|
+
|
|
69
|
+
if (conversationWith_segments.length === 4) {
|
|
70
|
+
projectId = conversationWith_segments[2]
|
|
71
|
+
this.logger.log('[CANNED] - loadTagsCanned projectId ', projectId)
|
|
72
|
+
this.getAndShowCannedResponses(strSearch, projectId)
|
|
73
|
+
} else {
|
|
74
|
+
this.getProjectIdByConversationWith(strSearch, this.conversationWith)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getProjectIdByConversationWith(strSearch, conversationWith: string) {
|
|
79
|
+
const tiledeskToken = this.tiledeskAuthService.getTiledeskToken()
|
|
80
|
+
|
|
81
|
+
this.tiledeskService.getProjectIdByConvRecipient(tiledeskToken, conversationWith).subscribe((res) => {
|
|
82
|
+
this.logger.log('[CANNED] - loadTagsCanned - GET PROJECTID BY CONV RECIPIENT RES', res)
|
|
83
|
+
if (res) {
|
|
84
|
+
const projectId = res.id_project
|
|
85
|
+
this.logger.log('[CANNED] - loadTagsCanned - GET PROJECTID BY CONV RECIPIENT projectId ', projectId)
|
|
86
|
+
if (projectId) {
|
|
87
|
+
this.getAndShowCannedResponses(strSearch, projectId)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}, (error) => {
|
|
91
|
+
this.logger.error('[CANNED] - loadTagsCanned - GET PROJECTID BY CONV RECIPIENT - ERROR ', error)
|
|
92
|
+
}, () => {
|
|
93
|
+
this.logger.log('[CANNED] - loadTagsCanned - GET PROJECTID BY CONV RECIPIENT * COMPLETE *')
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getAndShowCannedResponses(strSearch, projectId) {
|
|
98
|
+
const tiledeskToken = this.tiledeskAuthService.getTiledeskToken()
|
|
99
|
+
this.logger.log('[CANNED] - loadTagsCanned tagsCanned.length', this.tagsCanned.length)
|
|
100
|
+
//if(this.tagsCanned.length <= 0 ){
|
|
101
|
+
this.tagsCanned = []
|
|
102
|
+
this.cannedResponsesService.getAll(tiledeskToken, projectId).subscribe((res) => {
|
|
103
|
+
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses RES', res)
|
|
104
|
+
|
|
105
|
+
this.tagsCanned = res
|
|
106
|
+
this.tagsCannedCount = res.length
|
|
107
|
+
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses tagsCannedCount', this.tagsCannedCount)
|
|
108
|
+
// if (this.HIDE_CANNED_RESPONSES === false) {
|
|
109
|
+
this.showTagsCanned(strSearch)
|
|
110
|
+
// }
|
|
111
|
+
}, (error) => {
|
|
112
|
+
this.logger.error('[CANNED] - loadTagsCanned getCannedResponses - ERROR ', error)
|
|
113
|
+
}, () => {
|
|
114
|
+
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses * COMPLETE *')
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
showTagsCanned(strSearch) {
|
|
119
|
+
this.logger.log('[CANNED] - showTagsCanned strSearch ', strSearch)
|
|
120
|
+
this.tagsCannedFilter = []
|
|
121
|
+
var tagsCannedClone = JSON.parse(JSON.stringify(this.tagsCanned))
|
|
122
|
+
this.logger.log('[CANNED] - showTagsCanned tagsCannedClone ', tagsCannedClone)
|
|
123
|
+
//this.logger.log("that.contacts lenght:: ", strSearch);
|
|
124
|
+
this.tagsCannedFilter = this.filterItems(tagsCannedClone, strSearch)
|
|
125
|
+
this.logger.log('[CANNED] - showTagsCanned tagsCannedFilter ', this.tagsCannedFilter)
|
|
126
|
+
|
|
127
|
+
this.tagsCannedFilter.sort(compareValues('title', 'asc'))
|
|
128
|
+
var strReplace = strSearch
|
|
129
|
+
if (strSearch.length > 0) {
|
|
130
|
+
strReplace = "<b class='highlight-search-string'>" + strSearch + '</b>'
|
|
131
|
+
}
|
|
132
|
+
// for (var i = 0; i < this.tagsCannedFilter.length; i++) {
|
|
133
|
+
// let text = htmlEntities(this.tagsCannedFilter[i].text);
|
|
134
|
+
// // const textCanned = "<div class='cannedText'>" + this.replacePlaceholderInCanned(this.tagsCannedFilter[i].text) + '</div>'
|
|
135
|
+
// const textCanned = "<div class='cannedText'>" + this.replacePlaceholderInCanned(text) + '</div>'
|
|
136
|
+
// let title = htmlEntities(this.tagsCannedFilter[i].title)
|
|
137
|
+
// // this.tagsCannedFilter[i].title = "<div class='cannedContent'><div class='cannedTitle'>" + this.tagsCannedFilter[i].title.toString().replace(strSearch, strReplace.trim()) + '</div>' + textCanned + '</div>'
|
|
138
|
+
// this.tagsCannedFilter[i].title = "<div class='cannedContent'><div class='cannedTitle'>" + title.toString().replace(strSearch, strReplace.trim()) + '</div>' + textCanned + '</div>'
|
|
139
|
+
// }
|
|
140
|
+
this.tagsCannedFilter.forEach(canned => {
|
|
141
|
+
canned.text = this.replacePlaceholderInCanned(canned.text);
|
|
142
|
+
canned.disabled = true
|
|
143
|
+
});
|
|
144
|
+
if (this.tagsCannedCount === 0) {
|
|
145
|
+
// const button = this.renderer.createElement('button');
|
|
146
|
+
// const buttonText = this.renderer.createText('Click me');
|
|
147
|
+
// this.renderer.appendChild(button, buttonText);
|
|
148
|
+
// console.log('[CANNED] - this.el.nativeElement ', this.el.nativeElement)
|
|
149
|
+
// this.renderer.listen(button, 'click', () => { alert('hi'); });
|
|
150
|
+
// let nocanned = {}
|
|
151
|
+
// if (this.USER_ROLE !== 'agent') {
|
|
152
|
+
const nocanned = {
|
|
153
|
+
// "<div class='cannedContent'><div class='cannedTitle nocannedTitle #noCannedTitle'>" + this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') + ".</div><div class='cannedText'>" + this.translationMap.get('TO_CREATE_THEM_GO_TO_THE_PROJECT') + '</div></div>'
|
|
154
|
+
// <div class='cannedText no-canned-available-text'>" + this.translationMap.get('AddNewCannedResponse') + '</div>
|
|
155
|
+
title: this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') ,
|
|
156
|
+
text: '',
|
|
157
|
+
}
|
|
158
|
+
// } else if (this.USER_ROLE === 'agent') {
|
|
159
|
+
// nocanned = {
|
|
160
|
+
// // "<div class='cannedContent'><div class='cannedTitle nocannedTitle #noCannedTitle'>" + this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') + ".</div><div class='cannedText'>" + this.translationMap.get('TO_CREATE_THEM_GO_TO_THE_PROJECT') + '</div></div>'
|
|
161
|
+
// title:
|
|
162
|
+
// "<div class='cannedContent'><div class='cannedTitle nocannedTitle #noCannedTitle'>" + this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') + ".</div></div>",
|
|
163
|
+
// text: 'There are no canned responses available',
|
|
164
|
+
// }
|
|
165
|
+
// }
|
|
166
|
+
this.tagsCannedFilter.push(nocanned)
|
|
167
|
+
}
|
|
168
|
+
this.onLoadedCannedResponses.emit(this.tagsCannedFilter)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
filterItems(items, searchTerm) {
|
|
172
|
+
this.logger.log('[CANNED] filterItems tagsCannedClone ', items, ' searchTerm: ', searchTerm)
|
|
173
|
+
//this.logger.log("filterItems::: ",searchTerm);
|
|
174
|
+
return items.filter((item) => {
|
|
175
|
+
//this.logger.log("filterItems::: ", item.title.toString().toLowerCase());
|
|
176
|
+
this.logger.log('[CANNED] filtered tagsCannedClone item ', item)
|
|
177
|
+
return item.title.toString().toLowerCase().indexOf(searchTerm.toString().toLowerCase()) > -1
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
replacePlaceholderInCanned(str) {
|
|
182
|
+
this.logger.log('[CANNED] - replacePlaceholderInCanned str ', str)
|
|
183
|
+
str = str.replace('$recipient_name', this.conversationWithFullname)
|
|
184
|
+
if (this.loggedUser && this.loggedUser.fullname) {
|
|
185
|
+
str = str.replace('$agent_name', this.loggedUser.fullname)
|
|
186
|
+
}
|
|
187
|
+
return str
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
onEditCanned(canned, ev){
|
|
192
|
+
ev.preventDefault()
|
|
193
|
+
ev.stopPropagation()
|
|
194
|
+
canned.disabled = false
|
|
195
|
+
this.logger.log('[CANNED] onEditCanned ', canned)
|
|
196
|
+
setTimeout(() => {
|
|
197
|
+
this.el.nativeElement.querySelector('#titleCanned_'+canned._id).setFocus()
|
|
198
|
+
}, 500);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
onConfirmEditCanned(canned, ev){
|
|
202
|
+
ev.preventDefault()
|
|
203
|
+
ev.stopPropagation()
|
|
204
|
+
const tiledeskToken = this.tiledeskAuthService.getTiledeskToken()
|
|
205
|
+
this.logger.log('[CANNED] onConfirmEditCanned ', canned, ev)
|
|
206
|
+
this.cannedResponsesService.edit(tiledeskToken, canned.id_project, canned).subscribe(cannedRes=> {
|
|
207
|
+
canned.disabled = true
|
|
208
|
+
}, (error) => {
|
|
209
|
+
this.logger.error('[CANNED] - onConfirmEditCanned - ERROR ', error)
|
|
210
|
+
}, () => {
|
|
211
|
+
this.logger.log('[CANNED] - onConfirmEditCanned * COMPLETE *')
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
onDeleteCanned(canned, ev){
|
|
216
|
+
ev.preventDefault()
|
|
217
|
+
ev.stopPropagation()
|
|
218
|
+
const tiledeskToken = this.tiledeskAuthService.getTiledeskToken()
|
|
219
|
+
this.logger.log('[CANNED] onDeleteCanned ', canned)
|
|
220
|
+
this.cannedResponsesService.delete(tiledeskToken, canned.id_project, canned._id).subscribe(cannedRes=> {
|
|
221
|
+
if(cannedRes.status === 1000){
|
|
222
|
+
this.tagsCannedFilter.splice(this.tagsCannedFilter.findIndex(el => el._id === canned._id), 1)
|
|
223
|
+
}
|
|
224
|
+
}, (error) => {
|
|
225
|
+
this.logger.error('[CANNED] - onConfirmEditCanned - ERROR ', error)
|
|
226
|
+
}, () => {
|
|
227
|
+
this.logger.log('[CANNED] - onConfirmEditCanned * COMPLETE *')
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
onClickCannedFN(canned, event){
|
|
232
|
+
if(!canned.disabled){
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
event.stopPropagation();
|
|
235
|
+
} else if(this.tagsCannedCount > 0){
|
|
236
|
+
this.onClickCanned.emit(canned)
|
|
237
|
+
} else {
|
|
238
|
+
this.logger.log('[CANNED] THERE IS NOT CANNED ', canned.text)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
onClickAddCannedResponseFN(){
|
|
243
|
+
this.onClickAddCannedResponse.emit()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@HostListener('document:keydown', ['$event'])
|
|
248
|
+
handleKeyboardEvent(event: KeyboardEvent) {
|
|
249
|
+
this.logger.log("CONVERSATION-DETAIL handleKeyboardEvent event.key ", event);
|
|
250
|
+
|
|
251
|
+
if (this.tagsCannedFilter.length > 0) {
|
|
252
|
+
if (event.key === 'ArrowDown') {
|
|
253
|
+
this.arrowkeyLocation++
|
|
254
|
+
if (this.arrowkeyLocation === this.tagsCannedFilter.length) {
|
|
255
|
+
this.arrowkeyLocation--
|
|
256
|
+
}
|
|
257
|
+
// this.replaceTagInMessage(this.tagsCannedFilter[this.arrowkeyLocation])
|
|
258
|
+
} else if (event.key === 'ArrowUp') {
|
|
259
|
+
if (this.arrowkeyLocation > 0) {
|
|
260
|
+
this.arrowkeyLocation--
|
|
261
|
+
} else if (this.arrowkeyLocation < 0) {
|
|
262
|
+
this.arrowkeyLocation++
|
|
263
|
+
}
|
|
264
|
+
// this.replaceTagInMessage(this.tagsCannedFilter[this.arrowkeyLocation])
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (event.key === 'Enter') {
|
|
268
|
+
const canned_selected = this.tagsCannedFilter[this.arrowkeyLocation]
|
|
269
|
+
this.logger.log('[CONVS-DETAIL] replaceTagInMessage canned_selected ',canned_selected)
|
|
270
|
+
if (canned_selected) {
|
|
271
|
+
this.arrowkeyLocation = -1
|
|
272
|
+
this.tagsCannedFilter = []
|
|
273
|
+
this.onClickCanned.emit(canned_selected)
|
|
274
|
+
// event.preventDefault();
|
|
275
|
+
// return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
}
|
package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UserModel } from 'src/chat21-core/models/user';
|
|
2
|
-
import { Component, OnInit, Output, EventEmitter, Input, AfterViewInit, ViewChild, ElementRef, OnChanges, HostListener, Renderer2 } from '@angular/core';
|
|
2
|
+
import { Component, OnInit, Output, EventEmitter, Input, AfterViewInit, ViewChild, ElementRef, OnChanges, HostListener, Renderer2, SimpleChange, SimpleChanges } from '@angular/core';
|
|
3
3
|
|
|
4
4
|
import { Chooser } from '@ionic-native/chooser/ngx';
|
|
5
5
|
import { IonTextarea, ModalController, ToastController } from '@ionic/angular';
|
|
@@ -43,7 +43,7 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
43
43
|
|
|
44
44
|
@Input() loggedUser: UserModel;
|
|
45
45
|
@Input() conversationWith: string;
|
|
46
|
-
@Input() tagsCannedFilter: any
|
|
46
|
+
@Input() tagsCannedFilter: any;
|
|
47
47
|
@Input() tagsCannedCount: number;
|
|
48
48
|
@Input() areVisibleCAR: boolean;
|
|
49
49
|
@Input() supportMode: boolean;
|
|
@@ -54,8 +54,8 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
54
54
|
@Input() dropEvent: any;
|
|
55
55
|
@Input() disableTextarea: boolean;
|
|
56
56
|
@Output() eventChangeTextArea = new EventEmitter<object>();
|
|
57
|
-
@Output() hasClickedOpenCannedResponses = new EventEmitter<boolean>();
|
|
58
57
|
@Output() eventSendMessage = new EventEmitter<object>();
|
|
58
|
+
@Output() onClickOpenCannedResponses = new EventEmitter<boolean>();
|
|
59
59
|
@Output() onPresentModalScrollToBottom = new EventEmitter<boolean>();
|
|
60
60
|
|
|
61
61
|
public conversationEnabled = false;
|
|
@@ -69,6 +69,7 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
69
69
|
public currentWindowWidth: any;
|
|
70
70
|
private logger: LoggerService = LoggerInstance.getInstance();
|
|
71
71
|
public countClicks: number = 0;
|
|
72
|
+
public openCanned: boolean = false;
|
|
72
73
|
public IS_SUPPORT_GROUP_CONVERSATION: boolean;
|
|
73
74
|
public IS_ON_MOBILE_DEVICE: boolean;
|
|
74
75
|
TYPE_MSG_TEXT = TYPE_MSG_TEXT;
|
|
@@ -140,9 +141,7 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
ngOnChanges() {
|
|
144
|
+
ngOnChanges(changes: SimpleChanges) {
|
|
146
145
|
if (this.translationMap) {
|
|
147
146
|
// this.LONG_TEXAREA_PLACEHOLDER = this.translationMap.get('LABEL_ENTER_MSG')
|
|
148
147
|
// this.SHORT_TEXAREA_PLACEHOLDER = this.translationMap.get('LABEL_ENTER_MSG_SHORT')
|
|
@@ -580,7 +579,8 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
580
579
|
}
|
|
581
580
|
|
|
582
581
|
openCannedResponses() {
|
|
583
|
-
this.
|
|
582
|
+
this.openCanned = !this.openCanned
|
|
583
|
+
this.onClickOpenCannedResponses.emit(this.openCanned);
|
|
584
584
|
}
|
|
585
585
|
|
|
586
586
|
|
|
@@ -698,8 +698,9 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
698
698
|
|
|
699
699
|
@HostListener('document:keydown', ['$event'])
|
|
700
700
|
handleKeyboardEvent(event: KeyboardEvent) {
|
|
701
|
-
|
|
701
|
+
this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] handleKeyboardEvent event.key ", event);
|
|
702
702
|
// Note: on mac keyboard "metakey" matches "cmd"
|
|
703
|
+
|
|
703
704
|
if (event.key === 'Enter' && event.altKey || event.key === 'Enter' && event.ctrlKey || event.key === 'Enter' && event.metaKey) {
|
|
704
705
|
this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] HAS PRESSED COMBO KEYS this.messageString', this.messageString);
|
|
705
706
|
if (this.messageString !== undefined && this.messageString.trim() !== '') {
|