@chat21/chat21-web-widget 5.1.26 → 5.1.27-rc1

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 (39) hide show
  1. package/.github/workflows/docker-community-push-latest.yml +23 -13
  2. package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
  3. package/CHANGELOG.md +88 -13
  4. package/Dockerfile +4 -5
  5. package/angular.json +2 -1
  6. package/deploy_amazon_beta.sh +17 -7
  7. package/docs/changelog/this-branch.md +36 -0
  8. package/package.json +1 -1
  9. package/src/app/app.component.html +9 -2
  10. package/src/app/app.component.scss +59 -0
  11. package/src/app/app.component.ts +128 -33
  12. package/src/app/component/conversation-detail/conversation/conversation.component.html +13 -2
  13. package/src/app/component/conversation-detail/conversation/conversation.component.scss +30 -2
  14. package/src/app/component/conversation-detail/conversation/conversation.component.ts +190 -5
  15. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +16 -3
  16. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +12 -9
  17. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +15 -1
  18. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +1 -1
  19. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +103 -80
  20. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +40 -13
  21. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +40 -1
  22. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +4 -4
  23. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.ts +1 -0
  24. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.ts +0 -18
  25. package/src/app/component/home/home.component.html +3 -3
  26. package/src/app/component/launcher-button/launcher-button.component.html +1 -1
  27. package/src/app/component/launcher-button/launcher-button.component.ts +3 -2
  28. package/src/app/providers/global-settings.service.ts +38 -0
  29. package/src/app/providers/translator.service.ts +2 -0
  30. package/src/app/sass/_variables.scss +1 -0
  31. package/src/app/utils/globals.ts +8 -2
  32. package/src/assets/i18n/en.json +2 -0
  33. package/src/assets/i18n/es.json +2 -0
  34. package/src/assets/i18n/fr.json +2 -0
  35. package/src/assets/i18n/it.json +2 -0
  36. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  37. package/src/chat21-core/utils/utils.ts +5 -2
  38. package/src/iframe-style.css +5 -5
  39. package/deploy_amazon_prod.sh +0 -41
@@ -1,23 +1,25 @@
1
-
1
+ .textarea-container-wrapper{
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 8px;
5
+ }
2
6
  .textarea-container{
3
- // padding: 8px 34px;
4
- // padding-left: 70px;
5
- // padding-right: 45px;
6
7
  display: flex;
7
- // width: 100%;
8
8
  align-items: center;
9
9
  justify-content: space-between;
10
10
  gap: 8px;
11
+ }
12
+ .close-chat-container{
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ justify-content: center;
17
+ gap: 8px;
11
18
 
12
- //if attachment icon OR emoji icon is not in DOM -> increment textarea width
13
- &:has(:not(#chat21-start-upload-doc), :not(#chat21-emoticon-picker)) .visible-text-area {
14
- width: 80%;
19
+ .c21-close{
20
+ height: 30px !important;
21
+ margin: 0px !important;
15
22
  }
16
- //if attachment icon AND emoji icon is not in DOM -> increment textarea width
17
- &:has(:not(#chat21-start-upload-doc)):has(:not(#chat21-emoticon-picker)) .visible-text-area {
18
- width: 90%;
19
- }
20
-
21
23
  }
22
24
 
23
25
  .icons-container{
@@ -419,3 +421,28 @@ textarea:active{
419
421
  border: none;
420
422
  // margin: -2px -2px 0px;
421
423
  }
424
+
425
+
426
+ // aggiungi un'animazione di fade in e fade out quando .star-rating-widget è visibile con transition
427
+ .star-rating-widget {
428
+ transition: all 0.5s ease-in-out;
429
+ }
430
+
431
+ .star-rating-widget {
432
+ position: absolute;
433
+ left: 0;
434
+ right: 0;
435
+ bottom: -52px;
436
+ height: 100%;
437
+ width: 100%;
438
+ flex-direction: row;
439
+ justify-content: center;
440
+ background-color: rgb(255, 255, 255);
441
+ flex-wrap: nowrap;
442
+ &.active {
443
+ bottom: 0px;
444
+ }
445
+ &.inactive {
446
+ bottom: -52px;
447
+ }
448
+ }
@@ -42,6 +42,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
42
42
  @Input() isEmojiiPickerShow: boolean;
43
43
  @Input() footerMessagePlaceholder: string;
44
44
  @Input() fileUploadAccept: string;
45
+ @Input() closeChatInConversation: boolean;
45
46
  @Input() dropEvent: Event;
46
47
  @Input() poweredBy: string;
47
48
  @Input() stylesMap: Map<string, string>
@@ -52,6 +53,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
52
53
  @Output() onChangeTextArea = new EventEmitter<any>();
53
54
  @Output() onAttachmentFileButtonClicked = new EventEmitter<any>();
54
55
  @Output() onNewConversationButtonClicked = new EventEmitter();
56
+ @Output() onCloseChatButtonClicked = new EventEmitter();
55
57
 
56
58
  @ViewChild('chat21_file') public chat21_file: ElementRef;
57
59
  // @ViewChild('emojii_container', {read: ViewContainerRef}) selector;
@@ -87,6 +89,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
87
89
 
88
90
  file_size_limit = FILE_SIZE_LIMIT;
89
91
  attachmentTooltip: string = '';
92
+ isErrorNetwork: boolean = false;
90
93
 
91
94
 
92
95
  convertColorToRGBA = convertColorToRGBA;
@@ -513,14 +516,46 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
513
516
  onSendRecording(audioBlob: Blob | null) {
514
517
  this.isStartRec = false;
515
518
  if (audioBlob) {
516
- this.convertBlobToBase64(audioBlob);
519
+ this.prepareAndUpload(audioBlob);
520
+ // this.convertBlobToBase64(audioBlob);
517
521
  this.isStopRec = false;
518
522
  } else {
519
523
  this.isStopRec = false;
520
524
  }
521
525
  }
522
526
 
527
+ prepareAndUpload(audioBlob: Blob) {
523
528
 
529
+ this.isFilePendingToUpload = true;
530
+
531
+ // ⭐ NON modificare il MIME
532
+ const mimeType = audioBlob.type;
533
+
534
+ const size = audioBlob.size;
535
+ const uid = Date.now().toString(36);
536
+
537
+ // estensione coerente col MIME REALE
538
+ let ext = 'mp3';
539
+ const fileName = `audio-${uid}.${ext}`;
540
+
541
+ const file = new File([audioBlob], fileName, {
542
+ type: mimeType,
543
+ lastModified: Date.now()
544
+ });
545
+
546
+ // ✅ metadata SENZA base64
547
+ const metadata = {
548
+ name: fileName,
549
+ type: 'audio/mp3',
550
+ uid: uid,
551
+ size: size
552
+ };
553
+
554
+ this.logger.log('[UPLOAD] metadata:', metadata);
555
+
556
+ // stesso metodo che già usi
557
+ this.uploadSingle(metadata, file, '');
558
+ }
524
559
 
525
560
  // Funzione per convertire Blob in Base64 usando FileReader
526
561
  async convertBlobToBase64(audioBlob: Blob) {
@@ -677,6 +712,10 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
677
712
  this.onNewConversationButtonClicked.emit();
678
713
  }
679
714
 
715
+ onCloseChat(event){
716
+ this.onCloseChatButtonClicked.emit();
717
+ }
718
+
680
719
  // onContinueConversation(){
681
720
  // this.hideTextAreaContent = false;
682
721
  // this.onBackButton.emit(false)
@@ -16,7 +16,7 @@
16
16
  </button>
17
17
 
18
18
  <!-- ICON MENU OPTION -->
19
- <button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="toggleMenu()" >
19
+ <button *ngIf="!isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="toggleMenu()" >
20
20
  <svg aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor') }" xmlns="http://www.w3.org/2000/svg"
21
21
  width="24" height="24" viewBox="0 0 24 24">
22
22
  <path fill="none" d="M0 0h24v24H0V0z" />
@@ -27,7 +27,7 @@
27
27
 
28
28
 
29
29
  <!-- ICON MAXIMIZE -->
30
- <button *ngIf="size === 'min' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
30
+ <button *ngIf="size === 'min' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
31
31
  <svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor') }" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
32
32
  width="17" height="17" viewBox="0 0 17 17">
33
33
  <path d="M6.49001 8.30999L3.69 11.11V9.40999C3.69 8.93999 3.31 8.55999 2.84 8.55999C2.37 8.55999 1.99001 8.93999 1.99001 9.40999V14.01H6.59C7.06 14.01 7.44 13.63 7.44 13.16C7.44 12.69 7.06 12.31 6.59 12.31H4.89L7.69 9.50999L6.49001 8.30999ZM9.41 1.98999C8.94 1.98999 8.56001 2.36999 8.56001 2.83999C8.56001 3.30999 8.94 3.68999 9.41 3.68999H11.11L8.31001 6.48999L9.51 7.68999L12.31 4.88999V6.58999C12.31 7.05999 12.69 7.43999 13.16 7.43999C13.63 7.43999 14.01 7.05999 14.01 6.58999V1.98999H9.41Z"></path>
@@ -36,7 +36,7 @@
36
36
  </button>
37
37
 
38
38
  <!-- ICON MINIMIZE -->
39
- <button *ngIf="size==='top' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
39
+ <button *ngIf="size==='top' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
40
40
  <svg role="img" aria-labelledby="altIconTitle" class="icon-menu" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
41
41
  width="17" height="17" viewBox="0 0 17 17">
42
42
  <path d="M13.59 5.31h-1.7l3.3-3.3-1.2-1.2-3.3 3.3v-1.7a.85.85 0 1 0-1.7 0v4.6h4.6a.85.85 0 1 0 0-1.7M1.57 9.84c0 .47.38.85.85.85h1.7l-3.3 3.3 1.2 1.2 3.3-3.3v1.7a.85.85 0 1 0 1.7 0v-4.6h-4.6a.85.85 0 0 0-.85.85"></path>
@@ -45,7 +45,7 @@
45
45
  </button>
46
46
 
47
47
  <!-- ICON TOP -->
48
- <button *ngIf="size==='max' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
48
+ <button *ngIf="size==='max' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
49
49
  <svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
50
50
  width="17" height="17" viewBox="0 0 17 17">
51
51
  <path d="M3.7,7.6L2.5,6.4C2.2,6,2.2,5.5,2.5,5.2s0.9-0.4,1.2-0.1L7,8.4l-3.3,3.3c-0.4,0.4-0.8,0.3-1.1,0s-0.4-0.9-0.1-1.2l1.2-1.2 H1.5l0-1.7H3.7z"/>
@@ -21,6 +21,7 @@ export class ConversationHeaderComponent implements OnInit, OnChanges {
21
21
  @Input() isTypings: boolean;
22
22
  @Input() nameUserTypingNow: string;
23
23
  @Input() typingLocation: string;
24
+ @Input() isMobile: boolean;
24
25
  @Input() isTrascriptDownloadEnabled: boolean;
25
26
  @Input() fullscreenMode: boolean;
26
27
  @Input() size: 'min' | 'max' | 'top';
@@ -50,24 +50,6 @@ export class EyeeyeCatcherCardComponent implements OnInit {
50
50
  this.displayEyeCatcherCardCloseBtnWrapper = 'none';
51
51
  this.displayEyeCatcherCardCloseBtnIsMobileWrapper = 'none';
52
52
  this.displayEyeCatcherCardCloseBtn = 'none';
53
- /* EYE-CATCHER CLOSE BUTTON SWITCH */
54
- this.openIfCallOutTimer();
55
- }
56
-
57
-
58
- /**
59
- * OPEN THE EYE-CATCHER CARD
60
- * if calloutTimer >= 0
61
- */
62
- private openIfCallOutTimer() {
63
- const that = this;
64
- const calloutTimer = this.g.calloutTimer;
65
- if (calloutTimer >= 0) {
66
- const waitingTime = calloutTimer * 1000;
67
- setTimeout(function () {
68
- that.openEyeCatcher();
69
- }, waitingTime);
70
- }
71
53
  }
72
54
 
73
55
  /**
@@ -14,7 +14,7 @@
14
14
  <div class="c21-header-button" [ngStyle]="{'display': (g.hideHeaderCloseButton)?'none':'block'}">
15
15
 
16
16
  <!-- ICON MAXIMIZE -->
17
- <div *ngIf="size === 'min' && !fullscreenMode" class="c21-size-button">
17
+ <div *ngIf="size === 'min' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
18
18
  <button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
19
19
  <svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor') }" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
20
20
  width="17" height="17" viewBox="0 0 17 17">
@@ -25,7 +25,7 @@
25
25
  </div>
26
26
 
27
27
  <!-- ICON MINIMIZE -->
28
- <div *ngIf="size==='top' && !fullscreenMode" class="c21-size-button">
28
+ <div *ngIf="size==='top' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
29
29
  <button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
30
30
  <svg role="img" aria-labelledby="altIconTitle" class="icon-menu" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
31
31
  width="17" height="17" viewBox="0 0 17 17">
@@ -36,7 +36,7 @@
36
36
  </div>
37
37
 
38
38
  <!-- ICON TOP -->
39
- <div *ngIf="size==='max' && !fullscreenMode" class="c21-size-button">
39
+ <div *ngIf="size==='max' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
40
40
  <button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
41
41
  <svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
42
42
  width="17" height="17" viewBox="0 0 17 17">
@@ -1,7 +1,7 @@
1
1
  <!-- tabindex="000"-->
2
2
 
3
3
  <button aflauncherbutton #aflauncherbutton id="c21-launcher-button" class="c21-button-clean scale-in-center"
4
- *ngIf="g.isLogged == true && g.isOpen == false"
4
+ *ngIf="g.isOpen == false"
5
5
  [ngClass]="{'c21-align-left' : g.align === 'left', 'c21-align-right' : g.align !== 'left'}"
6
6
  [ngStyle]="{ 'background-color': g.baloonImage? null: g.themeColor, 'bottom': g.marginY+'px!important', 'left':(g.align==='left')?g.marginX+'px!important':'', 'right':(g.align==='right')?g.marginX+'px!important':'', 'width': g.launcherWidth, 'height': g.launcherHeight, 'border-radius': g.baloonShape}"
7
7
  (click)="openCloseWidget()"
@@ -67,8 +67,9 @@ export class LauncherButtonComponent implements OnInit, AfterViewInit {
67
67
  // this.g.isOpen = !this.g.isOpen;
68
68
  // this.g.setIsOpen(!this.g.isOpen);
69
69
  // this.appStorageService.setItem('isOpen', this.g.isOpen);
70
- this.onButtonClicked.emit( this.g.isOpen );
71
- }
70
+
71
+ }
72
+ this.onButtonClicked.emit( this.g.isOpen );
72
73
  }
73
74
 
74
75
  }
@@ -324,11 +324,13 @@ export class GlobalSettingsService {
324
324
  }
325
325
  /** set button colors */
326
326
  this.setButtonColors();
327
+ this.globals.setParameter('isMobile', detectIfIsMobile(this.globals.windowContext));
327
328
 
328
329
  this.setVariableFromStorage(this.globals);
329
330
  this.setVariablesFromSettings(this.globals);
330
331
  this.setVariablesFromAttributeHtml(this.globals, this.el);
331
332
  this.setVariablesFromUrlParameters(this.globals);
333
+ this.enforceMobileFullscreenPolicy(this.globals);
332
334
 
333
335
  this.setDepartmentFromExternal();
334
336
  /** set color with gradient from theme's colors */
@@ -340,6 +342,18 @@ export class GlobalSettingsService {
340
342
  this.obsSettingsService.next(true);
341
343
  }
342
344
 
345
+ /**
346
+ * On mobile devices we always open the widget fullscreen.
347
+ * This also neutralizes any legacy `size` stored from previous sessions.
348
+ */
349
+ private enforceMobileFullscreenPolicy(globals: Globals) {
350
+ if (!globals || globals.isMobile !== true) {
351
+ return;
352
+ }
353
+ globals.fullscreenMode = true;
354
+ globals.size = 'max';
355
+ }
356
+
343
357
  private setButtonColors() {
344
358
  this.logger.debug('[GLOBAL-SET] ***** END SET PARAMETERS *****', this.globals);
345
359
  const bubbleSentBackground = this.globals?.bubbleSentBackground;
@@ -464,6 +478,10 @@ export class GlobalSettingsService {
464
478
  try {
465
479
  const variables = response.project.widget;
466
480
  if (typeof variables !== 'undefined') {
481
+ const hasCalloutTimer = Object.prototype.hasOwnProperty.call(variables, 'calloutTimer');
482
+ const hasCalloutTitle = Object.prototype.hasOwnProperty.call(variables, 'calloutTitle');
483
+ const hasCalloutMsg = Object.prototype.hasOwnProperty.call(variables, 'calloutMsg');
484
+ this.globals.hasCalloutInWidgetConfig = hasCalloutTimer || hasCalloutTitle || hasCalloutMsg;
467
485
  for (const key of Object.keys(variables)) {
468
486
  if (key === 'align' && variables[key] === 'left') {
469
487
  const divWidgetContainer = globals.windowContext.document.getElementById('tiledeskdiv');
@@ -1124,6 +1142,12 @@ export class GlobalSettingsService {
1124
1142
  if (TEMP !== undefined) {
1125
1143
  globals.size = TEMP;
1126
1144
  }
1145
+
1146
+ TEMP = tiledeskSettings['closeChatInConversation'];
1147
+ // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > closeChatInConversation:: ', TEMP]);
1148
+ if (TEMP !== undefined) {
1149
+ globals.closeChatInConversation = (TEMP === true) ? true : false;
1150
+ }
1127
1151
  }
1128
1152
 
1129
1153
  /**
@@ -1870,6 +1894,11 @@ export class GlobalSettingsService {
1870
1894
  if (TEMP) {
1871
1895
  globals.size = TEMP;
1872
1896
  }
1897
+
1898
+ TEMP = getParameterByName(windowContext, 'tiledesk_closeChatInConversation');
1899
+ if (TEMP) {
1900
+ globals.closeChatInConversation = stringToBoolean(TEMP);
1901
+ }
1873
1902
 
1874
1903
  }
1875
1904
 
@@ -1882,6 +1911,15 @@ export class GlobalSettingsService {
1882
1911
  setVariableFromStorage(globals: Globals) {
1883
1912
  this.logger.debug('[GLOBAL-SET] setVariableFromStorage :::::::: SET VARIABLE ---------->', Object.keys(globals));
1884
1913
  for (const key of Object.keys(globals)) {
1914
+ if (globals.isMobile === true && key === 'size') {
1915
+ // Backward compatibility: ignore legacy stored size on mobile.
1916
+ try {
1917
+ this.appStorageService.removeItem('size');
1918
+ } catch (e) {
1919
+ this.logger.warn('[GLOBAL-SET] setVariableFromStorage > cannot remove size from storage', e);
1920
+ }
1921
+ continue;
1922
+ }
1885
1923
  const val = this.appStorageService.getItem(key);
1886
1924
  // this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals KEY ---------->', key);
1887
1925
  // this.logger.debug('[GLOBAL-SET] setVariableFromStorage SET globals VAL ---------->', val);
@@ -302,6 +302,7 @@ export class TranslatorService {
302
302
  'CLOSED',
303
303
  'LABEL_PREVIEW',
304
304
  'MAX_ATTACHMENT',
305
+ 'MAX_ATTACHMENT_ERROR',
305
306
  'EMOJI'
306
307
  ];
307
308
 
@@ -358,6 +359,7 @@ export class TranslatorService {
358
359
  globals.LABEL_PREVIEW = res['LABEL_PREVIEW']
359
360
  globals.LABEL_ERROR_FIELD_REQUIRED= res['LABEL_ERROR_FIELD_REQUIRED']
360
361
  globals.MAX_ATTACHMENT = res['MAX_ATTACHMENT']
362
+ globals.MAX_ATTACHMENT_ERROR = res['MAX_ATTACHMENT_ERROR']
361
363
  globals.EMOJI = res['EMOJI']
362
364
 
363
365
 
@@ -36,6 +36,7 @@
36
36
 
37
37
  --chat-footer-height: 64px;
38
38
  --chat-footer-logo-height: 30px;
39
+ --chat-footer-close-button-height: 30px;
39
40
  --chat-footer-border-radius: 16px;
40
41
  --chat-footer-background-color: #f6f7fb;
41
42
  --chat-footer-color: #1a1a1a;
@@ -222,10 +222,13 @@ export class Globals {
222
222
 
223
223
  allowedOnSpecificUrl: boolean // ******* new ********
224
224
  allowedOnSpecificUrlList: Array<string> // ******* new ********
225
+ hasCalloutInWidgetConfig: boolean; // ******* new ********
225
226
 
226
227
  fontFamilySource: string; // ******* new ********
227
228
 
228
229
  size: 'min' | 'max' | 'top'; // ******* new ********
230
+
231
+ closeChatInConversation: boolean; // ******* new ********
229
232
  constructor(
230
233
  ) { }
231
234
 
@@ -247,7 +250,7 @@ export class Globals {
247
250
 
248
251
  // ============ BEGIN: SET EXTERNAL PARAMETERS ==============//
249
252
  this.baseLocation = 'https://widget.tiledesk.com/v2';
250
- this.autoStart = true;
253
+ this.autoStart = false;
251
254
  /** start Authentication and startUI */
252
255
  this.startHidden = false;
253
256
  /** show/hide all widget -> js call: showAllWidget */
@@ -438,9 +441,12 @@ export class Globals {
438
441
  this.allowedOnSpecificUrl = false
439
442
  /** set a list of pattern url able to load the widget */
440
443
  this.allowedOnSpecificUrlList = [];
444
+ /** true when server widget config has `callout` node */
445
+ this.hasCalloutInWidgetConfig = false;
441
446
  /** set widget size from 3 different positions: min, max, top */
442
447
  this.size = 'min';
443
-
448
+ /** enable to close the chat in conversation */
449
+ this.closeChatInConversation = false;
444
450
  // ============ END: SET EXTERNAL PARAMETERS ==============//
445
451
 
446
452
 
@@ -16,6 +16,7 @@
16
16
  "GUEST_LABEL": "Guest",
17
17
  "ALL_AGENTS_OFFLINE_LABEL": "All operators are offline at the moment",
18
18
  "LABEL_LOADING": "Loading...",
19
+ "LABEL_THINKING": "thinking",
19
20
  "CALLOUT_TITLE_PLACEHOLDER": "🖐 Need Help?",
20
21
  "CALLOUT_MSG_PLACEHOLDER": "Click here and start chatting with us!",
21
22
  "CUSTOMER_SATISFACTION": "Customer satisfaction",
@@ -96,5 +97,6 @@
96
97
  "EMOJI_NOT_ELLOWED":"Emoji not allowed",
97
98
  "DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain",
98
99
  "MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
100
+ "MAX_ATTACHMENT_ERROR": "The file exceeds the maximum allowed size",
99
101
  "EMOJI": "Emoji"
100
102
  }
@@ -16,6 +16,7 @@
16
16
  "GUEST_LABEL": "Huésped",
17
17
  "ALL_AGENTS_OFFLINE_LABEL": "Todos los operadores están desconectados en este momento.",
18
18
  "LABEL_LOADING": "Cargando...",
19
+ "LABEL_THINKING": "pensando",
19
20
  "CALLOUT_TITLE_PLACEHOLDER": "🖐 ¿Necesitas ayuda?",
20
21
  "CALLOUT_MSG_PLACEHOLDER": "¡Haz clic aquí y comienza a chatear con nosotros!",
21
22
  "CUSTOMER_SATISFACTION": "La satisfacción del cliente",
@@ -96,5 +97,6 @@
96
97
  "EMOJI_NOT_ELLOWED":"Emoji no permitido",
97
98
  "DOMAIN_NOT_ALLOWED":"La URL contiene un dominio no permitido",
98
99
  "MAX_ATTACHMENT": "Tamaño máximo permitido {{FILE_SIZE_LIMIT}}Mb",
100
+ "MAX_ATTACHMENT_ERROR": "El archivo supera el tamaño máximo permitido",
99
101
  "EMOJI": "Emoji"
100
102
  }
@@ -16,6 +16,7 @@
16
16
  "GUEST_LABEL": "Hôte",
17
17
  "ALL_AGENTS_OFFLINE_LABEL": "Tous les opérateurs sont actuellement hors ligne",
18
18
  "LABEL_LOADING": "Chargement en cours ...",
19
+ "LABEL_THINKING": "en train de reflechir",
19
20
  "CALLOUT_TITLE_PLACEHOLDER": "🖐 Besoin d'aide?",
20
21
  "CALLOUT_MSG_PLACEHOLDER": "Cliquez ici et commencez à discuter avec nous!",
21
22
  "CUSTOMER_SATISFACTION": "Évaluation des services",
@@ -96,5 +97,6 @@
96
97
  "EMOJI_NOT_ELLOWED":"Emoji non autorisé",
97
98
  "DOMAIN_NOT_ALLOWED":"L'URL contient un domaine non autorisé",
98
99
  "MAX_ATTACHMENT": "Taille maximale autorisée {{FILE_SIZE_LIMIT}}Mo",
100
+ "MAX_ATTACHMENT_ERROR": "Le fichier dépasse la taille maximale autorisée",
99
101
  "EMOJI": "Emoji"
100
102
  }
@@ -16,6 +16,7 @@
16
16
  "GUEST_LABEL": "Ospite",
17
17
  "ALL_AGENTS_OFFLINE_LABEL": "Tutti gli operatori sono offline al momento",
18
18
  "LABEL_LOADING": "Caricamento...",
19
+ "LABEL_THINKING": "sto pensando",
19
20
  "CALLOUT_TITLE_PLACEHOLDER": "🖐 Bisogno di aiuto?",
20
21
  "CALLOUT_MSG_PLACEHOLDER": "Clicca qui e inizia a chattare con noi!",
21
22
  "CUSTOMER_SATISFACTION": "Valutazione servizio",
@@ -94,5 +95,6 @@
94
95
  "EMOJI_NOT_ELLOWED":"Emoji non consentiti",
95
96
  "DOMAIN_NOT_ALLOWED":"L'URL contiene un dominio non consentito",
96
97
  "MAX_ATTACHMENT": "Dimensione massima consentita {{FILE_SIZE_LIMIT}}Mb",
98
+ "MAX_ATTACHMENT_ERROR": "Il file supera la dimensione massima consentita",
97
99
  "EMOJI": "Emoji"
98
100
  }
@@ -71,7 +71,7 @@ export class TiledeskRequestsService {
71
71
 
72
72
  public getMyRequests(): Promise<{ requests: Array<any>}> {
73
73
  this.tiledeskToken = this.appStorage.getItem('tiledeskToken')
74
- const url = this.URL_TILEDESK_REQUEST + '/me?preflight=true'
74
+ const url = this.URL_TILEDESK_REQUEST + 'me?preflight=true'
75
75
  this.logger.log('[TILEDESK-SERVICE] - GET REQUEST url ', url);
76
76
  const httpOptions = {
77
77
  headers: new HttpHeaders({
@@ -773,6 +773,11 @@ export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
773
773
  return nonWhitelistedDomains.length === 0;
774
774
  }
775
775
 
776
+ // function extractUrls(text: string): string[] {
777
+ // const urlRegex = /https?:\/\/[^\s]+/g;
778
+ // return text.match(urlRegex) || [];
779
+ // }
780
+
776
781
  function extractUrls(text: string): string[] {
777
782
  // Rileva URL con o senza protocollo (http/https)
778
783
  const urlRegex = /\b((https?:\/\/)?(www\.)?[a-z0-9.-]+\.[a-z]{2,})(\/[^\s]*)?/gi;
@@ -787,5 +792,3 @@ function extractUrls(text: string): string[] {
787
792
  }
788
793
 
789
794
 
790
-
791
-
@@ -13,7 +13,7 @@
13
13
  bottom: 0px;
14
14
  width: auto;
15
15
  height: auto;
16
- display: none;
16
+ display: block;
17
17
  z-index: 3000000000; /*999999*/;
18
18
  }
19
19
 
@@ -84,12 +84,12 @@
84
84
  max-width: 1024px;
85
85
  max-height: 100%;
86
86
 
87
- transition:
87
+ /* transition:
88
88
  width 300ms,
89
89
  height 300ms,
90
90
  max-height 300ms,
91
91
  transform 300ms cubic-bezier(0, 1.2, 1, 1),
92
- opacity 300ms ease-out;
92
+ opacity 300ms ease-out; */
93
93
  /* per migliorare le prestazioni quando si usa transform */
94
94
  will-change: transform, opacity, width, height;
95
95
  }
@@ -175,14 +175,14 @@
175
175
  }
176
176
 
177
177
  #tiledesk-container.open #tiledeskdiv.min-size {
178
- transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out;
178
+ /* transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out; */
179
179
  width: var(--iframeMinWidth);
180
180
  height: var(--iframeMinHeight);
181
181
  }
182
182
 
183
183
  #tiledesk-container.open #tiledeskdiv.max-size {
184
184
  /* transition: width 1s, height 1s; */
185
- transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out;
185
+ /* transition: width 200ms, height 200ms, max-height 200ms, transform 300ms cubic-bezier(0, 1.2, 1, 1), opacity 83ms ease-out; */
186
186
  width: var(--iframeMaxWidth);
187
187
  height: var(--iframeMaxHeight);
188
188
  }
@@ -1,41 +0,0 @@
1
- # npm version patch
2
- version=`node -e 'console.log(require("./package.json").version)'`
3
- echo "version $version"
4
-
5
- npm i
6
-
7
- cp src/environments/real_data/environment.prod.ts src/environments/environment.prod.ts
8
-
9
- # --build-optimizer=false if localstorage is disabled (webview) appears https://github.com/firebase/angularfire/issues/970
10
- ng build --configuration="prod" --aot=true
11
- ##--base-href='./v5/' --output-hashing none
12
-
13
- ### SET HASHING : START ###
14
- cp ./src/launch_template.js ./dist/browser/launch.js
15
- node ./src/build_launch.js
16
- ### SET HASHING : END ###
17
-
18
- #### FIREBASE #####
19
- # cd dist
20
- # # aws s3 sync . s3://tiledesk-widget/v5/latest/
21
- # aws s3 sync . s3://tiledesk-widget/v5/$version/ --cache-control max-age=300
22
- # aws s3 sync . s3://tiledesk-widget/v5/ --cache-control max-age=300
23
- # cd ..
24
-
25
- # #### MQTT #####
26
- cd dist/browser
27
- # aws s3 sync . s3://tiledesk-widget/v5/latest/
28
- aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control max-age=86400 --exclude='launch.js' #8days
29
- aws s3 sync . s3://tiledesk-widget/v6/$version/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
30
- aws s3 sync . s3://tiledesk-widget/v6/ --cache-control max-age=86400 --exclude='launch.js' #8days
31
- aws s3 sync . s3://tiledesk-widget/v6/ --cache-control "no-store,no-cache,private" --exclude='*' --include='launch.js'
32
- cd ../..
33
-
34
- aws cloudfront create-invalidation --distribution-id E3EJDWEHY08CZZ --paths "/*"
35
-
36
- git restore src/environments/environment.prod.ts
37
-
38
- echo new version deployed $version on s3://tiledesk-widget/v6
39
- echo available on https://s3.eu-west-1.amazonaws.com/tiledesk-widget/v6/index.html
40
- echo https://widget.tiledesk.com/v6/index.html
41
- echo https://widget.tiledesk.com/v6/$version/index.html