@chat21/chat21-web-widget 5.0.56-rc.3 → 5.0.56-rc.5

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 (24) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +1 -1
  3. package/src/app/app.component.html +1 -1
  4. package/src/app/component/conversation-detail/conversation/conversation.component.html +2 -1
  5. package/src/app/component/conversation-detail/conversation/conversation.component.scss +4 -0
  6. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +2 -2
  7. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +1 -36
  8. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +17 -13
  9. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +6 -2
  10. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +50 -0
  11. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +2 -1
  12. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html +1 -1
  13. package/src/app/component/last-message/last-message.component.html +64 -88
  14. package/src/app/component/last-message/last-message.component.scss +50 -93
  15. package/src/app/component/last-message/last-message.component.ts +64 -6
  16. package/src/app/component/message/bubble-message/bubble-message.component.scss +0 -25
  17. package/src/app/component/message/text/text.component.scss +8 -2
  18. package/src/app/utils/globals.ts +11 -0
  19. package/src/assets/twp/index-dev.html +34 -0
  20. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +1 -1
  21. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +1 -1
  22. package/src/chat21-core/utils/utils-message.ts +57 -21
  23. package/src/iframe-style.css +6 -2
  24. package/src/launch.js +13 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # chat21-web-widget ver 5.0
2
2
 
3
+ ### 5.0.56-rc.5
4
+ - added: if hideFooterTextReply is set to true, hide footer input area and display logo
5
+ - added: mobileMarginX and mobileMarginY property to dev page
6
+ - added: root css variable to manage dynamic iframe height
7
+ - changed: minor UI changes in last-messsage and bubble-message components to display trasnsparent background if image/iframe/gif is received/sent
8
+ - bug-fixed: dynamic height in .messagePreview container div modify the height of the entire iframe also when it is open
9
+
10
+ ### 5.0.56-rc.4
11
+ - added: function to manage messagePreview height programatically
12
+ - added: implementation of commands messages inside callout component
13
+ - added: isFirstMessage, isSameSender, isLastMessage, isFirstMessage function to utils-message
14
+ - removed: margin-block of inner p html tag in chat-text base message component
15
+ - bug-fixed: cannot read trim() of undefined with image text message
16
+
3
17
  ### 5.0.56-rc.3
4
18
  - added: widget loading in chatbot-panel.html page
5
19
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-web-widget",
3
3
  "author": "Tiledesk SRL",
4
- "version": "5.0.56-rc.3",
4
+ "version": "5.0.56-rc.5",
5
5
  "license": "MIT",
6
6
  "homepage": "https://www.tiledesk.com",
7
7
  "repository": {
@@ -104,7 +104,7 @@
104
104
  ******* EYE-CATCHER (aka CALLOUT) *********
105
105
  *******************************************
106
106
  tabindex -> 20 -->
107
- <chat-eyeeye-catcher-card *ngIf="g.senderId"
107
+ <chat-eyeeye-catcher-card *ngIf="g.senderId && !g.isOpenNewMessage"
108
108
  (onOpenChat)="onOpenCloseWidget($event)"
109
109
  (onCloseEyeCatcherCard)="onCloseEyeCatcherCard($event)">
110
110
  </chat-eyeeye-catcher-card>
@@ -92,7 +92,7 @@
92
92
  </chat-conversation-attachment-preview>
93
93
 
94
94
  <!-- FOOTER -->
95
- <div id="chat21-footer" [class.maximize-width]="(g?.singleConversation && hideTextAreaContent) || (isConversationArchived && !g?.allowReopen)">
95
+ <div id="chat21-footer" [class.maximize-width]="(g?.singleConversation && hideTextAreaContent) || (isConversationArchived && !g?.allowReopen)" [class.hideFooterReply]="hideFooterTextReply">
96
96
  <div *ngIf="showBadgeScroollToBottom" id="chat21-buttonToBottom" (click)="scrollToBottom()">
97
97
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path opacity=".87" fill="none" d="M24 24H0V0h24v24z"/><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6-1.41-1.41z"/></svg>
98
98
  <div *ngIf="messagesBadgeCount!=0" id="chat21-divBudge" class="c21-divBudge">{{messagesBadgeCount}}</div>
@@ -117,6 +117,7 @@
117
117
  [footerMessagePlaceholder]="footerMessagePlaceholder"
118
118
  [fileUploadAccept]="appConfigService?.getConfig().fileUploadAccept"
119
119
  [dropEvent]="dropEvent"
120
+ [poweredBy]="g?.poweredBy"
120
121
  [stylesMap]="stylesMap"
121
122
  [translationMap]="translationMapFooter"
122
123
  (onEmojiiPickerShow)="onEmojiiPickerShow($event)"
@@ -47,6 +47,10 @@
47
47
  padding: 8px 0px;
48
48
  }
49
49
 
50
+ &.hideFooterReply{
51
+ padding: 0px;
52
+ }
53
+
50
54
  /* button scroll to bottom page */
51
55
  #chat21-buttonToBottom {
52
56
  display: flex;
@@ -28,7 +28,7 @@
28
28
  <!--backgroundColor non viene ancora usato -->
29
29
  <!-- class="messages msg_sent slide-in-right" -->
30
30
  <chat-bubble-message class="messages msg_sent"
31
- [class.no-background]="(isImage(message) || isFrame(message)) && message?.text && message?.textmessage?.text.trim() === '' "
31
+ [class.no-background]="(isImage(message) || isFrame(message)) && ((message?.text && message?.text.trim() === '') || !message?.text)"
32
32
  [class.emoticon]="isEmojii(message?.text)"
33
33
  [ngStyle]="{'background': stylesMap.get('bubbleSentBackground'), 'color': stylesMap.get('bubbleSentTextColor')}"
34
34
  [ngClass]="{'button-in-msg' : message?.metadata && message?.metadata?.button}"
@@ -63,7 +63,7 @@
63
63
  <!-- [ngClass]="{'slide-in-left': !isFirstMessage(message?.sender, i)}" -->
64
64
  <chat-bubble-message class="messages msg_receive"
65
65
  [ngClass]="{'slide-in-left': false}"
66
- [class.no-background]="(isImage(message) || isFrame(message)) && message?.text && message?.text.trim() === '' "
66
+ [class.no-background]="(isImage(message) || isFrame(message)) && ((message?.text && message?.text.trim() === '') || !message?.text)"
67
67
  [class.emoticon]="isEmojii(message?.text)"
68
68
  [style.margin-left]="isSameSender(message?.sender, i)? '50px': null"
69
69
  [ngStyle]="{'background': stylesMap.get('bubbleReceivedBackground'), 'color': stylesMap.get('bubbleReceivedTextColor')}"
@@ -148,42 +148,7 @@
148
148
  // padding: 6px 6px 6px 6px;
149
149
  // box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
150
150
  // -webkit-animation: heartbeat 1.5s ease-in-out both;
151
- // animation: heartbeat 1.5s ease-in-out both;
152
-
153
- p {
154
- font-size: 1.4em;
155
- margin: 0;
156
- padding: 14px;
157
- font-style: normal;
158
- letter-spacing: normal;
159
- font-stretch: normal;
160
- font-variant: normal;
161
- font-weight: 300;
162
- overflow: hidden;
163
- }
164
- img {
165
- border-radius: 8px;
166
- padding: 3px;
167
- margin-bottom: 0px;
168
- max-width: calc(100% - 6px);
169
- width: auto;
170
- height: auto;
171
- object-fit: cover;
172
- }
173
- .message_innerhtml {
174
- margin: 0px;
175
- // padding: 0px 14px;
176
- &.marked{
177
- padding:8px;
178
- margin-block-start: -1em!important;
179
- margin-block-end: -1em!important;
180
- }
181
-
182
- .text-message {
183
- padding-top: 14px;
184
- }
185
- }
186
-
151
+ // animation: heartbeat 1.5s ease-in-out both;
187
152
  }
188
153
 
189
154
  .base_info {
@@ -6,7 +6,7 @@ import { UploadService } from 'src/chat21-core/providers/abstract/upload.service
6
6
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
7
7
  import { MESSAGE_TYPE_INFO, MESSAGE_TYPE_MINE, MESSAGE_TYPE_OTHERS } from 'src/chat21-core/utils/constants';
8
8
  import { isPopupUrl, popupUrl } from 'src/chat21-core/utils/utils';
9
- import { isEmojii, isFrame, isImage, isInfo, isMine, messageType } from 'src/chat21-core/utils/utils-message';
9
+ import { isEmojii, isFirstMessage, isFrame, isImage, isInfo, isLastMessage, isMine, isSameSender, messageType } from 'src/chat21-core/utils/utils-message';
10
10
 
11
11
  @Component({
12
12
  selector: 'chat-conversation-content',
@@ -198,27 +198,31 @@ export class ConversationContentComponent implements OnInit {
198
198
 
199
199
  // ========= END:: functions scroll position ======= //
200
200
  isLastMessage(idMessage: string):boolean {
201
- if (idMessage === this.messages[this.messages.length - 1].uid) {
202
- return true;
203
- }
204
- return false;
201
+ return isLastMessage(this.messages, idMessage)
202
+ // if (idMessage === this.messages[this.messages.length - 1].uid) {
203
+ // return true;
204
+ // }
205
+ // return false;
205
206
  }
206
207
 
207
208
  isSameSender(senderId, index):boolean{
208
- if(senderId && this.messages[index - 1] && (senderId === this.messages[index - 1].sender)){
209
- return true;
210
- }
211
- return false;
209
+ return isSameSender(this.messages, senderId, index)
210
+ // if(senderId && this.messages[index - 1] && (senderId === this.messages[index - 1].sender)){
211
+ // return true;
212
+ // }
213
+ // return false;
212
214
  }
213
215
 
214
216
 
215
217
  isFirstMessage(senderId, index):boolean{
216
- if(senderId && index == 0 && this.messages[index] && (this.messages[index] !== senderId)){
217
- return true;
218
- }
219
- return false;
218
+ return isFirstMessage(this.messages, senderId, index)
219
+ // if(senderId && index == 0 && this.messages[index] && (this.messages[index] !== senderId)){
220
+ // return true;
221
+ // }
222
+ // return false;
220
223
  }
221
224
 
225
+
222
226
  hideOutsideElements(){
223
227
  this.onMenuOptionShow.emit(false)
224
228
  this.onEmojiiPickerShow.emit(false)
@@ -18,7 +18,11 @@
18
18
  </button>
19
19
  </div>
20
20
 
21
- <div class="visible-text-area" *ngIf="!hideTextAreaContent" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
21
+ <div id="hiddenFooter" *ngIf="hideTextReply && !hideTextAreaContent" class="fade-in-bottom">
22
+ <div tabindex="-1" class="c21-powered-by" [innerHTML]="poweredBy"></div>
23
+ </div>
24
+
25
+ <div class="visible-text-area" *ngIf="!hideTextAreaContent && !hideTextReply" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
22
26
  <!-- isFilePendingToUpload || -->
23
27
  <textarea
24
28
  [attr.disabled] = "(hideTextReply)? true : null"
@@ -40,7 +44,7 @@
40
44
 
41
45
  </div>
42
46
  <!-- -->
43
- <div #div_attached *ngIf="!hideTextAreaContent">
47
+ <div #div_attached *ngIf="!hideTextAreaContent && !hideTextReply">
44
48
  <!-- ICON ATTACHMENT -->
45
49
  <label *ngIf="showAttachmentButton == true" tabindex="1502" aria-label="allegati" for="chat21-file" class="chat21-textarea-button" [class.active]="!isFilePendingToUpload && !hideTextReply" id="chat21-start-upload-doc">
46
50
  <span class="v-align-center">
@@ -251,6 +251,56 @@ textarea:active{
251
251
 
252
252
  }
253
253
 
254
+
255
+ #hiddenFooter{
256
+ .c21-powered-by {
257
+ height: 40px;
258
+ text-align: center;
259
+ padding: 0;
260
+ // margin: 5px 0;
261
+ // position: absolute;
262
+ color: var(--gray);
263
+ // top: 0;
264
+ // left: 20px; //60px;
265
+ // right: 60px;
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: center;
269
+
270
+ &::ng-deep a {
271
+ text-decoration: none;
272
+ cursor: pointer;
273
+ display: inline-block;
274
+ color: var(--gray);
275
+ font-size: 1.1em;
276
+ font-weight: 500;
277
+ line-height: 22px;
278
+
279
+ font-family: Mulish, sans-serif;
280
+ letter-spacing: -0.24px;
281
+ -webkit-font-smoothing: antialiased;
282
+
283
+ span {
284
+ display: inline-block;
285
+ position: relative;
286
+ top: 2px;
287
+ }
288
+
289
+ img {
290
+ width: 80px; //60px;
291
+ height: auto;
292
+ max-height: 40px;
293
+ position: relative;
294
+ vertical-align: middle;
295
+ object-fit: contain;
296
+ }
297
+ }
298
+ b{
299
+ font-weight: bolder;
300
+ }
301
+ }
302
+ }
303
+
254
304
  .fade-in-bottom {
255
305
  -webkit-animation: fade-in-bottom 0.5s cubic-bezier(0.600, -0.280, 0.735, 0.045) 0.0s;
256
306
  animation: fade-in-bottom 0.5s cubic-bezier(0.600, -0.280, 0.735, 0.045) 0.0s;
@@ -35,9 +35,10 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
35
35
  @Input() isEmojiiPickerShow: boolean;
36
36
  @Input() footerMessagePlaceholder: string;
37
37
  @Input() fileUploadAccept: string;
38
+ @Input() dropEvent: Event;
39
+ @Input() poweredBy: string;
38
40
  @Input() stylesMap: Map<string, string>
39
41
  @Input() translationMap: Map< string, string>;
40
- @Input() dropEvent: Event;
41
42
  @Output() onEmojiiPickerShow = new EventEmitter<boolean>();
42
43
  @Output() onBeforeMessageSent = new EventEmitter();
43
44
  @Output() onAfterSendMessage = new EventEmitter<MessageModel>();
@@ -1,6 +1,6 @@
1
1
 
2
2
  <!-- ******* EYE-CATCHER CARD - DISPLAYED ONLY IS-MOBILE IS FALSE ******** -->
3
- <div *ngIf="!g.isOpenNewMessage" class="eye-catcher-card scale-in-center"
3
+ <div class="eye-catcher-card scale-in-center"
4
4
  [class.mobile]="g.isMobile"
5
5
  [ngClass]="{'c21-align-left' : g.align === 'left', 'c21-align-right' : g.align !== 'left'}"
6
6
  [ngStyle]="{ 'display':g.displayEyeCatcherCard, 'bottom': g.marginY+'px', 'left':(g.align==='left')?g.marginX+'px':'', 'right':(g.align==='right')?g.marginX+'px':'' }">
@@ -1,94 +1,70 @@
1
- <div *ngIf="conversation && g.isOpenNewMessage" id="messagePreview" >
2
- <!-- message recipient:: -->
3
-
4
- <div class="headerPreviewMessage">
5
-
6
- <div class="boxButtons">
7
-
8
- <div role="button" tabindex="0" class="buttonMore" (click)="openConversationByID(conversation)">
9
- <span>View more</span>
1
+ <div id="messagePreview" *ngIf="g.isOpenNewMessage">
2
+ <div *ngFor="let message of messages; let i = index; first as isFirst; let last=last" class="message-wrp" #message_wrp>
3
+ <!-- message recipient:: -->
4
+
5
+ <div class="headerPreviewMessage" *ngIf="isFirst">
6
+
7
+ <div class="boxButtons">
8
+
9
+ <!-- <div role="button" tabindex="0" class="buttonMore" (click)="openConversationByID(conversation)">
10
+ <span>View more</span>
11
+ </div> -->
12
+
13
+ <div aria-label="Dismiss" role="button" tabindex="0" class="buttonClose" (click)="closeMessagePreview()">
14
+ <span>
15
+ <svg aria-labelledby="altIconTitle" height="20px" role="img" viewBox="0 0 24 24" width="20px" xmlns="http://www.w3.org/2000/svg" style="fill: rgb(255, 255, 255);">
16
+ <path d="M0 0h24v24H0V0z" fill="none"></path>
17
+ <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"></path>
18
+ </svg>
19
+ </span>
20
+ </div>
21
+
10
22
  </div>
11
-
12
- <div aria-label="Dismiss" role="button" tabindex="0" class="buttonClose" (click)="closeMessagePreview()">
13
- <span>
14
- <svg aria-labelledby="altIconTitle" height="20px" role="img" viewBox="0 0 24 24" width="20px" xmlns="http://www.w3.org/2000/svg" style="fill: rgb(255, 255, 255);">
15
- <path d="M0 0h24v24H0V0z" fill="none"></path>
16
- <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"></path>
17
- </svg>
18
- </span>
19
- </div>
20
-
23
+
21
24
  </div>
22
-
23
- </div>
24
-
25
-
26
- <div>
27
- <!-- <div role="messaggio" class="c21-text message_sender_fullname">{{conversation.sender_fullname}}</div> -->
28
- <!-- <img *ngIf="conversation.type == 'image' && conversation.metadata" class="message-content message-content-image"
29
- [src]="conversation.metadata.src" [width]="getSizeImg(conversation).width"
30
- [height]="getSizeImg(conversation).height" /> -->
31
-
32
-
33
- <div class="previewNewMessagge msg_container" (click)="openConversationByID(conversation)">
34
-
35
- <!-- <div *ngIf="isImage(conversation)">
36
- <chat-image
37
- [metadata]="fileSelected"
38
- [width]="fileSelected?.width"
39
- [height]="fileSelected?.height">
40
- </chat-image>
25
+
26
+
27
+ <div class="container">
28
+
29
+ <div class="previewNewMessagge" (click)="openConversationByID(conversation)"
30
+ [class.left-indicator]="isFirst && (!isImage(message) || isFrame(message))"
31
+ [class.no-background]="(isImage(message) || isFrame(message)) && message?.text?.trim() === ''">
32
+
33
+ <chat-bubble-message class="messages no-background"
34
+ [class.emoticon]="isEmojii(message?.text)"
35
+ [ngClass]="{'button-in-msg' : message?.metadata && message?.metadata?.button}"
36
+ [message]="message"
37
+ [isSameSender]="isSameSender(message?.sender, i)"
38
+ [fontColor]="stylesMap.get('bubbleReceivedTextColor')"
39
+ [fontSize]="stylesMap.get('fontSize')"
40
+ [fontFamily]="stylesMap.get('fontFamily')"
41
+ [stylesMap]="stylesMap">
42
+ </chat-bubble-message>
43
+
44
+ <div class="c21-icon-avatar" *ngIf="isFirst">
45
+ <div class="c21-avatar-image profile_image">
46
+ <chat-avatar-image class="slide-in-left"
47
+ [senderID]="message?.sender"
48
+ [senderFullname]="message?.sender_fullname"
49
+ [baseLocation]="baseLocation">
50
+ </chat-avatar-image>
51
+ </div>
52
+ </div>
53
+
41
54
  </div>
42
-
43
- <div *ngIf="conversation.type == 'text'" class="c21-box-text">
44
- <chat-text
45
- [text]="conversation?.last_message_text"
46
- [fontSize]="stylesMap?.get('fontSize')"
47
- [fontFamily]="stylesMap?.get('fontFamily')">
48
- </chat-text>
49
- </div> -->
50
-
51
- <chat-bubble-message class="messages no-background"
52
- [class.emoticon]="isEmojii(message?.text)"
53
- [ngClass]="{'button-in-msg' : message?.metadata && message?.metadata?.button}"
54
- [message]="message"
55
- [fontColor]="stylesMap.get('bubbleReceivedTextColor')"
56
- [fontSize]="stylesMap.get('fontSize')"
57
- [fontFamily]="stylesMap.get('fontFamily')"
58
- [stylesMap]="stylesMap">
59
- </chat-bubble-message>
60
-
61
- <div class="c21-icon-avatar">
62
- <div class="c21-avatar-image profile_image">
63
- <chat-avatar-image class="slide-in-left"
64
- [senderID]="message?.sender"
65
- [senderFullname]="message?.sender_fullname"
66
- [baseLocation]="baseLocation">
67
- </chat-avatar-image>
68
- </div>
55
+
56
+ <div *ngIf="message?.attributes && message?.attributes?.attachment && last" class="conversations-buttons">
57
+ <chat-message-attachment
58
+ style="height: 100%; display: block;"
59
+ [message]="message"
60
+ [isLastMessage] = "true"
61
+ [limit]="3"
62
+ [stylesMap]="stylesMap"
63
+ (onAttachmentButtonClicked)="onAttachmentButtonClicked($event)">
64
+ </chat-message-attachment>
69
65
  </div>
70
-
71
- </div>
72
-
73
- <div *ngIf="message.attributes && message.attributes.attachment " class="conversations-buttons">
74
- <chat-message-attachment
75
- style="height: 100%; display: block;"
76
- [message]="message"
77
- [isLastMessage] = "true"
78
- [limit]="3"
79
- [stylesMap]="stylesMap"
80
- (onAttachmentButtonClicked)="onAttachmentButtonClicked($event)">
81
- </chat-message-attachment>
66
+
82
67
  </div>
83
-
84
-
85
-
86
-
87
- <!-- <div class="c21-time c21-text">
88
- <time *ngIf="conversation.timestamp !== '{.sv: timestamp}'" >{{conversation.timestamp | amTimeAgo}} </time>
89
- </div> -->
90
-
91
-
92
- </div>
93
-
68
+
69
+ </div>
94
70
  </div>
@@ -9,6 +9,15 @@
9
9
  min-height: 32px;
10
10
  }
11
11
  }
12
+ :host .previewNewMessagge ::ng-deep > chat-bubble-message > #bubble-message > div > div > chat-text {
13
+ p {
14
+ overflow: hidden;
15
+ text-overflow: ellipsis;
16
+ display: -webkit-box;
17
+ -webkit-line-clamp: 4;
18
+ -webkit-box-orient: vertical;
19
+ }
20
+ }
12
21
 
13
22
  :host .slide-in-left ::ng-deep > chat-message-attachment > #buttons-in-message > span > chat-text-button-attachment{
14
23
 
@@ -19,36 +28,15 @@
19
28
  }
20
29
 
21
30
  #messagePreview {
22
- // position: relative;
23
- // width: 320px;
24
- // /* bottom: 90; */
25
- // max-height: 200px;
26
- // height: 200px; //100%;
27
- // padding: 0px 10px 10px;
28
- // background-color: transparent;
29
-
30
- // font-family: "Helvetica Neue", "Apple Color Emoji", Helvetica, Arial, sans-serif;
31
- // font-size: 100%;
32
- // font-style: normal;
33
- // letter-spacing: normal;
34
- // font-stretch: normal;
35
- // font-weight: normal;
36
- // text-align: left;
37
- // text-align-last: initial;
38
- // text-indent: 0px;
39
- // text-shadow: none;
40
- // text-transform: none;
41
- // box-sizing: content-box;
42
- // -webkit-font-smoothing: antialiased;
43
- // line-height: 1;
44
- // font-variant: normal;
45
-
46
31
  position: fixed;
47
32
  // right: 5px;
48
33
  bottom: 90px;
49
34
  // max-height: calc(100% - 75px);
50
35
  width: 375px;
51
36
  max-width: 100%;
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: 5px;
52
40
  }
53
41
 
54
42
  #messagePreview:hover {
@@ -59,13 +47,21 @@
59
47
  }
60
48
  }
61
49
 
50
+ .message-wrp{
51
+ animation: fade-in-dw-up 0.3s ease-in 0.0s;
52
+ }
53
+
54
+ .container{
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 5px;
58
+ }
62
59
 
63
60
  .messages {
64
- border-radius: var(--border-radius-bubble-message);
65
61
  padding: 0;
66
62
  word-wrap: break-word;
67
63
 
68
- max-height: 160px;
64
+ // max-height: 160px;
69
65
  display: flex;
70
66
  overflow-y: auto;
71
67
  // padding: 14px;
@@ -109,70 +105,37 @@
109
105
  position: relative;
110
106
  box-sizing: border-box;
111
107
  background-color: rgb(255, 255, 255);
112
- box-shadow: rgba(0, 18, 46, 0.16) 0px 8px 12px 0px;
108
+ box-shadow: rgba(35, 47, 53, 0.09) 0px 2px 8px 0px;
113
109
  clear: both;
114
110
  margin-left: 45px;
115
111
  margin-right: 16px;
116
- margin-bottom: 8px;
117
- border-radius: 12px 12px 12px 0px;
112
+ border-radius: 12px 12px 12px 12px;
118
113
  padding: 5px;
119
114
  }
120
115
 
121
- .previewNewMessagge::after {
122
- content: "";
123
- position: absolute;
124
- bottom: 0px;
125
- left: -5px;
126
- width: 0px;
127
- height: 0px;
128
- border-style: solid;
129
- border-width: 0px 0px 13px 5px;
130
- border-color: transparent transparent white;
131
- }
132
-
133
- .c21-text.message_sender_fullname {
134
- font-size: 13px;
135
- padding: 0px 10px;
136
- margin: 4px 0px;
137
- clear: both;
138
- color: rgb(104, 104, 104);
116
+ .previewNewMessagge.no-background{
117
+ background-color: transparent;
118
+ box-shadow: unset;
139
119
  }
140
120
 
141
- .c21-box-text {
142
- max-height: 110px;
143
- height: 100%;
144
- width: 100%;
145
- overflow-y: auto;
146
- overflow-x: hidden;
147
- border-radius: 12px 12px 12px 0px;
148
-
149
- &::-webkit-scrollbar {
150
- width: 6px;
151
- background-color: #00000000!important;
152
- }
153
-
154
- }
121
+ .left-indicator{
155
122
 
156
- .c21-box-text:hover {
157
- &::-webkit-scrollbar-track {
158
- background-color: #f9f9f9 !important;
159
- }
123
+ border-radius: 12px 12px 12px 0px;
160
124
 
161
- &::-webkit-scrollbar-thumb {
162
- background: #d3d6dc;
125
+ &::after {
126
+ content: "";
127
+ position: absolute;
128
+ bottom: 0px;
129
+ left: -5px;
130
+ width: 0px;
131
+ height: 0px;
132
+ border-style: solid;
133
+ border-width: 0px 0px 13px 5px;
134
+ border-color: transparent transparent white;
135
+
163
136
  }
164
137
  }
165
-
166
-
167
- .c21-text {
168
- font-size: 14px;
169
- color: black;
170
- padding: 0px 10px;
171
- margin: 0px 0px;// margin: 4 0;
172
- line-height: 1.4;
173
- word-break: break-word;
174
- }
175
-
138
+
176
139
  .overflow4Lines {
177
140
  overflow: hidden;
178
141
  text-overflow: ellipsis;
@@ -181,19 +144,6 @@
181
144
  -webkit-box-orient: vertical;
182
145
  }
183
146
 
184
- .c21-img{
185
- margin-left: 5px;
186
- width: 120px;
187
- // height: 100px;
188
- }
189
-
190
- .c21-text.c21-time {
191
- font-size: 13px;
192
- padding: 0px 10px;
193
- clear: both;
194
- color: rgb(115, 115, 118);
195
- }
196
-
197
147
  .c21-link {
198
148
  text-decoration: underline;
199
149
  padding: 8px;
@@ -224,11 +174,17 @@
224
174
  height: 100%;
225
175
  }
226
176
 
177
+
178
+ //__________START: HEADER ____________
227
179
  .headerPreviewMessage {
228
180
  margin-right: 16px;
229
181
  position: relative;
230
- height: 40;// height: 50;
231
- margin: 10px 0px 0px 50px;
182
+ // height: 40;// height: 50;
183
+ // margin: 10px 0px 0px 50px;
184
+ bottom: -20px;
185
+ right: -15px;
186
+ top: -15px;
187
+ z-index: 1;
232
188
  }
233
189
 
234
190
  .boxButtons {
@@ -275,6 +231,7 @@
275
231
  .buttonClose span svg {
276
232
  padding: 6px;
277
233
  }
234
+ //__________END: HEADER ____________
278
235
 
279
236
  #new_message {
280
237
  position: absolute;
@@ -1,4 +1,5 @@
1
- import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core';
1
+ import { style } from '@angular/animations';
2
+ import { AfterViewInit, Component, EventEmitter, Input, OnDestroy, OnInit, Output, SimpleChanges, ElementRef, QueryList, ViewChildren } from '@angular/core';
2
3
  import { Subscription } from 'rxjs';
3
4
  import { MessageModel } from './../../../chat21-core/models/message';
4
5
  import { EventsService } from './../../providers/events.service';
@@ -11,7 +12,7 @@ import { MIN_WIDTH_IMAGES } from 'src/app/utils/constants';
11
12
  import { ConversationModel } from 'src/chat21-core/models/conversation';
12
13
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
13
14
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
14
- import { conversationToMessage, isEmojii } from 'src/chat21-core/utils/utils-message';
15
+ import { commandToMessage, conversationToMessage, isEmojii, isFrame, isImage, isSameSender } from 'src/chat21-core/utils/utils-message';
15
16
 
16
17
 
17
18
  @Component({
@@ -21,6 +22,8 @@ import { conversationToMessage, isEmojii } from 'src/chat21-core/utils/utils-mes
21
22
  })
22
23
  export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
23
24
 
25
+ @ViewChildren("message_wrp") messageListWRP: QueryList<ElementRef>;
26
+
24
27
  @Input() conversation: ConversationModel
25
28
  @Input() baseLocation: string;
26
29
  @Input() stylesMap: Map<string, string>;
@@ -31,14 +34,17 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
31
34
  // ========= end:: sottoscrizioni ======= //
32
35
 
33
36
  isEmojii = isEmojii;
34
-
37
+ isImage = isImage;
38
+ isFrame = isFrame;
39
+
35
40
  private logger: LoggerService = LoggerInstance.getInstance();
36
41
  public fileSelected: any;
37
- public message: MessageModel;
42
+ public messages: MessageModel[] = [];
38
43
 
39
44
  constructor(
40
45
  private events: EventsService,
41
46
  public g: Globals,
47
+ private el: ElementRef
42
48
  // public conversationsService: ConversationsService
43
49
  ) { }
44
50
 
@@ -53,8 +59,14 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
53
59
  ngOnChanges(changes: SimpleChanges) {
54
60
  this.logger.debug('[LASTMESSAGE] onChanges', changes)
55
61
  if(this.conversation){
56
- this.message = conversationToMessage(this.conversation, this.g.senderId)
57
- console.log('messsageeeeeeeee', this.message)
62
+
63
+ if(this.conversation.attributes && this.conversation.attributes.commands){
64
+ this.addCommandMessage(this.conversation)
65
+ }else{
66
+ this.messages.push(conversationToMessage(this.conversation, this.g.senderId))
67
+ this.manageIframeHeight();
68
+ }
69
+ console.log('messsageeeeeeeee', this.messages)
58
70
  // if(isImage(this.conversation)){
59
71
  // this.fileSelected = Object.assign({}, this.conversation.metadata)
60
72
  // this.fileSelected = Object.assign(this.fileSelected, this.getMetadataSize(this.fileSelected))
@@ -103,6 +115,51 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
103
115
  }
104
116
 
105
117
 
118
+ addCommandMessage(conversation: ConversationModel){
119
+ const that = this;
120
+ const commands = conversation.attributes.commands;
121
+ let i=0;
122
+ function execute(command){
123
+ if(command.type === "message"){
124
+ that.messages.push(commandToMessage(command.message,that.conversation, that.g.senderId))
125
+ that.manageIframeHeight()
126
+ i += 1
127
+ if (i < commands.length) {
128
+ execute(commands[i])
129
+ }
130
+ else {
131
+ that.logger.debug('[FIREBASEConversationHandlerSERVICE] addCommandMessage --> last command executed (wait), exit')
132
+ }
133
+ }else if(command.type === "wait"){
134
+ setTimeout(function() {
135
+ i += 1
136
+ if (i < commands.length) {
137
+ execute(commands[i])
138
+ }
139
+ else {
140
+ that.logger.debug('[FIREBASEConversationHandlerSERVICE] addCommandMessage --> last command executed (send message), exit')
141
+ }
142
+ },command.time)
143
+ }
144
+ }
145
+ execute(commands[0])
146
+
147
+ }
148
+
149
+ private manageIframeHeight(){
150
+ setTimeout(() => {
151
+ if(this.messageListWRP.get(this.messages.length-1)){
152
+ let height = getComputedStyle(this.messageListWRP.get(this.messages.length-1).nativeElement).height
153
+ this.g.setWidgetPreviewContainerSize(0, +height.substring(0, height.length-2))
154
+ }
155
+ }, 50);
156
+ }
157
+ isSameSender(senderId: string, index: number){
158
+ return isSameSender(this.messages, senderId, index)
159
+ }
160
+
161
+
162
+
106
163
 
107
164
  // ========= begin:: event emitter function ============//
108
165
 
@@ -136,6 +193,7 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
136
193
  ngOnDestroy() {
137
194
  this.conversation = null;
138
195
  this.g.isOpenNewMessage = false;
196
+ this.messages = []
139
197
  // this.logger.debug('4 isOpenNewMessage: ' + this.g.isOpenNewMessage);
140
198
  //this.unsubscribe();
141
199
  }
@@ -11,17 +11,6 @@
11
11
  // -webkit-animation: heartbeat 1.5s ease-in-out both;
12
12
  // animation: heartbeat 1.5s ease-in-out both;
13
13
 
14
- // p {
15
- // font-size: 1.4em;
16
- // margin: 0;
17
- // padding: 14px;
18
- // font-style: normal;
19
- // letter-spacing: normal;
20
- // font-stretch: normal;
21
- // font-variant: normal;
22
- // font-weight: 300;
23
- // overflow: hidden;
24
- // }
25
14
 
26
15
  .message_sender_fullname{
27
16
  font-size: 12px;
@@ -37,18 +26,4 @@
37
26
  height: auto;
38
27
  object-fit: cover;
39
28
  }
40
- .message_innerhtml {
41
- margin: 0px;
42
- // padding: 0px 14px;
43
- &.marked{
44
- padding:8px;
45
- margin-block-start: -1em!important;
46
- margin-block-end: -1em!important;
47
- }
48
-
49
- .text-message {
50
- padding-top: 14px;
51
- }
52
- }
53
-
54
29
  }
@@ -5,8 +5,8 @@
5
5
  // padding: 0px 14px;
6
6
  &.marked{
7
7
  padding:8px;
8
- margin-block-start: -1em!important;
9
- margin-block-end: -1em!important;
8
+ margin-block-start: 0em!important;
9
+ margin-block-end: 0em!important;
10
10
  }
11
11
 
12
12
  .text-message {
@@ -25,8 +25,14 @@ p {
25
25
  font-variant: normal;
26
26
  font-weight: 300;
27
27
  overflow: hidden;
28
+
28
29
  }
29
30
 
30
31
  p ::ng-deep a {
31
32
  word-break: break-word;
33
+ }
34
+
35
+ p ::ng-deep p{
36
+ margin-block-end: 0em;
37
+ margin-block-start: 0em
32
38
  }
@@ -1,3 +1,4 @@
1
+ import { style } from '@angular/animations';
1
2
  import { Injectable } from '@angular/core';
2
3
  import { BehaviorSubject } from 'rxjs';
3
4
  import { environment } from '../../environments/environment';
@@ -586,6 +587,16 @@ export class Globals {
586
587
  }
587
588
  }
588
589
 
590
+ setWidgetPreviewContainerSize(width: number, height: number){
591
+ const divTiledeskWidget = this.windowContext.document.querySelector('.messagePreview');
592
+
593
+ let headerPadding = 10
594
+ let style = getComputedStyle(divTiledeskWidget)
595
+ // console.log('computedddd', style.getPropertyValue('--messagePreviewHeight'))
596
+ let currentHeight = +style.getPropertyValue('--messagePreviewHeight').substring(0, style.getPropertyValue('--messagePreviewHeight').length -2)
597
+ this.windowContext.document.documentElement.style.setProperty('--messagePreviewHeight', currentHeight + height + headerPadding + 'px');
598
+ }
599
+
589
600
 
590
601
  /**
591
602
  *
@@ -916,6 +916,22 @@
916
916
  window.Tiledesk('restart')
917
917
  }
918
918
 
919
+ function onClickMobileMarginX(){
920
+ let text = document.getElementById('mobileMarginX').value
921
+ text === ""? text= '100px': text
922
+ window.tiledeskSettings['mobileMarginX'] = text
923
+ console.log('onClickMobileMarginX:',window.tiledeskSettings);
924
+ window.Tiledesk('restart')
925
+ }
926
+
927
+ function onClickMobileMarginY(){
928
+ let text = document.getElementById('mobileMarginY').value
929
+ text === ""? text= '50px' : text //set default value if user not write a value
930
+ window.tiledeskSettings['mobileMarginY'] = text
931
+ console.log('onClickMobileMarginY:',window.tiledeskSettings);
932
+ window.Tiledesk('restart')
933
+ }
934
+
919
935
  function onClickAutoStart(){
920
936
  let status = document.querySelector('input[name="autoStart"]:checked').value
921
937
  window.tiledeskSettings['autoStart'] = stringToBoolean(status)
@@ -1816,6 +1832,24 @@
1816
1832
  <button class="btn btn-light" onclick="onClickMarginY()">Test this setting <i class="fa fa-magic" aria-hidden="true"></i></button>
1817
1833
  </div>
1818
1834
  </div>
1835
+ <div class="row">
1836
+ <div class="col-md-5 formElement"><span><em><strong>mobileMarginX</strong></em></span></div>
1837
+ <div class="col-md-5 formElement">
1838
+ <input class="form-control col-sm-2" type="text" id="mobileMarginX" name="mobileMarginX" placeholder="Ex. 100px, 1em">
1839
+ </div>
1840
+ <div class="col-md-2">
1841
+ <button class="btn btn-light" onclick="onClickMobileMarginX()">Test this setting <i class="fa fa-magic" aria-hidden="true"></i></button>
1842
+ </div>
1843
+ </div>
1844
+ <div class="row">
1845
+ <div class="col-md-5 formElement"><span><em><strong>mobileMarginY</strong></em></span></div>
1846
+ <div class="col-md-5 formElement">
1847
+ <input class="form-control col-sm-2" type="text" id="mobileMarginY" name="mobileMarginY" placeholder="Ex. 100px, 1em">
1848
+ </div>
1849
+ <div class="col-md-2 ">
1850
+ <button class="btn btn-light" onclick="onClickMobileMarginY()">Test this setting <i class="fa fa-magic" aria-hidden="true"></i></button>
1851
+ </div>
1852
+ </div>
1819
1853
  <div class="row">
1820
1854
  <div class="col-md-5 formElement"><span><em><strong>autoStart</strong></em></span></div>
1821
1855
  <div class="col-md-5">
@@ -299,7 +299,7 @@ export class FirebaseConversationHandler extends ConversationHandlerService {
299
299
  private messageGenerate(childSnapshot: any) {
300
300
  const msg: MessageModel = childSnapshot.val();
301
301
  msg.uid = childSnapshot.key;
302
- msg.text = msg.text.trim() //remove black msg with only spaces
302
+ if(msg.text) msg.text = msg.text.trim(); //remove black msg with only spaces
303
303
  // controllo fatto per i gruppi da rifattorizzare
304
304
  if (!msg.sender_fullname || msg.sender_fullname === 'undefined') {
305
305
  msg.sender_fullname = msg.sender;
@@ -297,7 +297,7 @@ export class MQTTConversationHandler extends ConversationHandlerService {
297
297
  this.logger.log("[MQTTConversationHandlerSERVICE] childSnapshot >" + JSON.stringify(childSnapshot));
298
298
  const msg = childSnapshot;
299
299
  // msg.uid = childSnapshot.key;
300
- msg.text = msg.text.trim() //remove black msg with only spaces
300
+ if(msg.text) msg.text = msg.text.trim(); //remove black msg with only spaces
301
301
  // controllo fatto per i gruppi da rifattorizzare
302
302
  if (!msg.sender_fullname || msg.sender_fullname === 'undefined') {
303
303
  msg.sender_fullname = msg.sender;
@@ -1,4 +1,3 @@
1
- import { convertMessage } from 'src/app/utils/utils';
2
1
  import { MessageModel } from './../models/message';
3
2
  import { ConversationModel } from './../models/conversation';
4
3
  import { v4 as uuidv4 } from 'uuid';
@@ -11,28 +10,12 @@ import {
11
10
  TYPE_SUPPORT_GROUP
12
11
  } from '../../chat21-core/utils/constants';
13
12
 
14
- /** */
15
- export function isFirstMessage(i: number) {
16
- if ( i > 0 ) {
17
- try {
18
- const message = this.messages[i];
19
- const prevMessage = this.messages[ i - 1 ];
20
- if (prevMessage.sender !== message.sender || message.headerDate || (prevMessage && this.isInfo(prevMessage))) {
21
- return true;
22
- }
23
- return false;
24
- } catch (err) {
25
- console.log('error: ', err);
26
- }
27
- }
28
- }
29
-
30
13
  /** */
31
14
  export function isImage(message: any) {
32
- if (message && message.type && message.metadata && message.metadata.src && message.type === 'image') {
33
- return true;
34
- }
35
- return false;
15
+ if (message && message.type && message.metadata && message.metadata.src && message.type === 'image') {
16
+ return true;
17
+ }
18
+ return false;
36
19
  }
37
20
 
38
21
  export function isFrame(message: any) {
@@ -85,6 +68,28 @@ export function isSender(sender: string, currentUserId: string) {
85
68
  }
86
69
  }
87
70
 
71
+ export function isSameSender(messages, senderId, index):boolean{
72
+ if(senderId && messages[index - 1] && (senderId === messages[index - 1].sender)){
73
+ return true;
74
+ }
75
+ return false;
76
+ }
77
+
78
+ export function isLastMessage(messages, idMessage):boolean {
79
+ if (idMessage === messages[messages.length - 1].uid) {
80
+ return true;
81
+ }
82
+ return false;
83
+ }
84
+
85
+ export function isFirstMessage(messages, senderId, index):boolean{
86
+ if(senderId && index == 0 && messages[index] && (messages[index] !== senderId)){
87
+ return true;
88
+ }
89
+ return false;
90
+ }
91
+
92
+
88
93
  /** */
89
94
  export function messageType(msgType: string, message: any) {
90
95
 
@@ -194,6 +199,18 @@ export function hideInfoMessage(msg, infoMessageKeyEnabled): boolean{
194
199
  return true
195
200
  }
196
201
 
202
+ export function getProjectIdSelectedConversation(conversationWith: string): string{
203
+ const conversationWith_segments = conversationWith.split('-')
204
+ // Removes the last element of the array if is = to the separator
205
+ if (conversationWith_segments[conversationWith_segments.length - 1] === '') {
206
+ conversationWith_segments.pop()
207
+ }
208
+ let projectId = ''
209
+ if (conversationWith_segments.length >= 4) {
210
+ projectId = conversationWith_segments[2]
211
+ }
212
+ return projectId
213
+ }
197
214
 
198
215
  export function conversationToMessage(conversation: ConversationModel, currentUserId: string): MessageModel{
199
216
  let message: any = {}
@@ -213,3 +230,22 @@ export function conversationToMessage(conversation: ConversationModel, currentUs
213
230
 
214
231
  return message as MessageModel
215
232
  }
233
+
234
+ export function commandToMessage(msg: MessageModel, conversation: ConversationModel, currentUserId: string): MessageModel{
235
+ let message: any = {}
236
+ message.uid = conversation['message_id']? conversation['message_id'] : uuidv4()
237
+ message.text = msg.text? msg.text.trim(): '';
238
+ message.sender = conversation.sender
239
+ message.sender_fullname = conversation.sender_fullname
240
+ message.recipient = conversation.recipient
241
+ message.recipient_fullname = conversation.recipient_fullname
242
+ message.status = +conversation.status
243
+ message.timestamp = conversation.timestamp
244
+ message.metadata = msg['metadata']
245
+ message.channel_type = conversation.channel_type
246
+ message.type = msg.type
247
+ message.isSender = isSender(message.sender, currentUserId)
248
+ message.attributes = { ...conversation.attributes, ...msg.attributes}
249
+
250
+ return message as MessageModel
251
+ }
@@ -1,3 +1,7 @@
1
+ :root{
2
+ --messagePreviewHeight: 100px;
3
+ }
4
+
1
5
  #tiledesk-container {
2
6
  position: fixed;
3
7
  right: 0px;
@@ -69,8 +73,8 @@
69
73
  max-width: 400px;
70
74
  }
71
75
  #tiledesk-container.closed #tiledeskdiv.messagePreview {
72
- width: 375px; /*340px*/
73
- height: 440px; /*300px*/
76
+ width: 340px; /*340px*/
77
+ height: var(--messagePreviewHeight); /*300px*/
74
78
  min-width: 340px;
75
79
  }
76
80
 
package/src/launch.js CHANGED
@@ -152,7 +152,19 @@ function loadIframe(tiledeskScriptBaseLocation) {
152
152
  var httpRequest = createCORSRequest('POST', event_data.detail.appConfigs.apiUrl+event_data.detail.default_settings.projectid+'/events',true); //set async to false because loadParams must return when the get is complete
153
153
  httpRequest.setRequestHeader('Content-type', 'application/json');
154
154
  httpRequest.setRequestHeader('Authorization',tiledeskToken);
155
- httpRequest.send(JSON.stringify({"name":"new_conversation","attributes": {"request_id":event_data.detail.newConvId, "department": event_data.detail.global.departmentSelected.id, "participants": event_data.detail.global.participants, "language": event_data.detail.global.lang, "subtype":"info", "fullname":event_data.detail.global.attributes.userFullname, "email":event_data.detail.global.attributes.userEmail, "attributes":event_data.detail.global.attributes}}));
155
+ httpRequest.send(JSON.stringify({ "name":"new_conversation",
156
+ "attributes": {
157
+ "request_id":event_data.detail.newConvId,
158
+ "department": event_data.detail.global.departmentSelected.id,
159
+ "participants": event_data.detail.global.participants,
160
+ "language": event_data.detail.global.lang,
161
+ "subtype":"info",
162
+ "fullname":event_data.detail.global.attributes.userFullname,
163
+ "email":event_data.detail.global.attributes.userEmail,
164
+ "attributes":event_data.detail.global.attributes
165
+ }
166
+ }
167
+ ));
156
168
  }
157
169
  });
158
170