@chat21/chat21-ionic 3.0.95 → 3.0.96-rc.2

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 (44) hide show
  1. package/.github/workflows/docker-community-push-latest.yml +1 -1
  2. package/.github/workflows/docker-image-tag-community-tag-push.yml +1 -1
  3. package/CHANGELOG.md +9 -0
  4. package/package.json +1 -1
  5. package/src/app/app.module.ts +4 -3
  6. package/src/app/chatlib/conversation-detail/conversation-content/conversation-content.component.ts +18 -15
  7. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.scss +0 -7
  8. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.ts +0 -1
  9. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.scss +0 -15
  10. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.ts +0 -1
  11. package/src/app/chatlib/conversation-detail/message/text/text.component.scss +7 -2
  12. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.html +5 -0
  13. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.scss +7 -0
  14. package/src/app/components/conversation-detail/message-text-area/message-text-area.component.ts +1 -1
  15. package/src/app/components/navbar/navbar.component.ts +1 -1
  16. package/src/app/pages/conversation-detail/conversation-detail.page.ts +39 -25
  17. package/src/app/services/websocket/websocket.service.ts +3 -3
  18. package/src/assets/i18n/ar.json +1 -0
  19. package/src/assets/i18n/az.json +1 -0
  20. package/src/assets/i18n/de.json +1 -0
  21. package/src/assets/i18n/en.json +1 -0
  22. package/src/assets/i18n/es.json +1 -0
  23. package/src/assets/i18n/fr.json +1 -0
  24. package/src/assets/i18n/it.json +1 -0
  25. package/src/assets/i18n/kk.json +1 -0
  26. package/src/assets/i18n/pt.json +1 -0
  27. package/src/assets/i18n/ru.json +1 -0
  28. package/src/assets/i18n/sr.json +1 -0
  29. package/src/assets/i18n/sv.json +1 -0
  30. package/src/assets/i18n/tr.json +1 -0
  31. package/src/assets/i18n/uk.json +1 -0
  32. package/src/assets/i18n/uz.json +1 -0
  33. package/src/assets/js/chat21client.js +5 -1
  34. package/src/chat21-core/providers/abstract/archivedconversations-handler.service.ts +5 -5
  35. package/src/chat21-core/providers/abstract/conversation-handler.service.ts +6 -6
  36. package/src/chat21-core/providers/abstract/conversations-handler.service.ts +6 -7
  37. package/src/chat21-core/providers/abstract/groups-handler.service.ts +5 -5
  38. package/src/chat21-core/providers/abstract/messagingAuth.service.ts +2 -2
  39. package/src/chat21-core/providers/abstract/presence.service.ts +3 -2
  40. package/src/chat21-core/providers/abstract/typing.service.ts +2 -2
  41. package/src/chat21-core/providers/abstract/upload.service.ts +1 -1
  42. package/src/chat21-core/providers/firebase/firebase-presence.service.ts +4 -0
  43. package/src/chat21-core/providers/mqtt/mqtt-presence.service.ts +25 -16
  44. package/src/chat21-core/utils/utils-message.ts +69 -16
@@ -14,7 +14,7 @@ jobs:
14
14
  steps:
15
15
  - uses: actions/checkout@v2
16
16
  name: Check out the repo
17
- - uses: docker/build-push-action@v2
17
+ - uses: docker/build-push-action@v1
18
18
  with:
19
19
  username: ${{ secrets.DOCKERHUB_USERNAME }}
20
20
  password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -13,7 +13,7 @@ jobs:
13
13
  - name: Check out the repo
14
14
  uses: actions/checkout@v2
15
15
  - name: Push to Docker Hub
16
- uses: docker/build-push-action@v2
16
+ uses: docker/build-push-action@v1
17
17
  with:
18
18
  username: ${{ secrets.DOCKERHUB_USERNAME }}
19
19
  password: ${{ secrets.DOCKERHUB_TOKEN }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # chat21-ionic ver 3.0
2
2
 
3
+ ### 3.0.96-rc.2
4
+ - changed: chat21client.js to v0.1.12.5 (window scope fixed)
5
+
6
+ ### 3.0.96-rc.1
7
+ - added: isFirstMessage, isSameSender, isLastMessage, isFirstMessage function to utils-message
8
+ - added: online/offline status check for offline automatic email -> presence service impl
9
+ - added: websocket as mqtt-presence service dep
10
+ - added: tip message if lead has an email and is offline, when agent is on chat section in conversation-detail footer component
11
+
3
12
  ### 3.0.95 in PROD
4
13
  - bug-fixed: cannot upload PDF files
5
14
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@chat21/chat21-ionic",
3
3
  "author": "Tiledesk SRL",
4
- "version": "3.0.95",
4
+ "version": "3.0.96-rc.2",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -29,6 +29,7 @@ import { CHAT_ENGINE_MQTT, CHAT_ENGINE_FIREBASE, UPLOAD_ENGINE_NATIVE } from '..
29
29
  // SERVICES
30
30
  import { AppConfigProvider } from './services/app-config';
31
31
  import { EventsService } from './services/events-service';
32
+ import { WebsocketService } from './services/websocket/websocket.service';
32
33
 
33
34
  // ABSTRACT SERVICES
34
35
  import { MessagingAuthService } from 'src/chat21-core/providers/abstract/messagingAuth.service';
@@ -197,10 +198,10 @@ export function typingFactory(appConfig: AppConfigProvider) {
197
198
  }
198
199
  }
199
200
 
200
- export function presenceFactory(appConfig: AppConfigProvider) {
201
+ export function presenceFactory(chat21Service: Chat21Service, appConfig: AppConfigProvider, webSockerService: WebsocketService) {
201
202
  const config = appConfig.getConfig()
202
203
  if (config.chatEngine === CHAT_ENGINE_MQTT) {
203
- return new MQTTPresenceService();
204
+ return new MQTTPresenceService(chat21Service, webSockerService)
204
205
  } else {
205
206
  return new FirebasePresenceService();
206
207
  }
@@ -317,7 +318,7 @@ const appInitializerFn = (appConfig: AppConfigProvider, logger: NGXLogger) => {
317
318
  {
318
319
  provide: PresenceService,
319
320
  useFactory: presenceFactory,
320
- deps: [AppConfigProvider]
321
+ deps: [Chat21Service, AppConfigProvider, WebsocketService]
321
322
  },
322
323
  {
323
324
  provide: TypingService,
@@ -5,7 +5,7 @@ import { MSG_STATUS_SENT, MSG_STATUS_RETURN_RECEIPT, MSG_STATUS_SENT_SERVER, MAX
5
5
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
6
6
  import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
7
7
  import { UploadService } from 'src/chat21-core/providers/abstract/upload.service';
8
- import { isEmojii, isInfo, isMine, messageType } from 'src/chat21-core/utils/utils-message';
8
+ import { isEmojii, isFirstMessage, isInfo, isLastMessage, isMine, isSameSender, messageType } from 'src/chat21-core/utils/utils-message';
9
9
  @Component({
10
10
  selector: 'tiledeskwidget-conversation-content',
11
11
  templateUrl: './conversation-content.component.html',
@@ -255,26 +255,29 @@ export class ConversationContentComponent implements OnInit {
255
255
  }, showDelay);
256
256
  }
257
257
 
258
- isLastMessage(idMessage: string) {
259
- // console.log('idMessage: ' + idMessage + 'id LAST Message: ' + this.messages[this.messages.length - 1].uid);
260
- if (idMessage === this.messages[this.messages.length - 1].uid) {
261
- return true;
262
- }
263
- return false;
258
+ isLastMessage(idMessage: string):boolean {
259
+ return isLastMessage(this.messages, idMessage)
260
+ // if (idMessage === this.messages[this.messages.length - 1].uid) {
261
+ // return true;
262
+ // }
263
+ // return false;
264
264
  }
265
265
 
266
266
  isSameSender(senderId, index):boolean{
267
- if(senderId && this.messages[index - 1] && (senderId === this.messages[index - 1].sender)){
268
- return true;
269
- }
270
- return false;
267
+ return isSameSender(this.messages, senderId, index)
268
+ // if(senderId && this.messages[index - 1] && (senderId === this.messages[index - 1].sender)){
269
+ // return true;
270
+ // }
271
+ // return false;
271
272
  }
272
273
 
274
+
273
275
  isFirstMessage(senderId, index):boolean{
274
- if(senderId && index == 0 && this.messages[index] && (this.messages[index] !== senderId)){
275
- return true;
276
- }
277
- return false;
276
+ return isFirstMessage(this.messages, senderId, index)
277
+ // if(senderId && index == 0 && this.messages[index] && (this.messages[index] !== senderId)){
278
+ // return true;
279
+ // }
280
+ // return false;
278
281
  }
279
282
 
280
283
  hideOutsideElements() {
@@ -2,13 +2,6 @@
2
2
  color: lightblue;
3
3
  }
4
4
 
5
- :host .base_sent .msg_sent ::ng-deep div > div > div > chat-text > p > p {
6
- margin-top: 12px !important;
7
- // white-space: nowrap;
8
- // overflow: hidden;
9
- // text-overflow: ellipsis;
10
- }
11
-
12
5
  :host .base_sent .msg_sent ::ng-deep > div > div > chat-image > div {
13
6
  // display: none !important;
14
7
  // border-radius: unset !important;
@@ -50,7 +50,6 @@ export class IonConversationDetailComponent extends ConversationContentComponent
50
50
 
51
51
  isMine = isMine;
52
52
  isInfo = isInfo;
53
- isFirstMessage = isFirstMessage;
54
53
  messageType = messageType;
55
54
  isChannelTypeGroup = isChannelTypeGroup;
56
55
  isEmojii = isEmojii;
@@ -83,21 +83,6 @@
83
83
  height: auto;
84
84
  object-fit: cover;
85
85
  }
86
-
87
- .message_innerhtml {
88
- margin: 0px;
89
- // padding: 0px 14px;
90
- &.marked {
91
- padding: 8px;
92
- margin-block-start: -1em !important;
93
- margin-block-end: -1em !important;
94
- }
95
-
96
- .text-message {
97
- padding-top: 14px;
98
- }
99
- }
100
-
101
86
  }
102
87
  // > .button-native
103
88
 
@@ -105,7 +105,6 @@ export class BubbleMessageComponent implements OnInit, OnChanges {
105
105
  }
106
106
  if(this.message && this.message.sender_fullname && this.message.sender_fullname.trim() !== ''){
107
107
  this.fullnameColor = getColorBck(this.message.sender_fullname)
108
- console.log('colorrrrrr', this.fullnameColor)
109
108
  }
110
109
  }
111
110
 
@@ -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
  a {
12
12
  word-break: break-all
@@ -31,4 +31,9 @@ p ::ng-deep a {
31
31
  word-break: break-word
32
32
  }
33
33
 
34
+ p ::ng-deep p{
35
+ margin-block-end: 0em;
36
+ margin-block-start: 0em
37
+ }
38
+
34
39
 
@@ -14,6 +14,11 @@
14
14
  {{translationMap.get('LABEL_EMAIL')}}
15
15
  </ion-button>
16
16
  </div>
17
+
18
+ <div *ngIf="section==='chat' && messageString && leadInfo?.presence['status']==='offline'" class="section-option offline-lead-tip" >
19
+ {{translationMap.get('EMAIL_OFFLINE_TIP')}}
20
+ </div>
21
+
17
22
  </div>
18
23
 
19
24
  <ion-row id="message-email" [style.display]="section==='email'? 'flex': 'none'">
@@ -33,6 +33,13 @@
33
33
  }
34
34
  }
35
35
  }
36
+
37
+ .offline-lead-tip{
38
+ font-size: 12px;
39
+ width: 100%;
40
+ display: block;
41
+ text-align: right;
42
+ }
36
43
  }
37
44
 
38
45
  #message-email{
@@ -48,7 +48,7 @@ export class MessageTextAreaComponent implements OnInit, AfterViewInit, OnChange
48
48
  @Input() tagsCannedCount: number;
49
49
  @Input() areVisibleCAR: boolean;
50
50
  @Input() supportMode: boolean;
51
- @Input() leadInfo: {lead_id: string, hasEmail: boolean, email: string, projectId: string};
51
+ @Input() leadInfo: {lead_id: string, hasEmail: boolean, email: string, projectId: string, presence: {}};
52
52
  @Input() fileUploadAccept: string;
53
53
  @Input() emailSection: boolean;
54
54
  @Input() isOpenInfoConversation: boolean;
@@ -21,7 +21,7 @@ export class NavbarComponent implements OnInit {
21
21
  private logger: LoggerService = LoggerInstance.getInstance();
22
22
  private tiledeskToken: string;
23
23
 
24
- public projects: Project[];
24
+ public projects: Project[] = [];
25
25
  public project: any = [];
26
26
  private USER_ROLE: string;
27
27
 
@@ -84,6 +84,7 @@ import { TiledeskService } from '../../services/tiledesk/tiledesk.service'
84
84
  import { NetworkService } from '../../services/network-service/network.service'
85
85
  import { EventsService } from '../../services/events-service'
86
86
  import { ScrollbarThemeDirective } from 'src/app/utils/scrollbar-theme.directive'
87
+ import { WebsocketService } from 'src/app/services/websocket/websocket.service';
87
88
 
88
89
  @Component({
89
90
  selector: 'app-conversation-detail',
@@ -114,7 +115,6 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
114
115
  public groupDetail: GroupModel
115
116
  public messageSelected: any
116
117
  public channelType: string
117
- public leadIsOnline: boolean
118
118
  public lastConnectionDate: string
119
119
  public showMessageWelcome: boolean
120
120
  public openInfoConversation = false
@@ -126,7 +126,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
126
126
  public translationsHeaderMap: Map<string, string> = new Map()
127
127
  public translationsContentMap: Map<string, string> = new Map()
128
128
  public conversationAvatar: any
129
- public leadInfo: {lead_id: string, hasEmail: boolean , email: string, projectId: string};
129
+ public leadInfo: {lead_id: string, hasEmail: boolean , email: string, projectId: string, presence: {}};
130
130
  public liveInfo: {sourcePage: string, sourceTitle: string}
131
131
  public member: UserModel
132
132
  public isFileSelected: boolean
@@ -230,6 +230,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
230
230
  public tiledeskService: TiledeskService,
231
231
  private networkService: NetworkService,
232
232
  private events: EventsService,
233
+ private webSocketService: WebsocketService,
233
234
  private sanitizer: DomSanitizer
234
235
  ) {
235
236
  // Change list on date change
@@ -626,6 +627,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
626
627
 
627
628
  "LABEL_CHAT",
628
629
  "LABEL_EMAIL",
630
+ "EMAIL_OFFLINE_TIP",
629
631
  "EMAIL_PLACEHOLDER",
630
632
  "EMAIL_NOT_FOUND_PLACEHOLDER",
631
633
  "SUBJECT",
@@ -917,8 +919,17 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
917
919
  this.tiledeskService.getRequest(this.conversationWith, projectId, tiledeskToken).subscribe((request: any)=>{
918
920
  that.logger.debug('[CONVS-DETAIL] getLeadDetail - selected REQUEST detail', request)
919
921
  if(request.lead && request.lead.email){
920
- that.leadInfo = {lead_id: request.lead.lead_id, hasEmail: true, email: request.lead.email, projectId: projectId}
922
+ that.leadInfo = {
923
+ lead_id: request.lead.lead_id,
924
+ hasEmail: true,
925
+ email: request.lead.email,
926
+ projectId: projectId,
927
+ presence: {
928
+ status: 'offline'
929
+ }
930
+ }
921
931
  that.presenceService.userIsOnline(this.leadInfo.lead_id);
932
+ that.webSocketService.subscribeToWS_RequesterPresence(projectId, that.leadInfo.lead_id)
922
933
  }
923
934
  }, (error)=>{
924
935
  this.logger.error('[CONVS-DETAIL] - getLeadDetail - GET REQUEST DETAIL - ERROR ', error)
@@ -1022,29 +1033,29 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1022
1033
 
1023
1034
  if ((msg && msg.trim() !== '') || type !== TYPE_MSG_TEXT) {
1024
1035
 
1025
- //FIX TEMPORARY
1026
- this.leadIsOnline = true;
1027
1036
 
1028
- if(this.isEmailEnabled && !this.leadIsOnline && this.leadInfo && this.leadInfo.email && !emailSectionMsg){
1037
+ if(this.isEmailEnabled &&
1038
+ this.leadInfo && this.leadInfo.presence && this.leadInfo.presence['status']=== 'offline' &&
1039
+ this.leadInfo.email && !emailSectionMsg){
1029
1040
  this.logger.log('[CONVS-DETAIL] - SEND MESSAGE --> SENDING EMAIL', msg, this.leadInfo.email)
1030
- // this.sendEmail(msg).subscribe(status => {
1031
- // if(status){
1032
- // //SEND MESSAGE ALSO AS EMAIL
1033
- // attributes['channel']= 'offline_'+TYPE_MSG_EMAIL
1034
- // }
1035
-
1036
- // this.conversationHandlerService.sendMessage(
1037
- // msg,
1038
- // type,
1039
- // metadata,
1040
- // this.conversationWith,
1041
- // this.conversationWithFullname,
1042
- // this.loggedUser.uid,
1043
- // fullname,
1044
- // this.channelType,
1045
- // attributes,
1046
- // )
1047
- // })
1041
+ this.sendEmail(msg).subscribe(status => {
1042
+ if(status){
1043
+ //SEND MESSAGE ALSO AS EMAIL
1044
+ attributes['channel']= 'offline_'+TYPE_MSG_EMAIL
1045
+ }
1046
+
1047
+ this.conversationHandlerService.sendMessage(
1048
+ msg,
1049
+ type,
1050
+ metadata,
1051
+ this.conversationWith,
1052
+ this.conversationWithFullname,
1053
+ this.loggedUser.uid,
1054
+ fullname,
1055
+ this.channelType,
1056
+ attributes,
1057
+ )
1058
+ })
1048
1059
  }else {
1049
1060
  //send STANDARD TEXT MESSAGE
1050
1061
  this.conversationHandlerService.sendMessage(
@@ -1147,7 +1158,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1147
1158
  const userId = data.uid;
1148
1159
  const isOnline = data.isOnline;
1149
1160
  if (this.leadInfo && this.leadInfo.lead_id === userId) {
1150
- this.leadIsOnline = isOnline;
1161
+ this.leadInfo.presence['status'] = isOnline? 'online': 'offline';
1151
1162
  }
1152
1163
  }
1153
1164
  });
@@ -1243,6 +1254,9 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1243
1254
  subscription.value.unsubscribe() // vedere come fare l'unsubscribe!!!!
1244
1255
  })
1245
1256
  this.subscriptions = []
1257
+ if(this.leadInfo){
1258
+ this.webSocketService.unsubscribeToWS_RequesterPresence(this.leadInfo.projectId, this.leadInfo.lead_id)
1259
+ }
1246
1260
 
1247
1261
  // https://www.w3schools.com/jsref/met_element_removeeventlistener.asp
1248
1262
  window.removeEventListener('keyboardWillShow', null)
@@ -307,19 +307,19 @@ export class WebsocketService {
307
307
  this.webSocketJs.ref(path, 'subscribeToWS_RequesterPresence',
308
308
 
309
309
  function (data, notification) {
310
- // self.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - CREATE data ", data);
310
+ // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - CREATE data ", data);
311
311
 
312
312
  self.wsRequesterStatus$.next(data);
313
313
 
314
314
  }, function (data, notification) {
315
- self.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - UPDATE data ", data);
315
+ // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - UPDATE data ", data);
316
316
 
317
317
  self.wsRequesterStatus$.next(data);
318
318
 
319
319
  }, function (data, notification) {
320
320
 
321
321
  if (data) {
322
- // self.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - ON-DATA data ", data);
322
+ // this.logger.log("[WS-REQUESTS-SERV] - SUBSCRIBE TO REQUESTER-PRECENCE - ON-DATA data ", data);
323
323
  }
324
324
  }
325
325
  );
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "إرسال",
25
25
  "LABEL_CHAT":"دردشة",
26
+ "EMAIL_OFFLINE_TIP":"تحذير: المستخدم غير متصل! سيتم إرسال الرسالة عبر البريد الإلكتروني",
26
27
  "EMAIL_PLACEHOLDER":"المسودة متاحة هنا - انقر للتعديل",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"لم يقدم هذا المستخدم عنوان بريد إلكتروني. قم بتحديث عنوان الزائر لإرسال بريد إلكتروني",
28
29
  "SUBJECT":"موضوعات",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Göndər",
25
25
  "LABEL_CHAT":"Söhbət",
26
+ "EMAIL_OFFLINE_TIP":"Xəbərdarlıq: istifadəçi oflayndır! Mesaj e-poçt vasitəsilə göndəriləcək",
26
27
  "EMAIL_PLACEHOLDER":"Qaralama burada mövcuddur - redaktə etmək üçün klikləyin",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Bu istifadəçi e-poçt ünvanı təqdim etməyib. E-poçt göndərmək üçün ziyarətçinin ünvanını yeniləyin",
28
29
  "SUBJECT":"Mövzu",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Senden",
25
25
  "LABEL_CHAT":"Plaudern",
26
+ "EMAIL_OFFLINE_TIP":"Achtung: Benutzer ist offline! Die Nachricht wird per E-Mail versendet",
26
27
  "EMAIL_PLACEHOLDER":"Entwurf hier verfügbar - zum Bearbeiten klicken",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Dieser Benutzer hat keine E-Mail-Adresse angegeben. Aktualisieren Sie die Adresse des Besuchers, um eine E-Mail zu senden",
28
29
  "SUBJECT":"Thema",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Send",
25
25
  "LABEL_CHAT":"Chat",
26
+ "EMAIL_OFFLINE_TIP":"Warning: user is offline! The message will be sent by email",
26
27
  "EMAIL_PLACEHOLDER":"Draft available here - click to edit",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"This user has not provided an email address. Update the visitor's address to send an email",
28
29
  "SUBJECT":"Subject",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Send",
25
25
  "LABEL_CHAT":"Charla",
26
+ "EMAIL_OFFLINE_TIP":"Advertencia: ¡el usuario está desconectado! El mensaje será enviado por correo electrónico",
26
27
  "EMAIL_PLACEHOLDER":"Borrador disponible aquí - haga clic para editar",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Este usuario no ha proporcionado una dirección de correo electrónico. Actualizar la dirección del visitante para enviar un correo electrónico",
28
29
  "SUBJECT":"Sujeto",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Envoyer",
25
25
  "LABEL_CHAT":"Chatter",
26
+ "EMAIL_OFFLINE_TIP":"Attention : l'utilisateur est hors ligne ! Le message sera envoyé par email",
26
27
  "EMAIL_PLACEHOLDER":"Brouillon disponible ici - cliquez pour modifier",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Cet utilisateur n'a pas fourni d'adresse e-mail. Mettre à jour l'adresse du visiteur pour envoyer un e-mail",
28
29
  "SUBJECT":"Matière",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Invia",
25
25
  "LABEL_CHAT":"Chat",
26
+ "EMAIL_OFFLINE_TIP":"Attenzione: l'utente è offline! Il messaggio sarà mandato per email",
26
27
  "EMAIL_PLACEHOLDER":"Bozza disponibile qui - clicca per modificare",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Questo utente non ha fornito un indirizzo email. Aggiorna l'indirizzo del visitatore per inviare un'e-mail",
28
29
  "SUBJECT":"Oggetto",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Жіберу",
25
25
  "LABEL_CHAT":"Чат",
26
+ "EMAIL_OFFLINE_TIP":"Ескерту: пайдаланушы желіден тыс! Хабарлама электрондық пошта арқылы жіберіледі",
26
27
  "EMAIL_PLACEHOLDER":"Жоба осы жерде қолжетімді - өңдеу үшін басыңыз",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Бұл пайдаланушы электрондық пошта мекенжайын көрсетпеді. Электрондық поштаны жіберу үшін келушінің мекенжайын жаңартыңыз",
28
29
  "SUBJECT":"Тақырып",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Mandar",
25
25
  "LABEL_CHAT":"Bater papo",
26
+ "EMAIL_OFFLINE_TIP":"Aviso: o usuário está offline! A mensagem será enviada por e-mail",
26
27
  "EMAIL_PLACEHOLDER":"Rascunho disponível aqui - clique para editar",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Este usuário não forneceu um endereço de e-mail. Atualize o endereço do visitante para enviar um e-mail",
28
29
  "SUBJECT":"Sujeito",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Отправлять",
25
25
  "LABEL_CHAT":"Чат",
26
+ "EMAIL_OFFLINE_TIP":"Внимание: пользователь не в сети! Сообщение будет отправлено по электронной почте",
26
27
  "EMAIL_PLACEHOLDER":"Черновик доступен здесь - нажмите, чтобы изменить",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Этот пользователь не указал адрес электронной почты. Обновите адрес посетителя, чтобы отправить электронное письмо",
28
29
  "SUBJECT":"Предмет",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Пошаљи",
25
25
  "LABEL_CHAT":"Ћаскање",
26
+ "EMAIL_OFFLINE_TIP":"Упозорење: корисник није на мрежи! Порука ће бити послата е-поштом",
26
27
  "EMAIL_PLACEHOLDER":"Нацрт је доступан овде - кликните да бисте уредили",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Овај корисник није навео адресу е-поште. Ажурирајте адресу посетиоца да бисте послали е-поштуОвај корисник није навео адресу е-поште. Ажурирајте адресу посетиоца да бисте послали е-пошту",
28
29
  "SUBJECT":"Предмет",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Skicka",
25
25
  "LABEL_CHAT":"Chat",
26
+ "EMAIL_OFFLINE_TIP":"Varning: användaren är offline! Meddelandet kommer att skickas via e-post",
26
27
  "EMAIL_PLACEHOLDER":"Utkast tillgängligt här - klicka för att redigera",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Den här användaren har inte angett någon e-postadress. Uppdatera besökarens adress för att skicka ett e-postmeddelande",
28
29
  "SUBJECT":"Ämne",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Göndermek",
25
25
  "LABEL_CHAT":"Sohbet",
26
+ "EMAIL_OFFLINE_TIP":"Uyarı: kullanıcı çevrimdışı! Mesaj e-posta ile gönderilecek",
26
27
  "EMAIL_PLACEHOLDER":"Taslak burada mevcut - düzenlemek için tıklayın",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Bu kullanıcı bir e-posta adresi sağlamadı. E-posta göndermek için ziyaretçinin adresini güncelleyin",
28
29
  "SUBJECT":"Ders",
@@ -23,6 +23,7 @@
23
23
  ],
24
24
  "LABEL_SEND": "Надіслати",
25
25
  "LABEL_CHAT":"Чат",
26
+ "EMAIL_OFFLINE_TIP":"Попередження: користувач офлайн! Повідомлення буде надіслано електронною поштою",
26
27
  "EMAIL_PLACEHOLDER":"Чернетка доступна тут - натисніть, щоб змінити",
27
28
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Цей користувач не вказав адресу електронної пошти. Оновіть адресу відвідувача, щоб надіслати електронний лист",
28
29
  "SUBJECT":"Тема",
@@ -24,6 +24,7 @@
24
24
  ],
25
25
  "LABEL_SEND": "Yuborish",
26
26
  "LABEL_CHAT":"Chat",
27
+ "EMAIL_OFFLINE_TIP":"Ogohlantirish: foydalanuvchi oflayn! Xabar elektron pochta orqali yuboriladi",
27
28
  "EMAIL_PLACEHOLDER":"Qoralama bu yerda mavjud - tahrirlash uchun bosing",
28
29
  "EMAIL_NOT_FOUND_PLACEHOLDER":"Bu foydalanuvchi elektron pochta manzilini ko'rsatmagan. Elektron pochta xabarini yuborish uchun tashrif buyuruvchining manzilini yangilang",
29
30
  "SUBJECT":"Mavzu",
@@ -1,9 +1,10 @@
1
1
  /*
2
2
  Chat21Client
3
3
 
4
- v0.1.12.4
4
+ v0.1.12.5
5
5
 
6
6
  @Author Andrea Sponziello
7
+ @Member Gabriele Panico
7
8
  (c) Tiledesk 2020
8
9
  */
9
10
 
@@ -29,6 +30,9 @@ class Chat21Client {
29
30
  console.log("MQTTendpoint relative url");
30
31
  }
31
32
  var loc = window.location, new_uri;
33
+ if(window.frameElement && window.frameElement.getAttribute('tiledesk_context') === 'parent'){
34
+ loc = window.parent.location
35
+ }
32
36
  if (loc.protocol === "https:") {
33
37
  // new_uri = "wss:";
34
38
  new_uri = "mqtt:";
@@ -7,14 +7,14 @@ import { ImageRepoService } from './image-repo.service';
7
7
  export abstract class ArchivedConversationsHandlerService {
8
8
 
9
9
  // BehaviorSubject
10
- abstract BSConversationDetail: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
11
- abstract archivedConversationAdded: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
12
- abstract archivedConversationChanged: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
13
- abstract archivedConversationRemoved: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
10
+ abstract BSConversationDetail: BehaviorSubject<ConversationModel>;
11
+ abstract archivedConversationAdded: BehaviorSubject<ConversationModel>;
12
+ abstract archivedConversationChanged: BehaviorSubject<ConversationModel>;
13
+ abstract archivedConversationRemoved: BehaviorSubject<ConversationModel>;
14
14
  // abstract readAllMessages: BehaviorSubject<string> = new BehaviorSubject<string>(null);
15
15
 
16
16
  // params
17
- abstract archivedConversations: Array<ConversationModel> = [];
17
+ abstract archivedConversations: Array<ConversationModel>;
18
18
  abstract uidConvSelected: string;
19
19
  //abstract imageRepo: ImageRepoService;
20
20
 
@@ -12,15 +12,15 @@ import { UserModel } from '../../models/user';
12
12
  export abstract class ConversationHandlerService {
13
13
 
14
14
  // BehaviorSubject
15
- abstract messageAdded: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
16
- abstract messageChanged: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
17
- abstract messageRemoved: BehaviorSubject<string> = new BehaviorSubject<string>(null);
18
- abstract messageWait: BehaviorSubject<any> = new BehaviorSubject<any>(null);
19
- abstract messageInfo: BehaviorSubject<MessageModel> = new BehaviorSubject<MessageModel>(null);
15
+ abstract messageAdded: BehaviorSubject<MessageModel>;
16
+ abstract messageChanged: BehaviorSubject<MessageModel>;
17
+ abstract messageRemoved: BehaviorSubject<string>;
18
+ abstract messageWait: BehaviorSubject<any>;
19
+ abstract messageInfo: BehaviorSubject<MessageModel>;
20
20
 
21
21
  // params
22
22
  abstract attributes: any;
23
- abstract messages: Array<MessageModel> = [];
23
+ abstract messages: Array<MessageModel>;
24
24
  abstract conversationWith: string;
25
25
 
26
26
  constructor() {}
@@ -14,20 +14,19 @@ import { ConversationModel } from './../../models/conversation';
14
14
  export abstract class ConversationsHandlerService {
15
15
 
16
16
  // BehaviorSubject
17
- abstract BSConversationDetail: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
18
- abstract conversationAdded: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
19
- abstract conversationChanged: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
20
- abstract conversationChangedDetailed: BehaviorSubject<{value: ConversationModel, previousValue: ConversationModel}> = new BehaviorSubject<{value: ConversationModel, previousValue: ConversationModel}>(null);
21
- abstract conversationRemoved: BehaviorSubject<ConversationModel> = new BehaviorSubject<ConversationModel>(null);
17
+ abstract BSConversationDetail: BehaviorSubject<ConversationModel>;
18
+ abstract conversationAdded: BehaviorSubject<ConversationModel>;
19
+ abstract conversationChanged: BehaviorSubject<ConversationModel>;
20
+ abstract conversationChangedDetailed: BehaviorSubject<{value: ConversationModel, previousValue: ConversationModel}>;
21
+ abstract conversationRemoved: BehaviorSubject<ConversationModel>;
22
22
  // abstract readAllMessages: BehaviorSubject<string> = new BehaviorSubject<string>(null);
23
23
 
24
24
  // params
25
- abstract conversations: Array<ConversationModel> = [];
25
+ abstract conversations: Array<ConversationModel>;
26
26
  abstract uidConvSelected: string;
27
27
 
28
28
  // functions
29
29
  abstract initialize(tenant: string, userId: string, translationMap: Map<string, string>): void;
30
- // abstract connect(): void;
31
30
  abstract subscribeToConversations(lastConversatioTimestamp: number, callback: any): void;
32
31
  abstract countIsNew(): number;
33
32
  abstract setConversationRead(conversationId: string): void;
@@ -11,11 +11,11 @@ import { UserModel } from 'src/chat21-core/models/user';
11
11
  export abstract class GroupsHandlerService {
12
12
 
13
13
  // BehaviorSubject
14
- abstract BSgroupDetail: BehaviorSubject<GroupModel> = new BehaviorSubject<GroupModel>(null);
15
- abstract SgroupDetail: Subject<GroupModel> = new Subject<GroupModel>();
16
- abstract groupAdded: BehaviorSubject<GroupModel> = new BehaviorSubject<GroupModel>(null);
17
- abstract groupChanged: BehaviorSubject<GroupModel> = new BehaviorSubject<GroupModel>(null);
18
- abstract groupRemoved: BehaviorSubject<GroupModel> = new BehaviorSubject<GroupModel>(null);
14
+ abstract BSgroupDetail: BehaviorSubject<GroupModel>;
15
+ abstract SgroupDetail: Subject<GroupModel>;
16
+ abstract groupAdded: BehaviorSubject<GroupModel>;
17
+ abstract groupChanged: BehaviorSubject<GroupModel>;
18
+ abstract groupRemoved: BehaviorSubject<GroupModel>;
19
19
 
20
20
  abstract initialize(tenant: string, loggedUserId: string): void;
21
21
  abstract connect(): void;
@@ -12,8 +12,8 @@ import { UserModel } from '../../models/user';
12
12
  export abstract class MessagingAuthService {
13
13
 
14
14
  // BehaviorSubject
15
- abstract BSAuthStateChanged: BehaviorSubject<any> = new BehaviorSubject<any>(null);
16
- abstract BSSignOut: BehaviorSubject<any> = new BehaviorSubject<any>(null);
15
+ abstract BSAuthStateChanged: BehaviorSubject<any>;
16
+ abstract BSSignOut: BehaviorSubject<any>;
17
17
 
18
18
  // params
19
19
  public DEFAULT_PERSISTENCE: string = 'NONE';
@@ -9,8 +9,8 @@ import { environment } from 'src/environments/environment';
9
9
  export abstract class PresenceService {
10
10
 
11
11
  // BehaviorSubject
12
- abstract BSIsOnline: BehaviorSubject<any> = new BehaviorSubject<any>(null);
13
- abstract BSLastOnline: BehaviorSubject<any> = new BehaviorSubject<any>(null);
12
+ abstract BSIsOnline: BehaviorSubject<any>;
13
+ abstract BSLastOnline: BehaviorSubject<any>;
14
14
 
15
15
  // params
16
16
  // abstract tenant = environment.tenant;
@@ -30,5 +30,6 @@ export abstract class PresenceService {
30
30
  abstract userIsOnline(userid: string): Observable<any>
31
31
  abstract lastOnlineForUser(userid: string): void;
32
32
  abstract setPresence(userid: string): void;
33
+ abstract imHere():void;
33
34
  abstract removePresence(): void;
34
35
  }
@@ -9,8 +9,8 @@ import { environment } from 'src/environments/environment';
9
9
  export abstract class TypingService {
10
10
 
11
11
  // BehaviorSubject
12
- BSIsTyping: BehaviorSubject<any> = new BehaviorSubject<any>(null);
13
- BSSetTyping: BehaviorSubject<any> = new BehaviorSubject<any>(null);
12
+ abstract BSIsTyping: BehaviorSubject<any>;
13
+ abstract BSSetTyping: BehaviorSubject<any>;
14
14
 
15
15
  // params
16
16
  // private _tenant: string;
@@ -28,7 +28,7 @@ export abstract class UploadService {
28
28
  }
29
29
 
30
30
  //BehaviorSubject
31
- abstract BSStateUpload: BehaviorSubject<any> = new BehaviorSubject<any>(null);
31
+ abstract BSStateUpload: BehaviorSubject<any>;
32
32
 
33
33
  // params
34
34
  // abstract tenant = environment.tenant;
@@ -146,6 +146,10 @@ export class FirebasePresenceService extends PresenceService {
146
146
  });
147
147
  }
148
148
 
149
+ public imHere(){
150
+ //NOT IMPLEMENTED FOR FIREBASE ENGINE
151
+ }
152
+
149
153
  /**
150
154
  * removePresence
151
155
  * richiamato prima del logout
@@ -1,4 +1,4 @@
1
- import { Injectable } from '@angular/core';
1
+ import { Inject, Injectable, Optional } from '@angular/core';
2
2
  import { BehaviorSubject, Observable } from 'rxjs';
3
3
 
4
4
  // firebase
@@ -11,6 +11,7 @@ import 'firebase/database';
11
11
  import { PresenceService } from '../abstract/presence.service';
12
12
  import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
13
13
  import { LoggerInstance } from '../logger/loggerInstance';
14
+ import { Chat21Service } from './chat-service';
14
15
 
15
16
 
16
17
  @Injectable({
@@ -27,7 +28,8 @@ export class MQTTPresenceService extends PresenceService {
27
28
  private urlNodePresence: string;
28
29
  private logger: LoggerService = LoggerInstance.getInstance();
29
30
  constructor(
30
- // private events: EventsService
31
+ public chat21Service: Chat21Service,
32
+ @Optional() @Inject('webSocketService') public webSocketService?: any,
31
33
  ) {
32
34
  super();
33
35
  }
@@ -40,20 +42,20 @@ export class MQTTPresenceService extends PresenceService {
40
42
  }
41
43
 
42
44
  userIsOnline(userid: string): Observable<any> {
43
- // console.log('userIsOnline', userid);
44
- // const that = this;
45
- // const urlNodeConnections = this.urlNodePresence + userid + '/connections';
46
- // console.log('userIsOnline: ', urlNodeConnections);
47
- // const connectionsRef = firebase.database().ref().child(urlNodeConnections);
48
- // connectionsRef.on('value', (child) => {
49
- // console.log('is-online-' + userid);
50
- // if (child.val()) {
51
- // that.events.publish('is-online-' + userid, userid, true);
52
- // } else {
53
- // that.events.publish('is-online-' + userid, userid, false);
54
- // }
55
- // });
56
- return this.BSIsOnline
45
+ const that = this;
46
+ let local_BSIsOnline = new BehaviorSubject<any>(null);
47
+ this.webSocketService.wsRequesterStatus$.subscribe((data: any) => {
48
+ this.logger.log('[NATIVEPresenceSERVICE] $subs to wsService - data ', data, userid);
49
+ if (data && data.presence && data.presence.status === 'online' ) {
50
+ that.BSIsOnline.next({ uid: data.uuid_user, isOnline: true });
51
+ local_BSIsOnline.next({ uid: data.uuid_user, isOnline: true });
52
+ } else {
53
+ that.BSIsOnline.next({ uid: data.uuid_user, isOnline: false });
54
+ local_BSIsOnline.next({ uid: data.uuid_user, isOnline: false });
55
+ }
56
+ });
57
+
58
+ return local_BSIsOnline
57
59
  }
58
60
 
59
61
  lastOnlineForUser(userid: string) {
@@ -93,6 +95,13 @@ export class MQTTPresenceService extends PresenceService {
93
95
  // });
94
96
  }
95
97
 
98
+ public imHere(): void {
99
+ this.logger.debug('[MQTT-PRESENCE] imHere', this.tenant);
100
+ setTimeout(() => {
101
+ this.chat21Service.chatClient.ImHere()
102
+ }, 2000);
103
+ }
104
+
96
105
  /**
97
106
  * removePresence
98
107
  * richiamato prima del logout
@@ -1,3 +1,6 @@
1
+ import { MessageModel } from '../models/message';
2
+ import { ConversationModel } from '../models/conversation';
3
+ import { v4 as uuidv4 } from 'uuid';
1
4
  import {
2
5
  MESSAGE_TYPE_INFO,
3
6
  MESSAGE_TYPE_MINE,
@@ -7,22 +10,6 @@ import {
7
10
  TYPE_SUPPORT_GROUP
8
11
  } from '../../chat21-core/utils/constants';
9
12
 
10
- /** */
11
- export function isFirstMessage(i: number) {
12
- if (i > 0) {
13
- try {
14
- const message = this.messages[i];
15
- const prevMessage = this.messages[i - 1];
16
- if (prevMessage.sender !== message.sender || message.headerDate || (prevMessage && this.isInfo(prevMessage))) {
17
- return true;
18
- }
19
- return false;
20
- } catch (err) {
21
- console.error('error: ', err);
22
- }
23
- }
24
- }
25
-
26
13
  /** */
27
14
  export function isImage(message: any) {
28
15
  if (message && message.type && message.metadata && message.metadata.src && message.type === 'image') {
@@ -74,6 +61,27 @@ export function isSender(sender: string, currentUserId: string) {
74
61
  }
75
62
  }
76
63
 
64
+ export function isSameSender(messages, senderId, index):boolean{
65
+ if(senderId && messages[index - 1] && (senderId === messages[index - 1].sender)){
66
+ return true;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ export function isLastMessage(messages, idMessage):boolean {
72
+ if (idMessage === messages[messages.length - 1].uid) {
73
+ return true;
74
+ }
75
+ return false;
76
+ }
77
+
78
+ export function isFirstMessage(messages, senderId, index):boolean{
79
+ if(senderId && index == 0 && messages[index] && (messages[index] !== senderId)){
80
+ return true;
81
+ }
82
+ return false;
83
+ }
84
+
77
85
  /** */
78
86
  export function messageType(msgType: string, message: any) {
79
87
 
@@ -153,6 +161,13 @@ export function isEmojii(message: any){
153
161
  }
154
162
  }
155
163
 
164
+ export function isJustRecived(startedAt, time) {
165
+ if (time > startedAt) {
166
+ return true;
167
+ }
168
+ return false;
169
+ }
170
+
156
171
  export function checkIfIsMemberJoinedGroup(msg, loggedUser): boolean{
157
172
  if(msg && msg.attributes && msg.attributes.messagelabel
158
173
  && msg.attributes.messagelabel['key']=== "MEMBER_JOINED_GROUP"
@@ -186,4 +201,42 @@ export function getProjectIdSelectedConversation(conversationWith: string): stri
186
201
  return projectId
187
202
  }
188
203
 
204
+ export function conversationToMessage(conversation: ConversationModel, currentUserId: string): MessageModel{
205
+ let message: any = {}
206
+ message.uid = conversation['message_id']? conversation['message_id'] : uuidv4()
207
+ message.text = conversation.text? conversation.text.trim(): conversation.last_message_text.trim()
208
+ message.sender = conversation.sender
209
+ message.sender_fullname = conversation.sender_fullname
210
+ message.recipient = conversation.recipient
211
+ message.recipient_fullname = conversation.recipient_fullname
212
+ message.status = +conversation.status
213
+ message.timestamp = conversation.timestamp
214
+ message.metadata = conversation['metadata']
215
+ message.channel_type = conversation.channel_type
216
+ message.type = conversation.type
217
+ message.isSender = isSender(message.sender, currentUserId)
218
+ message.attributes = conversation.attributes
219
+
220
+ return message as MessageModel
221
+ }
222
+
223
+ export function commandToMessage(msg: MessageModel, conversation: ConversationModel, currentUserId: string): MessageModel{
224
+ let message: any = {}
225
+ message.uid = conversation['message_id']? conversation['message_id'] : uuidv4()
226
+ message.text = msg.text? msg.text.trim(): '';
227
+ message.sender = conversation.sender
228
+ message.sender_fullname = conversation.sender_fullname
229
+ message.recipient = conversation.recipient
230
+ message.recipient_fullname = conversation.recipient_fullname
231
+ message.status = +conversation.status
232
+ message.timestamp = conversation.timestamp
233
+ message.metadata = msg['metadata']
234
+ message.channel_type = conversation.channel_type
235
+ message.type = msg.type
236
+ message.isSender = isSender(message.sender, currentUserId)
237
+ message.attributes = conversation.attributes
238
+
239
+ return message as MessageModel
240
+ }
241
+
189
242