@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.
Files changed (30) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +1 -1
  3. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.html +2 -2
  4. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.ts +12 -7
  5. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.html +1 -1
  6. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.ts +4 -30
  7. package/src/app/chatlib/conversation-detail/message/options/options.component.html +4 -1
  8. package/src/app/chatlib/conversation-detail/message/options/options.component.scss +7 -0
  9. package/src/app/chatlib/conversation-detail/message/options/options.component.ts +40 -8
  10. package/src/app/components/canned-response/canned-response.component.html +8 -3
  11. package/src/app/components/canned-response/canned-response.component.scss +26 -0
  12. package/src/app/components/canned-response/canned-response.component.ts +9 -31
  13. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +2 -3
  14. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +11 -0
  15. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +0 -1
  16. package/src/app/components/copilot-popover/copilot-popover.component.html +25 -0
  17. package/src/app/components/copilot-popover/copilot-popover.component.scss +101 -0
  18. package/src/app/components/copilot-popover/copilot-popover.component.spec.ts +24 -0
  19. package/src/app/components/copilot-popover/copilot-popover.component.ts +81 -0
  20. package/src/app/components/copilot-suggestions/copilot-suggestions.component.html +9 -4
  21. package/src/app/components/copilot-suggestions/copilot-suggestions.component.scss +27 -0
  22. package/src/app/components/copilot-suggestions/copilot-suggestions.component.ts +29 -14
  23. package/src/app/pages/conversation-detail/conversation-detail.module.ts +3 -1
  24. package/src/app/pages/conversation-detail/conversation-detail.page.html +4 -43
  25. package/src/app/pages/conversation-detail/conversation-detail.page.ts +32 -37
  26. package/src/app/services/copilot/copilot.service.ts +27 -4
  27. package/src/assets/i18n/en.json +5 -1
  28. package/src/assets/i18n/it.json +5 -1
  29. package/src/global.scss +6 -0
  30. 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-ionic",
3
3
  "author": "Tiledesk SRL",
4
- "version": "3.4.13-rc1",
4
+ "version": "3.4.13-rc3",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -132,7 +132,7 @@
132
132
  (onBeforeMessageRender)="onBeforeMessageRenderFN($event)"
133
133
  (onAfterMessageRender)="onAfterMessageRenderFN($event)"
134
134
  (onElementRendered)="onElementRenderedFN($event)"
135
- (onOptionsMessage)="onClickOptionsMessage($event)">
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
- (onOptionsMessage)="onClickOptionsMessage($event)">
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
- onClickOptionsMessage(event:{option: string, message: MessageModel}){
158
- this.logger.log('[CONVS-DETAIL][ION-CONVS-DETAIL] - onClickBubbleMenu', event);
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
 
@@ -12,7 +12,7 @@
12
12
  <chat-options
13
13
  [message]="message"
14
14
  [logLevel]="logger.getLoggerConfig().logLevel"
15
- (onOptionsMessage)="onOptionsMessageFN($event)">
15
+ (onOptionsDataReturned)="onOptionsDataReturnedFN($event)">
16
16
  </chat-options>
17
17
 
18
18
  <div>
@@ -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() onOptionsMessage = new EventEmitter<{option: string, message: MessageModel}>();
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
- onOptionsMessageFN(event){
166
- this.onOptionsMessage.emit(event)
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, message)" >
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>
@@ -28,6 +28,13 @@
28
28
 
29
29
  &:hover{
30
30
  cursor: pointer;
31
+ ion-icon#copilot{
32
+
33
+ transition: transform 1s ease-in-out;
34
+ transform: rotate(180deg);
35
+ color: #ac87eb;
36
+
37
+ }
31
38
  }
32
39
  }
33
40
 
@@ -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() onOptionsMessage = new EventEmitter<{option: string, message: MessageModel}>();
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, message){
26
- this.logger.log('[BUBBLE-MESSAGE] - onClickOptionsMessage', message);
27
- this.presentPopover(event, message)
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, message: MessageModel) {
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.onOptionsMessage.emit({option: dataReturned.data.option, message: message})
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="tagsCannedFilter.length === 0">
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="!canShowCanned">
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
- this.showTagsCanned(strSearch)
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 NOT CANNED ', canned.text)
252
+ this.logger.log('[CANNED] THERE IS CANNED ', canned.text)
253
+ this.onClickCanned.emit(canned)
276
254
  }
277
255
  }
278
256
 
@@ -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>
@@ -38,6 +38,17 @@
38
38
  margin-right: 4px;
39
39
  margin-left: 4px;
40
40
  }
41
+
42
+ &#copilot {
43
+ &:hover{
44
+ ion-icon {
45
+ transition: transform 1s ease-in-out;
46
+ transform: rotate(180deg);
47
+ color: #ac87eb;
48
+ }
49
+ }
50
+
51
+ }
41
52
  }
42
53
  }
43
54
 
@@ -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="suggestions.length === 0">
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
- <!-- <div *ngIf="!canShowCanned">
34
-
35
- </div> -->
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 suggestionsCount: number
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.copilotService.getAll(tiledeskToken, projectId, this.conversationWith).subscribe((res) => {
97
- this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses RES', res)
98
- this.suggestions = res.map(el => ({ ...el, disabled : true }))
99
- this.suggestionsCount = res.length
100
- this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses tagsCannedCount', this.suggestions)
101
- }, (error) => {
102
- this.logger.error('[COPILOT] - loadTagsCanned getCannedResponses - ERROR ', error)
103
- }, () => {
104
- this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses * COMPLETE *')
105
- this.onLoadedSuggestions.emit(this.suggestions)
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="!HIDE_CANNED_RESPONSES || SHOW_COPILOT_SUGGESTIONS"></div>
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="HIDE_CANNED_RESPONSES === false"
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 tagsCannedCount: number;
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.getStoredProjectAndUserRole();
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
- getStoredProjectAndUserRole() {
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.HIDE_CANNED_RESPONSES = true
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.HIDE_CANNED_RESPONSES = true
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.HIDE_CANNED_RESPONSES = false
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.HIDE_CANNED_RESPONSES = false
1558
+ this.SHOW_CANNED_RESPONSES = true
1547
1559
  } else if (beforeSlash[beforeSlash.length - 1].indexOf(' ') < 0 && afterSlash === '') {
1548
- this.HIDE_CANNED_RESPONSES = true
1560
+ this.SHOW_CANNED_RESPONSES = false
1549
1561
  } else if (beforeSlash[beforeSlash.length - 1].indexOf(' ') >= 0 && afterSlash === ' ') {
1550
- this.HIDE_CANNED_RESPONSES = true
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.HIDE_CANNED_RESPONSES = !this.HIDE_CANNED_RESPONSES
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 (!this.HIDE_CANNED_RESPONSES) {
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
- // var lastChar = textArea.value.substr(-1); // Selects the last character
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 + ' ' + suggestion.text
1688
+ var strTEMP = textArea.value + suggestion.text
1696
1689
  strTEMP = this.replacePlaceholderInCanned(strTEMP)
1697
- this.logger.log('[CONVS-DETAIL] replaceTagInMessage strSearch ', strTEMP)
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 cannedResponsesURL = this.apiUrl + projectid + "/copilot?request_id=" + conversWith;
28
- this.logger.log('[COPILOT-SERVICE] getAllSuggestions - URL ', cannedResponsesURL);
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(cannedResponsesURL, httpOptions).pipe(map((res: [any]) => {
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
  }
@@ -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
  }
@@ -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
@@ -715,6 +715,12 @@ ul.dropdown-menu > li > a {
715
715
  }
716
716
  }
717
717
 
718
+ .copilot-popover{
719
+ .popover-content{
720
+ width: 450px;
721
+ }
722
+ }
723
+
718
724
 
719
725
  //TOOLTIP
720
726
  .tooltip-container {
@@ -24,6 +24,7 @@ body {
24
24
  --icon-color: rgb(135, 150, 175);
25
25
  --basic-blue: #2a69c1;
26
26
  --basic-red: #EB1E23;
27
+ --bacis-white: #fff;
27
28
 
28
29
  // ***** Conversation-list: start ***** //
29
30
  --list-bkg-color: #f8fafc;