@chat21/chat21-ionic 3.0.78-rc.2 → 3.0.78-rc.3

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 (22) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/src/app/chatlib/conversation-detail/conversation-content/conversation-content.component.ts +8 -1
  4. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.html +20 -2
  5. package/src/app/chatlib/conversation-detail/ion-conversation-detail/ion-conversation-detail.component.scss +24 -2
  6. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.html +1 -1
  7. package/src/app/chatlib/conversation-detail/message/bubble-message/bubble-message.component.ts +3 -1
  8. package/src/app/chatlib/list-conversations-component/ion-list-conversations/ion-list-conversations.component.html +2 -2
  9. package/src/app/components/conversation-detail/header-conversation-detail/header-conversation-detail.component.html +2 -11
  10. package/src/app/components/conversation-detail/header-conversation-detail/header-conversation-detail.component.scss +1 -1
  11. package/src/app/components/conversation-detail/header-conversation-detail/header-conversation-detail.component.ts +2 -4
  12. package/src/app/components/ddp-header/ddp-header.component.html +1 -1
  13. package/src/app/components/ddp-header/ddp-header.component.scss +4 -0
  14. package/src/app/components/project-item/project-item.component.html +1 -1
  15. package/src/app/pages/conversation-detail/conversation-detail.page.html +4 -1
  16. package/src/app/pages/conversation-detail/conversation-detail.page.ts +96 -20
  17. package/src/chat21-core/providers/firebase/firebase-typing.service.ts +7 -9
  18. package/src/chat21-core/utils/constants.ts +4 -0
  19. package/src/chat21-core/utils/user-typing/user-typing.component.html +8 -5
  20. package/src/chat21-core/utils/user-typing/user-typing.component.scss +87 -17
  21. package/src/chat21-core/utils/user-typing/user-typing.component.ts +12 -94
  22. package/src/variables.scss +7 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # chat21-ionic ver 3.0
2
2
 
3
+ ### 3.0.78-rc.3
4
+ - changed: user-typing location moved from conversation-header to conversation-detail component
5
+ - changed: replace includes with startsWith for check what type of conversation is in project info conversation-list component
6
+ - added: styleMap integrations to some elements
7
+ - bug-fixed: no tooltip showed if no unserved request are present
8
+
3
9
  ### 3.0.78-rc.2
4
10
  - changed: project item UI and tooltip msg
5
11
  - changed: conversation UI in conversations list component
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.78-rc.2",
4
+ "version": "3.0.78-rc.3",
5
5
  "license": "MIT License",
6
6
  "homepage": "https://tiledesk.com/",
7
7
  "repository": {
@@ -17,11 +17,18 @@ export class ConversationContentComponent implements OnInit {
17
17
  @Input() messages: MessageModel[]
18
18
  @Input() senderId: string;
19
19
  @Input() baseLocation: string;
20
+ @Input() isConversationArchived: boolean;
21
+ @Input() isTypings: boolean;
22
+ @Input() idUserTypingNow: string;
23
+ @Input() nameUserTypingNow: string;
24
+ @Input() typingLocation: string;
25
+ @Input() fullscreenMode: boolean;
20
26
  @Input() translationMap: Map<string, string>;
21
27
  @Input() stylesMap: Map<string, string>;
22
28
  @Output() onBeforeMessageRender = new EventEmitter();
23
29
  @Output() onAfterMessageRender = new EventEmitter();
24
- @Output() onMenuOptionShow = new EventEmitter();
30
+ @Output() onMenuOptionShow = new EventEmitter<boolean>();
31
+ @Output() onEmojiiPickerShow = new EventEmitter<boolean>()
25
32
  @Output() onAttachmentButtonClicked = new EventEmitter();
26
33
  @Output() onScrollContent = new EventEmitter();
27
34
 
@@ -92,9 +92,12 @@
92
92
  <chat-bubble-message class="messages msg_sent" id="message_msg_sent" style="position: relative;"
93
93
  [ngClass]="{'has-metadata': (isImage(message) || isFrame(message)), 'privateMsg': (message?.attributes && message?.attributes?.subtype === 'private')}"
94
94
  [class.emoticon]="isEmojii(message?.text)"
95
+ [ngStyle]="{'background': stylesMap.get('bubbleSentBackground'), 'color': stylesMap.get('bubbleSentTextColor')}"
95
96
  [ngClass]="{'button-in-msg' : message.metadata && message.metadata.button}"
96
97
  [message]="message"
97
- [textColor]="'col-msg-sent'"
98
+ [fontColor]="stylesMap.get('bubbleSentTextColor')"
99
+ [fontSize]="stylesMap.get('fontSize')"
100
+ [fontFamily]="stylesMap.get('fontFamily')"
98
101
  [addAsCannedResponseTooltipText]="addAsCannedResponseTooltipText"
99
102
  [areVisibleCAR]="areVisibleCAR"
100
103
  [supportMode]="supportMode"
@@ -132,8 +135,11 @@
132
135
  <chat-bubble-message class="messages msg_receive" id="message_msg_receive" style="position: relative;"
133
136
  [ngClass]="{'has-metadata': (isImage(message) || isFrame(message)), 'privateMsg': (message?.attributes && message?.attributes?.subtype === 'private')}"
134
137
  [class.emoticon]="isEmojii(message?.text)"
138
+ [ngStyle]="{'background': stylesMap?.get('bubbleReceivedBackground'), 'color': stylesMap.get('bubbleReceivedTextColor')}"
135
139
  [message]="message"
136
- [textColor]="'black'"
140
+ [fontColor]="stylesMap?.get('bubbleReceivedTextColor')"
141
+ [fontSize]="stylesMap?.get('fontSize')"
142
+ [fontFamily]="stylesMap?.get('fontFamily')"
137
143
  [addAsCannedResponseTooltipText]="addAsCannedResponseTooltipText"
138
144
  [areVisibleCAR]="areVisibleCAR"
139
145
  [supportMode]="supportMode"
@@ -167,6 +173,18 @@
167
173
  </div>
168
174
  </div>
169
175
 
176
+ <div *ngIf="isTypings" class="msg_container base_receive typing_container">
177
+ <!-- !isSameSender(idUserTypingNow, i) -->
178
+ <!-- <div *ngIf="nameUserTypingNow">{{nameUserTypingNow}}</div> -->
179
+ <user-typing
180
+ [themeColor]="stylesMap?.get('themeColor')"
181
+ [translationMap]="translationMap"
182
+ [idUserTypingNow]="idUserTypingNow"
183
+ [nameUserTypingNow]="nameUserTypingNow">
184
+ </user-typing>
185
+ <div class="typing_info" *ngIf="nameUserTypingNow"> {{nameUserTypingNow}} {{translationMap.get('LABEL_IS_WRITING')}}</div>
186
+ </div>
187
+
170
188
  </div>
171
189
 
172
190
  <!-- fileType > {{fileType }} uploadProgress {{uploadProgress}} -->
@@ -111,6 +111,27 @@ ion-item {
111
111
  color: #080f1a;
112
112
  }
113
113
 
114
+ .typing_container{
115
+ display:flex;
116
+ align-items: center;
117
+
118
+ user-typing {
119
+ text-align: right;
120
+ }
121
+ .typing_info{
122
+ color: var(--basic-gray);
123
+ margin-left: 10px;
124
+ font-size: 12px;
125
+ animation: blinker 1s linear infinite;
126
+
127
+ @keyframes blinker {
128
+ 50% {
129
+ opacity: 0;
130
+ }
131
+ }
132
+ }
133
+ }
134
+
114
135
  .messages {
115
136
  border-radius: 18px;
116
137
  padding: 0;
@@ -187,8 +208,8 @@ ion-item {
187
208
  }
188
209
  /* message */
189
210
  .msg_receive {
190
- background-color: var(--light-white);
191
- color: #1a1a1a;
211
+ background-color: var(--bck-msg-received);
212
+ color: var(--col-msg-received);
192
213
  // max-width: 260px;
193
214
  max-width: calc(100% - 70px);
194
215
  min-width: 14px;
@@ -212,6 +233,7 @@ ion-item {
212
233
  .has-metadata {
213
234
  max-width: 100% !important;
214
235
  }
236
+
215
237
  }
216
238
 
217
239
  .time {
@@ -50,7 +50,7 @@
50
50
 
51
51
  <chat-text *ngIf="message?.type !=='html'"
52
52
  [text]="message?.text"
53
- [color]="textColor"
53
+ [color]="fontColor"
54
54
  [message]="message"
55
55
  (onBeforeMessageRender)="returnOnBeforeMessageRender($event)"
56
56
  (onAfterMessageRender)="returnOnAfterMessageRender($event)">
@@ -18,7 +18,9 @@ import { ModalController } from '@ionic/angular';
18
18
  export class BubbleMessageComponent implements OnInit, OnChanges {
19
19
 
20
20
  @Input() message: MessageModel;
21
- @Input() textColor: string;
21
+ @Input() fontColor: string;
22
+ @Input() fontSize: string;
23
+ @Input() fontFamily: string;
22
24
  @Input() areVisibleCAR: boolean;
23
25
  @Input() supportMode: boolean;
24
26
  @Output() onBeforeMessageRender = new EventEmitter();
@@ -100,12 +100,12 @@
100
100
  <span class="truncate">{{translationsMap.get('DIRECT_CHAT')}}</span>
101
101
  </div>
102
102
  <!-- GROUP CONV -->
103
- <div *ngIf="!conversation.uid.includes(TYPE_SUPPORT_GROUP) && conversation.channel_type !== TYPE_DIRECT">
103
+ <div *ngIf="conversation.uid.startsWith(TYPE_GROUP)">
104
104
  <svg xmlns="http://www.w3.org/2000/svg" height="15" width="15" viewBox="0 0 24 24" fill="#000000"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
105
105
  <span class="truncate">{{translationsMap.get('GROUP_CHAT')}}</span>
106
106
  </div>
107
107
  <!-- SUPPORT-GROUP CONV -->
108
- <div *ngIf="conversation.uid.includes(TYPE_SUPPORT_GROUP) > 0 ">
108
+ <div *ngIf="conversation.uid.startsWith(TYPE_SUPPORT_GROUP)">
109
109
  <svg xmlns="http://www.w3.org/2000/svg" data-v-78d18411="" width="15" height="15" fill="none" viewBox="0 0 24 24" class="inbox-icon"><path d="M22.002 12C22.002 6.477 17.524 2 12 2 6.476 1.999 2 6.477 2 12.001c0 5.186 3.947 9.45 9.001 9.952V20.11c-.778-.612-1.478-1.905-1.939-3.61h1.94V15H8.737a18.969 18.969 0 0 1-.135-5h6.794c.068.64.105 1.31.105 2h1.5c0-.684-.033-1.353-.095-2h3.358c.154.64.237 1.31.237 2h1.5ZM4.786 16.5h2.722l.102.396c.317 1.17.748 2.195 1.27 3.015a8.532 8.532 0 0 1-4.094-3.41ZM3.736 10h3.358a20.847 20.847 0 0 0-.095 2c0 1.043.075 2.051.217 3H4.043a8.483 8.483 0 0 1-.544-3c0-.682.08-1.347.232-1.983L3.736 10Zm5.122-5.902.023-.008C8.16 5.222 7.611 6.748 7.298 8.5H4.25c.905-2 2.56-3.587 4.608-4.402Zm3.026-.594L12 3.5l.126.006c1.262.126 2.48 2.125 3.045 4.995H8.83c.568-2.878 1.79-4.88 3.055-4.996Zm3.343.76-.107-.174.291.121a8.533 8.533 0 0 1 4.339 4.29h-3.048c-.298-1.665-.806-3.125-1.475-4.237Z M12 19a1 1 0 0 0 1 1h3v2h-.5a.5.5 0 1 0 0 1h4a.5.5 0 0 0 0-1H19v-2h3a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1v5Z" fill="currentColor"/></svg>
110
110
  <span *ngIf="conversation?.attributes?.project_name" class="truncate">{{conversation?.attributes?.project_name}}</span>
111
111
  <span *ngIf="!conversation?.attributes?.project_name" class="truncate">{{conversation?.attributes?.projectId}}</span>
@@ -44,27 +44,18 @@
44
44
  <span class="truncate">{{translationsMap.get('DIRECT_CHAT')}}</span>
45
45
  </div>
46
46
  <!-- GROUP CONV -->
47
- <div *ngIf="!conversationUid?.includes(TYPE_SUPPORT_GROUP) && !isDirect">
47
+ <div *ngIf="conversationUid?.startsWith(TYPE_GROUP)">
48
48
  <svg xmlns="http://www.w3.org/2000/svg" height="15" width="15" viewBox="0 0 24 24" fill="#000000"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>
49
49
  <span class="truncate">{{translationsMap.get('GROUP_CHAT')}}</span>
50
50
  </div>
51
51
  <!-- SUPPORT-GROUP CONV -->
52
- <div *ngIf="conversationUid?.includes(TYPE_SUPPORT_GROUP)">
52
+ <div *ngIf="conversationUid?.startsWith(TYPE_SUPPORT_GROUP)">
53
53
  <svg xmlns="http://www.w3.org/2000/svg" data-v-78d18411="" width="15" height="15" fill="none" viewBox="0 0 24 24" class="inbox-icon"><path d="M22.002 12C22.002 6.477 17.524 2 12 2 6.476 1.999 2 6.477 2 12.001c0 5.186 3.947 9.45 9.001 9.952V20.11c-.778-.612-1.478-1.905-1.939-3.61h1.94V15H8.737a18.969 18.969 0 0 1-.135-5h6.794c.068.64.105 1.31.105 2h1.5c0-.684-.033-1.353-.095-2h3.358c.154.64.237 1.31.237 2h1.5ZM4.786 16.5h2.722l.102.396c.317 1.17.748 2.195 1.27 3.015a8.532 8.532 0 0 1-4.094-3.41ZM3.736 10h3.358a20.847 20.847 0 0 0-.095 2c0 1.043.075 2.051.217 3H4.043a8.483 8.483 0 0 1-.544-3c0-.682.08-1.347.232-1.983L3.736 10Zm5.122-5.902.023-.008C8.16 5.222 7.611 6.748 7.298 8.5H4.25c.905-2 2.56-3.587 4.608-4.402Zm3.026-.594L12 3.5l.126.006c1.262.126 2.48 2.125 3.045 4.995H8.83c.568-2.878 1.79-4.88 3.055-4.996Zm3.343.76-.107-.174.291.121a8.533 8.533 0 0 1 4.339 4.29h-3.048c-.298-1.665-.806-3.125-1.475-4.237Z M12 19a1 1 0 0 0 1 1h3v2h-.5a.5.5 0 1 0 0 1h4a.5.5 0 0 0 0-1H19v-2h3a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1v5Z" fill="currentColor"/></svg>
54
54
  <span *ngIf="conversationAvatar?.project_name" class="truncate">{{conversationAvatar?.project_name}}</span>
55
55
  <span *ngIf="!conversationAvatar?.project_name" class="truncate">{{conversationAvatar?.projectId}}</span>
56
56
  </div>
57
57
  </div>
58
58
 
59
- <app-user-typing
60
- [idConversation]=conversationAvatar.uid
61
- [idCurrentUser]=idLoggedUser
62
- [isDirect]=isDirect
63
- [translationMap]=translationsMap
64
- [color]=fontColor
65
- [membersConversation]=membersConversation>
66
- </app-user-typing>
67
-
68
59
  </div>
69
60
  </div>
70
61
 
@@ -5,7 +5,7 @@ ion-header {
5
5
  border-color: var(--light-gray);
6
6
  border-bottom-width: thin;
7
7
  ion-toolbar{
8
- height: 60px;
8
+ height: --header-height;
9
9
  .flex-container{
10
10
  display: flex;
11
11
  }
@@ -1,3 +1,4 @@
1
+ import { TYPE_GROUP } from './../../../../chat21-core/utils/constants';
1
2
  import {
2
3
  Component,
3
4
  OnInit,
@@ -40,16 +41,15 @@ export class HeaderConversationDetailComponent implements OnInit, OnChanges {
40
41
  openInfoConversation = true
41
42
 
42
43
  isDirect = false
43
- isTyping = false
44
44
  borderColor = '#ffffff'
45
45
  fontColor = '#949494'
46
- membersConversation = ['SYSTEM']
47
46
  platformName: string
48
47
  conv_closed: boolean = false;
49
48
  IS_ON_IOS_MOBILE_DEVICE: boolean
50
49
  private logger: LoggerService = LoggerInstance.getInstance()
51
50
 
52
51
  TYPE_SUPPORT_GROUP = TYPE_SUPPORT_GROUP
52
+ TYPE_GROUP = TYPE_GROUP
53
53
 
54
54
  constructor(
55
55
  public imageRepoService: ImageRepoService,
@@ -100,8 +100,6 @@ export class HeaderConversationDetailComponent implements OnInit, OnChanges {
100
100
  this.getPlatformName()
101
101
  if ( this.conversationAvatar && this.conversationAvatar.channelType === TYPE_DIRECT ) {
102
102
  this.isDirect = true
103
- } else if (this.idLoggedUser) {
104
- this.membersConversation.push(this.idLoggedUser)
105
103
  }
106
104
  }
107
105
 
@@ -1,4 +1,4 @@
1
- <ion-toolbar style="height:60px" [ngClass]="{'bottom-border-on-mobile':IS_ON_MOBILE_DEVICE === true }">
1
+ <ion-toolbar [ngClass]="{'bottom-border-on-mobile':IS_ON_MOBILE_DEVICE === true }">
2
2
 
3
3
  <ion-buttons *ngIf="IS_ON_MOBILE_DEVICE === true || supportMode === false" slot="start" style="height:60px">
4
4
  <ion-button ion-button icon-only fill="clear" (click)="onOpenProfileInfo($event)">
@@ -1,3 +1,7 @@
1
+ ion-toolbar {
2
+ height: --header-height;
3
+ }
4
+
1
5
  ion-title img {
2
6
  height: 30px;
3
7
  }
@@ -100,7 +100,7 @@ c0.9-1.1,1.2-2.3,1.2-3.7V4h4.9v6.1c0,1.3,0.5,2.7,1.2,3.7H8.3z" />
100
100
 
101
101
 
102
102
  <ng-template #conversationsInQueueOnProjectName>
103
- <span *ngIf="unservedRequestCount > 0">
103
+ <span>
104
104
  ({{ unservedRequestCount }})
105
105
  {{translationMap?.get('UnassignedConversations') }}
106
106
  </span>
@@ -124,7 +124,10 @@
124
124
  [baseLocation]="window?.location?.origin"
125
125
  [areVisibleCAR]="areVisibleCAR"
126
126
  [supportMode]= "supportMode"
127
- [isMobile]="isMobile"
127
+ [isMobile]="isMobile"
128
+ [isTypings]="isTypings"
129
+ [idUserTypingNow]="idUserTypingNow"
130
+ [nameUserTypingNow]="nameUserTypingNow"
128
131
  [translationMap]="translationsContentMap"
129
132
  [stylesMap]="styleMap"
130
133
  (onBeforeMessageRender)="onBeforeMessageRenderFN($event)"
@@ -115,15 +115,12 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
115
115
  public openInfoConversation = false
116
116
  public isMobile = false
117
117
  public isLessThan991px = false // nk added
118
- public isTyping = false
119
- public nameUserTypingNow: string
120
118
 
121
119
  public heightMessageTextArea = ''
122
120
  public translationsMap: Map<string, string> = new Map()
123
121
  public translationsHeaderMap: Map<string, string> = new Map()
124
122
  public translationsContentMap: Map<string, string> = new Map()
125
123
  public conversationAvatar: any
126
- public membersConversation: any
127
124
  public member: UserModel
128
125
  public urlConversationSupportGroup: any
129
126
  public isFileSelected: boolean
@@ -169,6 +166,15 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
169
166
  public disableTextarea: boolean;
170
167
  appsidebarIsWide: boolean;
171
168
 
169
+ // ========== begin:: typying =======
170
+ public isTypings = false;
171
+ public isDirect = false;
172
+ public idUserTypingNow: string;
173
+ public nameUserTypingNow: string;
174
+ private setTimeoutWritingMessages;
175
+ membersConversation = ['SYSTEM'];
176
+ // ========== end:: typying =======
177
+
172
178
  /**
173
179
  * Constructor
174
180
  * @param route
@@ -237,21 +243,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
237
243
  // -----------------------------------------------------------
238
244
  ngOnInit() {
239
245
  this.logger.log('[CONVS-DETAIL] > ngOnInit - window.location: ', window.location);
240
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept: ', this.appConfigProvider.getConfig().fileUploadAccept);
241
- // const accept_files = this.appConfigProvider.getConfig().fileUploadAccept;
242
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept typeof accept_files ', typeof accept_files);
243
- // const accept_files_array = accept_files.split(',')
244
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept accept_files_array ', accept_files_array);
245
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept accept_files_array typeof: ', typeof accept_files_array);
246
-
247
- // accept_files_array.forEach(accept_file => {
248
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept accept_file ', accept_file);
249
- // const accept_file_segment = accept_file.split('/')
250
- // this.logger.log('[CONVS-DETAIL] > ngOnInit - fileUploadAccept accept_file_segment ', accept_file_segment);
251
- // if (accept_file_segment[1] === '*') {
252
-
253
- // }
254
- // });
246
+
255
247
  this.getConversations();
256
248
  this.watchToConnectionStatus();
257
249
  this.getOSCODE();
@@ -479,6 +471,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
479
471
  this.loggedUser = this.tiledeskAuthService.getCurrentUser()
480
472
  this.logger.log('[CONVS-DETAIL] - initialize -> loggedUser: ', this.loggedUser)
481
473
  this.translations()
474
+ this.setStyleMap()
482
475
  // this.conversationSelected = localStorage.getItem('conversationSelected');
483
476
  this.showButtonToBottom = false
484
477
  this.showMessageWelcome = false
@@ -531,6 +524,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
531
524
  this.addEventsKeyboard()
532
525
  this.startConversation()
533
526
  this.updateConversationBadge() // AGGIORNO STATO DELLA CONVERSAZIONE A 'LETTA' (is_new = false)
527
+
528
+ this.initializeTyping();
534
529
  }
535
530
 
536
531
  _getProjectIdByConversationWith(conversationWith: string) {
@@ -589,7 +584,7 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
589
584
  'LABEL_TO',
590
585
  'LABEL_LAST_ACCESS',
591
586
  'ARRAY_DAYS',
592
- 'LABEL_IS_WRITING',
587
+
593
588
  'LABEL_INFO_ADVANCED',
594
589
  'ID_CONVERSATION',
595
590
  'UPLOAD_FILE_ERROR',
@@ -629,7 +624,8 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
629
624
 
630
625
  const keysContentDetail = [
631
626
  'LABEL_OPEN_INFO_CONVERSATION',
632
- 'LABEL_CLOSE_GROUP'
627
+ 'LABEL_CLOSE_GROUP',
628
+ 'LABEL_IS_WRITING',
633
629
  ]
634
630
 
635
631
  this.translationsMap = this.customTranslateService.translateLanguage(keys)
@@ -662,6 +658,13 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
662
658
  return this.customTranslateService.translateLanguage(keys)
663
659
  }
664
660
 
661
+ private setStyleMap(){
662
+ this.styleMap.set('themeColor', 'var(--basic-gray)')
663
+ .set('bubbleReceivedBackground','var(--bck-msg-received)')
664
+ .set('bubbleReceivedTextColor', 'var(--col-msg-received)')
665
+ .set('bubbleSentBackground', 'var(--bck-msg-sent)')
666
+ .set('bubbleSentTextColor', 'var(--col-msg-sent)')
667
+ }
665
668
  // -------------------------------------------------------------------------------------
666
669
  // * retrieving the handler from chatManager
667
670
  // * if it DOESN'T EXIST I create a handler and connect and store it in the chatmanager
@@ -1000,6 +1003,22 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1000
1003
  this.subscriptions.push(subscribe)
1001
1004
  }
1002
1005
 
1006
+ subscriptionKey = 'conversationTyping';
1007
+ subscription = this.subscriptions.find(item => item.key === subscriptionKey);
1008
+ if (!subscription) {
1009
+ subscription = this.typingService.BSIsTyping.pipe(takeUntil(this.unsubscribe$)).subscribe((data: any) => {
1010
+ this.logger.debug('[CONVS-DETAIL] ***** BSIsTyping *****', data);
1011
+ if (data) {
1012
+ const isTypingUid = data.uid; //support-group-...
1013
+ if (this.conversationWith === isTypingUid) {
1014
+ that.subscribeTypings(data);
1015
+ }
1016
+ }
1017
+ });
1018
+ const subscribe = {key: subscriptionKey, value: subscription };
1019
+ this.subscriptions.push(subscribe);
1020
+ }
1021
+
1003
1022
  // subscriptionKey = 'onGroupChange';
1004
1023
  // subscription = this.subscriptions.find(item => item.key === subscriptionKey);
1005
1024
  // if (!subscription) {
@@ -1684,6 +1703,63 @@ export class ConversationDetailPage implements OnInit, OnDestroy, AfterViewInit
1684
1703
  return isAcceptFile
1685
1704
  }
1686
1705
  }
1706
+
1707
+
1708
+ initializeTyping() {
1709
+ this.logger.debug('[CONVS-DETAIL] membersconversation', this.membersConversation)
1710
+ this.membersConversation.push(this.loggedUser.uid)
1711
+ //this.setSubscriptions();
1712
+ this.typingService.isTyping(this.conversationWith, this.loggedUser.uid, this.isDirect);
1713
+
1714
+ }
1715
+
1716
+ /** */
1717
+ subscribeTypings(data: any) {
1718
+ const that = this;
1719
+ try {
1720
+ const key = data.uidUserTypingNow;
1721
+ const waitTime = data.waitTime
1722
+ this.nameUserTypingNow = null;
1723
+ this.idUserTypingNow = null;
1724
+
1725
+ if (data.nameUserTypingNow) {
1726
+ this.nameUserTypingNow = data.nameUserTypingNow;
1727
+ }
1728
+ if (data.uidUserTypingNow){
1729
+ this.idUserTypingNow = data.uidUserTypingNow
1730
+ }
1731
+ this.logger.debug('[CONV-COMP] subscribeTypings data:', data);
1732
+ const userTyping = this.membersConversation.includes(key);
1733
+ if ( !userTyping && key) {
1734
+ this.isTypings = true;
1735
+ setTimeout(function () {
1736
+ that.scrollBottom(0)
1737
+ }, 0);
1738
+ // clearTimeout(this.setTimeoutWritingMessages);
1739
+ this.setTimeoutWritingMessages = setTimeout(() => {
1740
+ that.isTypings = false;
1741
+ }, waitTime);
1742
+ // this.initiTimeout(waitTime)
1743
+ }
1744
+ } catch (error) {
1745
+ this.logger.error('[CONV-COMP] error: ', error);
1746
+ }
1747
+
1748
+ }
1749
+
1750
+ initiTimeout(waitTime){
1751
+ const that = this;
1752
+ this.setTimeoutWritingMessages = setTimeout(() => {
1753
+ that.isTypings = false;
1754
+ }, waitTime);
1755
+ }
1756
+
1757
+ resetTimeout(){
1758
+ this.isTypings = false
1759
+ this.setTimeoutWritingMessages = null;
1760
+ clearTimeout(this.setTimeoutWritingMessages)
1761
+ }
1762
+
1687
1763
  // -------------------------------------------------------------
1688
1764
  // DRAG FILE
1689
1765
  // -------------------------------------------------------------
@@ -12,11 +12,11 @@ import 'firebase/database';
12
12
  import { TypingService } from '../abstract/typing.service';
13
13
  import { CustomLogger } from '../logger/customLogger';
14
14
  import { LoggerInstance } from '../logger/loggerInstance';
15
+ import { TIME_TYPING_MESSAGE } from 'src/chat21-core/utils/constants';
15
16
 
16
17
 
17
18
  export class TypingModel {
18
19
 
19
-
20
20
  constructor(
21
21
  public uid: string,
22
22
  public timestamp: any,
@@ -35,14 +35,11 @@ export class FirebaseTypingService extends TypingService {
35
35
  BSIsTyping: BehaviorSubject<any> = new BehaviorSubject<any>(null);
36
36
  BSSetTyping: BehaviorSubject<any> = new BehaviorSubject<any>(null);
37
37
 
38
- // public params
39
- // public tenant: string;
40
- private tenant: string;
41
-
42
- // private params
43
38
  private urlNodeTypings: string;
44
39
  private setTimeoutWritingMessages: any;
40
+ private tenant: string;
45
41
  private logger: LoggerService = LoggerInstance.getInstance();
42
+ private ref: firebase.database.Query;
46
43
 
47
44
  constructor() {
48
45
  super();
@@ -64,10 +61,11 @@ export class FirebaseTypingService extends TypingService {
64
61
  urlTyping = this.urlNodeTypings + idCurrentUser + '/' + idConversation;
65
62
  }
66
63
  this.logger.debug('[FIREBASETypingSERVICE] urlTyping: ', urlTyping);
67
- const ref = firebase.database().ref(urlTyping);
68
- ref.on('child_changed', (childSnapshot) => {
64
+ this.ref = firebase.database().ref(urlTyping);
65
+ this.ref.on('child_changed', (childSnapshot) => {
69
66
  const precence: TypingModel = childSnapshot.val();
70
- this.BSIsTyping.next({uid: idConversation, uidUserTypingNow: precence.uid, nameUserTypingNow: precence.name});
67
+ this.logger.debug('[FIREBASETypingSERVICE] child_changed: ', precence);
68
+ this.BSIsTyping.next({uid: idConversation, uidUserTypingNow: precence.uid, nameUserTypingNow: precence.name, waitTime: TIME_TYPING_MESSAGE});
71
69
  });
72
70
  }
73
71
 
@@ -43,8 +43,12 @@ export const CHANNEL_TYPE_GROUP = 'group';
43
43
  // TYPES MESSAGES
44
44
  export const TYPE_MSG_TEXT = 'text';
45
45
  export const TYPE_MSG_IMAGE = 'image';
46
+ export const TYPE_MSG_FILE = 'file';
47
+ export const TYPE_MSG_BUTTON = 'button';
48
+
46
49
  export const MAX_WIDTH_IMAGES = 300;
47
50
  export const MIN_WIDTH_IMAGES = 130;
51
+ export const TIME_TYPING_MESSAGE = 2000;
48
52
  export const TYPE_DIRECT = 'direct';
49
53
  export const TYPE_GROUP = 'group';
50
54
  export const SYSTEM = 'system';
@@ -1,6 +1,9 @@
1
- <div class="tile-typing-now" [class.active]="isTyping">
2
- <span *ngIf="nameUserTypingNow">
3
- {{nameUserTypingNow}}
4
- </span>
5
- {{ translationMap?.get('LABEL_IS_WRITING') }}
1
+ <div class="tile-typing-now" *ngIf="typingLocation === 'header'">
2
+ <span *ngIf="nameUserTypingNow">{{nameUserTypingNow}} </span>
3
+ {{ translationMap?.get('LABEL_WRITING') }}
4
+ </div>
5
+ <div class="spinner" *ngIf="typingLocation === 'content'">
6
+ <div class="bounce1"></div>
7
+ <div class="bounce2"></div>
8
+ <div class="bounce3"></div>
6
9
  </div>
@@ -1,10 +1,24 @@
1
+ :root {
2
+ --themeColor: rgb(240, 242, 247);
3
+ --foregroundColor: black;
4
+ }
5
+
6
+
1
7
  .tile-typing-now {
2
- font-size: 12px;
3
- background-color: #fff;
4
- display: none;
5
- &.active {
6
- display: block;
7
- }
8
+ position: absolute;
9
+ left: 40px;
10
+ right: 40px;
11
+ bottom: 3px;
12
+ width: auto;
13
+ text-align: center;
14
+ margin: 0px;
15
+ padding: 0px;
16
+ font-size: 1.1em;
17
+ color: var(--foregroundColor);
18
+ //display: none;
19
+ // &.active {
20
+ // display: block;
21
+ // }
8
22
  }
9
23
 
10
24
  /* BEGIN LOADING */
@@ -14,49 +28,105 @@
14
28
  left: 0;
15
29
  top: 0;
16
30
  margin: 0;
17
- &.active {
18
- display: inline-block;
19
- width: 30px;
20
- }
31
+ // &.active {
32
+ // display: inline-block;
33
+ // width: 30px;
34
+ // }
21
35
  }
22
36
  #tile-spinner > div {
23
37
  width: 6px;
24
38
  height: 6px;
25
39
  background-color: var(--basic-blue);
26
40
  }
41
+ // .spinner {
42
+ // margin: 100px auto 0;
43
+ // width: 70px;
44
+ // text-align: center;
45
+ // }
46
+ // .spinner > div {
47
+ // width: 18px;
48
+ // height: 18px;
49
+ // background-color: #333;
50
+ // border-radius: 100%;
51
+ // display: inline-block;
52
+ // -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
53
+ // animation: sk-bouncedelay 1.4s infinite ease-in-out both;
54
+ // }
55
+ // .spinner .bounce1 {
56
+ // -webkit-animation-delay: -0.32s;
57
+ // animation-delay: -0.32s;
58
+ // }
59
+ // .spinner .bounce2 {
60
+ // -webkit-animation-delay: -0.16s;
61
+ // animation-delay: -0.16s;
62
+ // }
63
+ // @-webkit-keyframes sk-bouncedelay {
64
+ // 0%, 80%, 100% { -webkit-transform: scale(0) }
65
+ // 40% { -webkit-transform: scale(1.0) }
66
+ // }
67
+ // @keyframes sk-bouncedelay {
68
+ // 0%, 80%, 100% {
69
+ // -webkit-transform: scale(0);
70
+ // transform: scale(0);
71
+ // } 40% {
72
+ // -webkit-transform: scale(1.0);
73
+ // transform: scale(1.0);
74
+ // }
75
+ // }
76
+ /* END LOADING */
77
+
78
+
79
+ /* ******BOUNCE SPINNER START****** */
27
80
  .spinner {
28
- margin: 100px auto 0;
81
+ margin: 15px 10px; //remove it if activate avatar image
29
82
  width: 70px;
30
- text-align: center;
83
+ // text-align: center;
84
+ min-height: 20px;
85
+ display: block;
31
86
  }
87
+
32
88
  .spinner > div {
33
- width: 18px;
34
- height: 18px;
89
+ width: 9px;
90
+ height: 9px;
35
91
  background-color: #333;
92
+
36
93
  border-radius: 100%;
37
94
  display: inline-block;
38
95
  -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
39
96
  animation: sk-bouncedelay 1.4s infinite ease-in-out both;
40
97
  }
98
+
41
99
  .spinner .bounce1 {
42
100
  -webkit-animation-delay: -0.32s;
43
101
  animation-delay: -0.32s;
102
+ background-color: var(--themeColor)
44
103
  }
104
+
45
105
  .spinner .bounce2 {
46
106
  -webkit-animation-delay: -0.16s;
47
107
  animation-delay: -0.16s;
108
+ background-color: var(--themeColor);
109
+ opacity: 0.4
48
110
  }
111
+
112
+ .spinner .bounce3 {
113
+ background-color: var(--themeColor);
114
+ opacity: 0.6
115
+ }
116
+
117
+
49
118
  @-webkit-keyframes sk-bouncedelay {
50
119
  0%, 80%, 100% { -webkit-transform: scale(0) }
51
120
  40% { -webkit-transform: scale(1.0) }
52
121
  }
122
+
53
123
  @keyframes sk-bouncedelay {
54
124
  0%, 80%, 100% {
55
- -webkit-transform: scale(0);
56
- transform: scale(0);
125
+ -webkit-transform: scale(0);
126
+ transform: scale(0);
57
127
  } 40% {
58
128
  -webkit-transform: scale(1.0);
59
129
  transform: scale(1.0);
60
130
  }
61
131
  }
62
- /* END LOADING */
132
+ /* ******BOUNCE SPINNER END****** */
@@ -1,113 +1,31 @@
1
- import { Component, OnInit, OnDestroy, Input } from '@angular/core';
2
-
3
- // services
4
- import { TypingService } from '../../providers/abstract/typing.service';
5
-
6
- // Logger
7
- import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
8
- import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
1
+ import { Component, OnInit, OnDestroy, Input, ElementRef } from '@angular/core';
9
2
 
10
3
  @Component({
11
- selector: 'app-user-typing',
4
+ selector: 'user-typing',
12
5
  templateUrl: './user-typing.component.html',
13
6
  styleUrls: ['./user-typing.component.scss'],
14
7
  })
15
8
  export class UserTypingComponent implements OnInit, OnDestroy {
16
9
 
17
- @Input() idConversation: string;
18
- @Input() idCurrentUser: string;
19
- @Input() isDirect: boolean;
10
+ // @Input() idConversation: string;
11
+ // @Input() idCurrentUser: string;
12
+ // @Input() isDirect: boolean;
13
+ @Input() typingLocation: string = 'content'
20
14
  @Input() translationMap: Map<string, string>;
21
- @Input() color: string;
22
- @Input() membersConversation: [string];
23
-
24
- public status = '';
25
- public isTyping = false;
26
- public nameUserTypingNow: string;
27
-
28
- private setTimeoutWritingMessages: any;
29
- private subscriptions = [];
30
-
31
- private logger: LoggerService = LoggerInstance.getInstance();
15
+ @Input() themeColor: string;
16
+ @Input() idUserTypingNow: string;
17
+ @Input() nameUserTypingNow: string;
18
+ // @Input() membersConversation: [string];
32
19
 
33
- constructor(
34
- public typingService: TypingService
35
- ) { }
20
+ constructor(private elementRef: ElementRef) { }
36
21
 
37
22
  /** */
38
23
  ngOnInit() {
39
- this.logger.log('[USER-TYPING-COMPONENT] - ngOnInit');
40
- this.initialize();
24
+ this.elementRef.nativeElement.style.setProperty('--themeColor', this.themeColor);
41
25
  }
42
26
 
43
27
  /** */
44
28
  ngOnDestroy() {
45
- this.logger.log('UserTypingComponent - ngOnDestroy');
46
- // this.unsubescribeAll();
47
- }
48
-
49
- /** */
50
- initialize() {
51
- this.status = ''; // this.translationMap.get('LABEL_AVAILABLE');
52
- this.logger.log('this.translationMap', this.translationMap);
53
- this.logger.log('this.status', this.status);
54
- this.setSubscriptions();
55
- this.typingService.isTyping(this.idConversation, this.idCurrentUser, this.isDirect);
56
- }
57
-
58
- /** */
59
- private setSubscriptions() {
60
- const that = this;
61
- const conversationSelected = this.subscriptions.find(item => item.key === this.idConversation);
62
- if (!conversationSelected) {
63
- const subscribeBSIsTyping = this.typingService.BSIsTyping.subscribe((data: any) => {
64
- this.logger.log('***** BSIsTyping *****', data);
65
- if (data) {
66
- const isTypingUid = data.uid;
67
- if (this.idConversation === isTypingUid) {
68
- that.subscribeTypings(data);
69
- }
70
- }
71
- });
72
- const subscribe = {key: this.idConversation, value: subscribeBSIsTyping };
73
- this.subscriptions.push(subscribe);
74
- }
75
- }
76
-
77
- /** */
78
- subscribeTypings(data: any) {
79
- const that = this;
80
- try {
81
- const key = data.uidUserTypingNow;
82
- this.nameUserTypingNow = null;
83
- if (data.nameUserTypingNow) {
84
- this.nameUserTypingNow = data.nameUserTypingNow;
85
- }
86
- this.logger.log('subscribeTypings data:', data);
87
- const userTyping = this.membersConversation.includes(key);
88
- if ( !userTyping ) {
89
- this.isTyping = true;
90
- this.logger.log('child_changed key', key);
91
- this.logger.log('child_changed name', this.nameUserTypingNow);
92
- clearTimeout(this.setTimeoutWritingMessages);
93
- this.setTimeoutWritingMessages = setTimeout(() => {
94
- that.isTyping = false;
95
- }, 2000);
96
- }
97
- } catch (error) {
98
- this.logger.log('error: ', error);
99
- }
100
- }
101
-
102
-
103
- /** */
104
- private unsubescribeAll() {
105
- this.logger.log('UserTypingComponent unsubescribeAll: ', this.subscriptions);
106
- this.subscriptions.forEach((subscription: any) => {
107
- this.logger.log('unsubescribe: ', subscription);
108
- subscription.unsubescribe();
109
- });
110
- this.subscriptions = [];
111
29
  }
112
30
 
113
31
 
@@ -23,11 +23,17 @@
23
23
  --basic-yellow: #FFC627;
24
24
  --basic-red: #EB1E23;
25
25
 
26
- --bck-msg-sent: #62a8ea;
26
+ --bck-msg-sent: #2a6ac1;
27
27
  --col-msg-sent:#ffffff;
28
+
29
+ --bck-msg-received: #f0f2f7;
30
+ --col-msg-received: #06132b;
31
+
28
32
  --light-white: #f7f7f7;
29
33
  --black: #1a1a1a;
30
34
  --gray: #aaaaaa;
31
35
 
36
+ --header-height: 60px;
37
+
32
38
 
33
39
  }