@chat21/chat21-ionic 3.4.13-rc1 → 3.4.13-rc3
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 +8 -0
- package/package.json +1 -1
- package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.html +2 -2
- package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.ts +12 -7
- package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.html +1 -1
- package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.ts +4 -30
- package/src/app/chatlib/conversation-detail/message/options/options.component.html +4 -1
- package/src/app/chatlib/conversation-detail/message/options/options.component.scss +7 -0
- package/src/app/chatlib/conversation-detail/message/options/options.component.ts +40 -8
- package/src/app/components/canned-response/canned-response.component.html +8 -3
- package/src/app/components/canned-response/canned-response.component.scss +26 -0
- package/src/app/components/canned-response/canned-response.component.ts +9 -31
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +2 -3
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +11 -0
- package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +0 -1
- package/src/app/components/copilot-popover/copilot-popover.component.html +25 -0
- package/src/app/components/copilot-popover/copilot-popover.component.scss +101 -0
- package/src/app/components/copilot-popover/copilot-popover.component.spec.ts +24 -0
- package/src/app/components/copilot-popover/copilot-popover.component.ts +81 -0
- package/src/app/components/copilot-suggestions/copilot-suggestions.component.html +9 -4
- package/src/app/components/copilot-suggestions/copilot-suggestions.component.scss +27 -0
- package/src/app/components/copilot-suggestions/copilot-suggestions.component.ts +29 -14
- package/src/app/pages/conversation-detail/conversation-detail.module.ts +3 -1
- package/src/app/pages/conversation-detail/conversation-detail.page.html +4 -43
- package/src/app/pages/conversation-detail/conversation-detail.page.ts +32 -37
- package/src/app/services/copilot/copilot.service.ts +27 -4
- package/src/assets/i18n/en.json +5 -1
- package/src/assets/i18n/it.json +5 -1
- package/src/global.scss +6 -0
- package/src/variables.scss +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# chat21-ionic ver 3.0
|
|
2
2
|
|
|
3
|
+
### 3.4.13-rc.3
|
|
4
|
+
- added: copilot-popover on each received message
|
|
5
|
+
- changed: canned-responsed no data ui
|
|
6
|
+
|
|
7
|
+
### 3.4.13-rc.2
|
|
8
|
+
- added: no-suggestions in copilot component
|
|
9
|
+
- changed: HIDE_CANNED_RESPONSES with SHOW CANNED_RESPONSES
|
|
10
|
+
|
|
3
11
|
### 3.4.13-rc.1
|
|
4
12
|
- added: copilot suggestions for agent responses
|
|
5
13
|
|
package/package.json
CHANGED
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
(onBeforeMessageRender)="onBeforeMessageRenderFN($event)"
|
|
133
133
|
(onAfterMessageRender)="onAfterMessageRenderFN($event)"
|
|
134
134
|
(onElementRendered)="onElementRenderedFN($event)"
|
|
135
|
-
(
|
|
135
|
+
(onOptionsDataReturned)="onClickBubbleOptions($event)">
|
|
136
136
|
</chat-bubble-message>
|
|
137
137
|
</div>
|
|
138
138
|
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
(onBeforeMessageRender)="onBeforeMessageRenderFN($event)"
|
|
178
178
|
(onAfterMessageRender)="onAfterMessageRenderFN($event)"
|
|
179
179
|
(onElementRendered)="onElementRenderedFN($event)"
|
|
180
|
-
(
|
|
180
|
+
(onOptionsDataReturned)="onClickBubbleOptions($event)">
|
|
181
181
|
</chat-bubble-message>
|
|
182
182
|
|
|
183
183
|
</div>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { JsonMessagePage } from './../../../modals/json-message/json-message.page';
|
|
2
|
-
import { BubbleInfoPopoverComponent } from '../../../components/bubbleMessageInfo-popover/bubbleinfo-popover.component';
|
|
3
2
|
import { MessageModel } from 'src/chat21-core/models/message';
|
|
4
3
|
import { ConversationContentComponent } from '../conversation-content/conversation-content.component';
|
|
5
4
|
import { ChangeDetectorRef, Component, Input, OnInit, Output, EventEmitter, SimpleChange, SimpleChanges } from '@angular/core';
|
|
@@ -18,6 +17,7 @@ import * as moment from 'moment';
|
|
|
18
17
|
import { AppConfigProvider } from 'src/app/services/app-config';
|
|
19
18
|
import { ModalController, PopoverController, ToastController } from '@ionic/angular';
|
|
20
19
|
import { CreateCannedResponsePage } from 'src/app/modals/create-canned-response/create-canned-response.page';
|
|
20
|
+
import { EventsService } from 'src/app/services/events-service';
|
|
21
21
|
|
|
22
22
|
@Component({
|
|
23
23
|
selector: 'ion-conversation-detail',
|
|
@@ -73,7 +73,8 @@ export class IonConversationDetailComponent extends ConversationContentComponent
|
|
|
73
73
|
public appConfigProvider: AppConfigProvider,
|
|
74
74
|
public modalController: ModalController,
|
|
75
75
|
public popoverController: PopoverController,
|
|
76
|
-
public toastController: ToastController
|
|
76
|
+
public toastController: ToastController,
|
|
77
|
+
private eventService: EventsService
|
|
77
78
|
) {
|
|
78
79
|
super(cdref, uploadService)
|
|
79
80
|
|
|
@@ -154,16 +155,20 @@ export class IonConversationDetailComponent extends ConversationContentComponent
|
|
|
154
155
|
this.onAddUploadingBubble.emit(value);
|
|
155
156
|
}
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
this.logger.log('[CONVS-DETAIL][ION-CONVS-DETAIL] -
|
|
158
|
+
onClickBubbleOptions(event:{option: string, data: any}){
|
|
159
|
+
this.logger.log('[CONVS-DETAIL][ION-CONVS-DETAIL] - onClickBubbleOptions', event);
|
|
159
160
|
if(event.option==='copy'){
|
|
160
|
-
this.onClickCopyMessage(event.message)
|
|
161
|
+
this.onClickCopyMessage(event.data.message)
|
|
161
162
|
}else if(event.option === 'addCanned'){
|
|
162
163
|
if(this.areVisibleCAR && this.supportMode){
|
|
163
|
-
this.presentCreateCannedResponseModal(event.message)
|
|
164
|
+
this.presentCreateCannedResponseModal(event.data.message)
|
|
164
165
|
}
|
|
165
166
|
}else if(event.option === 'jsonInfo'){
|
|
166
|
-
this.presentJsonMessageModal(event.message)
|
|
167
|
+
this.presentJsonMessageModal(event.data.message)
|
|
168
|
+
} else if(event.option === 'copilot_question'){
|
|
169
|
+
console.log('hereeeeeee', event)
|
|
170
|
+
this.eventService.publish('copilot:new_question', {text: event.data.text})
|
|
171
|
+
|
|
167
172
|
}
|
|
168
173
|
}
|
|
169
174
|
|
package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.ts
CHANGED
|
@@ -29,7 +29,7 @@ export class BubbleMessageComponent implements OnInit, OnChanges {
|
|
|
29
29
|
@Output() onBeforeMessageRender = new EventEmitter();
|
|
30
30
|
@Output() onAfterMessageRender = new EventEmitter();
|
|
31
31
|
@Output() onElementRendered = new EventEmitter<{element: string, status: boolean}>();
|
|
32
|
-
@Output()
|
|
32
|
+
@Output() onOptionsDataReturned = new EventEmitter<{option: string, message: MessageModel}>();
|
|
33
33
|
|
|
34
34
|
isImage = isImage;
|
|
35
35
|
isFile = isFile;
|
|
@@ -54,8 +54,7 @@ export class BubbleMessageComponent implements OnInit, OnChanges {
|
|
|
54
54
|
public sanitizer: DomSanitizer,
|
|
55
55
|
private translate: TranslateService,
|
|
56
56
|
public tiledeskAuthService: TiledeskAuthService,
|
|
57
|
-
public modalController: ModalController
|
|
58
|
-
private popoverController: PopoverController
|
|
57
|
+
public modalController: ModalController
|
|
59
58
|
) {
|
|
60
59
|
// console.log('BUBBLE-MSG Hello !!!!')
|
|
61
60
|
}
|
|
@@ -162,34 +161,9 @@ export class BubbleMessageComponent implements OnInit, OnChanges {
|
|
|
162
161
|
// this.logger.log('[BUBBLE-MESSAGE] - onClickOptionsMessage', message);
|
|
163
162
|
// this.presentPopover(event, message)
|
|
164
163
|
// }
|
|
165
|
-
|
|
166
|
-
this.
|
|
164
|
+
onOptionsDataReturnedFN(event){
|
|
165
|
+
this.onOptionsDataReturned.emit(event)
|
|
167
166
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// async presentPopover(ev: any, message: MessageModel) {
|
|
171
|
-
// const attributes = {
|
|
172
|
-
// message: message,
|
|
173
|
-
// conversationWith: message.recipient
|
|
174
|
-
// }
|
|
175
|
-
// const popover = await this.popoverController.create({
|
|
176
|
-
// component: BubbleInfoPopoverComponent,
|
|
177
|
-
// cssClass: 'info-popover',
|
|
178
|
-
// componentProps: attributes,
|
|
179
|
-
// event: ev,
|
|
180
|
-
// translucent: true,
|
|
181
|
-
// keyboardClose: true,
|
|
182
|
-
// showBackdrop: false
|
|
183
|
-
// });
|
|
184
|
-
// popover.onDidDismiss().then((dataReturned: any) => {
|
|
185
|
-
// this.logger.log('[BUBBLE-MESSAGE] presentPopover dismissed. Returned value::', dataReturned.data)
|
|
186
|
-
// if(dataReturned.data){
|
|
187
|
-
// this.onOptionsMessage.emit({option: dataReturned.data.option, message: message})
|
|
188
|
-
// }
|
|
189
|
-
// })
|
|
190
|
-
|
|
191
|
-
// return await popover.present();
|
|
192
|
-
// }
|
|
193
167
|
// ========= begin:: event emitter function ============//
|
|
194
168
|
|
|
195
169
|
// returnOpenAttachment(event: String) {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<div class="options-container" >
|
|
2
|
-
<div class="options-logo" (click)="onClickOptionsMessage($event
|
|
2
|
+
<div class="options-logo" (click)="onClickOptionsMessage($event)" >
|
|
3
3
|
<ion-icon name="chevron-down"></ion-icon>
|
|
4
4
|
</div>
|
|
5
|
+
<div class="options-logo" (click)="onClickOptionsCopilot($event)">
|
|
6
|
+
<ion-icon id="copilot" src="assets/images/icons/copilot.svg"></ion-icon>
|
|
7
|
+
</div>
|
|
5
8
|
</div>
|
|
@@ -4,6 +4,7 @@ import { BubbleInfoPopoverComponent } from 'src/app/components/bubbleMessageInfo
|
|
|
4
4
|
import { MessageModel } from 'src/chat21-core/models/message';
|
|
5
5
|
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
6
6
|
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
7
|
+
import { CopilotPopoverComponent } from 'src/app/components/copilot-popover/copilot-popover.component';
|
|
7
8
|
|
|
8
9
|
@Component({
|
|
9
10
|
selector: 'chat-options',
|
|
@@ -14,7 +15,7 @@ export class OptionsComponent implements OnInit {
|
|
|
14
15
|
|
|
15
16
|
@Input() message: MessageModel;
|
|
16
17
|
@Input() logLevel: number;
|
|
17
|
-
@Output()
|
|
18
|
+
@Output() onOptionsDataReturned = new EventEmitter<{option: string, data: any}>();
|
|
18
19
|
|
|
19
20
|
private logger: LoggerService = LoggerInstance.getInstance()
|
|
20
21
|
|
|
@@ -22,17 +23,23 @@ export class OptionsComponent implements OnInit {
|
|
|
22
23
|
|
|
23
24
|
ngOnInit() {}
|
|
24
25
|
|
|
25
|
-
onClickOptionsMessage(event
|
|
26
|
-
this.logger.log('[BUBBLE-MESSAGE] - onClickOptionsMessage', message);
|
|
27
|
-
this.presentPopover(event
|
|
26
|
+
onClickOptionsMessage(event){
|
|
27
|
+
this.logger.log('[BUBBLE-MESSAGE] - onClickOptionsMessage', this.message);
|
|
28
|
+
this.presentPopover(event)
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
onClickOptionsCopilot(event){
|
|
32
|
+
this.logger.log('[BUBBLE-MESSAGE] - onClickOptionsCopilot', this.message);
|
|
33
|
+
this.presentCopilotPopover(event)
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
|
|
30
37
|
|
|
31
|
-
async presentPopover(ev: any
|
|
38
|
+
async presentPopover(ev: any) {
|
|
32
39
|
const attributes = {
|
|
33
|
-
message: message,
|
|
40
|
+
message: this.message,
|
|
34
41
|
logLevel: this.logLevel,
|
|
35
|
-
conversationWith: message.recipient
|
|
42
|
+
conversationWith: this.message.recipient
|
|
36
43
|
}
|
|
37
44
|
const popover = await this.popoverController.create({
|
|
38
45
|
component: BubbleInfoPopoverComponent,
|
|
@@ -46,7 +53,32 @@ export class OptionsComponent implements OnInit {
|
|
|
46
53
|
popover.onDidDismiss().then((dataReturned: any) => {
|
|
47
54
|
this.logger.log('[BUBBLE-MESSAGE] presentPopover dismissed. Returned value::', dataReturned.data)
|
|
48
55
|
if(dataReturned.data){
|
|
49
|
-
this.
|
|
56
|
+
this.onOptionsDataReturned.emit({option: dataReturned.data.option, data: {message: this.message}})
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return await popover.present();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async presentCopilotPopover(ev: any) {
|
|
64
|
+
const attributes = {
|
|
65
|
+
message: this.message,
|
|
66
|
+
logLevel: this.logLevel,
|
|
67
|
+
conversationWith: this.message.recipient
|
|
68
|
+
}
|
|
69
|
+
const popover = await this.popoverController.create({
|
|
70
|
+
component: CopilotPopoverComponent,
|
|
71
|
+
cssClass: 'copilot-popover',
|
|
72
|
+
componentProps: attributes,
|
|
73
|
+
event: ev,
|
|
74
|
+
translucent: true,
|
|
75
|
+
keyboardClose: true,
|
|
76
|
+
showBackdrop: false,
|
|
77
|
+
});
|
|
78
|
+
popover.onDidDismiss().then((dataReturned: any) => {
|
|
79
|
+
this.logger.log('[BUBBLE-MESSAGE] presentCopilotPopover dismissed. Returned value::', dataReturned.data)
|
|
80
|
+
if(dataReturned.data){
|
|
81
|
+
this.onOptionsDataReturned.emit({option: 'copilot_question', data: {text: dataReturned.data.text}})
|
|
50
82
|
}
|
|
51
83
|
})
|
|
52
84
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</ion-item>
|
|
22
22
|
</div>
|
|
23
23
|
<!-- LOADER -->
|
|
24
|
-
<div class="loader" *ngIf="
|
|
24
|
+
<div class="loader" *ngIf="showLoading">
|
|
25
25
|
<div class="box">
|
|
26
26
|
<!-- <div class="container">
|
|
27
27
|
<span class="circle" [ngStyle]="{'background-color': stylesMap?.get('themeColor')}"></span>
|
|
@@ -33,7 +33,12 @@
|
|
|
33
33
|
<div class="label">{{translationMap.get('LABEL_LOADING')}}</div>
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
|
-
<div *ngIf="!
|
|
37
|
-
|
|
36
|
+
<div class="no-data" *ngIf="tagsCannedFilter.length === 0 && !showLoading">
|
|
37
|
+
<div class="container">
|
|
38
|
+
<ion-item button="false" lines="none" class="canned-item no-ripple border">
|
|
39
|
+
<ion-icon name="cloud-offline" slot="start"></ion-icon>
|
|
40
|
+
<ion-label>{{translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE')}}</ion-label>
|
|
41
|
+
</ion-item>
|
|
42
|
+
</div>
|
|
38
43
|
</div>
|
|
39
44
|
</div>
|
|
@@ -255,4 +255,30 @@ ion-item {
|
|
|
255
255
|
opacity: 0;
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.no-data{
|
|
261
|
+
|
|
262
|
+
background-color: white !important;
|
|
263
|
+
width: 100%;
|
|
264
|
+
max-height: 310px;
|
|
265
|
+
overflow-y: auto;
|
|
266
|
+
// padding: 10px 0;
|
|
267
|
+
// margin: 0;
|
|
268
|
+
margin-bottom: 1px;
|
|
269
|
+
font-size: 14px;
|
|
270
|
+
line-height: 1.42857143;
|
|
271
|
+
color: #080f1a;
|
|
272
|
+
box-sizing: border-box;
|
|
273
|
+
-webkit-font-smoothing: antialiased;
|
|
274
|
+
// list-style: none;
|
|
275
|
+
z-index: 999999;
|
|
276
|
+
|
|
277
|
+
.container{
|
|
278
|
+
display: flex;
|
|
279
|
+
justify-content: center;
|
|
280
|
+
flex-direction: column;
|
|
281
|
+
align-items: center;
|
|
282
|
+
|
|
283
|
+
}
|
|
258
284
|
}
|
|
@@ -31,8 +31,8 @@ export class CannedResponseComponent implements OnInit {
|
|
|
31
31
|
public projectID: string;
|
|
32
32
|
|
|
33
33
|
public tagsCanned: any = []
|
|
34
|
-
public tagsCannedCount: number
|
|
35
34
|
public tagsCannedFilter: any = []
|
|
35
|
+
public showLoading: boolean = false
|
|
36
36
|
|
|
37
37
|
public arrowkeyLocation = -1
|
|
38
38
|
|
|
@@ -124,19 +124,21 @@ export class CannedResponseComponent implements OnInit {
|
|
|
124
124
|
this.logger.log('[CANNED] - loadTagsCanned tagsCanned.length', this.tagsCanned.length)
|
|
125
125
|
//if(this.tagsCanned.length <= 0 ){
|
|
126
126
|
this.tagsCanned = []
|
|
127
|
+
this.showLoading = true;
|
|
127
128
|
this.cannedResponsesService.getAll(tiledeskToken, projectId).subscribe((res) => {
|
|
128
129
|
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses RES', res)
|
|
129
130
|
|
|
130
131
|
this.tagsCanned = res
|
|
131
|
-
this.tagsCannedCount = res.length
|
|
132
|
-
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses tagsCannedCount', this.tagsCannedCount)
|
|
133
132
|
// if (this.HIDE_CANNED_RESPONSES === false) {
|
|
134
|
-
|
|
133
|
+
this.showTagsCanned(strSearch)
|
|
135
134
|
// }
|
|
136
135
|
}, (error) => {
|
|
137
136
|
this.logger.error('[CANNED] - loadTagsCanned getCannedResponses - ERROR ', error)
|
|
138
137
|
}, () => {
|
|
139
138
|
this.logger.log('[CANNED] - loadTagsCanned getCannedResponses * COMPLETE *')
|
|
139
|
+
setTimeout(() => {
|
|
140
|
+
this.showLoading = false
|
|
141
|
+
}, 1000);
|
|
140
142
|
})
|
|
141
143
|
}
|
|
142
144
|
|
|
@@ -166,32 +168,9 @@ export class CannedResponseComponent implements OnInit {
|
|
|
166
168
|
canned.text = this.replacePlaceholderInCanned(canned.text);
|
|
167
169
|
canned.disabled = true
|
|
168
170
|
});
|
|
169
|
-
if (this.tagsCannedFilter && this.tagsCannedFilter.length === 0) {
|
|
170
|
-
// const button = this.renderer.createElement('button');
|
|
171
|
-
// const buttonText = this.renderer.createText('Click me');
|
|
172
|
-
// this.renderer.appendChild(button, buttonText);
|
|
173
|
-
// console.log('[CANNED] - this.el.nativeElement ', this.el.nativeElement)
|
|
174
|
-
// this.renderer.listen(button, 'click', () => { alert('hi'); });
|
|
175
|
-
// let nocanned = {}
|
|
176
|
-
// if (this.USER_ROLE !== 'agent') {
|
|
177
|
-
const nocanned = {
|
|
178
|
-
// "<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>'
|
|
179
|
-
// <div class='cannedText no-canned-available-text'>" + this.translationMap.get('AddNewCannedResponse') + '</div>
|
|
180
|
-
title: this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') ,
|
|
181
|
-
text: '',
|
|
182
|
-
}
|
|
183
|
-
// } else if (this.USER_ROLE === 'agent') {
|
|
184
|
-
// nocanned = {
|
|
185
|
-
// // "<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>'
|
|
186
|
-
// title:
|
|
187
|
-
// "<div class='cannedContent'><div class='cannedTitle nocannedTitle #noCannedTitle'>" + this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') + ".</div></div>",
|
|
188
|
-
// text: 'There are no canned responses available',
|
|
189
|
-
// }
|
|
190
|
-
// }
|
|
191
|
-
this.tagsCannedFilter.push(nocanned)
|
|
192
|
-
}
|
|
193
171
|
this.appStorageService.setItem(this.projectID+'_canned', JSON.stringify(this.tagsCannedFilter))
|
|
194
172
|
this.onLoadedCannedResponses.emit(this.tagsCannedFilter)
|
|
173
|
+
|
|
195
174
|
}
|
|
196
175
|
|
|
197
176
|
filterItems(items, searchTerm) {
|
|
@@ -269,10 +248,9 @@ export class CannedResponseComponent implements OnInit {
|
|
|
269
248
|
if(!canned.disabled){
|
|
270
249
|
event.preventDefault();
|
|
271
250
|
event.stopPropagation();
|
|
272
|
-
} else if(this.tagsCannedCount > 0){
|
|
273
|
-
this.onClickCanned.emit(canned)
|
|
274
251
|
} else {
|
|
275
|
-
this.logger.log('[CANNED] THERE IS
|
|
252
|
+
this.logger.log('[CANNED] THERE IS CANNED ', canned.text)
|
|
253
|
+
this.onClickCanned.emit(canned)
|
|
276
254
|
}
|
|
277
255
|
}
|
|
278
256
|
|
package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<div>
|
|
32
32
|
<!-- COPILOT-OPTION -->
|
|
33
33
|
<div class="section-option" id="copilot" tooltip="{{translationMap?.get('COPILOT.ASK_AI')}}" placement="top">
|
|
34
|
-
<ion-button fill="clear" [class.active]="section ==='copilot'" (click)="onOpenSection('copilot')">
|
|
34
|
+
<ion-button id="copilot" fill="clear" [class.active]="section ==='copilot'" (click)="onOpenSection('copilot')">
|
|
35
35
|
<ion-icon class="channel-icon" src="assets/images/icons/copilot.svg"></ion-icon>
|
|
36
36
|
{{translationMap?.get('COPILOT.ASK_AI')}}
|
|
37
37
|
</ion-button>
|
|
@@ -55,8 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
<!-- CANNED RESPONSES -->
|
|
57
57
|
<ng-container *ngIf="areVisibleCAR && supportMode">
|
|
58
|
-
<div class="canned-responses-btn-wpr"
|
|
59
|
-
tooltip="{{translationMap?.get('CANNED_RESPONSES')}}" placement="top">
|
|
58
|
+
<div class="canned-responses-btn-wpr" tooltip="{{translationMap?.get('CANNED_RESPONSES')}}" placement="top">
|
|
60
59
|
<ion-button ion-button fill="clear" class="canned-responses-btn" (click)="openCannedResponses()"
|
|
61
60
|
[disabled]="!conversationWith?.startsWith(CHANNEL_TYPE.SUPPORT_GROUP) || disableTextarea">
|
|
62
61
|
<ion-icon slot="icon-only" name="flash-outline" style="font-size: 24px;"></ion-icon>
|
package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts
CHANGED
|
@@ -51,7 +51,6 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
|
|
|
51
51
|
@Input() channelType: string;
|
|
52
52
|
@Input() channel: string;
|
|
53
53
|
@Input() tagsCannedFilter: any;
|
|
54
|
-
@Input() tagsCannedCount: number;
|
|
55
54
|
@Input() areVisibleCAR: boolean;
|
|
56
55
|
@Input() supportMode: boolean;
|
|
57
56
|
@Input() leadInfo: {lead_id: string, hasEmail: boolean, email: string, projectId: string, presence: {}};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<div id="copilot-container">
|
|
2
|
+
<ion-header class="ion-no-border">
|
|
3
|
+
<ion-label class="main-title">{{translationsMap.get('HELLO')}}<span *ngIf="loggedUser?.firstname">, {{loggedUser?.firstname}}</span></ion-label>
|
|
4
|
+
<ion-label class="title">{{translationsMap.get('COPILOT.HOW_CAN_I_HELP_YOU')}}</ion-label>
|
|
5
|
+
</ion-header>
|
|
6
|
+
<ion-content>
|
|
7
|
+
<div class="content-container">
|
|
8
|
+
<div class="text-message">
|
|
9
|
+
<ion-textarea
|
|
10
|
+
[placeholder]="translationsMap.get('COPILOT.ASK_ME_SOMETHING')"
|
|
11
|
+
[(ngModel)]="text"
|
|
12
|
+
(ionChange)="ionChange($event);"
|
|
13
|
+
(ionFocus)="ionFocus()"
|
|
14
|
+
(keydown.enter)="onKeydown($event, messageString)">
|
|
15
|
+
</ion-textarea>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</ion-content>
|
|
19
|
+
<ion-footer class="ion-no-border">
|
|
20
|
+
<ion-button fill="clear" (click)="onClickCopilot()">
|
|
21
|
+
<ion-icon src="assets/images/icons/copilot.svg"></ion-icon>
|
|
22
|
+
{{translationsMap.get('COPILOT.ASK_AI') }}
|
|
23
|
+
</ion-button>
|
|
24
|
+
</ion-footer>
|
|
25
|
+
</div>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#copilot-container{
|
|
2
|
+
margin: 10px;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 15px;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ion-header{
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
gap: 5px;
|
|
12
|
+
|
|
13
|
+
.main-title{
|
|
14
|
+
background: linear-gradient(135deg, #217bfe 0, #078efb 33%, #ac87eb 100%);
|
|
15
|
+
background-clip: text;
|
|
16
|
+
inline-size: fit-content;
|
|
17
|
+
color: transparent;
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.title{
|
|
22
|
+
font-weight: 500;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ion-content{
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
.content-container{
|
|
30
|
+
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: 10px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
.text-message {
|
|
39
|
+
position: relative;
|
|
40
|
+
// margin: 0 35px;
|
|
41
|
+
// width: calc(100% - 70px);
|
|
42
|
+
// ----- new after adding canned open /close canned responses
|
|
43
|
+
// margin: 0 70px;
|
|
44
|
+
// width: calc(100% - 100px);
|
|
45
|
+
// ----- new after adding emoji picker
|
|
46
|
+
// margin: 0 108px;
|
|
47
|
+
width: 100%; //calc(100% - 140px);
|
|
48
|
+
ion-textarea {
|
|
49
|
+
// border-radius: 4px;
|
|
50
|
+
border-radius: 20px; // NK edited
|
|
51
|
+
padding: 0;
|
|
52
|
+
margin: 0;
|
|
53
|
+
height: auto;
|
|
54
|
+
overflow: auto;
|
|
55
|
+
// min-height: 30px;
|
|
56
|
+
min-height: 74px; // NK edited
|
|
57
|
+
max-height: 184px;
|
|
58
|
+
background-color: var(--textarea-background);
|
|
59
|
+
color: var(--textarea-color);
|
|
60
|
+
--placeholder-color: var(--textarea-placeholder-color);
|
|
61
|
+
// --padding-top: 5px; // NK edited
|
|
62
|
+
--padding-top: 8px;
|
|
63
|
+
--padding-bottom: 5px;
|
|
64
|
+
--padding-end: 5px;
|
|
65
|
+
// --padding-start: 5px; // NK edited
|
|
66
|
+
--padding-start: 10px;
|
|
67
|
+
line-height: 1.34;
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
ion-footer{
|
|
75
|
+
display: flex;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
|
|
78
|
+
ion-button{
|
|
79
|
+
background-color: var(--icon-color);
|
|
80
|
+
color: var(--bacis-white);
|
|
81
|
+
font-size: 11px;
|
|
82
|
+
margin: 2px;
|
|
83
|
+
padding-bottom: 0px;
|
|
84
|
+
--padding-start: 0px;
|
|
85
|
+
--ripple-color: transparent;
|
|
86
|
+
text-transform: unset;
|
|
87
|
+
height: 25px;
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
&.active{
|
|
90
|
+
color: var(--basic-blue);
|
|
91
|
+
fill: var(--basic-blue);
|
|
92
|
+
}
|
|
93
|
+
ion-icon{
|
|
94
|
+
margin-right: 4px;
|
|
95
|
+
margin-left: 4px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
2
|
+
import { IonicModule } from '@ionic/angular';
|
|
3
|
+
|
|
4
|
+
import { CopilotPopoverComponent } from './copilot-popover.component';
|
|
5
|
+
|
|
6
|
+
describe('CopilotPopoverComponent', () => {
|
|
7
|
+
let component: CopilotPopoverComponent;
|
|
8
|
+
let fixture: ComponentFixture<CopilotPopoverComponent>;
|
|
9
|
+
|
|
10
|
+
beforeEach(waitForAsync(() => {
|
|
11
|
+
TestBed.configureTestingModule({
|
|
12
|
+
declarations: [ CopilotPopoverComponent ],
|
|
13
|
+
imports: [IonicModule.forRoot()]
|
|
14
|
+
}).compileComponents();
|
|
15
|
+
|
|
16
|
+
fixture = TestBed.createComponent(CopilotPopoverComponent);
|
|
17
|
+
component = fixture.componentInstance;
|
|
18
|
+
fixture.detectChanges();
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
it('should create', () => {
|
|
22
|
+
expect(component).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Component, Input, OnInit } from '@angular/core';
|
|
2
|
+
import { PopoverController } from '@ionic/angular';
|
|
3
|
+
import { MessageModel } from 'src/chat21-core/models/message';
|
|
4
|
+
import { UserModel } from 'src/chat21-core/models/user';
|
|
5
|
+
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
6
|
+
import { CustomTranslateService } from 'src/chat21-core/providers/custom-translate.service';
|
|
7
|
+
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
8
|
+
import { TiledeskAuthService } from 'src/chat21-core/providers/tiledesk/tiledesk-auth.service';
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: 'app-copilot-popover',
|
|
12
|
+
templateUrl: './copilot-popover.component.html',
|
|
13
|
+
styleUrls: ['./copilot-popover.component.scss'],
|
|
14
|
+
})
|
|
15
|
+
export class CopilotPopoverComponent implements OnInit {
|
|
16
|
+
|
|
17
|
+
@Input() message: MessageModel
|
|
18
|
+
|
|
19
|
+
text: string;
|
|
20
|
+
loggedUser: UserModel
|
|
21
|
+
|
|
22
|
+
public translationsMap: Map<string, string>;
|
|
23
|
+
private logger: LoggerService = LoggerInstance.getInstance()
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
private ctr: PopoverController,
|
|
27
|
+
private tiledeskAuthService: TiledeskAuthService,
|
|
28
|
+
private customTranslateService: CustomTranslateService,
|
|
29
|
+
) { }
|
|
30
|
+
|
|
31
|
+
ngOnInit() {
|
|
32
|
+
this.logger.debug('[COPILOT-POPOVER] ngOnInit message data:', this.message)
|
|
33
|
+
this.loggedUser = this.tiledeskAuthService.getCurrentUser();
|
|
34
|
+
this.text = this.message.text
|
|
35
|
+
this.initTranslations();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onClose(){
|
|
39
|
+
this.ctr.dismiss()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
initTranslations(){
|
|
43
|
+
let keys= [
|
|
44
|
+
"HELLO",
|
|
45
|
+
"COPILOT.ASK_AI",
|
|
46
|
+
"COPILOT.INSERT_PROMPT_HERE",
|
|
47
|
+
"COPILOT.HOW_CAN_I_HELP_YOU"
|
|
48
|
+
]
|
|
49
|
+
this.translationsMap = this.customTranslateService.translateLanguage(keys)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
onClickCopilot(){
|
|
53
|
+
this.logger.debug('[COPILOT-POPOVER] onClickCopilot')
|
|
54
|
+
this.ctr.dismiss({text: this.text})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
ionChange(e: any) {
|
|
59
|
+
this.logger.log("[COPILOT-POPOVER] ionChange event ", e);
|
|
60
|
+
// this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ionChange detail.value ", e.detail.value);
|
|
61
|
+
|
|
62
|
+
const message = e.detail.value
|
|
63
|
+
this.logger.log("[COPILOT-POPOVER] [MSG-TEXT-AREA] ionChange message ", message);
|
|
64
|
+
// this.logger.log("[CONVS-DETAIL] [MSG-TEXT-AREA] ionChange this.messageString ", this.messageString);
|
|
65
|
+
const footerSelectionHeight = 33
|
|
66
|
+
const height = e.target.offsetHeight + footerSelectionHeight + 20; // nk added +20
|
|
67
|
+
|
|
68
|
+
// this.eventChangeTextArea.emit({ msg: message, offsetHeight: height });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ionFocus(){
|
|
72
|
+
this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ionFocus event ");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onKeydown(e: any, text: string) {
|
|
76
|
+
this.logger.log("[COPILOT-POPOVER] - returnChangeTextArea - onKeydown in MSG-TEXT-AREA event", e)
|
|
77
|
+
this.logger.log("[COPILOT-POPOVER] - returnChangeTextArea - onKeydown in MSG-TEXT-AREA text", text)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</ion-item> -->
|
|
19
19
|
</div>
|
|
20
20
|
<!-- LOADER -->
|
|
21
|
-
<div class="loader" *ngIf="
|
|
21
|
+
<div class="loader" *ngIf="showLoading">
|
|
22
22
|
<div class="box">
|
|
23
23
|
<!-- <div class="container">
|
|
24
24
|
<span class="circle" [ngStyle]="{'background-color': stylesMap?.get('themeColor')}"></span>
|
|
@@ -30,7 +30,12 @@
|
|
|
30
30
|
<div class="label">{{translationMap.get('LABEL_LOADING')}}</div>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
<div class="no-data" *ngIf="suggestions.length === 0 && !showLoading">
|
|
34
|
+
<div class="container">
|
|
35
|
+
<ion-item button="false" lines="none" class="canned-item no-ripple border">
|
|
36
|
+
<ion-icon name="cloud-offline" slot="start"></ion-icon>
|
|
37
|
+
<ion-label>{{translationMap.get('COPILOT.NO_SUGGESTIONS_PRESENT')}}</ion-label>
|
|
38
|
+
</ion-item>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
36
41
|
</div>
|
|
@@ -202,4 +202,31 @@ ion-item {
|
|
|
202
202
|
opacity: 0;
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
.no-data{
|
|
209
|
+
|
|
210
|
+
background-color: white !important;
|
|
211
|
+
width: 100%;
|
|
212
|
+
max-height: 310px;
|
|
213
|
+
overflow-y: auto;
|
|
214
|
+
// padding: 10px 0;
|
|
215
|
+
// margin: 0;
|
|
216
|
+
margin-bottom: 1px;
|
|
217
|
+
font-size: 14px;
|
|
218
|
+
line-height: 1.42857143;
|
|
219
|
+
color: #080f1a;
|
|
220
|
+
box-sizing: border-box;
|
|
221
|
+
-webkit-font-smoothing: antialiased;
|
|
222
|
+
// list-style: none;
|
|
223
|
+
z-index: 999999;
|
|
224
|
+
|
|
225
|
+
.container{
|
|
226
|
+
display: flex;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
flex-direction: column;
|
|
229
|
+
align-items: center;
|
|
230
|
+
|
|
231
|
+
}
|
|
205
232
|
}
|
|
@@ -16,6 +16,7 @@ import { getProjectIdSelectedConversation } from 'src/chat21-core/utils/utils';
|
|
|
16
16
|
export class CopilotSuggestionsComponent implements OnInit {
|
|
17
17
|
|
|
18
18
|
// @Input() tagsCannedFilter: any = []
|
|
19
|
+
@Input() question: string;
|
|
19
20
|
@Input() conversationWith: string;
|
|
20
21
|
@Input() conversationWithFullname: string;
|
|
21
22
|
@Input() currentString: string;
|
|
@@ -28,7 +29,7 @@ export class CopilotSuggestionsComponent implements OnInit {
|
|
|
28
29
|
public projectID: string;
|
|
29
30
|
|
|
30
31
|
public suggestions: any = []
|
|
31
|
-
public
|
|
32
|
+
public showLoading: boolean = false
|
|
32
33
|
|
|
33
34
|
public arrowkeyLocation = -1
|
|
34
35
|
|
|
@@ -93,17 +94,32 @@ export class CopilotSuggestionsComponent implements OnInit {
|
|
|
93
94
|
this.logger.log('[COPILOT] - loadTagsCanned tagsCanned.length', this.suggestions.length)
|
|
94
95
|
//if(this.tagsCanned.length <= 0 ){
|
|
95
96
|
this.suggestions = []
|
|
96
|
-
this.
|
|
97
|
-
|
|
98
|
-
this.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
this.showLoading = true;
|
|
98
|
+
if(this.question && this.question !== ''){
|
|
99
|
+
this.copilotService.getAllFromQuestion(this.question, tiledeskToken, projectId, this.conversationWith).subscribe((res) => {
|
|
100
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses RES', res)
|
|
101
|
+
this.suggestions = res.map(el => ({ ...el, disabled : true }))
|
|
102
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses tagsCannedCount', this.suggestions)
|
|
103
|
+
}, (error) => {
|
|
104
|
+
this.logger.error('[COPILOT] - loadTagsCanned getCannedResponses - ERROR ', error)
|
|
105
|
+
}, () => {
|
|
106
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses * COMPLETE *')
|
|
107
|
+
this.showLoading = false
|
|
108
|
+
this.onLoadedSuggestions.emit(this.suggestions)
|
|
109
|
+
})
|
|
110
|
+
} else {
|
|
111
|
+
this.copilotService.getAll(tiledeskToken, projectId, this.conversationWith).subscribe((res) => {
|
|
112
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses RES', res)
|
|
113
|
+
this.suggestions = res.map(el => ({ ...el, disabled : true }))
|
|
114
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses tagsCannedCount', this.suggestions)
|
|
115
|
+
}, (error) => {
|
|
116
|
+
this.logger.error('[COPILOT] - loadTagsCanned getCannedResponses - ERROR ', error)
|
|
117
|
+
}, () => {
|
|
118
|
+
this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses * COMPLETE *')
|
|
119
|
+
this.showLoading = false
|
|
120
|
+
this.onLoadedSuggestions.emit(this.suggestions)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
|
|
@@ -111,10 +127,9 @@ export class CopilotSuggestionsComponent implements OnInit {
|
|
|
111
127
|
if(!suggestion.disabled){
|
|
112
128
|
event.preventDefault();
|
|
113
129
|
event.stopPropagation();
|
|
114
|
-
} else if(this.suggestionsCount > 0){
|
|
115
|
-
this.onClickSuggestion.emit(suggestion)
|
|
116
130
|
} else {
|
|
117
131
|
this.logger.log('[CANNED] THERE IS NOT CANNED ', suggestion.text)
|
|
132
|
+
this.onClickSuggestion.emit(suggestion)
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
135
|
|
|
@@ -44,6 +44,7 @@ import { OptionsComponent } from 'src/app/chatlib/conversation-detail/message/op
|
|
|
44
44
|
import { UserTypingComponent } from 'src/chat21-core/utils/user-typing/user-typing.component';
|
|
45
45
|
import { AvatarProfileComponent } from 'src/app/components/utils/avatar-profile/avatar-profile.component';
|
|
46
46
|
import { CopilotSuggestionsComponent } from 'src/app/components/copilot-suggestions/copilot-suggestions.component';
|
|
47
|
+
import { CopilotPopoverComponent } from 'src/app/components/copilot-popover/copilot-popover.component';
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
@NgModule({
|
|
@@ -66,7 +67,7 @@ import { CopilotSuggestionsComponent } from 'src/app/components/copilot-suggesti
|
|
|
66
67
|
MomentModule
|
|
67
68
|
],
|
|
68
69
|
// entryComponents: [MessageTextAreaComponent],
|
|
69
|
-
entryComponents: [ BubbleInfoPopoverComponent],
|
|
70
|
+
entryComponents: [ BubbleInfoPopoverComponent, CopilotPopoverComponent],
|
|
70
71
|
declarations: [
|
|
71
72
|
ConversationDetailPage,
|
|
72
73
|
//******** COMPONENTS - init ********//
|
|
@@ -90,6 +91,7 @@ import { CopilotSuggestionsComponent } from 'src/app/components/copilot-suggesti
|
|
|
90
91
|
ReturnReceiptComponent,
|
|
91
92
|
OptionsComponent,
|
|
92
93
|
BubbleInfoPopoverComponent,
|
|
94
|
+
CopilotPopoverComponent,
|
|
93
95
|
UserTypingComponent,
|
|
94
96
|
// --------- footer --------- //
|
|
95
97
|
MessageTextAreaComponent,
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
here is ignored
|
|
62
62
|
</span>
|
|
63
63
|
|
|
64
|
-
<div class="overlay" *ngIf="
|
|
64
|
+
<div class="overlay" *ngIf="SHOW_CANNED_RESPONSES || SHOW_COPILOT_SUGGESTIONS" (click)="this.SHOW_COPILOT_SUGGESTIONS=false; this.SHOW_CANNED_RESPONSES=false"></div>
|
|
65
65
|
|
|
66
66
|
<ng-template #content_welcome>
|
|
67
67
|
<!-- <div class="messageFirst">
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
<!-- ----------------------------------------------------------- -->
|
|
169
169
|
<!-- Canned responses -->
|
|
170
170
|
<!-- ----------------------------------------------------------- -->
|
|
171
|
-
<app-canned-response *ngIf="
|
|
171
|
+
<app-canned-response *ngIf="SHOW_CANNED_RESPONSES"
|
|
172
172
|
id="canned"
|
|
173
173
|
[canShowCanned]="canShowCanned"
|
|
174
174
|
[conversationWith]="conversationWith"
|
|
@@ -183,6 +183,7 @@
|
|
|
183
183
|
|
|
184
184
|
<copilot-suggestions *ngIf="SHOW_COPILOT_SUGGESTIONS"
|
|
185
185
|
id="copilot"
|
|
186
|
+
[question]="copilotQuestion"
|
|
186
187
|
[conversationWith]="conversationWith"
|
|
187
188
|
[conversationWithFullname]="conversationWithFullname"
|
|
188
189
|
[currentString]="messageStr"
|
|
@@ -192,46 +193,7 @@
|
|
|
192
193
|
(onClickSuggestion)="replaceSuggestionInMessage($event)">
|
|
193
194
|
</copilot-suggestions>
|
|
194
195
|
|
|
195
|
-
|
|
196
|
-
<!-- <div id="canned" *ngIf="tagsCannedFilter.length > 0 && HIDE_CANNED_RESPONSES === false">
|
|
197
|
-
<div class="header">
|
|
198
|
-
<ion-item lines="none"> <ion-icon class="canned-response-icon-header" name="flash-outline"></ion-icon> Canned responses</ion-item>
|
|
199
|
-
<ion-item lines="none" (click)="presentCreateCannedResponseModal()">
|
|
200
|
-
<ion-icon class="canned-response-icon-header" name="add" slot="start"></ion-icon>
|
|
201
|
-
New response
|
|
202
|
-
</ion-item>
|
|
203
|
-
<ion-item lines="none" (click)="closeListCannedResponse()"> <ion-icon class="canned-response-icon-header" name="close" ></ion-icon></ion-item>
|
|
204
|
-
</div>
|
|
205
|
-
<ion-list class="canned-list" >
|
|
206
|
-
<ion-item button="true" [ngClass]="{'is_active_item': i == arrowkeyLocation}" lines="none"
|
|
207
|
-
class="canned-item no-ripple border" id="{{'canned-item_'+ i }}"
|
|
208
|
-
*ngFor="let canned of tagsCannedFilter; let i = index;"
|
|
209
|
-
(click)="replaceTagInMessage(canned, $event)">
|
|
210
|
-
<div class="cannedContent">
|
|
211
|
-
<ion-input [(ngModel)]="canned.title" class="title" id="{{'titleCanned_'+canned._id}}" [disabled]="canned.disabled"></ion-input>
|
|
212
|
-
<ion-input [(ngModel)]="canned.text" class="text" [disabled]="canned.disabled"></ion-input>
|
|
213
|
-
</div>
|
|
214
|
-
<ion-icon class="canned-item-icon" name="checkmark-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && !canned.disabled" (click)="onConfirmEditCanned(canned, $event)"></ion-icon>
|
|
215
|
-
<ion-icon class="canned-item-icon" name="pencil-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid && canned.disabled" (click)="onEditCanned(canned, $event)"></ion-icon>
|
|
216
|
-
<ion-icon class="canned-item-icon" name="trash-sharp" slot=end *ngIf="canned.createdBy === loggedUser.uid" (click)="onDeleteCanned(canned, $event)"></ion-icon>
|
|
217
|
-
</ion-item>
|
|
218
|
-
|
|
219
|
-
<ion-item class="canned-item add-canned-response-wpr" button="true" lines="none" (click)="presentCreateCannedResponseModal()">
|
|
220
|
-
<ion-icon class="add-canned-response-icon" name="flash-outline"></ion-icon>
|
|
221
|
-
<span class="add-canned-response-add-icon">+</span>
|
|
222
|
-
<label class="add-canned-response-label" >{{translationMap?.get('AddNewCannedResponse')}}</label>
|
|
223
|
-
</ion-item>
|
|
224
|
-
</ion-list>
|
|
225
|
-
<!- - <ion-list class="canned-list" *ngIf="tagsCannedFilter.length === 0 && HIDE_CANNED_RESPONSES === false">
|
|
226
|
-
<ion-item button="true" >
|
|
227
|
-
There are no canned responses available
|
|
228
|
-
</ion-item>
|
|
229
|
-
</ion-list> - ->
|
|
230
|
-
</div> -->
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
196
|
+
|
|
235
197
|
<!-- (eventReplaceMessageWithCanned)="replaceTagInMessage($event)" -->
|
|
236
198
|
<!-- [tagsCannedFilter]="tagsCannedFilter" -->
|
|
237
199
|
<!-- openInfoConversation {{openInfoConversation}} - isMobile {{isMobile}} -->
|
|
@@ -241,7 +203,6 @@
|
|
|
241
203
|
[channelType]="channelType"
|
|
242
204
|
[channel]="conversation?.attributes?.request_channel"
|
|
243
205
|
[tagsCannedFilter]="tagsCannedFilter"
|
|
244
|
-
[tagsCannedCount]="tagsCannedCount"
|
|
245
206
|
[areVisibleCAR]="areVisibleCAR"
|
|
246
207
|
[supportMode]="supportMode"
|
|
247
208
|
[leadInfo]="leadInfo"
|
|
@@ -132,8 +132,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
132
132
|
|
|
133
133
|
public messageStr: string;
|
|
134
134
|
public tagsCannedFilter: Array<any> = [];
|
|
135
|
-
public
|
|
136
|
-
public HIDE_CANNED_RESPONSES: boolean = true
|
|
135
|
+
public SHOW_CANNED_RESPONSES: boolean = false
|
|
137
136
|
public canShowCanned: boolean = true
|
|
138
137
|
|
|
139
138
|
public SHOW_COPILOT_SUGGESTIONS: boolean = false;
|
|
@@ -163,6 +162,10 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
163
162
|
conversation: ConversationModel;
|
|
164
163
|
USER_ROLE: string;
|
|
165
164
|
|
|
165
|
+
/**COPILOT : start */
|
|
166
|
+
copilotQuestion: string = '';
|
|
167
|
+
/**COPILOT : end */
|
|
168
|
+
|
|
166
169
|
isMine = isMine
|
|
167
170
|
isInfo = isInfo
|
|
168
171
|
isFirstMessage = isFirstMessage
|
|
@@ -259,7 +262,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
259
262
|
this.getConversations();
|
|
260
263
|
this.watchToConnectionStatus();
|
|
261
264
|
this.getOSCODE();
|
|
262
|
-
this.
|
|
265
|
+
this.listenToEventServiceEvents();
|
|
263
266
|
this.listenToDsbrdPostMsgs();
|
|
264
267
|
}
|
|
265
268
|
|
|
@@ -298,7 +301,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
|
|
301
|
-
|
|
304
|
+
listenToEventServiceEvents() {
|
|
302
305
|
this.events.subscribe('storage:last_project', project => {
|
|
303
306
|
this.logger.log('[CONVS-DETAIL] stored_project ', project)
|
|
304
307
|
if (project && project !== 'undefined') {
|
|
@@ -306,6 +309,14 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
306
309
|
this.logger.log('[CONVS-DETAIL] USER_ROLE ', this.USER_ROLE)
|
|
307
310
|
}
|
|
308
311
|
});
|
|
312
|
+
|
|
313
|
+
this.events.subscribe('copilot:new_question', data => {
|
|
314
|
+
this.logger.log('[CONVS-DETAIL] copilot:new_question ', data)
|
|
315
|
+
if(data?.text){
|
|
316
|
+
this.copilotQuestion = data.text
|
|
317
|
+
this.SHOW_COPILOT_SUGGESTIONS = !this.SHOW_COPILOT_SUGGESTIONS
|
|
318
|
+
}
|
|
319
|
+
})
|
|
309
320
|
}
|
|
310
321
|
|
|
311
322
|
getConversations() {
|
|
@@ -686,7 +697,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
686
697
|
"WHATSAPP.ERROR_WHATSAPP_NOT_INSTALLED",
|
|
687
698
|
"WHATSAPP.ERROR_WHATSAPP_GENERIC_ERROR",
|
|
688
699
|
|
|
689
|
-
"COPILOT.ASK_AI"
|
|
700
|
+
"COPILOT.ASK_AI",
|
|
701
|
+
"COPILOT.NO_SUGGESTIONS_PRESENT"
|
|
690
702
|
|
|
691
703
|
]
|
|
692
704
|
|
|
@@ -1492,7 +1504,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1492
1504
|
|
|
1493
1505
|
if (pos === -1) {
|
|
1494
1506
|
// this.tagsCannedFilter = []
|
|
1495
|
-
this.
|
|
1507
|
+
this.SHOW_CANNED_RESPONSES = false
|
|
1496
1508
|
}
|
|
1497
1509
|
// test
|
|
1498
1510
|
// var rest = message.substring(0, message.lastIndexOf("/") + 1);
|
|
@@ -1521,12 +1533,12 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1521
1533
|
|
|
1522
1534
|
var after_slash = message.substring(message.lastIndexOf('/') + 1, message.length)
|
|
1523
1535
|
if (pos === 0 && after_slash.length === 1 && after_slash.trim() === '') {
|
|
1524
|
-
this.logger.log('[CONVS-DETAIL] - returnChangeTextArea after_slash --> there is a white space after ')
|
|
1525
|
-
this.
|
|
1536
|
+
this.logger.log('[CONVS-DETAIL] - returnChangeTextArea after_slash --> there is a white space after ');
|
|
1537
|
+
this.SHOW_CANNED_RESPONSES = false
|
|
1526
1538
|
// this.tagsCannedFilter = []
|
|
1527
1539
|
} else if (pos === 0 && after_slash.length === 0) {
|
|
1528
1540
|
this.logger.log('[CONVS-DETAIL] - returnChangeTextArea after_slash --> there is NOT a white space after')
|
|
1529
|
-
this.
|
|
1541
|
+
this.SHOW_CANNED_RESPONSES = true
|
|
1530
1542
|
}
|
|
1531
1543
|
|
|
1532
1544
|
if (pos > 0) {
|
|
@@ -1543,11 +1555,11 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1543
1555
|
this.logger.log('[CONVS-DETAIL] - returnChangeTextArea --> afterSlash', afterSlash)
|
|
1544
1556
|
|
|
1545
1557
|
if (beforeSlash[beforeSlash.length - 1].indexOf(' ') >= 0 && afterSlash === '') {
|
|
1546
|
-
this.
|
|
1558
|
+
this.SHOW_CANNED_RESPONSES = true
|
|
1547
1559
|
} else if (beforeSlash[beforeSlash.length - 1].indexOf(' ') < 0 && afterSlash === '') {
|
|
1548
|
-
this.
|
|
1560
|
+
this.SHOW_CANNED_RESPONSES = false
|
|
1549
1561
|
} else if (beforeSlash[beforeSlash.length - 1].indexOf(' ') >= 0 && afterSlash === ' ') {
|
|
1550
|
-
this.
|
|
1562
|
+
this.SHOW_CANNED_RESPONSES = false
|
|
1551
1563
|
// this.tagsCannedFilter = []
|
|
1552
1564
|
}
|
|
1553
1565
|
}
|
|
@@ -1583,7 +1595,6 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1583
1595
|
this.logger.log('[CONVS-DETAIL] onLoadedCannedResponses --> ', event)
|
|
1584
1596
|
if (event && event.length > 0) {
|
|
1585
1597
|
this.tagsCannedFilter = event
|
|
1586
|
-
this.tagsCannedCount = event.length
|
|
1587
1598
|
}
|
|
1588
1599
|
}
|
|
1589
1600
|
|
|
@@ -1619,13 +1630,6 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1619
1630
|
|
|
1620
1631
|
}
|
|
1621
1632
|
|
|
1622
|
-
|
|
1623
|
-
closeListCannedResponse() {
|
|
1624
|
-
this.logger.log('[CONVS-DETAIL] close list canned . . . ')
|
|
1625
|
-
this.HIDE_CANNED_RESPONSES = true
|
|
1626
|
-
this.tagsCannedFilter = []
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
1633
|
async presentCreateCannedResponseModal(): Promise<any> {
|
|
1630
1634
|
const elTextArea = this.rowTextArea['el']
|
|
1631
1635
|
const textArea = elTextArea.getElementsByTagName('ion-textarea')[0]
|
|
@@ -1648,11 +1652,12 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1648
1652
|
|
|
1649
1653
|
onClickOpenCannedResponses($event) {
|
|
1650
1654
|
this.logger.log('[CONVS-DETAIL] - onClickOpenCannedResponses ', $event)
|
|
1651
|
-
this.
|
|
1655
|
+
this.SHOW_CANNED_RESPONSES = !this.SHOW_CANNED_RESPONSES
|
|
1656
|
+
this.SHOW_COPILOT_SUGGESTIONS = false;
|
|
1652
1657
|
|
|
1653
1658
|
//HIDE_CANNED_RESPONSES: true --> not show CANNED component
|
|
1654
1659
|
//HIDE_CANNED_RESPONSES: false --> show CANNED component and place '/' char in textarea
|
|
1655
|
-
if (
|
|
1660
|
+
if (this.SHOW_CANNED_RESPONSES) {
|
|
1656
1661
|
const elTextArea = this.rowTextArea['el']
|
|
1657
1662
|
const textArea = elTextArea.getElementsByTagName('ion-textarea')[0]
|
|
1658
1663
|
if (elTextArea) {
|
|
@@ -1671,30 +1676,18 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1671
1676
|
/** COPILOT SUGGGESTIONS : start */
|
|
1672
1677
|
onLoadedSuggestions(event){
|
|
1673
1678
|
this.logger.log('[CONVS-DETAIL] onLoadedSuggestions --> ', event)
|
|
1674
|
-
if (event && event.length > 0) {
|
|
1675
|
-
// this.tagsCannedFilter = event
|
|
1676
|
-
// this.tagsCannedCount = event.length
|
|
1677
|
-
}
|
|
1678
1679
|
}
|
|
1679
1680
|
|
|
1680
1681
|
replaceSuggestionInMessage(suggestion, event?) {
|
|
1681
1682
|
const elTextArea = this.rowTextArea['el']
|
|
1682
1683
|
const textArea = elTextArea.getElementsByTagName('ion-textarea')[0] as HTMLInputElement;
|
|
1683
|
-
// console.log('[CONVS-DETAIL] replaceTagInMessage textArea ', textArea)
|
|
1684
|
-
// console.log('[CONVS-DETAIL] replaceTagInMessage textArea value', textArea.value,)
|
|
1685
1684
|
|
|
1686
|
-
|
|
1687
|
-
// if (lastChar === '/') {
|
|
1688
|
-
// textArea.value = textArea.value.substring(0, textArea.value.length() - 1);
|
|
1689
|
-
// }
|
|
1690
|
-
// this.insertAtCursor(this.textArea, textArea.value)
|
|
1691
|
-
|
|
1692
|
-
this.logger.log('[CONVS-DETAIL] replaceTagInMessage canned text ', suggestion.text)
|
|
1685
|
+
this.logger.log('[CONVS-DETAIL] replaceSuggestionInMessage canned text ', suggestion.text)
|
|
1693
1686
|
|
|
1694
1687
|
// replace text
|
|
1695
|
-
var strTEMP = textArea.value +
|
|
1688
|
+
var strTEMP = textArea.value + suggestion.text
|
|
1696
1689
|
strTEMP = this.replacePlaceholderInCanned(strTEMP)
|
|
1697
|
-
this.logger.log('[CONVS-DETAIL]
|
|
1690
|
+
this.logger.log('[CONVS-DETAIL] replaceSuggestionInMessage strSearch ', strTEMP)
|
|
1698
1691
|
// strTEMP = this.replacePlaceholderInCanned(strTEMP);
|
|
1699
1692
|
// textArea.value = '';
|
|
1700
1693
|
// that.messageString = strTEMP;
|
|
@@ -1906,6 +1899,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
|
|
|
1906
1899
|
}
|
|
1907
1900
|
if(event === 'copilot'){
|
|
1908
1901
|
this.SHOW_COPILOT_SUGGESTIONS = !this.SHOW_COPILOT_SUGGESTIONS
|
|
1902
|
+
this.SHOW_CANNED_RESPONSES = false
|
|
1903
|
+
this.copilotQuestion = ''
|
|
1909
1904
|
}
|
|
1910
1905
|
}
|
|
1911
1906
|
|
|
@@ -24,8 +24,8 @@ export class CopilotService {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
public getAll(token: string, projectid: string, conversWith: string) {
|
|
27
|
-
const
|
|
28
|
-
this.logger.log('[COPILOT-SERVICE] getAllSuggestions - URL ',
|
|
27
|
+
const url = this.apiUrl + projectid + "/copilot?request_id=" + conversWith;
|
|
28
|
+
this.logger.log('[COPILOT-SERVICE] getAllSuggestions - URL ', url);
|
|
29
29
|
|
|
30
30
|
const httpOptions = {
|
|
31
31
|
headers: new HttpHeaders({
|
|
@@ -34,11 +34,34 @@ export class CopilotService {
|
|
|
34
34
|
})
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
return this.http.get(
|
|
37
|
+
return this.http.get(url, httpOptions).pipe(map((res: [any]) => {
|
|
38
38
|
let suggestions = res.filter(el => el !== null).map(el => ({ ...el, _id: uuid.v4()} ));
|
|
39
39
|
this.logger.log('[COPILOT-SERVICE] getCannedResponses - RES ', suggestions);
|
|
40
40
|
return suggestions
|
|
41
41
|
}))
|
|
42
|
-
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public getAllFromQuestion(question: string, token: string, projectid: string, conversWith: string) {
|
|
45
|
+
const url = this.apiUrl + projectid + "/copilot?request_id=" + conversWith;
|
|
46
|
+
this.logger.log('[COPILOT-SERVICE] getAllSuggestions - URL ', url);
|
|
47
|
+
|
|
48
|
+
const httpOptions = {
|
|
49
|
+
headers: new HttpHeaders({
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
Authorization: token
|
|
52
|
+
})
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
console.log('questionnnn', question)
|
|
56
|
+
const body = {
|
|
57
|
+
text: question
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return this.http.post(url, body, httpOptions).pipe(map((res: [any]) => {
|
|
61
|
+
let suggestions = res.filter(el => el !== null).map(el => ({ ...el, _id: uuid.v4()} ));
|
|
62
|
+
this.logger.log('[COPILOT-SERVICE] getCannedResponses - RES ', suggestions);
|
|
63
|
+
return suggestions
|
|
64
|
+
}))
|
|
65
|
+
}
|
|
43
66
|
|
|
44
67
|
}
|
package/src/assets/i18n/en.json
CHANGED
|
@@ -305,7 +305,11 @@
|
|
|
305
305
|
"SUBJECT_OFFLINE_MESSAGE":"Tiledesk Offline message 💬",
|
|
306
306
|
"SEND_EMAIL_SUCCESS_OFFLINE_MESSAGE":"Message also sent by email 📩"
|
|
307
307
|
},
|
|
308
|
+
"HELLO":"Hello",
|
|
308
309
|
"COPILOT": {
|
|
309
|
-
"ASK_AI":"Ask to AI"
|
|
310
|
+
"ASK_AI":"Ask to AI",
|
|
311
|
+
"NO_SUGGESTIONS_PRESENT":"No suggestions found",
|
|
312
|
+
"INSERT_PROMPT_HERE":"Inster a prompt here",
|
|
313
|
+
"HOW_CAN_I_HELP_YOU":"How can i help you?"
|
|
310
314
|
}
|
|
311
315
|
}
|
package/src/assets/i18n/it.json
CHANGED
|
@@ -305,7 +305,11 @@
|
|
|
305
305
|
"SUBJECT_OFFLINE_MESSAGE":"Messaggio offline di Tiledesk 💬",
|
|
306
306
|
"SEND_EMAIL_SUCCESS_OFFLINE_MESSAGE":"Messaggio inviato anche via mail 📩"
|
|
307
307
|
},
|
|
308
|
+
"HELLO":"Ciao",
|
|
308
309
|
"COPILOT": {
|
|
309
|
-
"ASK_AI":"Chiedi all'AI"
|
|
310
|
+
"ASK_AI":"Chiedi all'AI",
|
|
311
|
+
"NO_SUGGESTIONS_PRESENT":"Nessun suggerimento trovato",
|
|
312
|
+
"INSERT_PROMPT_HERE":"Inserisci un prompt qui",
|
|
313
|
+
"HOW_CAN_I_HELP_YOU":"Come posso aiutarti?"
|
|
310
314
|
}
|
|
311
315
|
}
|
package/src/global.scss
CHANGED