@chat21/chat21-ionic 3.0.70-rc.2 → 3.0.71

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 (21) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +14 -4
  3. package/package.json +1 -1
  4. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.html +1 -1
  5. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.scss +5 -0
  6. package/src/app/chatlib/conversation-detail/message/info-message/info-message.component.html +20 -5
  7. package/src/app/chatlib/conversation-detail/message/info-message/info-message.component.scss +39 -2
  8. package/src/app/chatlib/conversation-detail/message/info-message/info-message.component.ts +11 -0
  9. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +5 -5
  10. package/src/app/components/sidebar-user-details/sidebar-user-details.component.ts +1 -2
  11. package/src/app/pages/conversation-detail/conversation-detail.page.ts +33 -0
  12. package/src/app/pages/conversations-list/conversations-list.page.html +2 -2
  13. package/src/app/pages/conversations-list/conversations-list.page.scss +24 -0
  14. package/src/app/pages/loader-preview/loader-preview.page.html +7 -2
  15. package/src/app/pages/loader-preview/loader-preview.page.ts +3 -2
  16. package/src/chat-config-mqtt.json +1 -1
  17. package/src/chat21-core/providers/abstract/conversation-handler.service.ts +3 -1
  18. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +4 -0
  19. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +6 -2
  20. package/src/chat21-core/providers/native/native-upload-service.ts +4 -2
  21. package/src/chat21-core/utils/utils-message.ts +3 -3
package/CHANGELOG.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # chat21-ionic ver 3.0
2
2
 
3
+ ### 3.0.71 in PROD
4
+
5
+ ### 3.0.71-rc.1
6
+ - changed: native downloadURL on new file uploaded
7
+ - added: update lead info in conversation-detail and conversation-header when agent updates
8
+ - added: private message UI when agent receive a private message from other agents
9
+ - removed: scroll-bar from conversation-list page
10
+
11
+ ### 3.0.70 in PROD
12
+
3
13
  ### 3.0.70-rc.2
4
14
  - added: cache control max-age
15
+ - added: tooltip on info message in conversation-detail page
5
16
 
6
17
  ### 3.0.70-rc.1
7
18
  - changed: README and LICENSE files
package/README.md CHANGED
@@ -4,10 +4,20 @@
4
4
  >
5
5
  > ***Use [Docker Compose Tiledesk installation](https://github.com/Tiledesk/tiledesk-deployment/blob/master/docker-compose/README.md) guide***
6
6
 
7
- Chat21 is the core of the open source live chat platform [Tiledesk.com](http://www.tiledesk.com).
7
+ # Introduction
8
8
 
9
- ## Community? Questions? Support?
10
- If you need help or just want to hang out, come, say hi on our [<img width="15" alt="Tiledesk discord" src="https://seeklogo.com/images/D/discord-color-logo-E5E6DFEF80-seeklogo.com.png"> Discord](https://discord.gg/WQPfqShJ) server.
9
+ Chat21 is the core of the open source live chat platform [Tiledesk.com](http://www.tiledesk.com). Tiledesk is an Open Source Live Chat platform with integrated Chatbots written in NodeJs and Express. Build your own customer support with a multi-channel platform for Web, Android and iOS.
10
+
11
+ Designed to be open source since the beginning, we actively worked on it to create a totally new, first class customer service platform based on instant messaging.
12
+
13
+ What is Tiledesk today? It became the open source “conversational app development” platform that everyone needs 😌
14
+
15
+ You can use Tiledesk to increase sales for your website or for post-sales customer service. Every conversation can be automated using our first class native chatbot technology. You can also connect your own applications using our APIs or Webhooks. Moreover you can deploy entire visual applications inside a conversation. And your applications can converse with your chatbots or your end-users! We know this is cool 😎
16
+
17
+ Tiledesk is multichannel in a totally new way. You can write your chatbot scripts with images, buttons and other cool elements that your channels support. But you will configureyour chatbot replies only once. They will run on every channel, auto-adapting the responses to the target channel whatever it is, Whatsapp, Facebook Messenger, Telegram etc.
18
+
19
+ # Community? Questions? Support?
20
+ If you need help or just want to hang out, come, say hi on our [<img width="15" alt="Tiledesk discord" src="https://seeklogo.com/images/D/discord-color-logo-E5E6DFEF80-seeklogo.com.png"> Discord](https://discord.gg/nERZEZ7SmG) server.
11
21
 
12
22
  # Features #
13
23
  With Chat21-ionic you can:
@@ -188,4 +198,4 @@ To auto login pass the JWT token as a query parameter of your Chat url as in the
188
198
 
189
199
  "http://localhost:8100/#/conversation-detail?jwt=<JWT_TOKEN>"
190
200
 
191
- ```
201
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-ionic",
3
3
  "author": "Tiledesk SRL",
4
- "version": "3.0.70-rc.2",
4
+ "version": "3.0.71",
5
5
  "license": "AGPL-3.0",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -119,7 +119,7 @@
119
119
  <!--backgroundColor non viene ancora usato -->
120
120
 
121
121
  <chat-bubble-message class="messages msg_receive" id="message_msg_receive" style="position: relative;"
122
- [ngClass]="{'has-metadata': (isImage(message) || isFrame(message))}"
122
+ [ngClass]="{'has-metadata': (isImage(message) || isFrame(message)), 'privateMsg': (message?.attributes && message?.attributes?.subtype === 'private')}"
123
123
  [class.emoticon]="isEmojii(message?.text)"
124
124
  [message]="message"
125
125
  [textColor]="'black'"
@@ -152,6 +152,11 @@ ion-item {
152
152
  width: auto;
153
153
  border-top-left-radius: 8px;
154
154
  border-bottom-left-radius: 0px;
155
+
156
+ &.privateMsg{
157
+ background-color: var(--bubble-privateMsg);
158
+ color: var(--bubble-privateMsgColor)
159
+ }
155
160
  }
156
161
 
157
162
  .emoticon {
@@ -1,5 +1,20 @@
1
- <span class="base_info" [innerHTML]="message?.text | htmlEntiesEncode | marked" [tooltip]="timeTooltipLeft" placement="left" content-type="template">
2
- <!-- <span class="base_info" [innerHTML]="message_text | marked"></span> -->
3
- <ng-template #timeTooltipLeft>
4
- <span>{{message.timestamp | amTimeAgo}} ({{message.timestamp | amLocal | amDateFormat: 'L HH:mm:ss'}})</span>
5
- </ng-template>
1
+ <div class="info-container">
2
+ <!-- <div class="spinner">
3
+ <div class="bounce3"></div>
4
+ <div class="bounce2"></div>
5
+ <div class="bounce1"></div>
6
+ </div> -->
7
+
8
+ <div>
9
+ <span class="base_info" [innerHTML]="message?.text | marked" [options]="tooltipOptions" [tooltip]="timeTooltipLeft" placement="left" content-type="template"></span>
10
+ <ng-template #timeTooltipLeft>
11
+ <span>{{message.timestamp | amTimeAgo}} ({{message.timestamp | amLocal | amDateFormat: 'L HH:mm:ss'}})</span>
12
+ </ng-template>
13
+ </div>
14
+
15
+ <!-- <div class="spinner">
16
+ <div class="bounce1"></div>
17
+ <div class="bounce2"></div>
18
+ <div class="bounce3"></div>
19
+ </div> -->
20
+ </div>
@@ -1,3 +1,9 @@
1
+ .info-container{
2
+ display: flex;
3
+ align-content: center;
4
+ justify-content: center;
5
+ }
6
+
1
7
  .base_info {
2
8
  border-radius: 14px;
3
9
  border: 1px solid #C9E4F6;
@@ -8,8 +14,39 @@
8
14
  background: #C9E4F6;
9
15
  font-size: 0.70em;
10
16
  color: var(--basic-gray);
11
- margin-left: 32px;
12
- margin-right: 32px;
17
+ margin-left: 5px; //32px;
18
+ margin-right: 5px; //32px;
13
19
 
14
20
  }
15
21
 
22
+ .spinner {
23
+ // margin: 15px 10px; //remove it if activate avatar image
24
+ width: 45px;
25
+ // text-align: center;
26
+ min-height: 100%;
27
+ margin: auto 0px;
28
+ }
29
+
30
+ .spinner > div {
31
+ width: 10px;
32
+ height: 10px;
33
+ background-color: #333;
34
+
35
+ border-radius: 100%;
36
+ display: inline-block;
37
+ margin: 0px 2px;
38
+ }
39
+
40
+ .spinner .bounce1 {
41
+ background-color: #C9E4F6;
42
+ }
43
+
44
+ .spinner .bounce2 {
45
+ background-color: #C9E4F6;
46
+ opacity: 0.6
47
+ }
48
+
49
+ .spinner .bounce3 {
50
+ background-color: #C9E4F6;
51
+ opacity: 0.4
52
+ }
@@ -16,6 +16,17 @@ export class InfoMessageComponent implements OnInit, OnChanges {
16
16
 
17
17
  public message_text: string
18
18
  private logger: LoggerService = LoggerInstance.getInstance()
19
+
20
+ tooltipOptions = {
21
+ 'show-delay': 500,
22
+ 'tooltip-class': 'chat-tooltip',
23
+ 'theme': 'light',
24
+ 'shadow': false,
25
+ 'hide-delay-mobile': 0,
26
+ 'hideDelayAfterClick': 3000,
27
+ 'hide-delay': 200
28
+ };
29
+
19
30
  constructor() { }
20
31
 
21
32
  ngOnInit() {
@@ -157,11 +157,11 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
157
157
  } else {
158
158
  this.IS_SUPPORT_GROUP_CONVERSATION = false
159
159
  }
160
- this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges supportMode ', this.supportMode)
161
- this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges disableTextarea ', this.disableTextarea)
162
- this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges DROP EVENT ", this.dropEvent);
163
- this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges tagsCannedFilter ", this.tagsCannedFilter);
164
- this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges areVisibleCAR; ", this.areVisibleCAR);
160
+ // this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges supportMode ', this.supportMode)
161
+ // this.logger.log('[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges disableTextarea ', this.disableTextarea)
162
+ // this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges DROP EVENT ", this.dropEvent);
163
+ // this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges tagsCannedFilter ", this.tagsCannedFilter);
164
+ // this.logger.log("[CONVS-DETAIL][MSG-TEXT-AREA] ngOnChanges areVisibleCAR; ", this.areVisibleCAR);
165
165
 
166
166
 
167
167
  this.logger.log('[CONVS-DETAIL] - returnChangeTextArea ngOnChanges in [MSG-TEXT-AREA] this.tagsCannedFilter.length ', this.tagsCannedFilter.length)
@@ -137,8 +137,7 @@ export class SidebarUserDetailsComponent implements OnInit, OnChanges {
137
137
 
138
138
  @HostListener('document:click', ['$event'])
139
139
  clickout(event) {
140
- this.logger.log('[SIDEBAR-USER-DETAILSS-CHAT] clickout event.target)', event.target)
141
- this.logger.log('[SIDEBAR-USER-DETAILSS-CHAT] clickout event.target)', event.target.id)
140
+ // this.logger.log('[SIDEBAR-USER-DETAILSS-CHAT] clickout event.target)', event.target)
142
141
  const clicked_element_id = event.target.id
143
142
  if (this.eRef.nativeElement.contains(event.target)) {
144
143
  // this.logger.log('[SIDEBAR-USER-DETAILS] clicked inside')
@@ -971,6 +971,20 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
971
971
  this.subscriptions.push(subscribe)
972
972
  }
973
973
 
974
+ subscriptionKey = 'messageInfo'
975
+ subscription = this.subscriptions.find((item) => item.key === subscriptionKey)
976
+ if (!subscription) {
977
+ subscription = this.conversationHandlerService.messageInfo.subscribe((msg: any) => {
978
+ this.logger.log('[CONVS-DETAIL] subscribe to messageInfo - messageId ', msg)
979
+ if (msg) {
980
+ that.updateLeadInfo(msg)
981
+ // this.setHeaderContent()
982
+ }
983
+ })
984
+ const subscribe = { key: subscriptionKey, value: subscription }
985
+ this.subscriptions.push(subscribe)
986
+ }
987
+
974
988
  // subscriptionKey = 'onGroupChange';
975
989
  // subscription = this.subscriptions.find(item => item.key === subscriptionKey);
976
990
  // if (!subscription) {
@@ -1009,6 +1023,25 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1009
1023
  })
1010
1024
  }
1011
1025
 
1026
+ updateLeadInfo(msg){
1027
+ if (msg.attributes && msg.attributes['updateUserFullname']) {
1028
+ const userFullname = msg.attributes['updateUserFullname'];
1029
+ this.logger.debug('[CONVS-DETAIL] newMessageAdded --> updateUserFullname', userFullname)
1030
+ this.conversationWithFullname = userFullname //update info for next sendMessage object
1031
+ //updates conversation header info
1032
+ this.conversationAvatar = setConversationAvatar(
1033
+ this.conversationWith,
1034
+ this.conversationWithFullname,
1035
+ this.conversationAvatar.channel_type
1036
+ )
1037
+
1038
+ }
1039
+ if (msg.attributes && msg.attributes['updateUserEmail']) {
1040
+ const userEmail = msg.attributes['updateUserEmail'];
1041
+ this.logger.debug('[CONVS-DETAIL] newMessageAdded --> userEmail', userEmail)
1042
+ }
1043
+ }
1044
+
1012
1045
  // ----------------------------------------------------------------
1013
1046
  // @ Unsubscribe all subscribed events (called in ionViewWillLeave)
1014
1047
  // ----------------------------------------------------------------
@@ -15,8 +15,8 @@
15
15
  (onBackButton)=onBackButtonFN($event)>
16
16
  </app-option-header>
17
17
  </ion-header>
18
-
19
- <ion-content id="convs-list" #ioncontentconvlist class="list-avatar-page" appScrollbarTheme>
18
+ <!-- appScrollbarTheme -->
19
+ <ion-content id="convs-list" #ioncontentconvlist class="list-avatar-page" >
20
20
  <!-- class="ps" style="position: relative; max-width: 600px; max-height: 100%;" [perfectScrollbar]="config" -->
21
21
  <div id="scrollbar2">
22
22
  <ion-list>
@@ -6,6 +6,30 @@ ion-header {
6
6
  border-bottom-width: thin;
7
7
  }
8
8
 
9
+ ion-content {
10
+ // overwrite inline styles
11
+ --offset-bottom: auto!important;
12
+ --overflow: hidden;
13
+ overflow: scroll;
14
+
15
+ &::-webkit-scrollbar {
16
+ width: 6px;
17
+ height: 8px;
18
+ display: none;
19
+ }
20
+
21
+ &::-webkit-scrollbar-track {
22
+ background: #f9f9f9;
23
+ }
24
+ &::-webkit-scrollbar-thumb {
25
+ background-color: #b9b9b9;
26
+ border-radius: 0px;
27
+ }
28
+ &::-webkit-scrollbar-thumb:hover {
29
+ background-color: #727272;
30
+ }
31
+ }
32
+
9
33
  ion-list {
10
34
  display: block;
11
35
  margin-block-start: 1em;
@@ -27,8 +27,13 @@
27
27
  <ion-item>
28
28
  <ion-label color="primary" position="floating" floating> {{'AddACaption' | translate}}...</ion-label>
29
29
  <!-- <ion-input clearInput></ion-input> -->
30
- <ion-textarea #messageTextArea #imageCaptionTexarea rows="1" autosize="false" auto-grow="true" [(ngModel)]="messageString"
31
- (ionInput)="onChangeTextArea($event);" (keyup.enter)="pressedOnKeyboard($event, messageString);">
30
+ <ion-textarea #messageTextArea #imageCaptionTexarea
31
+ rows="1"
32
+ autosize="false"
33
+ auto-grow="true"
34
+ [(ngModel)]="messageString"
35
+ (ionInput)="onChangeTextArea($event);"
36
+ (keyup.enter)="onKeyUp($event, messageString);">
32
37
  </ion-textarea>
33
38
  </ion-item>
34
39
 
@@ -333,8 +333,9 @@ export class LoaderPreviewPage implements OnInit, AfterViewInit {
333
333
  }
334
334
  }
335
335
 
336
- pressedOnKeyboard(e: any, text: string) {
337
- this.logger.log('[LOADER-PREVIEW-PAGE] pressedOnKeyboard - event:: ', e)
336
+
337
+ onKeyUp(event: any, text: string) {
338
+ this.logger.log('[LOADER-PREVIEW-PAGE] onKeyUp - event:: ', event)
338
339
  // const message = e.target.textContent.trim();
339
340
  // if (e.inputType === 'insertLineBreak' && message === '') {
340
341
  // this.messageString = '';
@@ -11,7 +11,7 @@
11
11
  "messagingSenderId": "269505353043",
12
12
  "appId": "1:269505353043:web:b82af070572669e3707da6",
13
13
  "chat21ApiUrl": "https://us-central1-chat21-pre-01.cloudfunctions.net",
14
- "tenant":"tilechat"
14
+ "tenant": "tilechat"
15
15
  },
16
16
  "chat21Config": {
17
17
  "appId": "tilechat",
@@ -15,7 +15,9 @@ export abstract class ConversationHandlerService {
15
15
  abstract messageAdded: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
16
16
  abstract messageChanged: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
17
17
  abstract messageRemoved: BehaviorSubject<string> = new BehaviorSubject<string>(null);
18
-
18
+ abstract messageWait: BehaviorSubject<any> = new BehaviorSubject<any>(null);
19
+ abstract messageInfo: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
20
+
19
21
  // params
20
22
  abstract attributes: any;
21
23
  abstract messages: Array<MessageModel> = [];
@@ -36,6 +36,7 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
36
36
  messageChanged: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);;
37
37
  messageRemoved: BehaviorSubject<string> = new BehaviorSubject<string>(null);
38
38
  messageWait: BehaviorSubject<any> = new BehaviorSubject<string>(null);
39
+ messageInfo: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
39
40
 
40
41
  // public variables
41
42
  public attributes: any;
@@ -245,6 +246,9 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
245
246
  if (this.skipMessage && messageType(MESSAGE_TYPE_INFO, msg)) {
246
247
  return;
247
248
  }
249
+ if(!this.skipMessage && messageType(MESSAGE_TYPE_INFO, msg)) {
250
+ this.messageInfo.next(msg)
251
+ }
248
252
  this.addRepalceMessageInArray(childSnapshot.key, msg);
249
253
  this.messageAdded.next(msg);
250
254
  }
@@ -34,7 +34,8 @@ export class MQTTConversationHandler extends ConversationHandlerService {
34
34
  messageChanged: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);;
35
35
  messageRemoved: BehaviorSubject<string> = new BehaviorSubject<string>(null);
36
36
  messageWait: BehaviorSubject<any> = new BehaviorSubject<string>(null);
37
-
37
+ messageInfo: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
38
+
38
39
  // public variables
39
40
  public attributes: any;
40
41
  public messages: MessageModel[];
@@ -230,9 +231,12 @@ export class MQTTConversationHandler extends ConversationHandlerService {
230
231
  private addedMessage(messageSnapshot: any) {
231
232
  const msg = this.messageGenerate(messageSnapshot);
232
233
  msg.uid = msg.message_id;
233
- if(this.skipInfoMessage && messageType(MESSAGE_TYPE_INFO, msg) ){
234
+ if(this.skipInfoMessage && messageType(MESSAGE_TYPE_INFO, msg)){
234
235
  return;
235
236
  }
237
+ if(!this.skipInfoMessage && messageType(MESSAGE_TYPE_INFO, msg)){
238
+ this.messageInfo.next(msg)
239
+ }
236
240
  // imposto il giorno del messaggio per visualizzare o nascondere l'header data
237
241
  msg.headerDate = null;
238
242
  const headerDate = setHeaderDate(this.translationMap, msg.timestamp);
@@ -63,8 +63,10 @@ export class NativeUploadService extends UploadService {
63
63
  const url = this.URL_TILEDESK_FILE + '/users'
64
64
  return new Promise((resolve, reject) => {
65
65
  that.http.post(url, formData, requestOptions).subscribe(data => {
66
- const downloadURL = this.URL_TILEDESK_FILE + '?path=' + encodeURI(data['filename']);
67
- resolve(downloadURL)
66
+ let downloadURL = this.URL_TILEDESK_FILE + '/download' + '?path=' + encodeURI(data['filename']);
67
+ if(upload.file.type.includes('pdf')){
68
+ downloadURL = this.URL_TILEDESK_FILE + '?path=' + encodeURI(data['filename']);
69
+ }
68
70
  // that.BSStateUpload.next({upload: upload});
69
71
  }, (error) => {
70
72
  this.logger.error('[NATIVE UPLOAD] - ERROR upload new file ', error)
@@ -72,13 +72,13 @@ export function messageType(msgType: string, message: any) {
72
72
  return false;
73
73
  }
74
74
  if (msgType === MESSAGE_TYPE_INFO) {
75
- return this.isInfo(message);
75
+ return isInfo(message);
76
76
  }
77
77
  if (msgType === MESSAGE_TYPE_MINE) {
78
- return this.isMine(message);
78
+ return isMine(message);
79
79
  }
80
80
  if (msgType === MESSAGE_TYPE_OTHERS) {
81
- if (this.isInfo(message) === false && this.isMine(message) === false) {
81
+ if (isInfo(message) === false && isMine(message) === false) {
82
82
  return true;
83
83
  }
84
84
  return false;