@chat21/chat21-web-widget 5.1.32-rc3 → 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 +6 -41
  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 +2 -2
  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 +1 -6
  14. package/src/app/component/conversation-detail/conversation/conversation.component.scss +2 -2
  15. package/src/app/component/conversation-detail/conversation/conversation.component.ts +5 -34
  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 -1
  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 -131
  21. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +7 -108
  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 -1
  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 -264
  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
@@ -12,164 +12,97 @@
12
12
  <div tabindex="-1" class="alertText">{{translationMap.get('EMOJI_NOT_ELLOWED')}}</div>
13
13
  </div>
14
14
 
15
- <!-- STREAM AUDIO: cerchio con onde animate -->
16
- <div id="streamAudioAlert" *ngIf="!hideTextAreaContent && isStreamAudioActive" class="fade-in-bottom stream-audio-alert" [class.hideTextReply]="hideTextReply" role="status" [attr.aria-label]="translationMap?.get('STREAM_AUDIO_LISTENING') || 'Stream audio attivo'">
17
- <div class="stream-audio-alert__orb" [ngStyle]="{ color: stylesMap?.get('themeColor') }">
18
- <svg class="stream-audio-alert__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
19
- <circle cx="50" cy="50" r="46" fill="currentColor" opacity="0.14"/>
20
- <g class="stream-audio-alert__waves" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
21
- <g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--1">
22
- <path [attr.d]="wavePath1"></path>
23
- </g>
24
-
25
- <g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--2">
26
- <path [attr.d]="wavePath2"></path>
27
- </g>
28
-
29
- <g class="stream-audio-alert__wave-layer stream-audio-alert__wave-layer--3">
30
- <path [attr.d]="wavePath3"></path>
31
- </g>
32
- </g>
33
- </svg>
34
- </div>
35
- </div>
36
-
37
15
  </div>
38
16
 
39
- <div class="textarea-container-wrapper" *ngIf="!hideTextAreaContent && !hideTextReply">
40
- <!-- TEXTAREA + ICONS: conv active-->
41
- <div class="textarea-container">
42
-
43
- <div *ngIf="!isStopRec" class="icons-container">
44
- <!-- ICON ATTACHMENT -->
45
- <label *ngIf="showAttachmentFooterButton" tabindex="1502" aria-label="allegati" for="chat21-file" class="chat21-textarea-button" [class.active]="!isFilePendingToUpload && !hideTextReply" id="chat21-start-upload-doc">
46
- <span class="v-align-center">
47
- <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" width="24px" height="24" viewBox="0 0 24 24" fill="currentColor">
48
- <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"/>
49
- <title id="altIconTitle">{{ 'MAX_ATTACHMENT' | translate: { FILE_SIZE_LIMIT: file_size_limit } }}</title>
50
- </svg>
51
-
52
- </span>
53
- <input
54
- [attr.disabled] = "(isFilePendingToUpload || isConversationArchived || hideTextReply)? true : null"
55
- tabindex="1503"
56
- type="file"
57
- aria-label="seleziona allegato"
58
- [accept]="fileUploadAccept"
59
- name="chat21-file"
60
- id="chat21-file"
61
- #chat21_file
62
- class="inputfile"
63
- [ngStyle]="{'display': 'block', height:'1px', width:'1px', overflow: 'hidden' }"
64
- (change)="detectFiles($event)"/>
65
- </label>
66
- <!-- ICON EMOJII -->
67
- <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()">
68
- <span class="v-align-center">
69
- <svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
70
- <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"/>
71
- <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"/>
72
- <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"/>
73
- <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"/>
74
- <title id="altIconTitle">{{ translationMap?.get('EMOJI') }}</title>
75
-
76
- <!-- <path d="M0,0H20.57V20.57H0V0Z" fill="none"/>
77
- <circle cx="15.02" cy="9.86" r="1.29"/>
78
- <circle cx="9.02" cy="9.86" r="1.29"/>
79
- <path d="M12.02,15.43c-1.27,0-2.36-.69-2.96-1.71h-1.43c.69,1.76,2.39,3,4.39,3s3.7-1.24,4.39-3h-1.43c-.6,1.02-1.69,1.71-2.96,1.71Zm0-12C7.28,3.43,3.45,7.27,3.45,12s3.83,8.57,8.56,8.57,8.58-3.84,8.58-8.57S16.75,3.43,12.01,3.43Zm0,15.43c-3.79,0-6.86-3.07-6.86-6.86s3.07-6.86,6.86-6.86,6.86,3.07,6.86,6.86-3.07,6.86-6.86,6.86Z"/> -->
80
- </svg>
81
- </span>
82
- </label>
83
- </div>
84
-
85
-
86
-
87
-
88
- <div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
89
- <!-- isFilePendingToUpload || -->
90
- <textarea
91
- [attr.disabled] = "(hideTextReply)? true : null"
92
- [attr.placeholder] ="(footerMessagePlaceholder)? footerMessagePlaceholder : translationMap?.get('LABEL_PLACEHOLDER')"
93
- start-focus-chat21-conversation-component
94
- inputTextArea
95
- #textbox
96
- tabindex="1501"
97
- aria-labelledby="altTextArea"
98
- rows="1"
99
- id="chat21-main-message-context"
100
- class='f21textarea c21-button-clean'
101
- [(ngModel)]="textInputTextArea"
102
- (ngModelChange)="onTextAreaChange()"
103
- (keypress)="onkeypress($event)"
104
- (keydown)="onkeydown($event)"
105
- (paste)="onPaste($event)">
106
- </textarea>
107
-
108
- </div>
109
-
110
- <!-- ICON SEND -->
111
- <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)">
17
+ <!-- TEXTAREA + ICONS: conv active-->
18
+ <div class="textarea-container" *ngIf="!hideTextAreaContent && !hideTextReply">
19
+
20
+ <div *ngIf="!isStopRec" class="icons-container">
21
+ <!-- ICON ATTACHMENT -->
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">
112
23
  <span class="v-align-center">
113
- <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">
114
- <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"/>
115
- </svg>
116
- </span>
117
- </div>
118
-
119
- <!-- ICON REC -->
120
- <div *ngIf="showAudioRecorderFooterButton && !textInputTextArea" tabindex="-1" class="chat21-audio-button" [class.active]="isStopRec" id="chat21-button-rec">
121
- <chat-audio-recorder
122
- (startRecordingEvent)="onStartRecording()"
123
- (deleteRecordingEvent)="onDeleteRecording()"
124
- (endRecordingEvent)="onEndRecording($event)"
125
- (sendRecordingEvent)="onSendRecording($event)"
126
- [stylesMap]="stylesMap">
127
- </chat-audio-recorder>
128
- </div>
129
-
130
- <!-- ICON STREAM / CHIUDI STREAM (cerchio, icone bianche su iconColor) -->
131
- <div *ngIf="showAudioStreamFooterButton" tabindex="-1" id="chat21-button-stream"
132
- class="chat21-textarea-button chat21-stream-button" [class.active]="isStreamAudioActive || (!textInputTextArea && !hideTextReply)"
133
- (click)="onStreamPressed($event)" [attr.aria-label]="isStreamAudioActive ? (translationMap?.get('CLOSE') || 'Chiudi stream') : (translationMap?.get('STREAM_AUDIO') || 'Stream audio')"
134
- [ngStyle]="{ 'background-color': stylesMap?.get('iconColor') || stylesMap?.get('themeColor') }">
135
- <span class="v-align-center chat21-stream-button__icon" *ngIf="!isStreamAudioActive">
136
- <svg role="img" xmlns="http://www.w3.org/2000/svg" version="1.1" width="24" height="24" viewBox="0 0 30 30" fill="#ffffff" aria-hidden="true" preserveAspectRatio="xMidYMid meet">
137
- <path class="s0" d="m5.21 7.41c-1.21 0-2.21 0.99-2.21 2.21v8.14c0 1.21 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-8.14c0-1.21-0.99-2.21-2.21-2.21z"/>
138
- <path class="s0" d="m11.64 3.01c-1.22 0-2.21 0.99-2.21 2.2v16.94c0 1.21 0.99 2.2 2.21 2.2 1.22 0 2.21-0.98 2.21-2.2v-16.94c0-1.21-0.99-2.21-2.21-2.21z"/>
139
- <path class="s0" d="m15.86 9.25v8.88c0 1.21 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-8.88c0-1.22-0.99-2.21-2.21-2.21-1.22 0-2.21 0.99-2.21 2.21z"/>
140
- <path class="s0" d="m24.5 8.97c-1.22 0-2.21 0.99-2.21 2.21v5.02c0 1.22 0.99 2.21 2.21 2.21 1.22 0 2.21-0.99 2.21-2.21v-5.02c0-1.21-0.99-2.21-2.21-2.21z"/>
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">
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>
141
27
  </svg>
28
+
142
29
  </span>
143
- <span class="v-align-center chat21-stream-button__icon" *ngIf="isStreamAudioActive">
144
- <svg role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ffffff" aria-hidden="true">
145
- <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/>
30
+ <input
31
+ [attr.disabled] = "(isFilePendingToUpload || isConversationArchived || hideTextReply)? true : null"
32
+ tabindex="1503"
33
+ type="file"
34
+ aria-label="seleziona allegato"
35
+ [accept]="fileUploadAccept"
36
+ name="chat21-file"
37
+ id="chat21-file"
38
+ #chat21_file
39
+ class="inputfile"
40
+ [ngStyle]="{'display': 'block', height:'1px', width:'1px', overflow: 'hidden' }"
41
+ (change)="detectFiles($event)"/>
42
+ </label>
43
+ <!-- ICON EMOJII -->
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()">
45
+ <span class="v-align-center">
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">
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"/>
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"/>
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"/>
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>
52
+
53
+ <!-- <path d="M0,0H20.57V20.57H0V0Z" fill="none"/>
54
+ <circle cx="15.02" cy="9.86" r="1.29"/>
55
+ <circle cx="9.02" cy="9.86" r="1.29"/>
56
+ <path d="M12.02,15.43c-1.27,0-2.36-.69-2.96-1.71h-1.43c.69,1.76,2.39,3,4.39,3s3.7-1.24,4.39-3h-1.43c-.6,1.02-1.69,1.71-2.96,1.71Zm0-12C7.28,3.43,3.45,7.27,3.45,12s3.83,8.57,8.56,8.57,8.58-3.84,8.58-8.57S16.75,3.43,12.01,3.43Zm0,15.43c-3.79,0-6.86-3.07-6.86-6.86s3.07-6.86,6.86-6.86,6.86,3.07,6.86,6.86-3.07,6.86-6.86,6.86Z"/> -->
146
57
  </svg>
147
58
  </span>
148
- </div>
59
+ </label>
149
60
  </div>
150
61
 
151
62
 
152
- <div class="close-chat-container" *ngIf="closeChatInConversation">
153
- <button tabindex="1040" aflistconv #aflistconv class="c21-button-primary c21-close" (click)="onCloseChat($event)" [ngStyle]="{'background-color': stylesMap.get('themeColor'), 'border-color': stylesMap.get('themeColor'), 'color': stylesMap?.get('foregroundColor')}">
154
- <span class="v-align-center">
155
- <!-- <svg [ngStyle]="{'fill': 'yellow' }" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
156
- <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}"/>
157
- </svg> -->
158
- <svg [ngStyle]="{'stroke': stylesMap?.get('foregroundColor'), 'fill': stylesMap?.get('foregroundColor') }" role="img" id="archive" aria-labelledby="altIconTitle" class="icon-menu" xmlns="http://www.w3.org/2000/svg"
159
- width="15px" height="15px" viewBox="0 0 512 512">
160
- <path d="M80 152v256a40.12 40.12 0 0040 40h272a40.12 40.12 0 0040-40V152" stroke-linecap="round" stroke-linejoin="round" stroke-width="50px" fill="none"></path>
161
- <rect x="48" y="64" width="416" height="80" rx="28" ry="28" stroke-linejoin="round" stroke-width="50px" fill="none" ></rect>
162
- <path stroke-linecap="round" stroke-linejoin="round" d="M320 304l-64 64-64-64M256 345.89V224" stroke-width="50px" fill="none"></path>
163
- <title id="altIconTitle">{{ translationMap?.get('CLOSE_CHAT') }}</title>
164
- </svg>
165
- </span>
166
- <span class="v-align-center c21-label-button">
167
- {{translationMap?.get('CLOSE_CHAT')}}
168
- </span>
169
- <div class="clear"></div>
170
- </button>
63
+
64
+
65
+ <div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
66
+ <!-- isFilePendingToUpload || -->
67
+ <textarea
68
+ [attr.disabled] = "(hideTextReply)? true : null"
69
+ [attr.placeholder] ="(footerMessagePlaceholder)? footerMessagePlaceholder : translationMap?.get('LABEL_PLACEHOLDER')"
70
+ start-focus-chat21-conversation-component
71
+ inputTextArea
72
+ #textbox
73
+ tabindex="1501"
74
+ aria-labelledby="altTextArea"
75
+ rows="1"
76
+ id="chat21-main-message-context"
77
+ class='f21textarea c21-button-clean'
78
+ [(ngModel)]="textInputTextArea"
79
+ (ngModelChange)="onTextAreaChange()"
80
+ (keypress)="onkeypress($event)"
81
+ (keydown)="onkeydown($event)"
82
+ (paste)="onPaste($event)">
83
+ </textarea>
84
+
171
85
  </div>
172
86
 
87
+ <!-- ICON SEND -->
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)">
89
+ <span class="v-align-center">
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">
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"/>
92
+ </svg>
93
+ </span>
94
+ </div>
95
+
96
+ <!-- ICON REC -->
97
+ <div *ngIf="showAudioRecorderFooterButton && !textInputTextArea" tabindex="-1" class="chat21-audio-button" [class.active]="isStopRec" id="chat21-button-rec">
98
+ <chat-audio-recorder
99
+ (startRecordingEvent)="onStartRecording()"
100
+ (deleteRecordingEvent)="onDeleteRecording()"
101
+ (endRecordingEvent)="onEndRecording($event)"
102
+ (sendRecordingEvent)="onSendRecording($event)"
103
+ [stylesMap]="stylesMap">
104
+ </chat-audio-recorder>
105
+ </div>
173
106
  </div>
174
107
 
175
108
 
@@ -1,25 +1,23 @@
1
- .textarea-container-wrapper{
2
- display: flex;
3
- flex-direction: column;
4
- gap: 8px;
5
- }
1
+
6
2
  .textarea-container{
3
+ // padding: 8px 34px;
4
+ // padding-left: 70px;
5
+ // padding-right: 45px;
7
6
  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;
18
11
 
19
- .c21-close{
20
- height: 30px !important;
21
- margin: 0px !important;
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%;
22
15
  }
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
+
23
21
  }
24
22
 
25
23
  .icons-container{
@@ -84,30 +82,6 @@
84
82
  border-radius: 50%;
85
83
  }
86
84
 
87
- /** Stream audio: cerchio pieno, glyph bianco su sfondo iconColor (stylesMap) */
88
- .chat21-stream-button.chat21-textarea-button {
89
- width: 36px;
90
- height: 36px;
91
- min-width: 36px;
92
- border-radius: 50%;
93
- box-sizing: border-box;
94
- flex-shrink: 0;
95
- color: #ffffff;
96
-
97
- .chat21-stream-button__icon svg {
98
- width: 20px;
99
- height: 20px;
100
- path {
101
- fill: #ffffff;
102
- }
103
- }
104
-
105
- &.chat21-textarea-button span svg:hover {
106
- background: rgba(255, 255, 255, 0.2) !important;
107
- border-radius: 50%;
108
- }
109
- }
110
-
111
85
  textarea,
112
86
  textarea:visited,
113
87
  textarea:focus,
@@ -390,73 +364,6 @@ textarea:active{
390
364
  }
391
365
  }
392
366
 
393
- #streamAudioAlert {
394
- bottom: 100%;
395
- width: 100%;
396
- min-height: 96px;
397
- display: flex;
398
- align-items: center;
399
- justify-content: center;
400
- background-color: var(--content-background-color);
401
- position: absolute;
402
- padding: 10px 0;
403
-
404
- &.hideTextReply {
405
- position: unset;
406
- min-height: auto;
407
- padding: 16px 0;
408
- box-shadow: none;
409
- }
410
- }
411
-
412
- .stream-audio-alert__orb {
413
- display: flex;
414
- align-items: center;
415
- justify-content: center;
416
- width: 88px;
417
- height: 88px;
418
- border-radius: 50%;
419
- border: 2px solid currentColor;
420
- background: var(--content-background-color);
421
- box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.04);
422
- }
423
-
424
- .stream-audio-alert__svg {
425
- width: 72px;
426
- height: 72px;
427
- display: block;
428
- }
429
-
430
- .stream-audio-alert__wave-layer {
431
- transform-origin: 50px 50px;
432
- transform-box: fill-box;
433
- animation: stream-wave-float 1.35s ease-in-out infinite;
434
- }
435
-
436
- .stream-audio-alert__wave-layer--1 {
437
- animation-delay: 0s;
438
- }
439
-
440
- .stream-audio-alert__wave-layer--2 {
441
- animation-delay: 0.18s;
442
- }
443
-
444
- .stream-audio-alert__wave-layer--3 {
445
- animation-delay: 0.36s;
446
- }
447
-
448
- @keyframes stream-wave-float {
449
- 0%,
450
- 100% {
451
- transform: translateY(0);
452
- opacity: 0.85;
453
- }
454
- 50% {
455
- transform: translateY(-6px);
456
- opacity: 1;
457
- }
458
- }
459
-
460
367
  #textAlert{
461
368
  bottom: 100%;
462
369
  width: 100%;
@@ -512,28 +419,3 @@ textarea:active{
512
419
  border: none;
513
420
  // margin: -2px -2px 0px;
514
421
  }
515
-
516
-
517
- // aggiungi un'animazione di fade in e fade out quando .star-rating-widget è visibile con transition
518
- .star-rating-widget {
519
- transition: all 0.5s ease-in-out;
520
- }
521
-
522
- .star-rating-widget {
523
- position: absolute;
524
- left: 0;
525
- right: 0;
526
- bottom: -52px;
527
- height: 100%;
528
- width: 100%;
529
- flex-direction: row;
530
- justify-content: center;
531
- background-color: rgb(255, 255, 255);
532
- flex-wrap: nowrap;
533
- &.active {
534
- bottom: 0px;
535
- }
536
- &.inactive {
537
- bottom: -52px;
538
- }
539
- }
@@ -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,59 +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() {
185
- this.voiceAudioSubscription?.unsubscribe();
186
- this.voiceAudioSubscription = undefined;
187
-
188
- this.voiceVolumeSubscription?.unsubscribe();
189
- this.voiceVolumeSubscription = undefined;
190
-
191
- await this.voiceService.stopSession();
192
- }
193
-
194
- updateWave(volume: number) {
195
- const intensity = Math.min(volume / 80, 1); // più sensibile
196
-
197
- const amp1 = 4 + intensity * 22;
198
- const amp2 = 2 + intensity * 16;
199
- const amp3 = 1 + intensity * 12;
200
-
201
- this.wavePath1 = this.buildWave(42, amp1);
202
- this.wavePath2 = this.buildWave(50, amp2);
203
- this.wavePath3 = this.buildWave(58, amp3);
204
- }
205
-
206
- buildWave(y: number, amp: number): string {
207
- return `
208
- M6 ${y}
209
- Q24 ${y - amp} 42 ${y}
210
- T78 ${y}
211
- T98 ${y}
212
- `;
213
- }
214
-
215
- ngOnDestroy() {
216
- void this.stopVoice();
217
- }
218
-
219
145
  // ========= begin:: functions send image ======= //
220
146
  // START LOAD IMAGE //
221
147
  /** load the selected image locally and open the pop up preview */
@@ -595,7 +521,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
595
521
  }
596
522
  }
597
523
 
598
- prepareAndUpload(audioBlob: Blob, text: string = '') {
524
+ prepareAndUpload(audioBlob: Blob) {
599
525
 
600
526
  this.isFilePendingToUpload = true;
601
527
 
@@ -625,7 +551,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
625
551
  this.logger.log('[UPLOAD] metadata:', metadata);
626
552
 
627
553
  // stesso metodo che già usi
628
- this.uploadSingle(metadata, file, text);
554
+ this.uploadSingle(metadata, file, '');
629
555
  }
630
556
 
631
557
  // Funzione per convertire Blob in Base64 usando FileReader
@@ -732,29 +658,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
732
658
  }
733
659
  }
734
660
 
735
- async onStreamPressed(event: Event) {
736
- this.logger.log('[CONV-FOOTER] onStreamPressed:event', event);
737
- event.preventDefault();
738
- if (this.showAlertEmoji) {
739
- return;
740
- }
741
- const turningOn = !this.isStreamAudioActive;
742
- if (turningOn) {
743
- try {
744
- await this.initVoice();
745
- this.isStreamAudioActive = true;
746
- } catch (e) {
747
- this.logger.error('[CONV-FOOTER] onStreamPressed: initVoice failed', e);
748
- this.isStreamAudioActive = false;
749
- }
750
- } else {
751
- await this.stopVoice();
752
- this.isStreamAudioActive = false;
753
- }
754
- this.onStreamAudioActiveChange.emit(this.isStreamAudioActive);
755
- this.logger.log('[CONV-FOOTER] isStreamAudioActive', this.isStreamAudioActive);
756
- }
757
-
758
661
  async onEmojiiPickerClicked(){
759
662
  // if(this.loadPickerModule){
760
663
  // this.loadPickerModule = false;
@@ -806,10 +709,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges, OnDestroy
806
709
  this.onNewConversationButtonClicked.emit();
807
710
  }
808
711
 
809
- onCloseChat(event){
810
- this.onCloseChatButtonClicked.emit();
811
- }
812
-
813
712
  // onContinueConversation(){
814
713
  // this.hideTextAreaContent = false;
815
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)