@chat21/chat21-web-widget 5.1.4 → 5.1.7-rc14

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 (47) 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 +53 -0
  4. package/Dockerfile +4 -5
  5. package/angular.json +2 -1
  6. package/package.json +1 -1
  7. package/src/app/app.component.html +11 -4
  8. package/src/app/app.component.scss +60 -1
  9. package/src/app/app.component.ts +83 -36
  10. package/src/app/app.module.ts +16 -10
  11. package/src/app/component/conversation-detail/conversation/conversation.component.scss +1 -1
  12. package/src/app/component/conversation-detail/conversation/conversation.component.ts +20 -5
  13. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -0
  14. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +8 -11
  15. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +25 -0
  16. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +57 -23
  17. package/src/app/component/{network-offline/network-offline.component.html → error-alert/error-alert.component.html} +4 -2
  18. package/src/app/component/{network-offline/network-offline.component.scss → error-alert/error-alert.component.scss} +3 -1
  19. package/src/app/component/{network-offline/network-offline.component.spec.ts → error-alert/error-alert.component.spec.ts} +8 -6
  20. package/src/app/component/error-alert/error-alert.component.ts +47 -0
  21. package/src/app/component/launcher-button/launcher-button.component.html +1 -1
  22. package/src/app/component/launcher-button/launcher-button.component.ts +3 -2
  23. package/src/app/component/message/buttons/action-button/action-button.component.scss +6 -6
  24. package/src/app/component/message/buttons/action-button/action-button.component.ts +1 -1
  25. package/src/app/component/message/buttons/link-button/link-button.component.scss +5 -5
  26. package/src/app/component/message/buttons/link-button/link-button.component.ts +2 -2
  27. package/src/app/component/message/buttons/text-button/text-button.component.scss +9 -12
  28. package/src/app/component/message/buttons/text-button/text-button.component.ts +4 -4
  29. package/src/app/component/message-attachment/message-attachment.component.html +3 -7
  30. package/src/app/providers/global-settings.service.ts +3 -3
  31. package/src/app/providers/translator.service.ts +8 -2
  32. package/src/app/sass/_variables.scss +1 -1
  33. package/src/app/utils/constants.ts +3 -0
  34. package/src/app/utils/globals.ts +2 -2
  35. package/src/app/utils/utils.ts +10 -12
  36. package/src/assets/i18n/en.json +4 -1
  37. package/src/assets/i18n/es.json +6 -1
  38. package/src/assets/i18n/fr.json +6 -1
  39. package/src/assets/i18n/it.json +6 -3
  40. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +2 -2
  41. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +22 -11
  42. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  43. package/src/chat21-core/utils/utils.ts +15 -4
  44. package/src/iframe-style.css +6 -6
  45. package/deploy_amazon_beta.sh +0 -47
  46. package/deploy_amazon_prod.sh +0 -41
  47. package/src/app/component/network-offline/network-offline.component.ts +0 -24
@@ -223,6 +223,7 @@
223
223
  .msg_receive {
224
224
  background-color: var(--light-white);
225
225
  color: var(--black);
226
+ min-height: 38px;
226
227
  // max-width: 260px;
227
228
  max-width: calc(100% - 70px);
228
229
  min-width: 14px;
@@ -4,7 +4,7 @@
4
4
  <div tabindex="-1" class="c21-powered-by" [innerHTML]="poweredBy" (click)="managePoweredBy($event)"></div>
5
5
  </div>
6
6
 
7
- <!-- ALERT EMOJI & URLS -->
7
+ <!-- ALERT EMOJI -->
8
8
  <div id="textAlert" *ngIf="!hideTextAreaContent && showAlertEmoji" class="fade-in-bottom" [class.hideTextReply]="hideTextReply">
9
9
  <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" version="1.1" viewBox="0 0 110 135">
10
10
  <path d="M55,25.8c-23,0-41.7,18.7-41.7,41.7s18.7,41.7,41.7,41.7,41.7-18.7,41.7-41.7-18.7-41.7-41.7-41.7ZM55,91.5c-3.4,0-6.2-2.8-6.2-6.2s2.8-6.2,6.2-6.2,6.2,2.8,6.2,6.2-2.8,6.2-6.2,6.2ZM60.3,70.1c-.2,2.8-2.5,4.9-5.3,4.9s-5.1-2.2-5.3-4.9l-1.6-22.3c-.3-4,2.9-7.4,6.9-7.4s7.2,3.4,6.9,7.4l-1.6,22.3Z"/>
@@ -12,12 +12,6 @@
12
12
  <div tabindex="-1" class="alertText">{{translationMap.get('EMOJI_NOT_ELLOWED')}}</div>
13
13
  </div>
14
14
 
15
- <div id="textAlert" *ngIf="!hideTextAreaContent && showAlertUrl" class="fade-in-bottom" [class.hideTextReply]="hideTextReply">
16
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" version="1.1" viewBox="0 0 110 135">
17
- <path d="M55,25.8c-23,0-41.7,18.7-41.7,41.7s18.7,41.7,41.7,41.7,41.7-18.7,41.7-41.7-18.7-41.7-41.7-41.7ZM55,91.5c-3.4,0-6.2-2.8-6.2-6.2s2.8-6.2,6.2-6.2,6.2,2.8,6.2,6.2-2.8,6.2-6.2,6.2ZM60.3,70.1c-.2,2.8-2.5,4.9-5.3,4.9s-5.1-2.2-5.3-4.9l-1.6-22.3c-.3-4,2.9-7.4,6.9-7.4s7.2,3.4,6.9,7.4l-1.6,22.3Z"/>
18
- </svg>
19
- <div tabindex="-1" class="alertText">{{translationMap.get('DOMAIN_NOT_ALLOWED')}}</div>
20
- </div>
21
15
  </div>
22
16
 
23
17
  <!-- TEXTAREA + ICONS: conv active-->
@@ -27,9 +21,11 @@
27
21
  <!-- ICON ATTACHMENT -->
28
22
  <label *ngIf="showAttachmentFooterButton" tabindex="1502" aria-label="allegati" for="chat21-file" class="chat21-textarea-button" [class.active]="!isFilePendingToUpload && !hideTextReply" id="chat21-start-upload-doc">
29
23
  <span class="v-align-center">
30
- <svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24" viewBox="0 0 24 24" fill="currentColor">
24
+ <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" width="24px" height="24" viewBox="0 0 24 24" fill="currentColor">
31
25
  <path d="M9.9,22.7c0,0-.1,0-.2,0-1.9.3-3.7-.2-5.2-1.4-3-2.3-3.6-6.4-1.4-9.5L9.5,2.5c.4-.5,1.1-.6,1.6-.3.5.4.6,1.1.3,1.6l-6.5,9.4c-1.4,2-1,4.8.9,6.3,1,.8,2.2,1.1,3.5.9,1.3-.2,2.4-.9,3.1-1.9l6-8.7c.9-1.2.6-3-.6-3.9-.6-.5-1.4-.6-2.1-.5-.8.1-1.4.5-1.9,1.1l-5.8,8.2c-.3.5-.2,1.1.2,1.5.2.2.5.3.8.2.3,0,.6-.2.7-.4l4.7-6.2c.4-.5,1.1-.6,1.6-.2.5.4.6,1.1.2,1.6l-4.7,6.2c-.5.7-1.4,1.2-2.3,1.3-.9.1-1.8-.2-2.5-.7-1.4-1.1-1.6-3.1-.6-4.6l5.8-8.2c.8-1.1,2-1.9,3.4-2.1,1.4-.2,2.7.1,3.8,1,2.2,1.7,2.7,4.8,1.1,7.1l-6,8.7c-1.1,1.5-2.6,2.5-4.4,2.8h0Z"/>
26
+ <title id="altIconTitle">{{ 'MAX_ATTACHMENT' | translate: { FILE_SIZE_LIMIT: file_size_limit } }}</title>
32
27
  </svg>
28
+
33
29
  </span>
34
30
  <input
35
31
  [attr.disabled] = "(isFilePendingToUpload || isConversationArchived || hideTextReply)? true : null"
@@ -47,11 +43,12 @@
47
43
  <!-- ICON EMOJII -->
48
44
  <label *ngIf="showEmojiFooterButton" tabindex="1504" aria-label="emojii" for="chat21-emojii" class="chat21-textarea-button" [class.active]="!isFilePendingToUpload && !hideTextReply" id="chat21-emoticon-picker" (click)="onEmojiiPickerClicked()">
49
45
  <span class="v-align-center">
50
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
46
+ <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
51
47
  <path stroke-width=".4px" stroke="currentColor" d="M12,20.8c-5.1,0-9.3-4.2-9.3-9.3S6.9,2.2,12,2.2s9.3,4.2,9.3,9.3-4.2,9.3-9.3,9.3ZM12,3.6c-4.4,0-7.9,3.6-7.9,7.9s3.6,7.9,7.9,7.9,7.9-3.6,7.9-7.9-3.6-7.9-7.9-7.9Z"/>
52
48
  <path stroke-width=".4px" stroke="currentColor" d="M12,17.2c-2.7,0-4.3-1.9-4.6-2.3-.2-.3-.2-.7.1-1s.7-.2,1,.1c.1.2,1.4,1.8,3.5,1.8s2.2,0,3.5-1.8c.2-.3.7-.4,1-.1s.4.7.1,1c-1.7,2.2-4.1,2.3-4.6,2.3Z"/>
53
49
  <path d="M8.7,10.9c-.9,0-1.6-.7-1.6-1.6s.7-1.6,1.6-1.6,1.6.7,1.6,1.6-.7,1.6-1.6,1.6Z"/>
54
50
  <path d="M15.5,10.9c-.9,0-1.6-.7-1.6-1.6s.7-1.6,1.6-1.6,1.6.7,1.6,1.6-.7,1.6-1.6,1.6Z"/>
51
+ <title id="altIconTitle">{{ translationMap?.get('EMOJI') }}</title>
55
52
 
56
53
  <!-- <path d="M0,0H20.57V20.57H0V0Z" fill="none"/>
57
54
  <circle cx="15.02" cy="9.86" r="1.29"/>
@@ -65,7 +62,7 @@
65
62
 
66
63
 
67
64
 
68
- <div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji || showAlertUrl" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
65
+ <div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
69
66
  <!-- isFilePendingToUpload || -->
70
67
  <textarea
71
68
  [attr.disabled] = "(hideTextReply)? true : null"
@@ -88,7 +85,7 @@
88
85
  </div>
89
86
 
90
87
  <!-- ICON SEND -->
91
- <div *ngIf="(textInputTextArea !== '' && !isStopRec) || !showAudioRecorderFooterButton" tabindex="-1" class="chat21-textarea-button" [class.disabled]="showAlertEmoji || showAlertUrl" [class.active]="textInputTextArea && !hideTextReply" id="chat21-button-send" (click)="onSendPressed($event)">
88
+ <div *ngIf="(textInputTextArea !== '' && !isStopRec) || !showAudioRecorderFooterButton" tabindex="-1" class="chat21-textarea-button" [class.disabled]="showAlertEmoji" [class.active]="textInputTextArea && !hideTextReply" id="chat21-button-send" (click)="onSendPressed($event)">
92
89
  <span class="v-align-center">
93
90
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="24" width="24" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve" fill="currentColor">
94
91
  <path d="M1.8,20.6V3.4l20.2,8.6L1.8,20.6ZM3.9,17.3l12.6-5.4L3.9,6.6v3.7l6.4,1.6-6.4,1.6v3.8ZM3.9,17.3V6.6v10.7Z"/>
@@ -418,3 +418,28 @@ textarea:active{
418
418
  border: none;
419
419
  // margin: -2px -2px 0px;
420
420
  }
421
+
422
+
423
+ // aggiungi un'animazione di fade in e fade out quando .star-rating-widget è visibile con transition
424
+ .star-rating-widget {
425
+ transition: all 0.5s ease-in-out;
426
+ }
427
+
428
+ .star-rating-widget {
429
+ position: absolute;
430
+ left: 0;
431
+ right: 0;
432
+ bottom: -52px;
433
+ height: 100%;
434
+ width: 100%;
435
+ flex-direction: row;
436
+ justify-content: center;
437
+ background-color: rgb(255, 255, 255);
438
+ flex-wrap: nowrap;
439
+ &.active {
440
+ bottom: 0px;
441
+ }
442
+ &.inactive {
443
+ bottom: -52px;
444
+ }
445
+ }
@@ -1,4 +1,6 @@
1
1
  import { Component, ComponentFactoryResolver, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core';
2
+ import { error } from 'console';
3
+ import { FILE_SIZE_LIMIT } from 'src/app/utils/constants';
2
4
  import { Globals } from 'src/app/utils/globals';
3
5
  import { checkAcceptedFile } from 'src/app/utils/utils';
4
6
  import { MessageModel } from 'src/chat21-core/models/message';
@@ -82,7 +84,11 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
82
84
  }
83
85
 
84
86
  showAlertEmoji: boolean = false
85
- showAlertUrl: boolean = false;
87
+
88
+ file_size_limit = FILE_SIZE_LIMIT;
89
+ attachmentTooltip: string = '';
90
+ isErrorNetwork: boolean = false;
91
+
86
92
 
87
93
  convertColorToRGBA = convertColorToRGBA;
88
94
  private logger: LoggerService = LoggerInstance.getInstance()
@@ -91,8 +97,10 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
91
97
  private uploadService: UploadService) { }
92
98
 
93
99
  ngOnInit() {
100
+ // this.updateAttachmentTooltip();
94
101
  }
95
102
 
103
+
96
104
  ngOnChanges(changes: SimpleChanges){
97
105
  if(changes['conversationWith'] && changes['conversationWith'].currentValue !== undefined){
98
106
  this.conversationHandlerService = this.chatManager.getConversationHandlerByConversationId(this.conversationWith);
@@ -105,6 +113,10 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
105
113
  this.onDrop(this.dropEvent)
106
114
  }
107
115
 
116
+ // if(changes['translationMap'] && changes['translationMap'].currentValue !== undefined){
117
+ // this.updateAttachmentTooltip();
118
+ // }
119
+
108
120
  }
109
121
 
110
122
  ngAfterViewInit() {
@@ -112,8 +124,25 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
112
124
  // setTimeout(() => {
113
125
  this.showEmojiPicker = true
114
126
  // }, 500);
127
+ // this.updateAttachmentTooltip();
115
128
  }
116
129
 
130
+
131
+ // updateAttachmentTooltip() {
132
+ // // Use setTimeout to wait for the async translation map to be populated
133
+ // setTimeout(() => {
134
+ // this.logger.log('[CONV-FOOTER] updateAttachmentTooltip - translationMap:', this.translationMap);
135
+ // if (this.translationMap && this.translationMap.has('MAX_ATTACHMENT')) {
136
+ // const template = this.translationMap.get('MAX_ATTACHMENT');
137
+ // this.logger.log('[CONV-FOOTER] MAX_ATTACHMENT template:', template);
138
+ // // this.attachmentTooltip = template.replace('{{file_size_limit}}', this.file_size_limit.toString());
139
+ // this.logger.log('[CONV-FOOTER] attachmentTooltip:', this.attachmentTooltip);
140
+ // } else {
141
+ // this.logger.log('[CONV-FOOTER] MAX_ATTACHMENT not found in translationMap');
142
+ // }
143
+ // }, 500);
144
+ // }
145
+
117
146
  // ========= begin:: functions send image ======= //
118
147
  // START LOAD IMAGE //
119
148
  /** load the selected image locally and open the pop up preview */
@@ -202,7 +231,12 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
202
231
  const fileXLoad = this.arrayFilesLoad[0].file;
203
232
  const uid = this.arrayFilesLoad[0].uid;
204
233
  const type = this.arrayFilesLoad[0].type;
205
- const size = this.arrayFilesLoad[0].size
234
+ const size = this.arrayFilesLoad[0].size;
235
+ if(size > this.file_size_limit * 1024 * 1024){
236
+ this.logger.error('[CONV-FOOTER] file size is greater than the limit: ', size, this.file_size_limit * 1024 * 1024);
237
+ this.showErrorNetwork();
238
+ return;
239
+ }
206
240
  this.logger.log('[CONV-FOOTER] that.fileXLoad: ', type);
207
241
  let metadata;
208
242
  if (type.startsWith('image') && !type.includes('svg')) {
@@ -239,6 +273,17 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
239
273
  }
240
274
 
241
275
 
276
+ private showErrorNetwork() {
277
+ // posso anche passare solo keyMessage, nel caso non voglio passare un messaggio custom posso passare message e params(se il messaggio possiede dei parametri),
278
+ //window.dispatchEvent(new CustomEvent('tooltipErrorMessage', { detail: { error: true, message: 'File size is greater than the limit {{file_size_limit}}', keyMessage: null, params: { file_size_limit: this.file_size_limit } } }));
279
+ window.dispatchEvent(new CustomEvent('tooltipErrorMessage', { detail: { error: true, keyMessage: 'MAX_ATTACHMENT' } }));
280
+ setTimeout(() => {
281
+ this.isFilePendingToUpload = false;
282
+ this.hideTextReply = false;
283
+ window.dispatchEvent(new CustomEvent('tooltipErrorMessage', { detail: { error: false, message: '', keyMessage: null } }));
284
+ }, 5000);
285
+ }
286
+
242
287
  uploadSingle(metadata, file, messageText?: string) {
243
288
  const that = this;
244
289
  try {
@@ -319,14 +364,14 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
319
364
  * @param additional_attributes
320
365
  */
321
366
  sendMessage(msg: string, type: string, metadata?: any, additional_attributes?: any) { // sponziello
367
+
322
368
  (metadata) ? metadata = metadata : metadata = '';
323
369
  this.onEmojiiPickerShow.emit(false)
324
370
  this.logger.log('[CONV-FOOTER] SEND MESSAGE: ', msg, type, metadata, additional_attributes);
325
371
 
326
-
327
- let checkUrlDomain = this.checkForUrlDomain(this.textInputTextArea)
328
- if(!checkUrlDomain){
329
- return
372
+ let check = this.checkForEmojii(this.textInputTextArea)
373
+ if(!check){
374
+ return;
330
375
  }
331
376
 
332
377
  if (msg && msg.trim() !== '' || type === TYPE_MSG_IMAGE || type === TYPE_MSG_FILE ) {
@@ -536,22 +581,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
536
581
  this.showAlertEmoji = false;
537
582
  return true
538
583
  }
539
-
540
- checkForUrlDomain(text){
541
- if(this.project && this.project.settings?.allowed_urls === true && this.project.settings?.allowed_urls_list){
542
- this.showAlertUrl = !isAllowedUrlInText(text, this.project.settings?.allowed_urls_list);
543
- if(this.showAlertUrl){
544
- return false
545
- }
546
- this.showAlertUrl = false
547
- return true
548
- }
549
- this.showAlertUrl = false
550
- return true
551
-
552
-
553
- }
554
-
555
584
 
556
585
 
557
586
  onTextAreaChange(){
@@ -560,7 +589,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
560
589
 
561
590
  //reset alert to defalt values before checking again
562
591
  this.showAlertEmoji= false;
563
- this.showAlertUrl = false;
564
592
  let check = this.checkForEmojii(this.textInputTextArea)
565
593
  if(!check){
566
594
  return;
@@ -570,6 +598,9 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
570
598
  onSendPressed(event) {
571
599
  this.logger.log('[CONV-FOOTER] onSendPressed:event', event);
572
600
  event.preventDefault();
601
+ if(this.showAlertEmoji){
602
+ return;
603
+ }
573
604
  this.logger.log('[CONV-FOOTER] AppComponent::onSendPressed::isFilePendingToUpload:', this.isFilePendingToUpload);
574
605
  if (this.isFilePendingToUpload) {
575
606
  this.logger.log('[CONV-FOOTER] AppComponent::onSendPressed', 'is a file');
@@ -697,6 +728,9 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
697
728
  const keyCode = event.which || event.keyCode;
698
729
  this.textInputTextArea = ((document.getElementById('chat21-main-message-context') as HTMLInputElement).value);
699
730
  if (keyCode === 13) { // ENTER pressed
731
+ if(this.showAlertEmoji){
732
+ return;
733
+ }
700
734
  if (this.textInputTextArea && this.textInputTextArea.trim() !== '') {
701
735
  // that.logger.log('[CONV-FOOTER] sendMessage -> ', this.textInputTextArea);
702
736
  // this.resizeInputField();
@@ -3,6 +3,8 @@
3
3
  <path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/>
4
4
  </svg>
5
5
  <div class="alert-content">
6
- {{ translationMap.get('CONNECTION_NETWORK_ERROR')}}
6
+ {{ errorMessage }}
7
7
  </div>
8
- </div>
8
+ </div>
9
+
10
+
@@ -28,4 +28,6 @@ span.material-icons-outlined{
28
28
  font-size: 11px;
29
29
  line-height: 18px;
30
30
  /* // letter-spacing: -0.01em; */
31
- }
31
+ }
32
+
33
+
@@ -1,18 +1,18 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
2
 
3
- import { NetworkOfflineComponent } from './network-offline.component';
3
+ import { ErrorAlertComponent } from './error-alert.component';
4
4
 
5
- describe('NetworkOfflineComponent', () => {
6
- let component: NetworkOfflineComponent;
7
- let fixture: ComponentFixture<NetworkOfflineComponent>;
5
+ describe('ErrorAlertComponent', () => {
6
+ let component: ErrorAlertComponent;
7
+ let fixture: ComponentFixture<ErrorAlertComponent>;
8
8
 
9
9
  beforeEach(async () => {
10
10
  await TestBed.configureTestingModule({
11
- declarations: [ NetworkOfflineComponent ]
11
+ declarations: [ ErrorAlertComponent ]
12
12
  })
13
13
  .compileComponents();
14
14
 
15
- fixture = TestBed.createComponent(NetworkOfflineComponent);
15
+ fixture = TestBed.createComponent(ErrorAlertComponent);
16
16
  component = fixture.componentInstance;
17
17
  fixture.detectChanges();
18
18
  });
@@ -21,3 +21,5 @@ describe('NetworkOfflineComponent', () => {
21
21
  expect(component).toBeTruthy();
22
22
  });
23
23
  });
24
+
25
+
@@ -0,0 +1,47 @@
1
+ import { Component, Input, OnInit } from '@angular/core';
2
+ import { CustomTranslateService } from 'src/chat21-core/providers/custom-translate.service';
3
+ import * as CONSTANTS from 'src/app/utils/constants';
4
+
5
+ @Component({
6
+ selector: 'chat-error-alert',
7
+ templateUrl: './error-alert.component.html',
8
+ styleUrls: ['./error-alert.component.scss']
9
+ })
10
+ export class ErrorAlertComponent implements OnInit {
11
+
12
+ @Input() errorMessage: string = '';
13
+ @Input() errorKeyMessage: string = '';
14
+ @Input() errorParams: Record<string, any> = {};
15
+
16
+ translationMap: Map<string, string>;
17
+
18
+ constructor(
19
+ private customTranslateService: CustomTranslateService,
20
+ ){}
21
+
22
+ ngOnInit(): void {
23
+ let rawMessage: string = '';
24
+ // Combina costanti globali + parametri passati come input
25
+ const replacements = { ...CONSTANTS, ...this.errorParams };
26
+ if (this.errorKeyMessage) {
27
+ // Traduci il messaggio e sostituisci i placeholder
28
+ rawMessage = this.customTranslateService
29
+ .translateLanguage([this.errorKeyMessage])
30
+ .get(this.errorKeyMessage);
31
+ } else if (this.errorMessage) {
32
+ rawMessage = this.errorMessage;
33
+ }
34
+ this.errorMessage = this.interpolate(rawMessage, replacements);
35
+ }
36
+
37
+ /** Sostituisce {{placeholders}} con i valori corrispondenti */
38
+ private interpolate(template: string, variables: Record<string, any>): string {
39
+ return template.replace(/\{\{(.*?)\}\}/g, (_, key) => {
40
+ const trimmedKey = key.trim();
41
+ return variables[trimmedKey] ?? `{{${trimmedKey}}}`;
42
+ });
43
+ }
44
+
45
+ }
46
+
47
+
@@ -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
  }
@@ -1,15 +1,15 @@
1
1
  :host {
2
2
  --backgroundColor: #{var(--blue)};
3
- --textColor: #{var(--bck-msg-sent)};
3
+ --buttonTextColor: #{var(--bck-msg-sent)};
4
4
  --hoverBackgroundColor: #{var(--bck-msg-sent)};
5
5
  --hoverTextColor: #{var(--blue)};
6
- --buttonFontSize2: #{var(--button-font-size)};
6
+ --buttonFontSize: #{var(--button-font-size)};
7
7
  --max-width: #{var(--button-in-msg-max-width)};
8
8
  --padding: #{var(--button-in-msg-padding)};
9
9
  --font-family: #{var(--button-in-msg-font-family)};
10
10
  --buttonBorderColor: #{var(--button-border-color)};
11
11
  --buttonColor: #{var(--button-color)};
12
- --buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
12
+ --buttonBackgroundColor: #{var(--button-background-color)};
13
13
  }
14
14
 
15
15
  .button-in-msg {
@@ -20,8 +20,8 @@
20
20
  border: 1px solid var(--buttonBorderColor);
21
21
  background: var(--buttonBackgroundColor);
22
22
  font-family: var(--font-family);
23
- font-size: var(--buttonFontSize2);
24
- color: var(--textColor);
23
+ font-size: var(--buttonFontSize);
24
+ color: var(--buttonTextColor);
25
25
  overflow: hidden;
26
26
  -o-text-overflow: ellipsis;
27
27
  text-overflow: ellipsis;
@@ -38,7 +38,7 @@
38
38
  }
39
39
 
40
40
  .action {
41
- background: var(--backgroundColor);
41
+ // background: var(--backgroundColor);
42
42
  transition: background-color .6s ease;
43
43
  &:focus,
44
44
  &:hover {
@@ -25,7 +25,7 @@ export class ActionButtonComponent implements OnInit {
25
25
  ngOnChanges(changes: SimpleChanges){
26
26
  //decomment if element should have same color of themeColor and fregroundColor
27
27
  if(this.fontSize) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--buttonFontSize', this.fontSize);
28
- if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--backgroundColor', this.backgroundColor);
28
+ if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--buttonBackgroundColor', this.backgroundColor);
29
29
  if(this.textColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--textColor', this.textColor);
30
30
  if(this.hoverBackgroundColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--hoverBackgroundColor', this.hoverBackgroundColor);
31
31
  if(this.hoverTextColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--hoverTextColor', this.hoverTextColor);
@@ -1,15 +1,15 @@
1
1
  :host {
2
2
  --backgroundColor: #{var(--blue)};
3
- --textColor: #{var(--bck-msg-sent)};
3
+ --buttonTextColor: #{var(--bck-msg-sent)};
4
4
  --hoverBackgroundColor: #{var(--bck-msg-sent)};
5
5
  --hoverTextColor: #{var(--blue)};
6
- --buttonFontSize2: #{var(--button-font-size)};
6
+ --buttonFontSize: #{var(--button-font-size)};
7
7
  --max-width: #{var(--button-in-msg-max-width)};
8
8
  --padding: #{var(--button-in-msg-padding)};
9
9
  --font-family: #{var(--button-in-msg-font-family)};
10
10
  --buttonBorderColor: #{var(--button-border-color)};
11
11
  --buttonColor: #{var(--button-color)};
12
- --buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
12
+ --buttonBackgroundColor: #{var(--button-background-color)};
13
13
  }
14
14
 
15
15
 
@@ -21,8 +21,8 @@
21
21
  border: 1px solid var(--buttonBorderColor);
22
22
  background: var(--buttonBackgroundColor);
23
23
  font-family: var(--font-family);
24
- font-size: var(--buttonFontSize2);
25
- color: var(--textColor);
24
+ font-size: var(--buttonFontSize);
25
+ color: var(--buttonTextColor);
26
26
  overflow: hidden;
27
27
  -o-text-overflow: ellipsis;
28
28
  text-overflow: ellipsis;
@@ -23,8 +23,8 @@ export class LinkButtonComponent implements OnInit {
23
23
  ngOnChanges(changes: SimpleChanges){
24
24
  //decomment if element should have same color of themeColor and fregroundColor
25
25
  if(this.fontSize) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--buttonFontSize', this.fontSize);
26
- if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--backgroundColor', this.backgroundColor);
27
- if(this.textColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--textColor', this.textColor);
26
+ if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--buttonBackgroundColor', this.backgroundColor);
27
+ if(this.textColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--buttonTextColor', this.textColor);
28
28
  if(this.hoverBackgroundColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--hoverBackgroundColor', this.hoverBackgroundColor);
29
29
  if(this.hoverTextColor) this.elementRef.nativeElement.querySelector('.url').style.setProperty('--hoverTextColor', this.hoverTextColor);
30
30
  }
@@ -1,15 +1,14 @@
1
1
  :host {
2
2
  --backgroundColor: #{var(--blue)};
3
- --textColor: #{var(--bck-msg-sent)};
4
- --hoverBackgroundColor: #{var(--bck-msg-sent)};
5
- --hoverTextColor: #{var(--blue)};
6
- --buttonFontSize2: #{var(--button-font-size)};
3
+ --buttonTextColor: #{var(--bck-msg-sent)};
4
+ --buttonHoverBackgroundColor: #{var(--bck-msg-sent)};
5
+ --buttonHoverTextColor: #{var(--blue)};
6
+ --buttonFontSize: #{var(--button-font-size)};
7
7
  --max-width: #{var(--button-in-msg-max-width)};
8
8
  --padding: #{var(--button-in-msg-padding)};
9
9
  --font-family: #{var(--button-in-msg-font-family)};
10
10
  --buttonBorderColor: #{var(--button-border-color)};
11
- // --buttonColor: #{var(--buttonColor)};
12
- --buttonBackgroundColor: #ffffff; //#{var(--button-background-color)};
11
+ --buttonBackgroundColor: #{var(--button-background-color)};
13
12
  --buttonColor: #{var(--button-color)};
14
13
  }
15
14
 
@@ -21,11 +20,9 @@
21
20
  cursor: pointer;
22
21
  border: 1px solid var(--buttonBorderColor);
23
22
  background: var(--buttonBackgroundColor);
24
- // background: var(--backgroundColor);
25
23
  font-family: var(--font-family);
26
- font-size: var(--buttonFontSize2);
27
- // color: var(--buttonColor);
28
- color: var(--textColor);
24
+ font-size: var(--buttonFontSize);
25
+ color: var(--buttonTextColor);
29
26
  overflow: hidden;
30
27
  -o-text-overflow: ellipsis;
31
28
  text-overflow: ellipsis;
@@ -47,8 +44,8 @@
47
44
  transition: background-color .6s ease;
48
45
  &:focus,
49
46
  &:hover {
50
- color: var(--hoverTextColor);
51
- background: var(--hoverBackgroundColor);
47
+ color: var(--buttonHoverTextColor);
48
+ background: var(--buttonHoverBackgroundColor);
52
49
  // transform: scale(1.05);
53
50
  .icon-button-action {
54
51
  svg {
@@ -26,10 +26,10 @@ export class TextButtonComponent implements OnInit {
26
26
  ngOnChanges(changes: SimpleChanges){
27
27
  //decomment if element should have same color of themeColor and fregroundColor
28
28
  if(this.fontSize) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--buttonFontSize', this.fontSize);
29
- if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--backgroundColor', this.backgroundColor);
30
- if(this.textColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--textColor', this.textColor);
31
- if(this.hoverBackgroundColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--hoverBackgroundColor', this.hoverBackgroundColor);
32
- if(this.hoverTextColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--hoverTextColor', this.hoverTextColor);
29
+ if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--buttonBackgroundColor', this.backgroundColor);
30
+ if(this.textColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--buttonTextColor', this.textColor);
31
+ if(this.hoverBackgroundColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--buttonHoverBackgroundColor', this.hoverBackgroundColor);
32
+ if(this.hoverTextColor) this.elementRef.nativeElement.querySelector('.text').style.setProperty('--buttonHoverTextColor', this.hoverTextColor);
33
33
  }
34
34
 
35
35
  onMouseOver(event){
@@ -3,15 +3,11 @@
3
3
 
4
4
  <span *ngFor="let button of buttons | slice:0:limit" class="div-button">
5
5
 
6
- <!--
7
- // bubbleReceivedBackground
8
- // buttonBackgroundColor
9
- -->
10
6
  <chat-text-button-attachment *ngIf="button.type === 'text' && isLastMessage === true" class="div-button"
11
7
  [button]="button"
12
8
  [isConversationArchived]="isConversationArchived"
13
9
  [fontSize]="stylesMap.get('buttonFontSize')"
14
- [backgroundColor]="stylesMap.get('bubbleReceivedBackground')"
10
+ [backgroundColor]="stylesMap.get('buttonBackgroundColor')"
15
11
  [textColor]="stylesMap.get('buttonTextColor')"
16
12
  [hoverBackgroundColor]="stylesMap.get('buttonHoverBackgroundColor')"
17
13
  [hoverTextColor]="stylesMap.get('buttonHoverTextColor')"
@@ -21,7 +17,7 @@
21
17
  <chat-link-button-attachment *ngIf="button.type === 'url'" class="div-button"
22
18
  [button]="button"
23
19
  [fontSize]="stylesMap.get('buttonFontSize')"
24
- [backgroundColor]="stylesMap.get('bubbleReceivedBackground')"
20
+ [backgroundColor]="stylesMap.get('buttonBackgroundColor')"
25
21
  [textColor]="stylesMap.get('buttonTextColor')"
26
22
  [hoverBackgroundColor]="stylesMap.get('buttonHoverBackgroundColor')"
27
23
  [hoverTextColor]="stylesMap.get('buttonHoverTextColor')"
@@ -32,7 +28,7 @@
32
28
  [button]="button"
33
29
  [isConversationArchived]="isConversationArchived"
34
30
  [fontSize]="stylesMap.get('buttonFontSize')"
35
- [backgroundColor]="stylesMap.get('bubbleReceivedBackground')"
31
+ [backgroundColor]="stylesMap.get('buttonBackgroundColor')"
36
32
  [textColor]="stylesMap.get('buttonTextColor')"
37
33
  [hoverBackgroundColor]="stylesMap.get('buttonHoverBackgroundColor')"
38
34
  [hoverTextColor]="stylesMap.get('buttonHoverTextColor')"
@@ -1936,7 +1936,7 @@ export class GlobalSettingsService {
1936
1936
  if (this.globals.departmentID) {
1937
1937
  this.globals.departments.forEach(department => {
1938
1938
  if (department._id === this.globals.departmentID) {
1939
- this.logger.debug('[GLOBAL-SET] setDepartmentFromExternal > EXTERNAL DEPARTMENT ::::' + department._id);
1939
+ console.log('[GLOBAL-SET] setDepartmentFromExternal > EXTERNAL DEPARTMENT ::::' + department._id);
1940
1940
  this.globals.setParameter('departmentDefault', department);
1941
1941
  this.setDepartment(department);
1942
1942
  isValidID = true;
@@ -1964,7 +1964,7 @@ export class GlobalSettingsService {
1964
1964
  * save attributes in this.appStorageService
1965
1965
  */
1966
1966
  setDepartment(department) {
1967
- this.logger.debug('[GLOBAL-SET] setDepartment: ', JSON.stringify(department));
1967
+ this.logger.log('[GLOBAL-SET] setDepartment: ', JSON.stringify(department));
1968
1968
  this.globals.setParameter('departmentSelected', department);
1969
1969
  // let attributes = this.globals.attributes;
1970
1970
  let attributes: any = JSON.parse(this.appStorageService.getItem('attributes'));
@@ -1983,7 +1983,7 @@ export class GlobalSettingsService {
1983
1983
  this.logger.debug('[GLOBAL-SET] setDepartment > setAttributes: ', JSON.stringify(attributes));
1984
1984
  this.globals.setParameter('departmentSelected', department);
1985
1985
  this.globals.setParameter('attributes', attributes);
1986
- // this.appStorageService.setItem('attributes', JSON.stringify(attributes));
1986
+ this.appStorageService.setItem('attributes', JSON.stringify(attributes));
1987
1987
 
1988
1988
  }
1989
1989
  // ========= end:: GET DEPARTEMENTS ============//
@@ -99,7 +99,7 @@ export class TranslatorService {
99
99
 
100
100
  // https://github.com/ngx-translate/core/issues/282
101
101
  initI18n(): Promise<any> {
102
- this._translate.addLangs(['en', 'it']);
102
+ this._translate.addLangs(['en', 'it', 'es', 'fr']);
103
103
  this.logger.debug('[TRANSLATOR-SERV]»»»» initI18n getLangs ', this._translate.getLangs());
104
104
 
105
105
  // Set the default language for translation strings.
@@ -261,7 +261,10 @@ export class TranslatorService {
261
261
  'WAITING_TIME_FOUND',
262
262
  'WAITING_TIME_NOT_FOUND',
263
263
  'CLOSED',
264
- 'LABEL_PREVIEW'
264
+ 'LABEL_PREVIEW',
265
+ 'MAX_ATTACHMENT',
266
+ 'MAX_ATTACHMENT_ERROR',
267
+ 'EMOJI'
265
268
  ];
266
269
 
267
270
 
@@ -316,6 +319,9 @@ export class TranslatorService {
316
319
  globals.CLOSED = res['CLOSED'];
317
320
  globals.LABEL_PREVIEW = res['LABEL_PREVIEW']
318
321
  globals.LABEL_ERROR_FIELD_REQUIRED= res['LABEL_ERROR_FIELD_REQUIRED']
322
+ globals.MAX_ATTACHMENT = res['MAX_ATTACHMENT']
323
+ globals.MAX_ATTACHMENT_ERROR = res['MAX_ATTACHMENT_ERROR']
324
+ globals.EMOJI = res['EMOJI']
319
325
 
320
326
 
321
327
  if(globals.WELCOME_TITLE === 'WELLCOME_TITLE') globals.WELCOME_TITLE = res['WELCOME_TITLE']