@chat21/chat21-ionic 3.4.13-rc2 → 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 (27) hide show
  1. package/CHANGELOG.md +4 -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 +7 -26
  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/copilot-popover/copilot-popover.component.html +25 -0
  16. package/src/app/components/copilot-popover/copilot-popover.component.scss +101 -0
  17. package/src/app/components/copilot-popover/copilot-popover.component.spec.ts +24 -0
  18. package/src/app/components/copilot-popover/copilot-popover.component.ts +81 -0
  19. package/src/app/components/copilot-suggestions/copilot-suggestions.component.ts +26 -11
  20. package/src/app/pages/conversation-detail/conversation-detail.module.ts +3 -1
  21. package/src/app/pages/conversation-detail/conversation-detail.page.html +2 -1
  22. package/src/app/pages/conversation-detail/conversation-detail.page.ts +17 -2
  23. package/src/app/services/copilot/copilot.service.ts +27 -4
  24. package/src/assets/i18n/en.json +4 -1
  25. package/src/assets/i18n/it.json +4 -1
  26. package/src/global.scss +6 -0
  27. package/src/variables.scss +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
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
+
3
7
  ### 3.4.13-rc.2
4
8
  - added: no-suggestions in copilot component
5
9
  - changed: HIDE_CANNED_RESPONSES with SHOW CANNED_RESPONSES
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-rc2",
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
  }
@@ -32,6 +32,7 @@ export class CannedResponseComponent implements OnInit {
32
32
 
33
33
  public tagsCanned: any = []
34
34
  public tagsCannedFilter: any = []
35
+ public showLoading: boolean = false
35
36
 
36
37
  public arrowkeyLocation = -1
37
38
 
@@ -123,17 +124,21 @@ export class CannedResponseComponent implements OnInit {
123
124
  this.logger.log('[CANNED] - loadTagsCanned tagsCanned.length', this.tagsCanned.length)
124
125
  //if(this.tagsCanned.length <= 0 ){
125
126
  this.tagsCanned = []
127
+ this.showLoading = true;
126
128
  this.cannedResponsesService.getAll(tiledeskToken, projectId).subscribe((res) => {
127
129
  this.logger.log('[CANNED] - loadTagsCanned getCannedResponses RES', res)
128
130
 
129
131
  this.tagsCanned = res
130
132
  // if (this.HIDE_CANNED_RESPONSES === false) {
131
- this.showTagsCanned(strSearch)
133
+ this.showTagsCanned(strSearch)
132
134
  // }
133
135
  }, (error) => {
134
136
  this.logger.error('[CANNED] - loadTagsCanned getCannedResponses - ERROR ', error)
135
137
  }, () => {
136
138
  this.logger.log('[CANNED] - loadTagsCanned getCannedResponses * COMPLETE *')
139
+ setTimeout(() => {
140
+ this.showLoading = false
141
+ }, 1000);
137
142
  })
138
143
  }
139
144
 
@@ -163,33 +168,9 @@ export class CannedResponseComponent implements OnInit {
163
168
  canned.text = this.replacePlaceholderInCanned(canned.text);
164
169
  canned.disabled = true
165
170
  });
166
- if (this.tagsCannedFilter && this.tagsCannedFilter.length === 0) {
167
- // const button = this.renderer.createElement('button');
168
- // const buttonText = this.renderer.createText('Click me');
169
- // this.renderer.appendChild(button, buttonText);
170
- // console.log('[CANNED] - this.el.nativeElement ', this.el.nativeElement)
171
- // this.renderer.listen(button, 'click', () => { alert('hi'); });
172
- // let nocanned = {}
173
- // if (this.USER_ROLE !== 'agent') {
174
- const nocanned = {
175
- // "<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>'
176
- // <div class='cannedText no-canned-available-text'>" + this.translationMap.get('AddNewCannedResponse') + '</div>
177
- title: this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') ,
178
- text: '',
179
- disabled: true
180
- }
181
- // } else if (this.USER_ROLE === 'agent') {
182
- // nocanned = {
183
- // // "<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>'
184
- // title:
185
- // "<div class='cannedContent'><div class='cannedTitle nocannedTitle #noCannedTitle'>" + this.translationMap.get('THERE_ARE_NO_CANNED_RESPONSES_AVAILABLE') + ".</div></div>",
186
- // text: 'There are no canned responses available',
187
- // }
188
- // }
189
- this.tagsCannedFilter.push(nocanned)
190
- }
191
171
  this.appStorageService.setItem(this.projectID+'_canned', JSON.stringify(this.tagsCannedFilter))
192
172
  this.onLoadedCannedResponses.emit(this.tagsCannedFilter)
173
+
193
174
  }
194
175
 
195
176
  filterItems(items, searchTerm) {
@@ -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
 
@@ -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
+ }
@@ -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;
@@ -94,17 +95,31 @@ export class CopilotSuggestionsComponent implements OnInit {
94
95
  //if(this.tagsCanned.length <= 0 ){
95
96
  this.suggestions = []
96
97
  this.showLoading = true;
97
- this.copilotService.getAll(tiledeskToken, projectId, this.conversationWith).subscribe((res) => {
98
- this.logger.log('[COPILOT] - loadTagsCanned getCannedResponses RES', res)
99
- this.suggestions = res.map(el => ({ ...el, disabled : true }))
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.showLoading = false
106
- this.onLoadedSuggestions.emit(this.suggestions)
107
- })
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
+ }
108
123
  }
109
124
 
110
125
 
@@ -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="SHOW_CANNED_RESPONSES || SHOW_COPILOT_SUGGESTIONS" (click)="this.SHOW_COPILOT_SUGGESTIONS=!this.SHOW_COPILOT_SUGGESTIONS; this.SHOW_CANNED_RESPONSES = !this.SHOW_CANNED_RESPONSES"></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">
@@ -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"
@@ -162,6 +162,10 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
162
162
  conversation: ConversationModel;
163
163
  USER_ROLE: string;
164
164
 
165
+ /**COPILOT : start */
166
+ copilotQuestion: string = '';
167
+ /**COPILOT : end */
168
+
165
169
  isMine = isMine
166
170
  isInfo = isInfo
167
171
  isFirstMessage = isFirstMessage
@@ -258,7 +262,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
258
262
  this.getConversations();
259
263
  this.watchToConnectionStatus();
260
264
  this.getOSCODE();
261
- this.getStoredProjectAndUserRole();
265
+ this.listenToEventServiceEvents();
262
266
  this.listenToDsbrdPostMsgs();
263
267
  }
264
268
 
@@ -297,7 +301,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
297
301
  }
298
302
 
299
303
 
300
- getStoredProjectAndUserRole() {
304
+ listenToEventServiceEvents() {
301
305
  this.events.subscribe('storage:last_project', project => {
302
306
  this.logger.log('[CONVS-DETAIL] stored_project ', project)
303
307
  if (project && project !== 'undefined') {
@@ -305,6 +309,14 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
305
309
  this.logger.log('[CONVS-DETAIL] USER_ROLE ', this.USER_ROLE)
306
310
  }
307
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
+ })
308
320
  }
309
321
 
310
322
  getConversations() {
@@ -1641,6 +1653,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1641
1653
  onClickOpenCannedResponses($event) {
1642
1654
  this.logger.log('[CONVS-DETAIL] - onClickOpenCannedResponses ', $event)
1643
1655
  this.SHOW_CANNED_RESPONSES = !this.SHOW_CANNED_RESPONSES
1656
+ this.SHOW_COPILOT_SUGGESTIONS = false;
1644
1657
 
1645
1658
  //HIDE_CANNED_RESPONSES: true --> not show CANNED component
1646
1659
  //HIDE_CANNED_RESPONSES: false --> show CANNED component and place '/' char in textarea
@@ -1886,6 +1899,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1886
1899
  }
1887
1900
  if(event === 'copilot'){
1888
1901
  this.SHOW_COPILOT_SUGGESTIONS = !this.SHOW_COPILOT_SUGGESTIONS
1902
+ this.SHOW_CANNED_RESPONSES = false
1903
+ this.copilotQuestion = ''
1889
1904
  }
1890
1905
  }
1891
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,8 +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
310
  "ASK_AI":"Ask to AI",
310
- "NO_SUGGESTIONS_PRESENT":"No suggestions found"
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?"
311
314
  }
312
315
  }
@@ -305,8 +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
310
  "ASK_AI":"Chiedi all'AI",
310
- "NO_SUGGESTIONS_PRESENT":"Nessun suggerimento trovato"
311
+ "NO_SUGGESTIONS_PRESENT":"Nessun suggerimento trovato",
312
+ "INSERT_PROMPT_HERE":"Inserisci un prompt qui",
313
+ "HOW_CAN_I_HELP_YOU":"Come posso aiutarti?"
311
314
  }
312
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;