@chat21/chat21-web-widget 5.1.32-rc4 → 5.1.33

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 (59) hide show
  1. package/.github/workflows/docker-community-push-latest.yml +13 -23
  2. package/.github/workflows/docker-image-tag-community-tag-push.yml +12 -22
  3. package/CHANGELOG.md +7 -50
  4. package/Dockerfile +5 -4
  5. package/angular.json +2 -5
  6. package/deploy_amazon_beta.sh +7 -17
  7. package/deploy_amazon_prod.sh +41 -0
  8. package/docs/changelog/this-branch.md +0 -36
  9. package/nginx.conf +2 -22
  10. package/package.json +1 -4
  11. package/src/app/app.component.ts +9 -10
  12. package/src/app/app.module.ts +0 -9
  13. package/src/app/component/conversation-detail/conversation/conversation.component.html +2 -8
  14. package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -12
  15. package/src/app/component/conversation-detail/conversation/conversation.component.ts +5 -45
  16. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +1 -1
  17. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -10
  18. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +0 -1
  19. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +79 -146
  20. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +13 -140
  21. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +7 -124
  22. package/src/app/component/last-message/last-message.component.ts +1 -4
  23. package/src/app/component/message/audio/audio.component.ts +5 -0
  24. package/src/app/component/message/bubble-message/bubble-message.component.html +1 -6
  25. package/src/app/component/message/bubble-message/bubble-message.component.ts +1 -2
  26. package/src/app/providers/global-settings.service.ts +0 -21
  27. package/src/app/providers/translator.service.ts +0 -2
  28. package/src/app/sass/_variables.scss +0 -3
  29. package/src/app/utils/globals.ts +1 -7
  30. package/src/assets/i18n/en.json +0 -1
  31. package/src/assets/i18n/es.json +0 -1
  32. package/src/assets/i18n/fr.json +0 -1
  33. package/src/assets/i18n/it.json +0 -1
  34. package/src/chat21-core/models/message.ts +1 -2
  35. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -3
  36. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +0 -12
  37. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  38. package/src/chat21-core/utils/utils-message.ts +0 -7
  39. package/src/chat21-core/utils/utils.ts +2 -5
  40. package/src/launch.js +41 -32
  41. package/src/launch_template.js +41 -32
  42. package/tsconfig.json +0 -5
  43. package/src/app/component/message/audio-sync/audio-sync.component.html +0 -19
  44. package/src/app/component/message/audio-sync/audio-sync.component.scss +0 -65
  45. package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +0 -23
  46. package/src/app/component/message/audio-sync/audio-sync.component.ts +0 -197
  47. package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +0 -12
  48. package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +0 -171
  49. package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +0 -39
  50. package/src/app/providers/voice/audio.types.ts +0 -34
  51. package/src/app/providers/voice/vad.service.spec.ts +0 -28
  52. package/src/app/providers/voice/vad.service.ts +0 -70
  53. package/src/app/providers/voice/voice.service.spec.ts +0 -60
  54. package/src/app/providers/voice/voice.service.ts +0 -294
  55. package/src/app/shims/onnxruntime-web-wasm.ts +0 -4
  56. package/src/assets/onnx/ort-wasm-simd-threaded.mjs +0 -59
  57. package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
  58. package/src/assets/vad/silero_vad_legacy.onnx +0 -0
  59. package/src/assets/vad/vad.worklet.bundle.min.js +0 -1
@@ -1,4 +1,4 @@
1
- import { Component, ComponentFactoryResolver, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
1
+ import { Component, ComponentFactoryResolver, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
2
2
  import { error } from 'console';
3
3
  import { FILE_SIZE_LIMIT } from 'src/app/utils/constants';
4
4
  import { Globals } from 'src/app/utils/globals';
@@ -15,15 +15,13 @@ import { TYPE_MSG_FILE, TYPE_MSG_IMAGE, TYPE_MSG_TEXT } from 'src/chat21-core/ut
15
15
  import { convertColorToRGBA, isAllowedUrlInText, isEmoji } from 'src/chat21-core/utils/utils';
16
16
  import { findAndRemoveEmoji, isImage } from 'src/chat21-core/utils/utils-message';
17
17
  import { ProjectModel } from 'src/models/project';
18
- import { Subscription } from 'rxjs';
19
- import { VoiceService } from 'src/app/providers/voice/voice.service';
20
18
 
21
19
  @Component({
22
20
  selector: 'chat-conversation-footer',
23
21
  templateUrl: './conversation-footer.component.html',
24
22
  styleUrls: ['./conversation-footer.component.scss']
25
23
  })
26
- export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy {
24
+ export class ConversationFooterComponent implements OnInit, OnChanges {
27
25
 
28
26
  @Input() conversationWith: string;
29
27
  @Input() attributes: string;
@@ -34,9 +32,8 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
34
32
  @Input() userFullname: string;
35
33
  @Input() userEmail: string;
36
34
  @Input() showAttachmentFooterButton: boolean;
37
- @Input() showEmojiFooterButton: boolean;
38
- @Input() showAudioRecorderFooterButton: boolean;
39
- @Input() showAudioStreamFooterButton: boolean;
35
+ @Input() showEmojiFooterButton: boolean
36
+ @Input() showAudioRecorderFooterButton: boolean
40
37
  // @Input() showContinueConversationButton: boolean;
41
38
  @Input() isConversationArchived: boolean;
42
39
  @Input() hideTextAreaContent: boolean;
@@ -45,7 +42,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
45
42
  @Input() isEmojiiPickerShow: boolean;
46
43
  @Input() footerMessagePlaceholder: string;
47
44
  @Input() fileUploadAccept: string;
48
- @Input() closeChatInConversation: boolean;
49
45
  @Input() dropEvent: Event;
50
46
  @Input() poweredBy: string;
51
47
  @Input() stylesMap: Map<string, string>
@@ -56,8 +52,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
56
52
  @Output() onChangeTextArea = new EventEmitter<any>();
57
53
  @Output() onAttachmentFileButtonClicked = new EventEmitter<any>();
58
54
  @Output() onNewConversationButtonClicked = new EventEmitter();
59
- @Output() onStreamAudioActiveChange = new EventEmitter<boolean>();
60
- @Output() onCloseChatButtonClicked = new EventEmitter();
61
55
 
62
56
  @ViewChild('chat21_file') public chat21_file: ElementRef;
63
57
  // @ViewChild('emojii_container', {read: ViewContainerRef}) selector;
@@ -91,28 +85,15 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
91
85
 
92
86
  showAlertEmoji: boolean = false
93
87
 
94
- /** Stream audio UI: icona equalizer → X; alert con onde animate sopra il footer */
95
- isStreamAudioActive = false;
96
- /** Sottoscrizione ai segmenti audio (VAD → WebM) dal {@link VoiceService}. */
97
- private voiceAudioSubscription?: Subscription;
98
- /** Sottoscrizione al volume audio (real-time) dal {@link VoiceService}. */
99
- private voiceVolumeSubscription?: Subscription;
100
- currentVolume = 0;
101
- wavePath1 = '';
102
- wavePath2 = '';
103
- wavePath3 = '';
104
-
105
88
  file_size_limit = FILE_SIZE_LIMIT;
106
89
  attachmentTooltip: string = '';
107
- isErrorNetwork: boolean = false;
108
90
 
109
91
 
110
92
  convertColorToRGBA = convertColorToRGBA;
111
93
  private logger: LoggerService = LoggerInstance.getInstance()
112
94
  constructor(private chatManager: ChatManager,
113
95
  private typingService: TypingService,
114
- private uploadService: UploadService,
115
- private voiceService: VoiceService) { }
96
+ private uploadService: UploadService) { }
116
97
 
117
98
  ngOnInit() {
118
99
  // this.updateAttachmentTooltip();
@@ -122,8 +103,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
122
103
  ngOnChanges(changes: SimpleChanges){
123
104
  if(changes['conversationWith'] && changes['conversationWith'].currentValue !== undefined){
124
105
  this.conversationHandlerService = this.chatManager.getConversationHandlerByConversationId(this.conversationWith);
125
- this.isStreamAudioActive = false;
126
- void this.stopVoice();
127
106
  }
128
107
  if(changes['hideTextReply'] && changes['hideTextReply'].currentValue !== undefined){
129
108
  this.restoreTextArea();
@@ -163,75 +142,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
163
142
  // }, 500);
164
143
  // }
165
144
 
166
- /**
167
- * Microfono + VAD: ogni fine parlato il servizio emette su `audioSegment$` → upload.
168
- */
169
- async initVoice() {
170
- this.voiceAudioSubscription?.unsubscribe();
171
- this.voiceVolumeSubscription?.unsubscribe();
172
-
173
- this.voiceAudioSubscription = this.voiceService.audioSegment$.subscribe((rec) => {
174
- console.log('[CONV-FOOTER] audioSegment$', rec);
175
- this.prepareAndUpload(rec.blob);
176
- });
177
- this.voiceVolumeSubscription = this.voiceService.volume$.subscribe((volume) => {
178
- this.currentVolume = volume;
179
- this.updateWave(volume);
180
- });
181
- await this.voiceService.startSession();
182
- }
183
-
184
- async stopVoice(options?: { discardInProgressSegment?: boolean }) {
185
- this.voiceAudioSubscription?.unsubscribe();
186
- this.voiceAudioSubscription = undefined;
187
-
188
- this.voiceVolumeSubscription?.unsubscribe();
189
- this.voiceVolumeSubscription = undefined;
190
-
191
- await this.voiceService.stopSession(options);
192
- }
193
-
194
- /**
195
- * Messaggio in arrivo da un altro mittente mentre lo stream è attivo: scarta solo il segmento
196
- * registrato in quel momento (nessun upload); mic + VAD restano attivi, `isStreamAudioActive` true.
197
- */
198
- interruptStreamDueToPeerMessage(): void {
199
- if (!this.isStreamAudioActive) {
200
- return;
201
- }
202
- this.logger.log('[CONV-FOOTER] discard recording segment: incoming message from peer (stream stays on)');
203
- try {
204
- this.voiceService.discardCurrentRecordingSegment();
205
- } catch (e) {
206
- this.logger.error('[CONV-FOOTER] interruptStreamDueToPeerMessage', e);
207
- }
208
- }
209
-
210
- updateWave(volume: number) {
211
- const intensity = Math.min(volume / 80, 1); // più sensibile
212
-
213
- const amp1 = 4 + intensity * 22;
214
- const amp2 = 2 + intensity * 16;
215
- const amp3 = 1 + intensity * 12;
216
-
217
- this.wavePath1 = this.buildWave(42, amp1);
218
- this.wavePath2 = this.buildWave(50, amp2);
219
- this.wavePath3 = this.buildWave(58, amp3);
220
- }
221
-
222
- buildWave(y: number, amp: number): string {
223
- return `
224
- M6 ${y}
225
- Q24 ${y - amp} 42 ${y}
226
- T78 ${y}
227
- T98 ${y}
228
- `;
229
- }
230
-
231
- ngOnDestroy() {
232
- void this.stopVoice();
233
- }
234
-
235
145
  // ========= begin:: functions send image ======= //
236
146
  // START LOAD IMAGE //
237
147
  /** load the selected image locally and open the pop up preview */
@@ -611,7 +521,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
611
521
  }
612
522
  }
613
523
 
614
- prepareAndUpload(audioBlob: Blob, text: string = '') {
524
+ prepareAndUpload(audioBlob: Blob) {
615
525
 
616
526
  this.isFilePendingToUpload = true;
617
527
 
@@ -641,7 +551,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
641
551
  this.logger.log('[UPLOAD] metadata:', metadata);
642
552
 
643
553
  // stesso metodo che già usi
644
- this.uploadSingle(metadata, file, text);
554
+ this.uploadSingle(metadata, file, '');
645
555
  }
646
556
 
647
557
  // Funzione per convertire Blob in Base64 usando FileReader
@@ -748,29 +658,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
748
658
  }
749
659
  }
750
660
 
751
- async onStreamPressed(event: Event) {
752
- this.logger.log('[CONV-FOOTER] onStreamPressed:event', event);
753
- event.preventDefault();
754
- if (this.showAlertEmoji) {
755
- return;
756
- }
757
- const turningOn = !this.isStreamAudioActive;
758
- if (turningOn) {
759
- try {
760
- await this.initVoice();
761
- this.isStreamAudioActive = true;
762
- } catch (e) {
763
- this.logger.error('[CONV-FOOTER] onStreamPressed: initVoice failed', e);
764
- this.isStreamAudioActive = false;
765
- }
766
- } else {
767
- await this.stopVoice();
768
- this.isStreamAudioActive = false;
769
- }
770
- this.onStreamAudioActiveChange.emit(this.isStreamAudioActive);
771
- this.logger.log('[CONV-FOOTER] isStreamAudioActive', this.isStreamAudioActive);
772
- }
773
-
774
661
  async onEmojiiPickerClicked(){
775
662
  // if(this.loadPickerModule){
776
663
  // this.loadPickerModule = false;
@@ -822,10 +709,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
822
709
  this.onNewConversationButtonClicked.emit();
823
710
  }
824
711
 
825
- onCloseChat(event){
826
- this.onCloseChatButtonClicked.emit();
827
- }
828
-
829
712
  // onContinueConversation(){
830
713
  // this.hideTextAreaContent = false;
831
714
  // this.onBackButton.emit(false)
@@ -12,7 +12,7 @@ import { MIN_WIDTH_IMAGES } from 'src/app/utils/constants';
12
12
  import { ConversationModel } from 'src/chat21-core/models/conversation';
13
13
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
14
14
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
15
- import { commandToMessage, conversationToMessage, isEmojii, isFrame, isImage, isMine, isSameSender, isSender } from 'src/chat21-core/utils/utils-message';
15
+ import { commandToMessage, conversationToMessage, isEmojii, isFrame, isImage, isSameSender } from 'src/chat21-core/utils/utils-message';
16
16
 
17
17
 
18
18
  @Component({
@@ -59,9 +59,6 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
59
59
  ngOnChanges(changes: SimpleChanges) {
60
60
  this.logger.debug('[LASTMESSAGE] onChanges', changes)
61
61
  if(this.conversation){
62
-
63
- /** if the message is sent by the logged user, do not add it to the messages array */
64
- if(isSender(this.conversation.sender, this.g.senderId)) return;
65
62
 
66
63
  if(this.conversation.attributes && this.conversation.attributes.commands){
67
64
  this.addCommandMessage(this.conversation)
@@ -154,10 +154,15 @@ export class AudioComponent implements AfterViewInit {
154
154
  // });
155
155
 
156
156
  const response = await fetch(this.rawAudioUrl!);
157
+ this.logger.debug('getAudioDuration: response ---> ', response)
157
158
  const arrayBuffer = await response.arrayBuffer();
159
+ this.logger.debug('getAudioDuration: arrayBuffer ---> ', arrayBuffer)
158
160
  const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
161
+ this.logger.debug('getAudioDuration: audioContext ---> ', audioContext)
159
162
  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
163
+ this.logger.debug('getAudioDuration: audioBuffer ---> ', audioBuffer)
160
164
  this.audioDuration = audioBuffer.duration;
165
+ this.logger.debug('getAudioDuration: audioDuration ---> ', this.audioDuration)
161
166
 
162
167
  }
163
168
 
@@ -64,11 +64,6 @@
64
64
  [stylesMap]="stylesMap">
65
65
  </chat-audio>
66
66
 
67
- <chat-audio-sync *ngIf="isAudioTTS(message)"
68
- [message]="message"
69
- [color]="fontColor">
70
- </chat-audio-sync>
71
-
72
67
 
73
68
  <!-- <chat-frame *ngIf="message.metadata && message.metadata.type && message.metadata.type.includes('video')"
74
69
  [metadata]="message.metadata"
@@ -80,7 +75,7 @@
80
75
  <!-- <div *ngIf="message.type == 'text'"> -->
81
76
 
82
77
  <!-- tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})" placement="bottom" -->
83
- <div *ngIf="message?.text && (!isAudio(message) && !isAudioTTS(message))" >
78
+ <div *ngIf="message?.text && !isAudio(message)" >
84
79
 
85
80
  <!-- [htmlEnabled]="(message?.type==='html')? true : false" -->
86
81
  <chat-text *ngIf="message?.type !=='html'"
@@ -5,7 +5,7 @@ import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service
5
5
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
6
6
  import { MAX_WIDTH_IMAGES, MESSAGE_TYPE_MINE, MESSAGE_TYPE_OTHERS, MIN_WIDTH_IMAGES } from 'src/chat21-core/utils/constants';
7
7
  import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
8
- import { isAudio, isAudioTTS, isFile, isFrame, isImage, messageType } from 'src/chat21-core/utils/utils-message';
8
+ import { isAudio, isFile, isFrame, isImage, messageType } from 'src/chat21-core/utils/utils-message';
9
9
  import { getColorBck } from 'src/chat21-core/utils/utils-user';
10
10
 
11
11
  @Component({
@@ -26,7 +26,6 @@ export class BubbleMessageComponent implements OnInit {
26
26
  isFile = isFile;
27
27
  isFrame = isFrame;
28
28
  isAudio = isAudio;
29
- isAudioTTS=isAudioTTS;
30
29
  convertColorToRGBA = convertColorToRGBA
31
30
 
32
31
  // ========== begin:: check message type functions ======= //
@@ -1125,22 +1125,11 @@ export class GlobalSettingsService {
1125
1125
  if (TEMP !== undefined) {
1126
1126
  globals.showAudioRecorderFooterButton = (TEMP === true) ? true : false;
1127
1127
  }
1128
- TEMP = tiledeskSettings['showAudioStreamFooterButton'];
1129
- // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > showAudioStreamFooterButton:: ', TEMP]);
1130
- if (TEMP !== undefined) {
1131
- globals.showAudioStreamFooterButton = (TEMP === true) ? true : false;
1132
- }
1133
1128
  TEMP = tiledeskSettings['size'];
1134
1129
  // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > size:: ', TEMP]);
1135
1130
  if (TEMP !== undefined) {
1136
1131
  globals.size = TEMP;
1137
1132
  }
1138
-
1139
- TEMP = tiledeskSettings['closeChatInConversation'];
1140
- // this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > closeChatInConversation:: ', TEMP]);
1141
- if (TEMP !== undefined) {
1142
- globals.closeChatInConversation = (TEMP === true) ? true : false;
1143
- }
1144
1133
  }
1145
1134
 
1146
1135
  /**
@@ -1878,11 +1867,6 @@ export class GlobalSettingsService {
1878
1867
  globals.showAttachmentFooterButton = stringToBoolean(TEMP);
1879
1868
  }
1880
1869
 
1881
- TEMP = getParameterByName(windowContext, 'tiledesk_showAudioStreamFooterButton');
1882
- if (TEMP) {
1883
- globals.showAudioStreamFooterButton = stringToBoolean(TEMP);
1884
- }
1885
-
1886
1870
  TEMP = getParameterByName(windowContext, 'tiledesk_showEmojiFooterButton');
1887
1871
  if (TEMP) {
1888
1872
  globals.showEmojiFooterButton = stringToBoolean(TEMP);
@@ -1892,11 +1876,6 @@ export class GlobalSettingsService {
1892
1876
  if (TEMP) {
1893
1877
  globals.size = TEMP;
1894
1878
  }
1895
-
1896
- TEMP = getParameterByName(windowContext, 'tiledesk_closeChatInConversation');
1897
- if (TEMP) {
1898
- globals.closeChatInConversation = stringToBoolean(TEMP);
1899
- }
1900
1879
 
1901
1880
  }
1902
1881
 
@@ -302,7 +302,6 @@ export class TranslatorService {
302
302
  'CLOSED',
303
303
  'LABEL_PREVIEW',
304
304
  'MAX_ATTACHMENT',
305
- 'MAX_ATTACHMENT_ERROR',
306
305
  'EMOJI'
307
306
  ];
308
307
 
@@ -359,7 +358,6 @@ export class TranslatorService {
359
358
  globals.LABEL_PREVIEW = res['LABEL_PREVIEW']
360
359
  globals.LABEL_ERROR_FIELD_REQUIRED= res['LABEL_ERROR_FIELD_REQUIRED']
361
360
  globals.MAX_ATTACHMENT = res['MAX_ATTACHMENT']
362
- globals.MAX_ATTACHMENT_ERROR = res['MAX_ATTACHMENT_ERROR']
363
361
  globals.EMOJI = res['EMOJI']
364
362
 
365
363
 
@@ -36,10 +36,7 @@
36
36
 
37
37
  --chat-footer-height: 64px;
38
38
  --chat-footer-logo-height: 30px;
39
- --chat-footer-close-button-height: 30px;
40
39
  --chat-footer-border-radius: 16px;
41
- --chat-footer-stream-button-height: 96px;
42
- --chat-footer-stream-button-padding: 10px 0;
43
40
  --chat-footer-background-color: #f6f7fb;
44
41
  --chat-footer-color: #1a1a1a;
45
42
  --chat-footer-border-color-error: #aa0404;
@@ -219,7 +219,6 @@ export class Globals {
219
219
  showEmojiFooterButton: boolean // ******* new ********
220
220
  showAttachmentFooterButton: boolean // ******* new ********
221
221
  showAudioRecorderFooterButton: boolean // ******* new ********
222
- showAudioStreamFooterButton: boolean // ******* new ********
223
222
 
224
223
  allowedOnSpecificUrl: boolean // ******* new ********
225
224
  allowedOnSpecificUrlList: Array<string> // ******* new ********
@@ -228,8 +227,6 @@ export class Globals {
228
227
  fontFamilySource: string; // ******* new ********
229
228
 
230
229
  size: 'min' | 'max' | 'top'; // ******* new ********
231
-
232
- closeChatInConversation: boolean; // ******* new ********
233
230
  constructor(
234
231
  ) { }
235
232
 
@@ -438,8 +435,6 @@ export class Globals {
438
435
  this.showAttachmentFooterButton = true;
439
436
  /** show/hide rec audio option in footer chat-detail page */
440
437
  this.showAudioRecorderFooterButton = true;
441
- /** show/hide stream audio option in footer chat-detail page */
442
- this.showAudioStreamFooterButton = true;
443
438
  /** enabled to set a list of pattern url able to load the widget **/
444
439
  this.allowedOnSpecificUrl = false
445
440
  /** set a list of pattern url able to load the widget */
@@ -448,8 +443,7 @@ export class Globals {
448
443
  this.hasCalloutInWidgetConfig = false;
449
444
  /** set widget size from 3 different positions: min, max, top */
450
445
  this.size = 'min';
451
- /** enable to close the chat in conversation */
452
- this.closeChatInConversation = false;
446
+
453
447
  // ============ END: SET EXTERNAL PARAMETERS ==============//
454
448
 
455
449
 
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji not allowed",
98
98
  "DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain",
99
99
  "MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
100
- "MAX_ATTACHMENT_ERROR": "The file exceeds the maximum allowed size",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji no permitido",
98
98
  "DOMAIN_NOT_ALLOWED":"La URL contiene un dominio no permitido",
99
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",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -97,6 +97,5 @@
97
97
  "EMOJI_NOT_ELLOWED":"Emoji non autorisé",
98
98
  "DOMAIN_NOT_ALLOWED":"L'URL contient un domaine non autorisé",
99
99
  "MAX_ATTACHMENT": "Taille maximale autorisée {{FILE_SIZE_LIMIT}}Mo",
100
- "MAX_ATTACHMENT_ERROR": "Le fichier dépasse la taille maximale autorisée",
101
100
  "EMOJI": "Emoji"
102
101
  }
@@ -95,6 +95,5 @@
95
95
  "EMOJI_NOT_ELLOWED":"Emoji non consentiti",
96
96
  "DOMAIN_NOT_ALLOWED":"L'URL contiene un dominio non consentito",
97
97
  "MAX_ATTACHMENT": "Dimensione massima consentita {{FILE_SIZE_LIMIT}}Mb",
98
- "MAX_ATTACHMENT_ERROR": "Il file supera la dimensione massima consentita",
99
98
  "EMOJI": "Emoji"
100
99
  }
@@ -14,7 +14,6 @@ export class MessageModel {
14
14
  public attributes: any,
15
15
  public channel_type: string,
16
16
  public isSender: boolean,
17
- public emoticon?: boolean,
18
- public isJustRecived?: boolean
17
+ public emoticon?: boolean
19
18
  ) { }
20
19
  }
@@ -253,7 +253,9 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
253
253
  }
254
254
  }
255
255
 
256
+
256
257
 
258
+
257
259
  this.addRepalceMessageInArray(msg.uid, msg);
258
260
  this.messageAdded.next(msg);
259
261
  } else {
@@ -492,9 +494,6 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
492
494
  commands[i+1]? commands[i+1].time = 0 : null
493
495
  }
494
496
  }
495
-
496
- command.message.isJustRecived = isJustRecived( that.startTime.getTime(), msg.timestamp );
497
-
498
497
  that.generateMessageObject(msg, command.message, function () {
499
498
  i += 1
500
499
  if (i < commands.length) {
@@ -273,16 +273,6 @@ export class MQTTConversationHandler extends ConversationHandlerService {
273
273
  if(isInfoMessage){
274
274
  this.messageInfo.next(msg)
275
275
  }
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
276
 
287
277
  if(isInfoMessage && hideInfoMessage(msg, this.showInfoMessage)){
288
278
  //if showBubbleInfoMessage array keys not includes msg.attributes.messagelabel['key'] exclude CURRENT INFO MESSAGE
@@ -502,8 +492,6 @@ export class MQTTConversationHandler extends ConversationHandlerService {
502
492
  }
503
493
  }
504
494
 
505
- command.message.isJustRecived = isJustRecived( that.startTime.getTime(), msg.timestamp );
506
-
507
495
  that.generateMessageObject(msg, command.message, i, function () {
508
496
  i += 1
509
497
  if (i < commands.length) {
@@ -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({
@@ -48,13 +48,6 @@ export function isAudio(message: any) {
48
48
  return false;
49
49
  }
50
50
 
51
- export function isAudioTTS(message: any) {
52
- if (message && message.type && message.type === 'tts' && message.metadata && message.metadata.src && message.metadata.type.includes('audio') ) {
53
- return true;
54
- }
55
- return false;
56
- }
57
-
58
51
  /** */
59
52
  export function isInfo(message: any) {
60
53
  if (message && message.attributes && (message.attributes.subtype === 'info' || message.attributes.subtype === 'info/support')) {
@@ -773,11 +773,6 @@ 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
-
781
776
  function extractUrls(text: string): string[] {
782
777
  // Rileva URL con o senza protocollo (http/https)
783
778
  const urlRegex = /\b((https?:\/\/)?(www\.)?[a-z0-9.-]+\.[a-z]{2,})(\/[^\s]*)?/gi;
@@ -792,3 +787,5 @@ function extractUrls(text: string): string[] {
792
787
  }
793
788
 
794
789
 
790
+
791
+
package/src/launch.js CHANGED
@@ -218,67 +218,76 @@ function loadIframe(tiledeskScriptBaseLocation) {
218
218
  iDiv.appendChild(ifrm);
219
219
 
220
220
  // Funzione helper per caricare iframe con fallback per compatibilità CSP (Wix, etc.)
221
- // Usa Blob URL come metodo principale (più compatibile con CSP) con fallback a srcdoc e document.write
222
- function loadIframeContent(iframe, htmlContent, baseLocation) {
223
- var isLocalhost = baseLocation.includes('localhost');
221
+ // Priorità: document.write / srcdoc prima della Blob URL. Le Blob URL spesso danno origine opaca
222
+ // (blob:null): l'iframe non può leggere window.parent.tiledeskSettings → projectid mancante.
223
+ function loadIframeContent(iframe, htmlContent) {
224
224
  var blobUrl = null;
225
-
226
- // Metodo 1: Blob URL (più compatibile con CSP di Wix e altre piattaforme)
227
- // Usa Blob URL come metodo principale perché è meno spesso bloccato da CSP rispetto a srcdoc
225
+
226
+ // 1) document.write: iframe stessa origine della pagina host tiledeskSettings sul parent accessibile
227
+ try {
228
+ var cw = iframe.contentWindow;
229
+ if (cw && cw.document) {
230
+ cw.document.open();
231
+ cw.document.write(htmlContent);
232
+ cw.document.close();
233
+ return;
234
+ }
235
+ } catch (e) {
236
+ console.warn('[Tiledesk] iframe document.write failed, trying srcdoc/blob:', e);
237
+ }
238
+
239
+ // 2) srcdoc: stessa origine del parent (HTML5); utile se document.write è bloccato
240
+ if ('srcdoc' in iframe) {
241
+ try {
242
+ iframe.srcdoc = htmlContent;
243
+ return;
244
+ } catch (e) {
245
+ console.warn('[Tiledesk] iframe srcdoc failed, trying blob:', e);
246
+ }
247
+ }
248
+
249
+ // 3) Blob URL (spesso permesso da CSP dove srcdoc/write no; può rompere lettura parent.tiledeskSettings)
228
250
  if (typeof Blob !== 'undefined' && typeof URL !== 'undefined' && URL.createObjectURL) {
229
251
  try {
230
252
  var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
231
253
  blobUrl = URL.createObjectURL(blob);
232
254
  iframe.src = blobUrl;
233
-
234
- // Cleanup del blob URL dopo il caricamento per liberare memoria
255
+
235
256
  var originalOnload = iframe.onload;
236
257
  iframe.onload = function() {
237
- // Revoca il blob URL dopo un delay per assicurarsi che tutto sia caricato
238
258
  setTimeout(function() {
239
259
  if (blobUrl) {
240
260
  try {
241
261
  URL.revokeObjectURL(blobUrl);
242
262
  blobUrl = null;
243
- } catch(e) {
244
- console.warn('Error revoking blob URL:', e);
263
+ } catch (err) {
264
+ console.warn('Error revoking blob URL:', err);
245
265
  }
246
266
  }
247
267
  }, 1000);
248
268
  if (originalOnload) originalOnload.call(this);
249
269
  };
250
- return; // Blob URL impostato con successo
251
- } catch(e) {
252
- console.warn('Blob URL not available, trying srcdoc:', e);
270
+ return;
271
+ } catch (e) {
272
+ console.warn('Blob URL not available:', e);
253
273
  }
254
274
  }
255
-
256
- // Metodo 2: srcdoc (fallback se Blob URL non disponibile)
257
- // Skip per localhost (usa document.write per compatibilità sviluppo)
258
- if (!isLocalhost && 'srcdoc' in iframe) {
259
- try {
260
- iframe.srcdoc = htmlContent;
261
- return; // srcdoc impostato
262
- } catch(e) {
263
- console.warn('srcdoc not allowed, trying document.write:', e);
264
- }
265
- }
266
-
267
- // Metodo 3: document.write (fallback finale, funziona su localhost e browser vecchi)
268
- if (isLocalhost || (iframe.contentWindow && iframe.contentWindow.document)) {
275
+
276
+ // 4) Ultimo tentativo document.write (iframe magari non pronto al primo passo)
277
+ if (iframe.contentWindow && iframe.contentWindow.document) {
269
278
  try {
270
279
  iframe.contentWindow.document.open();
271
280
  iframe.contentWindow.document.write(htmlContent);
272
281
  iframe.contentWindow.document.close();
273
- return; // document.write completato
274
- } catch(e) {
275
- console.error('All iframe loading methods failed:', e);
282
+ return;
283
+ } catch (e) {
284
+ console.error('[Tiledesk] All iframe loading methods failed:', e);
276
285
  }
277
286
  }
278
287
  }
279
288
 
280
289
  // Carica il contenuto dell'iframe con fallback automatico
281
- loadIframeContent(ifrm, srcTileDesk, tiledeskScriptBaseLocation);
290
+ loadIframeContent(ifrm, srcTileDesk);
282
291
 
283
292
 
284
293
  }