@chat21/chat21-web-widget 5.1.0-rc6 → 5.1.0-rc7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,9 @@
6
6
  ### **Copyrigth**:
7
7
  *Tiledesk SRL*
8
8
 
9
+ # 5.1.0-rc.7
10
+ - **added**: ability to allows emoji after message is sent
11
+
9
12
  # 5.1.0-rc.6
10
13
  - **removed**: hideRestartConversationOptionsMenu
11
14
 
package/Dockerfile CHANGED
@@ -15,7 +15,7 @@ COPY . .
15
15
 
16
16
  ## Build the angular app in production mode and store the artifacts in dist folder
17
17
 
18
- RUN npm run ng build -- --configuration="prod" --output-path=dist --base-href="./" --output-hashing=none
18
+ RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
19
19
 
20
20
 
21
21
  ### STAGE 2: Setup ###
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-web-widget",
3
3
  "author": "Tiledesk SRL",
4
- "version": "5.1.0-rc6",
4
+ "version": "5.1.0-rc7",
5
5
  "license": "MIT",
6
6
  "homepage": "https://www.tiledesk.com",
7
7
  "repository": {
@@ -112,7 +112,7 @@
112
112
  [attributes]="g?.attributes"
113
113
  [senderId]="senderId"
114
114
  [tenant]="g?.tenant"
115
- [projectid]="g?.projectid"
115
+ [project]="g?.project"
116
116
  [channelType]="g?.channelType"
117
117
  [userFullname]="g?.userFullname"
118
118
  [userEmail]="g?.userEmail"
@@ -11,7 +11,8 @@ import { ChatManager } from 'src/chat21-core/providers/chat-manager';
11
11
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
12
12
  import { TYPE_MSG_FILE, TYPE_MSG_IMAGE, TYPE_MSG_TEXT } from 'src/chat21-core/utils/constants';
13
13
  import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
14
- import { isImage } from 'src/chat21-core/utils/utils-message';
14
+ import { findAndRemoveEmoji, isImage } from 'src/chat21-core/utils/utils-message';
15
+ import { ProjectModel } from 'src/models/project';
15
16
 
16
17
  @Component({
17
18
  selector: 'chat-conversation-footer',
@@ -24,7 +25,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
24
25
  @Input() attributes: string;
25
26
  @Input() senderId: string;
26
27
  @Input() tenant: string;
27
- @Input() projectid: string;
28
+ @Input() project: ProjectModel;
28
29
  @Input() channelType: string;
29
30
  @Input() userFullname: string;
30
31
  @Input() userEmail: string;
@@ -83,8 +84,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
83
84
 
84
85
  convertColorToRGBA = convertColorToRGBA;
85
86
  private logger: LoggerService = LoggerInstance.getInstance()
86
- constructor(public g: Globals,
87
- private chatManager: ChatManager,
87
+ constructor(private chatManager: ChatManager,
88
88
  private typingService: TypingService,
89
89
  private uploadService: UploadService) { }
90
90
 
@@ -253,7 +253,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
253
253
  // return snapshot.ref.getDownloadURL(); // Will return a promise with the download link
254
254
  // }).then(downloadURL => {
255
255
  // that.logger.log('[CONV-FOOTER] AppComponent::uploadSingle:: downloadURL', downloadURL]);
256
- // that.g.wdLog([`Successfully uploaded file and got download link - ${downloadURL}`]);
257
256
 
258
257
  // metadata.src = downloadURL;
259
258
  // let type_message = TYPE_MSG_TEXT;
@@ -321,6 +320,8 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
321
320
  (metadata) ? metadata = metadata : metadata = '';
322
321
  this.onEmojiiPickerShow.emit(false)
323
322
  this.logger.log('[CONV-FOOTER] SEND MESSAGE: ', msg, type, metadata, additional_attributes);
323
+
324
+ msg = this.checkForEmojii(msg)
324
325
  if (msg && msg.trim() !== '' || type === TYPE_MSG_IMAGE || type === TYPE_MSG_FILE ) {
325
326
 
326
327
  // msg = htmlEntities(msg);
@@ -345,7 +346,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
345
346
  // fine-sponziello
346
347
  // this.conversationHandlerService = this.chatManager.getConversationHandlerByConversationId(this.conversationWith)
347
348
  const senderId = this.senderId;
348
- const projectid = this.projectid;
349
+ const projectid = this.project.id;
349
350
  const channelType = this.channelType;
350
351
  const userFullname = this.userFullname;
351
352
  const userEmail = this.userEmail;
@@ -514,6 +515,15 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
514
515
  //}, false);
515
516
  }
516
517
 
518
+
519
+ checkForEmojii(text){
520
+ //remove emojii only if "emojii" exist and is set to false
521
+ if(this.project && this.project.settings?.allow_send_emoji === false){
522
+ return findAndRemoveEmoji(text)
523
+ }
524
+ return text
525
+ }
526
+
517
527
 
518
528
 
519
529
  onTextAreaChange(){
@@ -632,7 +642,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
632
642
  * @param str
633
643
  */
634
644
  setWritingMessages(str) {
635
- //this.messagingService.setWritingMessages(str, this.g.channelType);
636
645
  this.typingService.setTyping(this.conversationWith, str, this.senderId, this.userFullname )
637
646
  }
638
647
 
@@ -1,5 +1,7 @@
1
1
  import { Component, ElementRef, AfterViewInit, Input, ViewChild } from '@angular/core';
2
2
  import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
3
+ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
4
+ import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
3
5
  import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
4
6
 
5
7
  @Component({
@@ -26,13 +28,13 @@ export class AudioComponent implements AfterViewInit {
26
28
  currentTime: number = 0;
27
29
  isPlaying: boolean = false;
28
30
 
31
+ private logger: LoggerService = LoggerInstance.getInstance();
29
32
  constructor(
30
33
  private sanitizer: DomSanitizer,
31
34
  private elementRef: ElementRef
32
35
  ) {}
33
36
 
34
37
  ngAfterViewInit() {
35
- console.log('stylesssss', this.stylesMap)
36
38
  if (this.audioBlob) {
37
39
  this.rawAudioUrl = URL.createObjectURL(this.audioBlob);
38
40
  this.audioUrl = this.sanitizer.bypassSecurityTrustUrl(this.rawAudioUrl);
@@ -136,21 +138,33 @@ export class AudioComponent implements AfterViewInit {
136
138
  return `${minutes}:${sec < 10 ? '0' + sec : sec}`;
137
139
  }
138
140
 
139
- getAudioDuration() {
140
- const audio = new Audio();
141
- audio.src = this.rawAudioUrl!;
142
- audio.addEventListener('loadedmetadata', () => {
143
- if (audio.duration === Infinity) {
144
- audio.currentTime = Number.MAX_SAFE_INTEGER;
145
- audio.ontimeupdate = () => {
146
- audio.ontimeupdate = null;
147
- audio.currentTime = 0;
148
- this.audioDuration = audio.duration;
149
- };
150
- } else {
151
- this.audioDuration = audio.duration;
152
- }
153
- });
141
+ async getAudioDuration() {
142
+ // const audio = new Audio();
143
+ // audio.src = this.rawAudioUrl!;
144
+ // audio.addEventListener('loadedmetadata', () => {
145
+ // if (audio.duration === Infinity) {
146
+ // audio.currentTime = Number.MAX_SAFE_INTEGER;
147
+ // audio.ontimeupdate = () => {
148
+ // audio.ontimeupdate = null;
149
+ // audio.currentTime = 0;
150
+ // this.audioDuration = audio.duration;
151
+ // };
152
+ // } else {
153
+ // this.audioDuration = audio.duration;
154
+ // }
155
+ // });
156
+
157
+ const response = await fetch(this.rawAudioUrl!);
158
+ this.logger.debug('getAudioDuration: response ---> ', response)
159
+ const arrayBuffer = await response.arrayBuffer();
160
+ this.logger.debug('getAudioDuration: arrayBuffer ---> ', arrayBuffer)
161
+ const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
162
+ this.logger.debug('getAudioDuration: audioContext ---> ', audioContext)
163
+ const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
164
+ this.logger.debug('getAudioDuration: audioBuffer ---> ', audioBuffer)
165
+ this.audioDuration = audioBuffer.duration;
166
+ this.logger.debug('getAudioDuration: audioDuration ---> ', this.audioDuration)
167
+
154
168
  }
155
169
 
156
170
  extractFirstColor(gradient: string): string | null {
@@ -613,7 +613,7 @@
613
613
  var brandJson = JSON.parse(xhr.response)
614
614
  if(brandJson){
615
615
  /** TITLE AND FAVICON **/
616
- brandJson['WIDGET'].META_TITLE? document.body.title = brandJson['WIDGET'].META_TITLE : null;
616
+ brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
617
617
  brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
618
618
  /** FOOTER-LOGO **/
619
619
  brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
@@ -624,6 +624,13 @@
624
624
  brandJson['COMMON'].BRAND_PRIMARY_COLOR? document.body.style.setProperty('--base-company-logo', brandJson['COMMON'].BRAND_PRIMARY_COLOR): null;
625
625
  /** IFRAME TITLE**/
626
626
  brandJson['COMMON'].COMPANY_NAME? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
627
+ /** META sharing ELEMENTS */
628
+ if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
629
+ Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
630
+ var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
631
+ meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
632
+ })
633
+ }
627
634
  }
628
635
  }
629
636
 
@@ -719,7 +719,7 @@
719
719
  var brandJson = JSON.parse(xhr.response)
720
720
  if(brandJson){
721
721
  /** TITLE AND FAVICON **/
722
- brandJson['WIDGET'].META_TITLE? document.body.title = brandJson['WIDGET'].META_TITLE : null;
722
+ brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
723
723
  brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
724
724
  /** FOOTER-LOGO **/
725
725
  brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
@@ -737,6 +737,13 @@
737
737
  }
738
738
  /** IFRAME TITLE**/
739
739
  brandJson['COMMON'].COMPANY_LOGO? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
740
+ /** META sharing ELEMENTS */
741
+ if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
742
+ Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
743
+ var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
744
+ meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
745
+ })
746
+ }
740
747
  }
741
748
  }
742
749
  }
@@ -6,7 +6,7 @@
6
6
  <meta charset="utf-8">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8
8
 
9
- <title>Widget test page </title>
9
+ <title>Widget test page</title>
10
10
  <style>
11
11
 
12
12
  @-moz-keyframes blink {0%{opacity:1;} 50%{opacity:0;} 100%{opacity:1;}} /* Firefox */
@@ -295,7 +295,10 @@
295
295
  window.Tiledesk('onBeforeInit', function(event_data) {
296
296
  console.log("onBeforeInit Tiledesk FN", event_data);
297
297
 
298
- var brandSrc = event_data.detail.appConfigs.brandSrc? getBrandResources(event_data.detail.appConfigs.brandSrc) : null;
298
+ if(event_data.detail.appConfigs.brandSrc){
299
+ getBrandResources(event_data.detail.appConfigs.brandSrc)
300
+ }
301
+ // var brandSrc = event_data.detail.appConfigs.brandSrc? : null;
299
302
 
300
303
  setTimeout(() => {
301
304
  if(event_data && event_data.detail && event_data.detail.appConfigs){
@@ -408,7 +411,7 @@
408
411
  var brandJson = JSON.parse(xhr.response)
409
412
  if(brandJson){
410
413
  /** TITLE AND FAVICON **/
411
- brandJson['WIDGET'].META_TITLE? document.body.title = brandJson['WIDGET'].META_TITLE : null;
414
+ brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
412
415
  brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
413
416
  /** FOOTER-LOGO **/
414
417
  brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
@@ -421,6 +424,13 @@
421
424
  brandJson['COMMON'].DOCS? null: document.getElementById('share').style.display = 'none'
422
425
  /** IFRAME TITLE**/
423
426
  brandJson['COMMON'].COMPANY_LOGO? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
427
+ /** META sharing ELEMENTS */
428
+ if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
429
+ Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
430
+ var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
431
+ meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
432
+ })
433
+ }
424
434
  }
425
435
 
426
436
  }
@@ -194,9 +194,13 @@ export function isEmojii(message: any){
194
194
  // https://localcoder.org/javascript-detect-if-a-string-contains-only-unicode-emojis
195
195
  try {
196
196
  if(!message) return false;
197
+ // Removes all characters that are NOT emojis (unicode > \u1eeff)
197
198
  const onlyEmojis = message.replace(new RegExp('[\u0000-\u1eeff]', 'g'), '')
199
+ // Removes spaces, line breaks, and carriage returns from the string
198
200
  const visibleChars = message.replace(new RegExp('[\n\r\s]+|( )+', 'g'), '')
201
+ // Removes Chinese characters from the string
199
202
  const chineseChars = message.replace(new RegExp('[\u4e00-\u9fa5]', 'g'), '')
203
+
200
204
  if(onlyEmojis === '' || visibleChars == '' || chineseChars=='') return false
201
205
  return (onlyEmojis.length === visibleChars.length && onlyEmojis.length <= 2)
202
206
  } catch(e) {
@@ -204,6 +208,22 @@ export function isEmojii(message: any){
204
208
  }
205
209
  }
206
210
 
211
+ export function findAndRemoveEmoji(text): string{
212
+
213
+ if (!text) return text;
214
+
215
+ // Regex to find most unicode emojis
216
+ // Source: https://thekevinscott.com/emojis-in-javascript/
217
+ const emojiRegex = /([\u2700-\u27BF]|[\uE000-\uF8FF]|[\uD83C-\uDBFF][\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83D[\uDE00-\uDE4F])/g;
218
+
219
+ // Removes all found emojis
220
+ text = text.replace(emojiRegex, '');
221
+
222
+ // Removes any multiple spaces left by the removal of emojis
223
+ text = text.replace(/\s{2,}/g, ' ').trim();
224
+ return text
225
+ }
226
+
207
227
  export function isJustRecived(startedAt, time) {
208
228
  if (time > startedAt) {
209
229
  return true;
@@ -24,7 +24,8 @@ export class ProjectModel {
24
24
  public color?: string,
25
25
  public welcomeTitle?: string,
26
26
  public welcomeMsg?: string,
27
- public attributes?: IRules
27
+ public attributes?: IRules,
28
+ public settings?:{ [key: string]: any },
28
29
  ) { }
29
30
 
30
31
  initialize (
@@ -43,6 +44,7 @@ export class ProjectModel {
43
44
  trialDaysLeft?: number,
44
45
  trialExpired?: boolean,
45
46
  updatedAt?: string,
47
+ settings?: { [key: string]: any },
46
48
  versions?: string,
47
49
  ) {
48
50
  this.id = id;
@@ -60,6 +62,7 @@ export class ProjectModel {
60
62
  this.trialDaysLeft = trialDaysLeft;
61
63
  this.trialExpired = trialExpired;
62
64
  this.updatedAt = updatedAt;
65
+ this.settings = settings;
63
66
  this.versions = versions;
64
67
  }
65
68