stream-chat-angular 2.6.0 → 2.8.0

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.
@@ -16,7 +16,7 @@ import transliterate from '@stream-io/transliterate';
16
16
  import * as i5 from 'angular-mentions';
17
17
  import { MentionModule } from 'angular-mentions';
18
18
 
19
- const version = '2.6.0';
19
+ const version = '2.8.0';
20
20
 
21
21
  class NotificationService {
22
22
  constructor() {
@@ -61,9 +61,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
61
61
  }], ctorParameters: function () { return []; } });
62
62
 
63
63
  class ChatClientService {
64
- constructor(ngZone, appRef, notificationService) {
64
+ constructor(ngZone, notificationService) {
65
65
  this.ngZone = ngZone;
66
- this.appRef = appRef;
67
66
  this.notificationService = notificationService;
68
67
  this.notificationSubject = new ReplaySubject(1);
69
68
  this.connectionStateSubject = new ReplaySubject(1);
@@ -72,48 +71,37 @@ class ChatClientService {
72
71
  this.connectionState$ = this.connectionStateSubject.asObservable();
73
72
  this.appSettings$ = this.appSettingsSubject.asObservable();
74
73
  }
75
- init(apiKey, userId, userToken) {
74
+ init(apiKey, userOrId, userTokenOrProvider) {
76
75
  return __awaiter(this, void 0, void 0, function* () {
77
76
  this.chatClient = StreamChat.getInstance(apiKey);
78
77
  yield this.ngZone.runOutsideAngular(() => __awaiter(this, void 0, void 0, function* () {
79
- yield this.chatClient.connectUser({ id: userId }, userToken);
78
+ const user = typeof userOrId === 'string' ? { id: userOrId } : userOrId;
79
+ yield this.chatClient.connectUser(user, userTokenOrProvider);
80
80
  this.chatClient.setUserAgent(`stream-chat-angular-${version}-${this.chatClient.getUserAgent()}`);
81
+ this.chatClient.getAppSettings;
81
82
  }));
82
83
  this.appSettingsSubject.next(undefined);
83
- this.chatClient.on('notification.added_to_channel', (e) => {
84
+ this.chatClient.on((e) => {
84
85
  this.notificationSubject.next({
85
- eventType: 'notification.added_to_channel',
86
+ eventType: e.type,
86
87
  event: e,
87
88
  });
88
- this.appRef.tick();
89
- });
90
- this.chatClient.on('notification.message_new', (e) => {
91
- this.notificationSubject.next({
92
- eventType: 'notification.message_new',
93
- event: e,
94
- });
95
- this.appRef.tick();
96
- });
97
- this.chatClient.on('notification.removed_from_channel', (e) => {
98
- this.notificationSubject.next({
99
- eventType: 'notification.removed_from_channel',
100
- event: e,
101
- });
102
- this.appRef.tick();
103
89
  });
104
90
  let removeNotification;
105
91
  this.chatClient.on('connection.changed', (e) => {
106
- const isOnline = e.online;
107
- if (isOnline) {
108
- if (removeNotification) {
109
- removeNotification();
92
+ this.ngZone.run(() => {
93
+ const isOnline = e.online;
94
+ if (isOnline) {
95
+ if (removeNotification) {
96
+ removeNotification();
97
+ }
110
98
  }
111
- }
112
- else {
113
- removeNotification = this.notificationService.addPermanentNotification('streamChat.Connection failure, reconnecting now...');
114
- }
115
- this.connectionStateSubject.next(isOnline ? 'online' : 'offline');
116
- this.appRef.tick();
99
+ else {
100
+ removeNotification =
101
+ this.notificationService.addPermanentNotification('streamChat.Connection failure, reconnecting now...');
102
+ }
103
+ this.connectionStateSubject.next(isOnline ? 'online' : 'offline');
104
+ });
117
105
  });
118
106
  });
119
107
  }
@@ -147,14 +135,14 @@ class ChatClientService {
147
135
  });
148
136
  }
149
137
  }
150
- ChatClientService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChatClientService, deps: [{ token: i0.NgZone }, { token: i0.ApplicationRef }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Injectable });
138
+ ChatClientService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChatClientService, deps: [{ token: i0.NgZone }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Injectable });
151
139
  ChatClientService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChatClientService, providedIn: 'root' });
152
140
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChatClientService, decorators: [{
153
141
  type: Injectable,
154
142
  args: [{
155
143
  providedIn: 'root',
156
144
  }]
157
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ApplicationRef }, { type: NotificationService }]; } });
145
+ }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: NotificationService }]; } });
158
146
 
159
147
  const createMessagePreview = (user, text, attachments, mentionedUsers) => {
160
148
  const clientSideId = `${user.id}-${v4()}`;
@@ -187,9 +175,8 @@ const getReadBy = (message, channel) => {
187
175
  };
188
176
 
189
177
  class ChannelService {
190
- constructor(chatClientService, appRef, ngZone) {
178
+ constructor(chatClientService, ngZone) {
191
179
  this.chatClientService = chatClientService;
192
- this.appRef = appRef;
193
180
  this.ngZone = ngZone;
194
181
  this.channelsSubject = new BehaviorSubject(undefined);
195
182
  this.activeChannelSubject = new BehaviorSubject(undefined);
@@ -363,10 +350,7 @@ class ChannelService {
363
350
  return [];
364
351
  }
365
352
  const result = yield activeChannel.queryMembers({
366
- $or: [
367
- { id: { $autocomplete: searchTerm } },
368
- { name: { $autocomplete: searchTerm } },
369
- ],
353
+ name: { $autocomplete: searchTerm },
370
354
  id: { $ne: this.chatClientService.chatClient.userID },
371
355
  });
372
356
  return Object.values(result.members);
@@ -400,39 +384,43 @@ class ChannelService {
400
384
  return __awaiter(this, void 0, void 0, function* () {
401
385
  switch (notification.eventType) {
402
386
  case 'notification.message_new': {
403
- if (this.customNewMessageNotificationHandler) {
404
- this.customNewMessageNotificationHandler(notification, this.channelListSetter);
405
- }
406
- else {
407
- yield this.handleNewMessageNotification(notification);
408
- }
387
+ yield this.ngZone.run(() => __awaiter(this, void 0, void 0, function* () {
388
+ if (this.customNewMessageNotificationHandler) {
389
+ this.customNewMessageNotificationHandler(notification, this.channelListSetter);
390
+ }
391
+ else {
392
+ yield this.handleNewMessageNotification(notification);
393
+ }
394
+ }));
409
395
  break;
410
396
  }
411
397
  case 'notification.added_to_channel': {
412
- if (this.customAddedToChannelNotificationHandler) {
413
- this.customAddedToChannelNotificationHandler(notification, this.channelListSetter);
414
- }
415
- else {
416
- yield this.handleAddedToChannelNotification(notification);
417
- }
398
+ yield this.ngZone.run(() => __awaiter(this, void 0, void 0, function* () {
399
+ if (this.customAddedToChannelNotificationHandler) {
400
+ this.customAddedToChannelNotificationHandler(notification, this.channelListSetter);
401
+ }
402
+ else {
403
+ yield this.handleAddedToChannelNotification(notification);
404
+ }
405
+ }));
418
406
  break;
419
407
  }
420
408
  case 'notification.removed_from_channel': {
421
- if (this.customRemovedFromChannelNotificationHandler) {
422
- this.customRemovedFromChannelNotificationHandler(notification, this.channelListSetter);
423
- }
424
- else {
425
- this.handleRemovedFromChannelNotification(notification);
426
- }
409
+ this.ngZone.run(() => {
410
+ if (this.customRemovedFromChannelNotificationHandler) {
411
+ this.customRemovedFromChannelNotificationHandler(notification, this.channelListSetter);
412
+ }
413
+ else {
414
+ this.handleRemovedFromChannelNotification(notification);
415
+ }
416
+ });
427
417
  }
428
418
  }
429
419
  });
430
420
  }
431
421
  handleRemovedFromChannelNotification(notification) {
432
- this.ngZone.run(() => {
433
- const channelIdToBeRemoved = notification.event.channel.cid;
434
- this.removeFromChannelList(channelIdToBeRemoved);
435
- });
422
+ const channelIdToBeRemoved = notification.event.channel.cid;
423
+ this.removeFromChannelList(channelIdToBeRemoved);
436
424
  }
437
425
  handleNewMessageNotification(notification) {
438
426
  return __awaiter(this, void 0, void 0, function* () {
@@ -450,12 +438,10 @@ class ChannelService {
450
438
  const channel = this.chatClientService.chatClient.channel((_a = notification.event.channel) === null || _a === void 0 ? void 0 : _a.type, (_b = notification.event.channel) === null || _b === void 0 ? void 0 : _b.id);
451
439
  yield channel.watch();
452
440
  this.watchForChannelEvents(channel);
453
- this.ngZone.run(() => {
454
- this.channelsSubject.next([
455
- channel,
456
- ...(this.channelsSubject.getValue() || []),
457
- ]);
458
- });
441
+ this.channelsSubject.next([
442
+ channel,
443
+ ...(this.channelsSubject.getValue() || []),
444
+ ]);
459
445
  });
460
446
  }
461
447
  removeFromChannelList(cid) {
@@ -484,15 +470,17 @@ class ChannelService {
484
470
  this.activeChannelSubscriptions.push(channel.on('reaction.deleted', (e) => this.messageReactionEventReceived(e)));
485
471
  this.activeChannelSubscriptions.push(channel.on('reaction.updated', (e) => this.messageReactionEventReceived(e)));
486
472
  this.activeChannelSubscriptions.push(channel.on('message.read', (e) => {
487
- let latestMessage;
488
- this.activeChannelMessages$.pipe(first()).subscribe((messages) => {
489
- latestMessage = messages[messages.length - 1];
473
+ this.ngZone.run(() => {
474
+ let latestMessage;
475
+ this.activeChannelMessages$.pipe(first()).subscribe((messages) => {
476
+ latestMessage = messages[messages.length - 1];
477
+ });
478
+ if (!latestMessage || !e.user) {
479
+ return;
480
+ }
481
+ latestMessage.readBy = getReadBy(latestMessage, channel);
482
+ this.activeChannelMessagesSubject.next(this.activeChannelMessagesSubject.getValue());
490
483
  });
491
- if (!latestMessage || !e.user) {
492
- return;
493
- }
494
- latestMessage.readBy = getReadBy(latestMessage, channel);
495
- this.activeChannelMessagesSubject.next(this.activeChannelMessagesSubject.getValue());
496
484
  }));
497
485
  }
498
486
  messageUpdated(event) {
@@ -566,66 +554,72 @@ class ChannelService {
566
554
  channel.on((event) => {
567
555
  switch (event.type) {
568
556
  case 'message.new': {
569
- if (this.customNewMessageHandler) {
570
- this.customNewMessageHandler(event, channel, this.channelListSetter, this.messageListSetter);
571
- }
572
- else {
573
- this.handleNewMessage(event, channel);
574
- }
557
+ this.ngZone.run(() => {
558
+ if (this.customNewMessageHandler) {
559
+ this.customNewMessageHandler(event, channel, this.channelListSetter, this.messageListSetter);
560
+ }
561
+ else {
562
+ this.handleNewMessage(event, channel);
563
+ }
564
+ });
575
565
  break;
576
566
  }
577
567
  case 'channel.hidden': {
578
- if (this.customChannelHiddenHandler) {
579
- this.customChannelHiddenHandler(event, channel, this.channelListSetter, this.messageListSetter);
580
- }
581
- else {
582
- this.handleChannelHidden(event);
583
- }
584
- this.appRef.tick();
568
+ this.ngZone.run(() => {
569
+ if (this.customChannelHiddenHandler) {
570
+ this.customChannelHiddenHandler(event, channel, this.channelListSetter, this.messageListSetter);
571
+ }
572
+ else {
573
+ this.handleChannelHidden(event);
574
+ }
575
+ });
585
576
  break;
586
577
  }
587
578
  case 'channel.deleted': {
588
- if (this.customChannelDeletedHandler) {
589
- this.customChannelDeletedHandler(event, channel, this.channelListSetter, this.messageListSetter);
590
- }
591
- else {
592
- this.handleChannelDeleted(event);
593
- }
594
- this.appRef.tick();
579
+ this.ngZone.run(() => {
580
+ if (this.customChannelDeletedHandler) {
581
+ this.customChannelDeletedHandler(event, channel, this.channelListSetter, this.messageListSetter);
582
+ }
583
+ else {
584
+ this.handleChannelDeleted(event);
585
+ }
586
+ });
595
587
  break;
596
588
  }
597
589
  case 'channel.visible': {
598
- if (this.customChannelVisibleHandler) {
599
- this.customChannelVisibleHandler(event, channel, this.channelListSetter, this.messageListSetter);
600
- }
601
- else {
602
- this.handleChannelVisible(event, channel);
603
- }
604
- this.appRef.tick();
590
+ this.ngZone.run(() => {
591
+ if (this.customChannelVisibleHandler) {
592
+ this.customChannelVisibleHandler(event, channel, this.channelListSetter, this.messageListSetter);
593
+ }
594
+ else {
595
+ this.handleChannelVisible(event, channel);
596
+ }
597
+ });
605
598
  break;
606
599
  }
607
600
  case 'channel.updated': {
608
- if (this.customChannelUpdatedHandler) {
609
- this.customChannelUpdatedHandler(event, channel, this.channelListSetter, this.messageListSetter);
610
- }
611
- else {
612
- this.handleChannelUpdate(event);
613
- }
614
- this.appRef.tick();
601
+ this.ngZone.run(() => {
602
+ if (this.customChannelUpdatedHandler) {
603
+ this.customChannelUpdatedHandler(event, channel, this.channelListSetter, this.messageListSetter);
604
+ }
605
+ else {
606
+ this.handleChannelUpdate(event);
607
+ }
608
+ });
615
609
  break;
616
610
  }
617
611
  case 'channel.truncated': {
618
- if (this.customChannelTruncatedHandler) {
619
- this.customChannelTruncatedHandler(event, channel, this.channelListSetter, this.messageListSetter);
620
- }
621
- else {
622
- this.handleChannelTruncate(event);
623
- }
624
- this.appRef.tick();
612
+ this.ngZone.run(() => {
613
+ if (this.customChannelTruncatedHandler) {
614
+ this.customChannelTruncatedHandler(event, channel, this.channelListSetter, this.messageListSetter);
615
+ }
616
+ else {
617
+ this.handleChannelTruncate(event);
618
+ }
619
+ });
625
620
  break;
626
621
  }
627
622
  }
628
- setTimeout(() => this.appRef.tick(), 0);
629
623
  });
630
624
  }
631
625
  handleNewMessage(_, channel) {
@@ -684,14 +678,14 @@ class ChannelService {
684
678
  return capabilites.indexOf('read-events') !== -1;
685
679
  }
686
680
  }
687
- ChannelService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0.ApplicationRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
681
+ ChannelService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
688
682
  ChannelService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, providedIn: 'root' });
689
683
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelService, decorators: [{
690
684
  type: Injectable,
691
685
  args: [{
692
686
  providedIn: 'root',
693
687
  }]
694
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: i0.ApplicationRef }, { type: i0.NgZone }]; } });
688
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: i0.NgZone }]; } });
695
689
 
696
690
  class ThemeService {
697
691
  constructor() {
@@ -1251,7 +1245,7 @@ class AttachmentPreviewListComponent {
1251
1245
  }
1252
1246
  }
1253
1247
  AttachmentPreviewListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentPreviewListComponent, deps: [{ token: AttachmentService }], target: i0.ɵɵFactoryTarget.Component });
1254
- AttachmentPreviewListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", ngImport: i0, template: "<div class=\"rfu-image-previewer\">\n <ng-container\n *ngFor=\"\n let attachmentUpload of attachmentUploads$ | async;\n trackBy: trackByFile\n \"\n >\n <div\n *ngIf=\"attachmentUpload.type === 'image'\"\n class=\"rfu-image-previewer__image\"\n [class.rfu-image-previewer__image--loaded]=\"\n attachmentUpload.state === 'success'\n \"\n data-testclass=\"attachment-image-preview\"\n >\n <div\n *ngIf=\"attachmentUpload.state === 'error'\"\n class=\"rfu-image-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n data-testclass=\"upload-error\"\n >\n <stream-icon icon=\"retry\"></stream-icon>\n </div>\n <div class=\"rfu-thumbnail__wrapper\" style=\"width: 100; height: 100\">\n <div class=\"rfu-thumbnail__overlay\">\n <div\n class=\"rfu-icon-button\"\n data-testclass=\"delete-attachment\"\n role=\"button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n <stream-icon icon=\"close\"></stream-icon>\n </div>\n </div>\n <img\n *ngIf=\"attachmentUpload.url || attachmentUpload.previewUri\"\n src=\"{{\n attachmentUpload.url\n ? attachmentUpload.url\n : attachmentUpload.previewUri\n }}\"\n alt=\"attachmentUpload.file.name\"\n class=\"rfu-thumbnail__image\"\n data-testclass=\"attachment-image\"\n />\n </div>\n <stream-loading-indicator\n data-testclass=\"loading-indicator\"\n color=\"rgba(255,255,255,0.7)\"\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n ></stream-loading-indicator>\n </div>\n <div\n class=\"rfu-file-previewer\"\n *ngIf=\"attachmentUpload.type === 'file'\"\n data-testclass=\"attachment-file-preview\"\n >\n <ol>\n <li\n class=\"rfu-file-previewer__file\"\n [class.rfu-file-previewer__file--uploading]=\"\n attachmentUpload.state === 'uploading'\n \"\n [class.rfu-file-previewer__file--failed]=\"\n attachmentUpload.state === 'error'\n \"\n >\n <stream-icon icon=\"file\"></stream-icon>\n\n <a\n data-testclass=\"file-download-link\"\n href=\"{{ attachmentUpload.url }}\"\n (click)=\"attachmentUpload.url ? null : $event.preventDefault()\"\n (keyup.enter)=\"\n attachmentUpload.url ? null : $event.preventDefault()\n \"\n download\n >\n {{ attachmentUpload.file.name }}\n <ng-container *ngIf=\"attachmentUpload.state === 'error'\">\n <div\n data-testclass=\"file-upload-retry\"\n class=\"rfu-file-previewer__failed\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.failed\n </div>\n <div\n class=\"rfu-file-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.retry\n </div>\n </ng-container>\n </a>\n\n <span\n data-testclass=\"file-delete\"\n class=\"rfu-file-previewer__close-button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n \u2718\n </span>\n <div\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n class=\"rfu-file-previewer__loading-indicator\"\n >\n <stream-loading-indicator></stream-loading-indicator>\n </div>\n </li>\n </ol>\n </div>\n </ng-container>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3.AsyncPipe } });
1248
+ AttachmentPreviewListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", ngImport: i0, template: "<div class=\"rfu-image-previewer\" *ngIf=\"(attachmentUploads$ | async)?.length\">\n <ng-container\n *ngFor=\"\n let attachmentUpload of attachmentUploads$ | async;\n trackBy: trackByFile\n \"\n >\n <div\n *ngIf=\"attachmentUpload.type === 'image'\"\n class=\"rfu-image-previewer__image\"\n [class.rfu-image-previewer__image--loaded]=\"\n attachmentUpload.state === 'success'\n \"\n data-testclass=\"attachment-image-preview\"\n >\n <div\n *ngIf=\"attachmentUpload.state === 'error'\"\n class=\"rfu-image-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n data-testclass=\"upload-error\"\n >\n <stream-icon icon=\"retry\"></stream-icon>\n </div>\n <div class=\"rfu-thumbnail__wrapper\" style=\"width: 100; height: 100\">\n <div class=\"rfu-thumbnail__overlay\">\n <div\n class=\"rfu-icon-button\"\n data-testclass=\"delete-attachment\"\n role=\"button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n <stream-icon icon=\"close\"></stream-icon>\n </div>\n </div>\n <img\n *ngIf=\"attachmentUpload.url || attachmentUpload.previewUri\"\n src=\"{{\n attachmentUpload.url\n ? attachmentUpload.url\n : attachmentUpload.previewUri\n }}\"\n alt=\"attachmentUpload.file.name\"\n class=\"rfu-thumbnail__image\"\n data-testclass=\"attachment-image\"\n />\n </div>\n <stream-loading-indicator\n data-testclass=\"loading-indicator\"\n color=\"rgba(255,255,255,0.7)\"\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n ></stream-loading-indicator>\n </div>\n <div\n class=\"rfu-file-previewer\"\n *ngIf=\"attachmentUpload.type === 'file'\"\n data-testclass=\"attachment-file-preview\"\n >\n <ol>\n <li\n class=\"rfu-file-previewer__file\"\n [class.rfu-file-previewer__file--uploading]=\"\n attachmentUpload.state === 'uploading'\n \"\n [class.rfu-file-previewer__file--failed]=\"\n attachmentUpload.state === 'error'\n \"\n >\n <stream-icon icon=\"file\"></stream-icon>\n\n <a\n data-testclass=\"file-download-link\"\n href=\"{{ attachmentUpload.url }}\"\n (click)=\"attachmentUpload.url ? null : $event.preventDefault()\"\n (keyup.enter)=\"\n attachmentUpload.url ? null : $event.preventDefault()\n \"\n download\n >\n {{ attachmentUpload.file.name }}\n <ng-container *ngIf=\"attachmentUpload.state === 'error'\">\n <div\n data-testclass=\"file-upload-retry\"\n class=\"rfu-file-previewer__failed\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.failed\n </div>\n <div\n class=\"rfu-file-previewer__retry\"\n (click)=\"retryAttachmentUpload(attachmentUpload.file)\"\n (keyup.enter)=\"retryAttachmentUpload(attachmentUpload.file)\"\n translate\n >\n streamChat.retry\n </div>\n </ng-container>\n </a>\n\n <span\n data-testclass=\"file-delete\"\n class=\"rfu-file-previewer__close-button\"\n (click)=\"deleteAttachment(attachmentUpload)\"\n (keyup.enter)=\"deleteAttachment(attachmentUpload)\"\n >\n \u2718\n </span>\n <div\n *ngIf=\"attachmentUpload.state === 'uploading'\"\n class=\"rfu-file-previewer__loading-indicator\"\n >\n <stream-loading-indicator></stream-loading-indicator>\n </div>\n </li>\n </ol>\n </div>\n </ng-container>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i3.AsyncPipe } });
1255
1249
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AttachmentPreviewListComponent, decorators: [{
1256
1250
  type: Component,
1257
1251
  args: [{
@@ -1700,7 +1694,7 @@ class MessageActionsBoxComponent {
1700
1694
  }
1701
1695
  }
1702
1696
  MessageActionsBoxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
1703
- MessageActionsBoxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: { messageInputTemplate: "messageInputTemplate", isOpen: "isOpen", isMine: "isMine", message: "message", enabledActions: "enabledActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: MessageInputComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box\"\n [class.str-chat__message-actions-box--open]=\"isOpen\"\n [class.str-chat__message-actions-box--mine]=\"isMine\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <button\n data-testid=\"quote-action\"\n *ngIf=\"isQuoteVisible\"\n (click)=\"quoteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Reply\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"pin-action\"\n *ngIf=\"isPinVisible\"\n (click)=\"pinClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{\n (message?.pinned ? \"streamChat.Unpin\" : \"streamChat.Pin\") | translate\n }}\n </li>\n </button>\n <button\n data-testid=\"flag-action\"\n *ngIf=\"isFlagVisible\"\n (click)=\"flagClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Flag\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"mute-action\"\n *ngIf=\"isMuteVisible\"\n (click)=\"muteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Mute\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"edit-action\"\n *ngIf=\"isEditVisible\"\n (click)=\"editClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Edit Message\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"delete-action\"\n *ngIf=\"isDeleteVisible\"\n (click)=\"deleteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Delete\" | translate }}\n </li>\n </button>\n </ul>\n</div>\n\n<stream-modal\n [isOpen]=\"isEditModalOpen\"\n (isOpenChange)=\"\n isEditModalOpen = $event; isEditModalOpen ? '' : modalClosed()\n \"\n>\n <div class=\"str-chat__edit-message-form\" *ngIf=\"isEditModalOpen\">\n <ng-container *ngIf=\"messageInputTemplate; else defaultInput\">\n <ng-container\n *ngTemplateOutlet=\"\n messageInputTemplate;\n context: {\n message: message,\n messageUpdateHandler: modalClosed\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultInput>\n <stream-message-input\n [message]=\"message\"\n (messageUpdate)=\"modalClosed()\"\n ></stream-message-input>\n </ng-template>\n <stream-notification-list></stream-notification-list>\n <div class=\"str-chat__message-team-form-footer\">\n <div></div>\n <div>\n <button translate data-testid=\"cancel-button\" (click)=\"modalClosed()\">\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n data-testid=\"send-button\"\n (click)=\"sendClicked()\"\n (keyup.enter)=\"sendClicked()\"\n >\n streamChat.Send\n </button>\n </div>\n </div>\n </div>\n</stream-modal>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mentionAutocompleteItemTemplate", "acceptedFileTypes", "isMultipleFileUploadEnabled", "message"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i10.TranslatePipe } });
1697
+ MessageActionsBoxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: { messageInputTemplate: "messageInputTemplate", isOpen: "isOpen", isMine: "isMine", message: "message", enabledActions: "enabledActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: MessageInputComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box\"\n [class.str-chat__message-actions-box--open]=\"isOpen\"\n [class.str-chat__message-actions-box--mine]=\"isMine\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <button\n data-testid=\"quote-action\"\n *ngIf=\"isQuoteVisible\"\n (click)=\"quoteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Reply\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"pin-action\"\n *ngIf=\"isPinVisible\"\n (click)=\"pinClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{\n (message?.pinned ? \"streamChat.Unpin\" : \"streamChat.Pin\") | translate\n }}\n </li>\n </button>\n <button\n data-testid=\"flag-action\"\n *ngIf=\"isFlagVisible\"\n (click)=\"flagClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Flag\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"mute-action\"\n *ngIf=\"isMuteVisible\"\n (click)=\"muteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Mute\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"edit-action\"\n *ngIf=\"isEditVisible\"\n (click)=\"editClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Edit Message\" | translate }}\n </li>\n </button>\n <button\n data-testid=\"delete-action\"\n *ngIf=\"isDeleteVisible\"\n (click)=\"deleteClicked()\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ \"streamChat.Delete\" | translate }}\n </li>\n </button>\n </ul>\n</div>\n\n<stream-modal\n [isOpen]=\"isEditModalOpen\"\n (isOpenChange)=\"\n isEditModalOpen = $event; isEditModalOpen ? '' : modalClosed()\n \"\n>\n <div class=\"str-chat__edit-message-form\" *ngIf=\"isEditModalOpen\">\n <ng-container *ngIf=\"messageInputTemplate; else defaultInput\">\n <ng-container\n *ngTemplateOutlet=\"\n messageInputTemplate;\n context: {\n message: message,\n messageUpdateHandler: modalClosed\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultInput>\n <stream-message-input\n [message]=\"message\"\n (messageUpdate)=\"modalClosed()\"\n ></stream-message-input>\n </ng-template>\n <stream-notification-list></stream-notification-list>\n <div\n class=\"\n str-chat__message-team-form-footer\n str-chat__message-team-form-footer-angular\n \"\n >\n <div class=\"str-chat__edit-message-form-options\">\n <button translate data-testid=\"cancel-button\" (click)=\"modalClosed()\">\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n data-testid=\"send-button\"\n (click)=\"sendClicked()\"\n (keyup.enter)=\"sendClicked()\"\n >\n streamChat.Send\n </button>\n </div>\n </div>\n </div>\n</stream-modal>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mentionAutocompleteItemTemplate", "acceptedFileTypes", "isMultipleFileUploadEnabled", "message"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i10.TranslatePipe } });
1704
1698
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, decorators: [{
1705
1699
  type: Component,
1706
1700
  args: [{
@@ -1847,8 +1841,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1847
1841
  }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChannelListToggleService }]; } });
1848
1842
 
1849
1843
  class ChannelPreviewComponent {
1850
- constructor(channelService) {
1844
+ constructor(channelService, ngZone) {
1851
1845
  this.channelService = channelService;
1846
+ this.ngZone = ngZone;
1852
1847
  this.isActive = false;
1853
1848
  this.isUnread = false;
1854
1849
  this.latestMessage = 'Nothing yet...';
@@ -1869,8 +1864,10 @@ class ChannelPreviewComponent {
1869
1864
  this.subscriptions.push(this.channel.on('message.updated', this.handleMessageEvent.bind(this)));
1870
1865
  this.subscriptions.push(this.channel.on('message.deleted', this.handleMessageEvent.bind(this)));
1871
1866
  this.subscriptions.push(this.channel.on('channel.truncated', this.handleMessageEvent.bind(this)));
1872
- this.subscriptions.push(this.channel.on('message.read', () => (this.isUnread =
1873
- !!this.channel.countUnread() && this.canSendReadEvents)));
1867
+ this.subscriptions.push(this.channel.on('message.read', () => this.ngZone.run(() => {
1868
+ this.isUnread =
1869
+ !!this.channel.countUnread() && this.canSendReadEvents;
1870
+ })));
1874
1871
  }
1875
1872
  ngOnDestroy() {
1876
1873
  this.subscriptions.forEach((s) => s.unsubscribe());
@@ -1891,17 +1888,19 @@ class ChannelPreviewComponent {
1891
1888
  void this.channelService.setAsActiveChannel(this.channel);
1892
1889
  }
1893
1890
  handleMessageEvent(event) {
1894
- var _a, _b, _c;
1895
- if (((_a = this.channel) === null || _a === void 0 ? void 0 : _a.state.messages.length) === 0) {
1896
- this.latestMessage = 'Nothing yet...';
1897
- return;
1898
- }
1899
- if (!event.message ||
1900
- ((_b = this.channel) === null || _b === void 0 ? void 0 : _b.state.messages[((_c = this.channel) === null || _c === void 0 ? void 0 : _c.state.messages.length) - 1].id) !== event.message.id) {
1901
- return;
1902
- }
1903
- this.setLatestMessage(event.message);
1904
- this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
1891
+ this.ngZone.run(() => {
1892
+ var _a, _b, _c;
1893
+ if (((_a = this.channel) === null || _a === void 0 ? void 0 : _a.state.messages.length) === 0) {
1894
+ this.latestMessage = 'Nothing yet...';
1895
+ return;
1896
+ }
1897
+ if (!event.message ||
1898
+ ((_b = this.channel) === null || _b === void 0 ? void 0 : _b.state.messages[((_c = this.channel) === null || _c === void 0 ? void 0 : _c.state.messages.length) - 1].id) !== event.message.id) {
1899
+ return;
1900
+ }
1901
+ this.setLatestMessage(event.message);
1902
+ this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
1903
+ });
1905
1904
  }
1906
1905
  setLatestMessage(message) {
1907
1906
  if (message === null || message === void 0 ? void 0 : message.deleted_at) {
@@ -1915,7 +1914,7 @@ class ChannelPreviewComponent {
1915
1914
  }
1916
1915
  }
1917
1916
  }
1918
- ChannelPreviewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelPreviewComponent, deps: [{ token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
1917
+ ChannelPreviewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelPreviewComponent, deps: [{ token: ChannelService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
1919
1918
  ChannelPreviewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelPreviewComponent, selector: "stream-channel-preview", inputs: { channel: "channel" }, ngImport: i0, template: "<button\n class=\"str-chat__channel-preview-messenger\"\n [class.str-chat__channel-preview-messenger--active]=\"isActive\"\n [class.str-chat__channel-preview-messenger--unread]=\"isUnread\"\n (click)=\"setAsActiveChannel()\"\n data-testid=\"channel-preview-container\"\n>\n <div class=\"str-chat__channel-preview-messenger--left\">\n <stream-avatar\n imageUrl=\"{{ avatarImage }}\"\n name=\"{{ avatarName }}\"\n [size]=\"40\"\n ></stream-avatar>\n </div>\n <div class=\"str-chat__channel-preview-messenger--right\">\n <div class=\"str-chat__channel-preview-messenger--name\">\n <span data-testid=\"channel-preview-title\">{{ title }}</span>\n </div>\n <div\n data-testid=\"latest-message\"\n class=\"str-chat__channel-preview-messenger--last-message\"\n >\n {{ latestMessage | translate }}\n </div>\n </div>\n</button>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i10.TranslatePipe } });
1920
1919
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelPreviewComponent, decorators: [{
1921
1920
  type: Component,
@@ -1924,7 +1923,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
1924
1923
  templateUrl: './channel-preview.component.html',
1925
1924
  styles: [],
1926
1925
  }]
1927
- }], ctorParameters: function () { return [{ type: ChannelService }]; }, propDecorators: { channel: [{
1926
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: i0.NgZone }]; }, propDecorators: { channel: [{
1928
1927
  type: Input
1929
1928
  }] } });
1930
1929
 
@@ -2336,7 +2335,7 @@ class MessageComponent {
2336
2335
  }
2337
2336
  }
2338
2337
  MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }], target: i0.ɵɵFactoryTarget.Component });
2339
- MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { messageInputTemplate: "messageInputTemplate", mentionTemplate: "mentionTemplate", message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage", canReceiveReadEvents: "canReceiveReadEvents" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"\n areReactionsEnabled && hasReactions\n \"\n data-testid=\"message-container\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n isMessageDeliveredAndRead && canReceiveReadEvents;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <stream-message-actions-box\n [isOpen]=\"isActionBoxOpen\"\n [isMine]=\"isSentByCurrentUser\"\n [enabledActions]=\"enabledMessageActions\"\n [message]=\"message\"\n (displayedActionsCount)=\"visibleMessageActionsCount = $event\"\n (isEditing)=\"isEditing = $event; isActionBoxOpen = !isEditing\"\n [messageInputTemplate]=\"messageInputTemplate\"\n ></stream-message-actions-box>\n <stream-icon\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon>\n </div>\n <div\n *ngIf=\"areReactionsEnabled && canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon icon=\"reaction-icon\"></stream-icon>\n </div>\n </div>\n <stream-message-reactions\n *ngIf=\"areReactionsEnabled\"\n [messageReactionCounts]=\"message?.reaction_counts || {}\"\n [latestReactions]=\"message?.latest_reactions || []\"\n [(isSelectorOpen)]=\"isReactionSelectorOpen\"\n [messageId]=\"message?.id\"\n [ownReactions]=\"message?.own_reactions || []\"\n ></stream-message-reactions>\n <stream-attachment-list\n *ngIf=\"hasAttachment\"\n [attachments]=\"message!.attachments!\"\n ></stream-attachment-list>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n >\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-container *ngIf=\"mentionTemplate; else defaultMention\">\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate;\n context: { user: part.user! }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMention>\n <b>{{ part.content }}</b>\n </ng-template>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"sending-indicator\">\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span class=\"str-chat__message-simple-status\" data-testid=\"read-indicator\">\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n class=\"str-chat__message-simple-status\"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["messageInputTemplate", "isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["attachments"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i10.TranslatePipe } });
2338
+ MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { messageInputTemplate: "messageInputTemplate", mentionTemplate: "mentionTemplate", message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage", canReceiveReadEvents: "canReceiveReadEvents" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.mobile-press]=\"isPressedOnMobile\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"\n areReactionsEnabled && hasReactions\n \"\n data-testid=\"message-container\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n isMessageDeliveredAndRead && canReceiveReadEvents;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n </ng-container>\n <stream-avatar\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n ></stream-avatar>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions\"\n data-testid=\"message-options\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n >\n <stream-message-actions-box\n [isOpen]=\"isActionBoxOpen\"\n [isMine]=\"isSentByCurrentUser\"\n [enabledActions]=\"enabledMessageActions\"\n [message]=\"message\"\n (displayedActionsCount)=\"visibleMessageActionsCount = $event\"\n (isEditing)=\"isEditing = $event; isActionBoxOpen = !isEditing\"\n [messageInputTemplate]=\"messageInputTemplate\"\n ></stream-message-actions-box>\n <stream-icon\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n icon=\"action-icon\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n ></stream-icon>\n </div>\n <div\n *ngIf=\"areReactionsEnabled && canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon icon=\"reaction-icon\"></stream-icon>\n </div>\n </div>\n <stream-message-reactions\n *ngIf=\"areReactionsEnabled\"\n [messageReactionCounts]=\"message?.reaction_counts || {}\"\n [latestReactions]=\"message?.latest_reactions || []\"\n [(isSelectorOpen)]=\"isReactionSelectorOpen\"\n [messageId]=\"message?.id\"\n [ownReactions]=\"message?.own_reactions || []\"\n ></stream-message-reactions>\n <stream-attachment-list\n *ngIf=\"hasAttachment\"\n [attachments]=\"message!.attachments!\"\n ></stream-attachment-list>\n <div class=\"str-chat__message-text\" *ngIf=\"message?.text\">\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"str-chat__simple-message--error-message\"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div\n (click)=\"textClicked()\"\n (keyup.enter)=\"textClicked()\"\n data-testid=\"text\"\n >\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-container *ngIf=\"mentionTemplate; else defaultMention\">\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate;\n context: { user: part.user! }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMention>\n <b>{{ part.content }}</b>\n </ng-template>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <div class=\"str-chat__message-data str-chat__message-simple-data\">\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #sendingStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"sending-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n <stream-loading-indicator\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator>\n </span>\n</ng-template>\n<ng-template #readStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"read-indicator\"\n >\n <div class=\"str-chat__tooltip\" data-testid=\"read-by-tooltip\">\n {{ readByText }}\n </div>\n <stream-avatar\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n ></stream-avatar>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n</ng-template>\n<ng-template #deliveredStatus>\n <span\n class=\"\n str-chat__message-simple-status str-chat__message-simple-status-angular\n \"\n data-testid=\"delivered-indicator\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n <stream-icon\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon>\n </span>\n</ng-template>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["messageInputTemplate", "isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["attachments"] }, { type: LoadingIndicatorComponent, selector: "stream-loading-indicator", inputs: ["size", "color"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i10.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i10.TranslatePipe } });
2340
2339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, decorators: [{
2341
2340
  type: Component,
2342
2341
  args: [{
@@ -2430,24 +2429,28 @@ class AutocompleteTextareaComponent {
2430
2429
  this.send = new EventEmitter();
2431
2430
  this.userMentions = new EventEmitter();
2432
2431
  this.labelKey = 'autocompleteLabel';
2433
- this.triggerChar = '@';
2432
+ this.mentionTriggerChar = '@';
2434
2433
  this.autocompleteConfig = {
2435
2434
  mentions: [],
2436
2435
  };
2437
2436
  this.subscriptions = [];
2438
2437
  this.mentionedUsers = [];
2439
2438
  this.userMentionConfig = {
2440
- triggerChar: this.triggerChar,
2439
+ triggerChar: this.mentionTriggerChar,
2441
2440
  dropUp: true,
2442
2441
  labelKey: this.labelKey,
2443
2442
  returnTrigger: true,
2444
2443
  mentionFilter: (searchString, items) => this.filter(searchString, items),
2445
- mentionSelect: (item, triggerChar) => this.mentioned(item, triggerChar),
2444
+ mentionSelect: (item, triggerChar) => this.itemSelectedFromAutocompleteList(item, triggerChar),
2446
2445
  };
2447
2446
  this.searchTerm$ = new BehaviorSubject('');
2448
2447
  this.searchTerm$
2449
2448
  .pipe(debounceTime(300), distinctUntilChanged())
2450
- .subscribe((searchTerm) => void this.updateMentionOptions(searchTerm));
2449
+ .subscribe((searchTerm) => {
2450
+ if (searchTerm.startsWith(this.mentionTriggerChar)) {
2451
+ void this.updateMentionOptions(searchTerm);
2452
+ }
2453
+ });
2451
2454
  this.subscriptions.push(this.channelService.activeChannel$.subscribe(() => {
2452
2455
  this.mentionedUsers = [];
2453
2456
  this.userMentions.next([...this.mentionedUsers]);
@@ -2472,17 +2475,19 @@ class AutocompleteTextareaComponent {
2472
2475
  filter(searchString, items) {
2473
2476
  return items.filter((item) => this.transliterate(item.autocompleteLabel.toLowerCase()).includes(this.transliterate(searchString.toLowerCase())));
2474
2477
  }
2475
- mentioned(item, triggerChar = '') {
2476
- this.mentionedUsers.push((item.user ? item.user : item));
2477
- this.userMentions.next([...this.mentionedUsers]);
2478
+ itemSelectedFromAutocompleteList(item, triggerChar = '') {
2479
+ if (triggerChar === this.mentionTriggerChar) {
2480
+ this.mentionedUsers.push((item.user ? item.user : item));
2481
+ this.userMentions.next([...this.mentionedUsers]);
2482
+ }
2478
2483
  return triggerChar + item.autocompleteLabel;
2479
2484
  }
2480
2485
  autcompleteSearchTermChanged(searchTerm) {
2481
- if (searchTerm === this.triggerChar) {
2486
+ if (searchTerm === this.mentionTriggerChar) {
2482
2487
  void this.updateMentionOptions();
2483
2488
  }
2484
2489
  else {
2485
- this.searchTerm$.next(searchTerm.replace(this.triggerChar, ''));
2490
+ this.searchTerm$.next(searchTerm);
2486
2491
  }
2487
2492
  }
2488
2493
  inputChanged() {
@@ -2509,6 +2514,7 @@ class AutocompleteTextareaComponent {
2509
2514
  if (!this.areMentionsEnabled) {
2510
2515
  return;
2511
2516
  }
2517
+ searchTerm = searchTerm === null || searchTerm === void 0 ? void 0 : searchTerm.replace(this.mentionTriggerChar, '');
2512
2518
  const request = this.mentionScope === 'application'
2513
2519
  ? (s) => this.chatClientService.autocompleteUsers(s)
2514
2520
  : (s) => this.channelService.autocompleteMembers(s);
@@ -2526,7 +2532,7 @@ class AutocompleteTextareaComponent {
2526
2532
  const updatedMentionedUsers = [];
2527
2533
  this.mentionedUsers.forEach((u) => {
2528
2534
  const key = u.name || u.id;
2529
- if (this.value.includes(`${this.triggerChar}${key}`)) {
2535
+ if (this.value.includes(`${this.mentionTriggerChar}${key}`)) {
2530
2536
  updatedMentionedUsers.push(u);
2531
2537
  }
2532
2538
  });