@chat21/chat21-web-widget 5.1.26 → 5.1.30-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/docker-community-push-latest.yml +23 -13
- package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
- package/CHANGELOG.md +97 -13
- package/Dockerfile +4 -5
- package/angular.json +2 -1
- package/deploy_amazon_beta.sh +17 -7
- package/docs/changelog/badge_Bot_Umano.md +85 -0
- package/docs/changelog/this-branch.md +36 -0
- package/package.json +1 -1
- package/src/app/app.component.html +9 -2
- package/src/app/app.component.scss +59 -0
- package/src/app/app.component.ts +144 -36
- package/src/app/component/conversation-detail/conversation/conversation.component.html +13 -2
- package/src/app/component/conversation-detail/conversation/conversation.component.scss +30 -2
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +85 -5
- package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +16 -3
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +12 -9
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +15 -1
- package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +1 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +103 -80
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +40 -13
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +40 -1
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +3 -3
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.ts +1 -0
- package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.ts +0 -18
- package/src/app/component/home/home.component.html +3 -3
- package/src/app/component/last-message/last-message.component.ts +4 -1
- package/src/app/component/launcher-button/launcher-button.component.html +1 -1
- package/src/app/component/launcher-button/launcher-button.component.ts +3 -2
- package/src/app/providers/global-settings.service.ts +26 -0
- package/src/app/providers/translator.service.ts +2 -0
- package/src/app/sass/_variables.scss +1 -0
- package/src/app/utils/conversation-sender-classifier.ts +116 -0
- package/src/app/utils/globals.ts +33 -5
- package/src/assets/i18n/en.json +2 -0
- package/src/assets/i18n/es.json +2 -0
- package/src/assets/i18n/fr.json +2 -0
- package/src/assets/i18n/it.json +2 -0
- package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
- package/src/chat21-core/utils/utils.ts +5 -2
- package/src/iframe-style.css +5 -5
- package/deploy_amazon_prod.sh +0 -41
|
@@ -38,19 +38,32 @@ export class ConversationAudioRecorderComponent {
|
|
|
38
38
|
this.startTime = Date.now();
|
|
39
39
|
navigator.mediaDevices.getUserMedia({ audio: true })
|
|
40
40
|
.then(stream => {
|
|
41
|
+
|
|
42
|
+
this.audioChunks = [];
|
|
43
|
+
|
|
41
44
|
this.mediaRecorder = new MediaRecorder(stream);
|
|
42
45
|
this.mediaRecorder.start();
|
|
43
46
|
this.isRecording = true;
|
|
44
47
|
this.startRecordingEvent.emit();
|
|
45
48
|
this.mediaRecorder.addEventListener('dataavailable', (event) => {
|
|
46
|
-
|
|
49
|
+
if (event.data && event.data.size > 0) {
|
|
50
|
+
this.audioChunks.push(event.data);
|
|
51
|
+
}
|
|
47
52
|
});
|
|
48
53
|
|
|
49
54
|
this.mediaRecorder.addEventListener('stop', () => {
|
|
50
|
-
|
|
55
|
+
// ✅ MIME REALE del recorder
|
|
56
|
+
const mimeType = this.mediaRecorder.mimeType;
|
|
57
|
+
this.audioBlob = new Blob(this.audioChunks, {
|
|
58
|
+
type: mimeType
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ⭐ chiude microfono
|
|
62
|
+
stream.getTracks().forEach(track => track.stop());
|
|
63
|
+
|
|
64
|
+
this.audioChunks = [];
|
|
51
65
|
this.rawAudioUrl = URL.createObjectURL(this.audioBlob);
|
|
52
66
|
this.audioUrl = this.sanitizer.bypassSecurityTrustUrl(this.rawAudioUrl);
|
|
53
|
-
this.audioChunks = [];
|
|
54
67
|
this.endRecordingEvent.emit(this.audioBlob);
|
|
55
68
|
});
|
|
56
69
|
})
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
[nameUserTypingNow]="nameUserTypingNow">
|
|
14
14
|
</user-typing>
|
|
15
15
|
</span>
|
|
16
|
-
|
|
17
16
|
|
|
18
17
|
<div id="chat21-sheet-content" class="chat21-sheet-content">
|
|
19
18
|
<div class="chat21-conversation-parts-container">
|
|
@@ -120,25 +119,21 @@
|
|
|
120
119
|
|
|
121
120
|
<!-- FILE PENDING UPLOAD -->
|
|
122
121
|
<!-- -->
|
|
123
|
-
<div *ngIf="showUploadProgress" class="msg_container base_sent" >
|
|
122
|
+
<div *ngIf="showUploadProgress && !showThinkingMessage" class="msg_container base_sent" >
|
|
124
123
|
<div class="chat21-spinner active" id="chat21-spinner" style="margin: 0px 6px 0px;">
|
|
125
124
|
<div class="chat21-bounce1" [ngStyle]="{'background-color': stylesMap.get('iconColor')}"></div>
|
|
126
125
|
<div class="chat21-bounce2" [ngStyle]="{'background-color': stylesMap.get('iconColor'), 'opacity': 0.4}"></div>
|
|
127
126
|
<div class="chat21-bounce3" [ngStyle]="{'background-color': stylesMap.get('iconColor'), 'opacity': 0.6}"></div>
|
|
128
127
|
</div>
|
|
129
|
-
|
|
130
|
-
|
|
131
128
|
</div>
|
|
132
129
|
|
|
133
130
|
|
|
134
|
-
<div *ngIf="isTypings && typingLocation==='content'
|
|
135
|
-
<!-- !isSameSender(idUserTypingNow, i) -->
|
|
131
|
+
<div *ngIf="isTypings && !showThinkingMessage && typingLocation==='content'" class="msg_container base_receive">
|
|
136
132
|
<chat-avatar-image *ngIf="idUserTypingNow " class="slide-in-left"
|
|
137
133
|
[senderID]="idUserTypingNow"
|
|
138
134
|
[senderFullname]="nameUserTypingNow"
|
|
139
135
|
[baseLocation]="baseLocation">
|
|
140
136
|
</chat-avatar-image>
|
|
141
|
-
|
|
142
137
|
<user-typing
|
|
143
138
|
[ngClass]="{'userTypingNowExist': !idUserTypingNow}"
|
|
144
139
|
[color]="stylesMap?.get('iconColor')"
|
|
@@ -147,7 +142,16 @@
|
|
|
147
142
|
[nameUserTypingNow]="nameUserTypingNow">
|
|
148
143
|
</user-typing>
|
|
149
144
|
</div>
|
|
150
|
-
|
|
145
|
+
|
|
146
|
+
<div *ngIf="showThinkingMessage" class="msg_container base_receive thinking_receive">
|
|
147
|
+
<user-typing class="loading thinking-dots"
|
|
148
|
+
[color]="stylesMap?.get('iconColor')"
|
|
149
|
+
[translationMap]="translationMap"
|
|
150
|
+
[idUserTypingNow]="idUserTypingNow"
|
|
151
|
+
[nameUserTypingNow]="nameUserTypingNow">
|
|
152
|
+
</user-typing>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
151
155
|
</div>
|
|
152
156
|
</div>
|
|
153
157
|
</div>
|
|
@@ -155,7 +159,6 @@
|
|
|
155
159
|
</div>
|
|
156
160
|
</div>
|
|
157
161
|
</div>
|
|
158
|
-
|
|
159
162
|
</div>
|
|
160
163
|
|
|
161
164
|
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
top: 0;
|
|
45
45
|
right: 0;
|
|
46
46
|
left: 0;
|
|
47
|
-
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height));
|
|
47
|
+
bottom: calc(var(--chat-footer-logo-height) + var(--chat-footer-height) + var(--chat-footer-close-button-height));
|
|
48
48
|
overflow: hidden;
|
|
49
49
|
.time{
|
|
50
50
|
margin-bottom: 20px;
|
|
@@ -122,6 +122,11 @@
|
|
|
122
122
|
text-align: center;
|
|
123
123
|
padding: 0px 0px 6px 0px
|
|
124
124
|
}
|
|
125
|
+
.thinking_receive {
|
|
126
|
+
.thinking-dots ::ng-deep > div.spinner{
|
|
127
|
+
margin: 25px 30px;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
125
130
|
/* ====== SET MESSAGES ====== */
|
|
126
131
|
.messages {
|
|
127
132
|
border-radius: var(--border-radius-bubble-message);
|
|
@@ -265,6 +270,15 @@
|
|
|
265
270
|
}// end c21-body-container
|
|
266
271
|
}// end c21-body
|
|
267
272
|
|
|
273
|
+
@keyframes thinking-dot {
|
|
274
|
+
0%, 80%, 100% {
|
|
275
|
+
opacity: 0.2;
|
|
276
|
+
}
|
|
277
|
+
40% {
|
|
278
|
+
opacity: 1;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
268
282
|
/* LOADING */
|
|
269
283
|
/*http://tobiasahlin.com/spinkit/*/
|
|
270
284
|
#chat21-spinner {
|
package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts
CHANGED
|
@@ -23,6 +23,7 @@ export class ConversationContentComponent implements OnInit {
|
|
|
23
23
|
@Input() idUserTypingNow: string;
|
|
24
24
|
@Input() nameUserTypingNow: string;
|
|
25
25
|
@Input() typingLocation: string;
|
|
26
|
+
@Input() showThinkingMessage: boolean;
|
|
26
27
|
@Input() fullscreenMode: boolean;
|
|
27
28
|
@Input() translationMap: Map< string, string>;
|
|
28
29
|
@Input() stylesMap: Map<string, string>;
|
|
@@ -224,7 +225,6 @@ export class ConversationContentComponent implements OnInit {
|
|
|
224
225
|
// return false;
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
|
|
228
228
|
hideOutsideElements(){
|
|
229
229
|
this.onMenuOptionShow.emit(false)
|
|
230
230
|
this.onEmojiiPickerShow.emit(false)
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html
CHANGED
|
@@ -14,94 +14,117 @@
|
|
|
14
14
|
|
|
15
15
|
</div>
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
17
|
+
<div class="textarea-container-wrapper" *ngIf="!hideTextAreaContent && !hideTextReply">
|
|
18
|
+
<!-- TEXTAREA + ICONS: conv active-->
|
|
19
|
+
<div class="textarea-container">
|
|
20
|
+
|
|
21
|
+
<div *ngIf="!isStopRec" class="icons-container">
|
|
22
|
+
<!-- ICON ATTACHMENT -->
|
|
23
|
+
<label *ngIf="showAttachmentFooterButton" tabindex="1502" aria-label="allegati" for="chat21-file" class="chat21-textarea-button" [class.active]="!isFilePendingToUpload && !hideTextReply" id="chat21-start-upload-doc">
|
|
24
|
+
<span class="v-align-center">
|
|
25
|
+
<svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" width="24px" height="24" viewBox="0 0 24 24" fill="currentColor">
|
|
26
|
+
<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"/>
|
|
27
|
+
<title id="altIconTitle">{{ 'MAX_ATTACHMENT' | translate: { FILE_SIZE_LIMIT: file_size_limit } }}</title>
|
|
28
|
+
</svg>
|
|
29
|
+
|
|
30
|
+
</span>
|
|
31
|
+
<input
|
|
32
|
+
[attr.disabled] = "(isFilePendingToUpload || isConversationArchived || hideTextReply)? true : null"
|
|
33
|
+
tabindex="1503"
|
|
34
|
+
type="file"
|
|
35
|
+
aria-label="seleziona allegato"
|
|
36
|
+
[accept]="fileUploadAccept"
|
|
37
|
+
name="chat21-file"
|
|
38
|
+
id="chat21-file"
|
|
39
|
+
#chat21_file
|
|
40
|
+
class="inputfile"
|
|
41
|
+
[ngStyle]="{'display': 'block', height:'1px', width:'1px', overflow: 'hidden' }"
|
|
42
|
+
(change)="detectFiles($event)"/>
|
|
43
|
+
</label>
|
|
44
|
+
<!-- ICON EMOJII -->
|
|
45
|
+
<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()">
|
|
46
|
+
<span class="v-align-center">
|
|
47
|
+
<svg role="img" aria-labelledby="altIconTitle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
|
|
48
|
+
<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"/>
|
|
49
|
+
<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"/>
|
|
50
|
+
<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"/>
|
|
51
|
+
<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"/>
|
|
52
|
+
<title id="altIconTitle">{{ translationMap?.get('EMOJI') }}</title>
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
<!-- <path d="M0,0H20.57V20.57H0V0Z" fill="none"/>
|
|
55
|
+
<circle cx="15.02" cy="9.86" r="1.29"/>
|
|
56
|
+
<circle cx="9.02" cy="9.86" r="1.29"/>
|
|
57
|
+
<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"/> -->
|
|
58
|
+
</svg>
|
|
59
|
+
</span>
|
|
60
|
+
</label>
|
|
61
|
+
</div>
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
66
|
+
<div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
|
|
67
|
+
<!-- isFilePendingToUpload || -->
|
|
68
|
+
<textarea
|
|
69
|
+
[attr.disabled] = "(hideTextReply)? true : null"
|
|
70
|
+
[attr.placeholder] ="(footerMessagePlaceholder)? footerMessagePlaceholder : translationMap?.get('LABEL_PLACEHOLDER')"
|
|
71
|
+
start-focus-chat21-conversation-component
|
|
72
|
+
inputTextArea
|
|
73
|
+
#textbox
|
|
74
|
+
tabindex="1501"
|
|
75
|
+
aria-labelledby="altTextArea"
|
|
76
|
+
rows="1"
|
|
77
|
+
id="chat21-main-message-context"
|
|
78
|
+
class='f21textarea c21-button-clean'
|
|
79
|
+
[(ngModel)]="textInputTextArea"
|
|
80
|
+
(ngModelChange)="onTextAreaChange()"
|
|
81
|
+
(keypress)="onkeypress($event)"
|
|
82
|
+
(keydown)="onkeydown($event)"
|
|
83
|
+
(paste)="onPaste($event)">
|
|
84
|
+
</textarea>
|
|
85
|
+
|
|
86
|
+
</div>
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
<!-- ICON SEND -->
|
|
89
|
+
<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)">
|
|
90
|
+
<span class="v-align-center">
|
|
91
|
+
<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">
|
|
92
|
+
<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"/>
|
|
93
|
+
</svg>
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<!-- ICON REC -->
|
|
98
|
+
<div *ngIf="showAudioRecorderFooterButton && !textInputTextArea" tabindex="-1" class="chat21-audio-button" [class.active]="isStopRec" id="chat21-button-rec">
|
|
99
|
+
<chat-audio-recorder
|
|
100
|
+
(startRecordingEvent)="onStartRecording()"
|
|
101
|
+
(deleteRecordingEvent)="onDeleteRecording()"
|
|
102
|
+
(endRecordingEvent)="onEndRecording($event)"
|
|
103
|
+
(sendRecordingEvent)="onSendRecording($event)"
|
|
104
|
+
[stylesMap]="stylesMap">
|
|
105
|
+
</chat-audio-recorder>
|
|
106
|
+
</div>
|
|
94
107
|
</div>
|
|
95
108
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
<div class="close-chat-container" *ngIf="closeChatInConversation">
|
|
110
|
+
<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')}">
|
|
111
|
+
<span class="v-align-center">
|
|
112
|
+
<!-- <svg [ngStyle]="{'fill': 'yellow' }" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
|
|
113
|
+
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}"/>
|
|
114
|
+
</svg> -->
|
|
115
|
+
<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"
|
|
116
|
+
width="15px" height="15px" viewBox="0 0 512 512">
|
|
117
|
+
<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>
|
|
118
|
+
<rect x="48" y="64" width="416" height="80" rx="28" ry="28" stroke-linejoin="round" stroke-width="50px" fill="none" ></rect>
|
|
119
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M320 304l-64 64-64-64M256 345.89V224" stroke-width="50px" fill="none"></path>
|
|
120
|
+
<title id="altIconTitle">{{ translationMap?.get('CLOSE_CHAT') }}</title>
|
|
121
|
+
</svg>
|
|
122
|
+
</span>
|
|
123
|
+
<span class="v-align-center c21-label-button">
|
|
124
|
+
{{translationMap?.get('CLOSE_CHAT')}}
|
|
125
|
+
</span>
|
|
126
|
+
<div class="clear"></div>
|
|
127
|
+
</button>
|
|
105
128
|
</div>
|
|
106
129
|
</div>
|
|
107
130
|
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
.textarea-container-wrapper{
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 8px;
|
|
5
|
+
}
|
|
2
6
|
.textarea-container{
|
|
3
|
-
// padding: 8px 34px;
|
|
4
|
-
// padding-left: 70px;
|
|
5
|
-
// padding-right: 45px;
|
|
6
7
|
display: flex;
|
|
7
|
-
// width: 100%;
|
|
8
8
|
align-items: center;
|
|
9
9
|
justify-content: space-between;
|
|
10
10
|
gap: 8px;
|
|
11
|
+
}
|
|
12
|
+
.close-chat-container{
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
gap: 8px;
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
.c21-close{
|
|
20
|
+
height: 30px !important;
|
|
21
|
+
margin: 0px !important;
|
|
15
22
|
}
|
|
16
|
-
//if attachment icon AND emoji icon is not in DOM -> increment textarea width
|
|
17
|
-
&:has(:not(#chat21-start-upload-doc)):has(:not(#chat21-emoticon-picker)) .visible-text-area {
|
|
18
|
-
width: 90%;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
.icons-container{
|
|
@@ -419,3 +421,28 @@ textarea:active{
|
|
|
419
421
|
border: none;
|
|
420
422
|
// margin: -2px -2px 0px;
|
|
421
423
|
}
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
// aggiungi un'animazione di fade in e fade out quando .star-rating-widget è visibile con transition
|
|
427
|
+
.star-rating-widget {
|
|
428
|
+
transition: all 0.5s ease-in-out;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.star-rating-widget {
|
|
432
|
+
position: absolute;
|
|
433
|
+
left: 0;
|
|
434
|
+
right: 0;
|
|
435
|
+
bottom: -52px;
|
|
436
|
+
height: 100%;
|
|
437
|
+
width: 100%;
|
|
438
|
+
flex-direction: row;
|
|
439
|
+
justify-content: center;
|
|
440
|
+
background-color: rgb(255, 255, 255);
|
|
441
|
+
flex-wrap: nowrap;
|
|
442
|
+
&.active {
|
|
443
|
+
bottom: 0px;
|
|
444
|
+
}
|
|
445
|
+
&.inactive {
|
|
446
|
+
bottom: -52px;
|
|
447
|
+
}
|
|
448
|
+
}
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -42,6 +42,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
42
42
|
@Input() isEmojiiPickerShow: boolean;
|
|
43
43
|
@Input() footerMessagePlaceholder: string;
|
|
44
44
|
@Input() fileUploadAccept: string;
|
|
45
|
+
@Input() closeChatInConversation: boolean;
|
|
45
46
|
@Input() dropEvent: Event;
|
|
46
47
|
@Input() poweredBy: string;
|
|
47
48
|
@Input() stylesMap: Map<string, string>
|
|
@@ -52,6 +53,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
52
53
|
@Output() onChangeTextArea = new EventEmitter<any>();
|
|
53
54
|
@Output() onAttachmentFileButtonClicked = new EventEmitter<any>();
|
|
54
55
|
@Output() onNewConversationButtonClicked = new EventEmitter();
|
|
56
|
+
@Output() onCloseChatButtonClicked = new EventEmitter();
|
|
55
57
|
|
|
56
58
|
@ViewChild('chat21_file') public chat21_file: ElementRef;
|
|
57
59
|
// @ViewChild('emojii_container', {read: ViewContainerRef}) selector;
|
|
@@ -87,6 +89,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
87
89
|
|
|
88
90
|
file_size_limit = FILE_SIZE_LIMIT;
|
|
89
91
|
attachmentTooltip: string = '';
|
|
92
|
+
isErrorNetwork: boolean = false;
|
|
90
93
|
|
|
91
94
|
|
|
92
95
|
convertColorToRGBA = convertColorToRGBA;
|
|
@@ -513,14 +516,46 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
513
516
|
onSendRecording(audioBlob: Blob | null) {
|
|
514
517
|
this.isStartRec = false;
|
|
515
518
|
if (audioBlob) {
|
|
516
|
-
this.
|
|
519
|
+
this.prepareAndUpload(audioBlob);
|
|
520
|
+
// this.convertBlobToBase64(audioBlob);
|
|
517
521
|
this.isStopRec = false;
|
|
518
522
|
} else {
|
|
519
523
|
this.isStopRec = false;
|
|
520
524
|
}
|
|
521
525
|
}
|
|
522
526
|
|
|
527
|
+
prepareAndUpload(audioBlob: Blob) {
|
|
523
528
|
|
|
529
|
+
this.isFilePendingToUpload = true;
|
|
530
|
+
|
|
531
|
+
// ⭐ NON modificare il MIME
|
|
532
|
+
const mimeType = audioBlob.type;
|
|
533
|
+
|
|
534
|
+
const size = audioBlob.size;
|
|
535
|
+
const uid = Date.now().toString(36);
|
|
536
|
+
|
|
537
|
+
// estensione coerente col MIME REALE
|
|
538
|
+
let ext = 'mp3';
|
|
539
|
+
const fileName = `audio-${uid}.${ext}`;
|
|
540
|
+
|
|
541
|
+
const file = new File([audioBlob], fileName, {
|
|
542
|
+
type: mimeType,
|
|
543
|
+
lastModified: Date.now()
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// ✅ metadata SENZA base64
|
|
547
|
+
const metadata = {
|
|
548
|
+
name: fileName,
|
|
549
|
+
type: 'audio/mp3',
|
|
550
|
+
uid: uid,
|
|
551
|
+
size: size
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
this.logger.log('[UPLOAD] metadata:', metadata);
|
|
555
|
+
|
|
556
|
+
// stesso metodo che già usi
|
|
557
|
+
this.uploadSingle(metadata, file, '');
|
|
558
|
+
}
|
|
524
559
|
|
|
525
560
|
// Funzione per convertire Blob in Base64 usando FileReader
|
|
526
561
|
async convertBlobToBase64(audioBlob: Blob) {
|
|
@@ -677,6 +712,10 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
677
712
|
this.onNewConversationButtonClicked.emit();
|
|
678
713
|
}
|
|
679
714
|
|
|
715
|
+
onCloseChat(event){
|
|
716
|
+
this.onCloseChatButtonClicked.emit();
|
|
717
|
+
}
|
|
718
|
+
|
|
680
719
|
// onContinueConversation(){
|
|
681
720
|
// this.hideTextAreaContent = false;
|
|
682
721
|
// this.onBackButton.emit(false)
|
package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
<!-- ICON MAXIMIZE -->
|
|
30
|
-
<button *ngIf="size === 'min' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
|
|
30
|
+
<button *ngIf="size === 'min' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
|
|
31
31
|
<svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor') }" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
32
32
|
width="17" height="17" viewBox="0 0 17 17">
|
|
33
33
|
<path d="M6.49001 8.30999L3.69 11.11V9.40999C3.69 8.93999 3.31 8.55999 2.84 8.55999C2.37 8.55999 1.99001 8.93999 1.99001 9.40999V14.01H6.59C7.06 14.01 7.44 13.63 7.44 13.16C7.44 12.69 7.06 12.31 6.59 12.31H4.89L7.69 9.50999L6.49001 8.30999ZM9.41 1.98999C8.94 1.98999 8.56001 2.36999 8.56001 2.83999C8.56001 3.30999 8.94 3.68999 9.41 3.68999H11.11L8.31001 6.48999L9.51 7.68999L12.31 4.88999V6.58999C12.31 7.05999 12.69 7.43999 13.16 7.43999C13.63 7.43999 14.01 7.05999 14.01 6.58999V1.98999H9.41Z"></path>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
</button>
|
|
37
37
|
|
|
38
38
|
<!-- ICON MINIMIZE -->
|
|
39
|
-
<button *ngIf="size==='top' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
|
|
39
|
+
<button *ngIf="size==='top' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
|
|
40
40
|
<svg role="img" aria-labelledby="altIconTitle" class="icon-menu" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
41
41
|
width="17" height="17" viewBox="0 0 17 17">
|
|
42
42
|
<path d="M13.59 5.31h-1.7l3.3-3.3-1.2-1.2-3.3 3.3v-1.7a.85.85 0 1 0-1.7 0v4.6h4.6a.85.85 0 1 0 0-1.7M1.57 9.84c0 .47.38.85.85.85h1.7l-3.3 3.3 1.2 1.2 3.3-3.3v1.7a.85.85 0 1 0 1.7 0v-4.6h-4.6a.85.85 0 0 0-.85.85"></path>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
</button>
|
|
46
46
|
|
|
47
47
|
<!-- ICON TOP -->
|
|
48
|
-
<button *ngIf="size==='max' && !fullscreenMode" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
|
|
48
|
+
<button *ngIf="size==='max' && !fullscreenMode && !isMobile" [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-header-button c21-right c21-button-clean" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
|
|
49
49
|
<svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
50
50
|
width="17" height="17" viewBox="0 0 17 17">
|
|
51
51
|
<path d="M3.7,7.6L2.5,6.4C2.2,6,2.2,5.5,2.5,5.2s0.9-0.4,1.2-0.1L7,8.4l-3.3,3.3c-0.4,0.4-0.8,0.3-1.1,0s-0.4-0.9-0.1-1.2l1.2-1.2 H1.5l0-1.7H3.7z"/>
|
package/src/app/component/conversation-detail/conversation-header/conversation-header.component.ts
CHANGED
|
@@ -21,6 +21,7 @@ export class ConversationHeaderComponent implements OnInit, OnChanges {
|
|
|
21
21
|
@Input() isTypings: boolean;
|
|
22
22
|
@Input() nameUserTypingNow: string;
|
|
23
23
|
@Input() typingLocation: string;
|
|
24
|
+
@Input() isMobile: boolean;
|
|
24
25
|
@Input() isTrascriptDownloadEnabled: boolean;
|
|
25
26
|
@Input() fullscreenMode: boolean;
|
|
26
27
|
@Input() size: 'min' | 'max' | 'top';
|
|
@@ -50,24 +50,6 @@ export class EyeeyeCatcherCardComponent implements OnInit {
|
|
|
50
50
|
this.displayEyeCatcherCardCloseBtnWrapper = 'none';
|
|
51
51
|
this.displayEyeCatcherCardCloseBtnIsMobileWrapper = 'none';
|
|
52
52
|
this.displayEyeCatcherCardCloseBtn = 'none';
|
|
53
|
-
/* EYE-CATCHER CLOSE BUTTON SWITCH */
|
|
54
|
-
this.openIfCallOutTimer();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* OPEN THE EYE-CATCHER CARD
|
|
60
|
-
* if calloutTimer >= 0
|
|
61
|
-
*/
|
|
62
|
-
private openIfCallOutTimer() {
|
|
63
|
-
const that = this;
|
|
64
|
-
const calloutTimer = this.g.calloutTimer;
|
|
65
|
-
if (calloutTimer >= 0) {
|
|
66
|
-
const waitingTime = calloutTimer * 1000;
|
|
67
|
-
setTimeout(function () {
|
|
68
|
-
that.openEyeCatcher();
|
|
69
|
-
}, waitingTime);
|
|
70
|
-
}
|
|
71
53
|
}
|
|
72
54
|
|
|
73
55
|
/**
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<div class="c21-header-button" [ngStyle]="{'display': (g.hideHeaderCloseButton)?'none':'block'}">
|
|
15
15
|
|
|
16
16
|
<!-- ICON MAXIMIZE -->
|
|
17
|
-
<div *ngIf="size === 'min' && !fullscreenMode" class="c21-size-button">
|
|
17
|
+
<div *ngIf="size === 'min' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
|
|
18
18
|
<button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('max')" >
|
|
19
19
|
<svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor') }" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
20
20
|
width="17" height="17" viewBox="0 0 17 17">
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
27
|
<!-- ICON MINIMIZE -->
|
|
28
|
-
<div *ngIf="size==='top' && !fullscreenMode" class="c21-size-button">
|
|
28
|
+
<div *ngIf="size==='top' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
|
|
29
29
|
<button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('min')" >
|
|
30
30
|
<svg role="img" aria-labelledby="altIconTitle" class="icon-menu" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
31
31
|
width="17" height="17" viewBox="0 0 17 17">
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
38
|
<!-- ICON TOP -->
|
|
39
|
-
<div *ngIf="size==='max' && !fullscreenMode" class="c21-size-button">
|
|
39
|
+
<div *ngIf="size==='max' && !fullscreenMode && !g?.isMobile" class="c21-size-button">
|
|
40
40
|
<button [attr.disabled]="(isButtonsDisabled)?true:null" tabindex="-1" class="c21-close-button-body" [ngStyle]="{'display': (hideHeaderConversationOptionsMenu)?'none':'flex'}" (click)="onChangeSize('top')" >
|
|
41
41
|
<svg role="img" aria-labelledby="altIconTitle" [ngStyle]="{'fill': stylesMap?.get('foregroundColor')}" xmlns="http://www.w3.org/2000/svg" transform="matrix(-1,0,0,1,0,0)"
|
|
42
42
|
width="17" height="17" viewBox="0 0 17 17">
|
|
@@ -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, isSameSender } from 'src/chat21-core/utils/utils-message';
|
|
15
|
+
import { commandToMessage, conversationToMessage, isEmojii, isFrame, isImage, isMine, isSameSender, isSender } from 'src/chat21-core/utils/utils-message';
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@Component({
|
|
@@ -59,6 +59,9 @@ 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;
|
|
62
65
|
|
|
63
66
|
if(this.conversation.attributes && this.conversation.attributes.commands){
|
|
64
67
|
this.addCommandMessage(this.conversation)
|