stream-chat-angular 2.1.0 → 2.4.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.
package/README.md CHANGED
@@ -35,7 +35,7 @@ For complete pricing and details visit our [Chat Pricing Page](https://getstream
35
35
  ### Install with NPM
36
36
 
37
37
  ```
38
- npm install stream-chat-angular stream-chat-css stream-chat @ngx-translate/core
38
+ npm install stream-chat-angular @stream-io/stream-chat-css stream-chat @ngx-translate/core
39
39
  ```
40
40
 
41
41
  **Important note** If you are using **Angular 12** you will need to add `--legacy-peer-deps` flag as `@ngx-translate/core`'s newest version only supports Angular 13.
@@ -77,5 +77,7 @@ export declare const en: {
77
77
  failed: string;
78
78
  retry: string;
79
79
  test: string;
80
+ 'Sending links is not allowed in this conversation': string;
81
+ "You can't send messages in this channel": string;
80
82
  };
81
83
  };
@@ -1 +1 @@
1
- export declare const version = "2.1.0";
1
+ export declare const version = "2.4.0";
@@ -353,7 +353,7 @@
353
353
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
354
354
  }
355
355
 
356
- var version = '2.1.0';
356
+ var version = '2.4.0';
357
357
 
358
358
  var NotificationService = /** @class */ (function () {
359
359
  function NotificationService() {
@@ -593,7 +593,9 @@
593
593
  channel.state.messages.forEach(function (m) {
594
594
  m.readBy = getReadBy(m, channel);
595
595
  });
596
- void channel.markRead();
596
+ if (this.canSendReadEvents) {
597
+ void channel.markRead();
598
+ }
597
599
  this.activeChannelMessagesSubject.next(__spreadArray([], __read(channel.state.messages)));
598
600
  };
599
601
  ChannelService.prototype.loadMoreMessages = function () {
@@ -979,9 +981,11 @@
979
981
  this.activeChannelSubscriptions.push(channel.on('message.new', function () {
980
982
  _this.ngZone.run(function () {
981
983
  _this.activeChannelMessagesSubject.next(__spreadArray([], __read(channel.state.messages)));
982
- _this.activeChannel$
983
- .pipe(operators.first())
984
- .subscribe(function (c) { return void (c === null || c === void 0 ? void 0 : c.markRead()); });
984
+ _this.activeChannel$.pipe(operators.first()).subscribe(function (c) {
985
+ if (_this.canSendReadEvents) {
986
+ void (c === null || c === void 0 ? void 0 : c.markRead());
987
+ }
988
+ });
985
989
  });
986
990
  }));
987
991
  this.activeChannelSubscriptions.push(channel.on('message.updated', function (event) { return _this.messageUpdated(event); }));
@@ -1200,6 +1204,19 @@
1200
1204
  enumerable: false,
1201
1205
  configurable: true
1202
1206
  });
1207
+ Object.defineProperty(ChannelService.prototype, "canSendReadEvents", {
1208
+ get: function () {
1209
+ var _a;
1210
+ var channel = this.activeChannelSubject.getValue();
1211
+ if (!channel) {
1212
+ return false;
1213
+ }
1214
+ var capabilites = (_a = channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
1215
+ return capabilites.indexOf('read-events') !== -1;
1216
+ },
1217
+ enumerable: false,
1218
+ configurable: true
1219
+ });
1203
1220
  return ChannelService;
1204
1221
  }());
1205
1222
  ChannelService.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0__namespace.ApplicationRef }, { token: i0__namespace.NgZone }], target: i0__namespace.ɵɵFactoryTarget.Injectable });
@@ -1602,6 +1619,8 @@
1602
1619
  failed: 'failed',
1603
1620
  retry: 'retry',
1604
1621
  test: 'success',
1622
+ 'Sending links is not allowed in this conversation': 'Sending links is not allowed in this conversation',
1623
+ "You can't send messages in this channel": "You can't send messages in this channel",
1605
1624
  },
1606
1625
  };
1607
1626
 
@@ -1712,9 +1731,11 @@
1712
1731
  this.send = new i0.EventEmitter();
1713
1732
  this.userMentions = new i0.EventEmitter();
1714
1733
  this.subscriptions = [];
1734
+ this.unpropagatedChanges = [];
1715
1735
  }
1716
1736
  TextareaDirective.prototype.ngOnChanges = function (changes) {
1717
1737
  var _this = this;
1738
+ this.unpropagatedChanges.push(changes);
1718
1739
  if (!this.componentRef) {
1719
1740
  return;
1720
1741
  }
@@ -1726,6 +1747,11 @@
1726
1747
  if (this.componentRef.instance.userMentions) {
1727
1748
  this.subscriptions.push(this.componentRef.instance.userMentions.subscribe(function (value) { return _this.userMentions.next(value); }));
1728
1749
  }
1750
+ this.componentRef.instance.areMentionsEnabled = this.areMentionsEnabled;
1751
+ this.componentRef.instance.mentionAutocompleteItemTemplate =
1752
+ this.mentionAutocompleteItemTemplate;
1753
+ this.componentRef.instance.mentionScope = this.mentionScope;
1754
+ this.componentRef.instance.value = this.value;
1729
1755
  }
1730
1756
  }
1731
1757
  if (changes.areMentionsEnabled) {
@@ -1742,8 +1768,11 @@
1742
1768
  this.componentRef.instance.value = this.value;
1743
1769
  }
1744
1770
  // ngOnChanges not called for dynamic components since we don't use template binding
1771
+ var changesToPropagate = {};
1772
+ this.unpropagatedChanges.forEach(function (c) { return (changesToPropagate = Object.assign(Object.assign({}, changesToPropagate), c)); });
1745
1773
  // eslint-disable-next-line @angular-eslint/no-lifecycle-call
1746
- this.componentRef.instance.ngOnChanges(changes);
1774
+ this.componentRef.instance.ngOnChanges(changesToPropagate);
1775
+ this.unpropagatedChanges = [];
1747
1776
  };
1748
1777
  return TextareaDirective;
1749
1778
  }());
@@ -1836,7 +1865,7 @@
1836
1865
  }], ctorParameters: function () { return [{ type: AttachmentService }]; } });
1837
1866
 
1838
1867
  var MessageInputComponent = /** @class */ (function () {
1839
- function MessageInputComponent(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver) {
1868
+ function MessageInputComponent(channelService, notificationService, attachmentService, configService, textareaType, componentFactoryResolver, cdRef) {
1840
1869
  var _this = this;
1841
1870
  this.channelService = channelService;
1842
1871
  this.notificationService = notificationService;
@@ -1844,10 +1873,18 @@
1844
1873
  this.configService = configService;
1845
1874
  this.textareaType = textareaType;
1846
1875
  this.componentFactoryResolver = componentFactoryResolver;
1876
+ this.cdRef = cdRef;
1847
1877
  this.messageUpdate = new i0.EventEmitter();
1848
1878
  this.textareaValue = '';
1849
1879
  this.mentionedUsers = [];
1850
1880
  this.subscriptions = [];
1881
+ this.isViewInited = false;
1882
+ this.subscriptions.push(this.attachmentService.attachmentUploadInProgressCounter$.subscribe(function (counter) {
1883
+ if (counter === 0 && _this.hideNotification) {
1884
+ _this.hideNotification();
1885
+ _this.hideNotification = undefined;
1886
+ }
1887
+ }));
1851
1888
  this.subscriptions.push(this.channelService.activeChannel$.subscribe(function (channel) {
1852
1889
  var _a;
1853
1890
  _this.textareaValue = '';
@@ -1856,12 +1893,12 @@
1856
1893
  if (capabilities) {
1857
1894
  _this.isFileUploadAuthorized =
1858
1895
  capabilities.indexOf('upload-file') !== -1;
1859
- }
1860
- }));
1861
- this.subscriptions.push(this.attachmentService.attachmentUploadInProgressCounter$.subscribe(function (counter) {
1862
- if (counter === 0 && _this.hideNotification) {
1863
- _this.hideNotification();
1864
- _this.hideNotification = undefined;
1896
+ _this.canSendLinks = capabilities.indexOf('send-links') !== -1;
1897
+ _this.canSendMessages = capabilities.indexOf('send-message') !== -1;
1898
+ if (_this.isViewInited) {
1899
+ _this.cdRef.detectChanges();
1900
+ _this.initTextarea();
1901
+ }
1865
1902
  }
1866
1903
  }));
1867
1904
  this.attachmentUploads$ = this.attachmentService.attachmentUploads$;
@@ -1874,10 +1911,9 @@
1874
1911
  this.configService.mentionAutocompleteItemTemplate;
1875
1912
  this.mentionScope = this.configService.mentionScope;
1876
1913
  }
1877
- MessageInputComponent.prototype.ngOnInit = function () {
1878
- var componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.textareaType);
1879
- this.textareaRef =
1880
- this.textareaAnchor.viewContainerRef.createComponent(componentFactory);
1914
+ MessageInputComponent.prototype.ngAfterViewInit = function () {
1915
+ this.isViewInited = true;
1916
+ this.initTextarea();
1881
1917
  };
1882
1918
  MessageInputComponent.prototype.ngOnChanges = function (changes) {
1883
1919
  if (changes.message) {
@@ -1932,6 +1968,10 @@
1932
1968
  if (!text && (!attachments || attachments.length === 0)) {
1933
1969
  return [2 /*return*/];
1934
1970
  }
1971
+ if (this.containsLinks && !this.canSendLinks) {
1972
+ this.notificationService.addTemporaryNotification('streamChat.Sending links is not allowed in this conversation');
1973
+ return [2 /*return*/];
1974
+ }
1935
1975
  if (!this.isUpdate) {
1936
1976
  this.textareaValue = '';
1937
1977
  }
@@ -1959,6 +1999,13 @@
1959
1999
  });
1960
2000
  });
1961
2001
  };
2002
+ Object.defineProperty(MessageInputComponent.prototype, "containsLinks", {
2003
+ get: function () {
2004
+ return /(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-&?=%.]+/.test(this.textareaValue);
2005
+ },
2006
+ enumerable: false,
2007
+ configurable: true
2008
+ });
1962
2009
  Object.defineProperty(MessageInputComponent.prototype, "accept", {
1963
2010
  get: function () {
1964
2011
  var _a;
@@ -1990,10 +2037,19 @@
1990
2037
  enumerable: false,
1991
2038
  configurable: true
1992
2039
  });
2040
+ MessageInputComponent.prototype.initTextarea = function () {
2041
+ if (!this.canSendMessages || this.textareaRef || !this.textareaAnchor) {
2042
+ return;
2043
+ }
2044
+ var componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.textareaType);
2045
+ this.textareaRef =
2046
+ this.textareaAnchor.viewContainerRef.createComponent(componentFactory);
2047
+ this.cdRef.detectChanges();
2048
+ };
1993
2049
  return MessageInputComponent;
1994
2050
  }());
1995
- MessageInputComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0__namespace.ComponentFactoryResolver }], target: i0__namespace.ɵɵFactoryTarget.Component });
1996
- MessageInputComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true, static: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n class=\"str-chat__input-flat\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n>\n <div class=\"str-chat__input-flat-wrapper\">\n <div class=\"str-chat__input-flat--textarea-wrapper\">\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea\">\n <ng-template\n streamTextarea\n [(value)]=\"textareaValue\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i1__namespace.TranslatePipe } });
2051
+ MessageInputComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0__namespace.ComponentFactoryResolver }, { token: i0__namespace.ChangeDetectorRef }], target: i0__namespace.ɵɵFactoryTarget.Component });
2052
+ MessageInputComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n class=\"str-chat__input-flat\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n>\n <div class=\"str-chat__input-flat-wrapper\">\n <div class=\"str-chat__input-flat--textarea-wrapper\">\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea\">\n <ng-template\n *ngIf=\"canSendMessages; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"\n 'streamChat.You can\\'t send messages in this channel' | translate\n \"\n class=\"rta__textarea str-chat__textarea__textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }], directives: [{ type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i3__namespace.AsyncPipe, "translate": i1__namespace.TranslatePipe } });
1997
2053
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, decorators: [{
1998
2054
  type: i0.Component,
1999
2055
  args: [{
@@ -2006,7 +2062,7 @@
2006
2062
  return [{ type: ChannelService }, { type: NotificationService }, { type: AttachmentService }, { type: MessageInputConfigService }, { type: i0__namespace.Type, decorators: [{
2007
2063
  type: i0.Inject,
2008
2064
  args: [textareaInjectionToken]
2009
- }] }, { type: i0__namespace.ComponentFactoryResolver }];
2065
+ }] }, { type: i0__namespace.ComponentFactoryResolver }, { type: i0__namespace.ChangeDetectorRef }];
2010
2066
  }, propDecorators: { isFileUploadEnabled: [{
2011
2067
  type: i0.Input
2012
2068
  }], areMentionsEnabled: [{
@@ -2028,7 +2084,7 @@
2028
2084
  args: ['fileInput']
2029
2085
  }], textareaAnchor: [{
2030
2086
  type: i0.ViewChild,
2031
- args: [TextareaDirective, { static: true }]
2087
+ args: [TextareaDirective, { static: false }]
2032
2088
  }] } });
2033
2089
 
2034
2090
  var ModalComponent = /** @class */ (function () {
@@ -2134,6 +2190,7 @@
2134
2190
 
2135
2191
  var MessageActionsBoxComponent = /** @class */ (function () {
2136
2192
  function MessageActionsBoxComponent(chatClientService, notificationService, channelService) {
2193
+ var _this = this;
2137
2194
  this.chatClientService = chatClientService;
2138
2195
  this.notificationService = notificationService;
2139
2196
  this.channelService = channelService;
@@ -2143,6 +2200,10 @@
2143
2200
  this.displayedActionsCount = new i0.EventEmitter();
2144
2201
  this.isEditing = new i0.EventEmitter();
2145
2202
  this.isEditModalOpen = false;
2203
+ this.modalClosed = function () {
2204
+ _this.isEditModalOpen = false;
2205
+ _this.isEditing.emit(false);
2206
+ };
2146
2207
  }
2147
2208
  MessageActionsBoxComponent.prototype.ngOnChanges = function (changes) {
2148
2209
  if (changes.isMine || changes.enabledActions) {
@@ -2250,10 +2311,6 @@
2250
2311
  var _a;
2251
2312
  (_a = this.messageInput) === null || _a === void 0 ? void 0 : _a.messageSent();
2252
2313
  };
2253
- MessageActionsBoxComponent.prototype.modalClosed = function () {
2254
- this.isEditModalOpen = false;
2255
- this.isEditing.emit(false);
2256
- };
2257
2314
  MessageActionsBoxComponent.prototype.deleteClicked = function () {
2258
2315
  return __awaiter(this, void 0, void 0, function () {
2259
2316
  var error_1;
@@ -2277,7 +2334,7 @@
2277
2334
  return MessageActionsBoxComponent;
2278
2335
  }());
2279
2336
  MessageActionsBoxComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageActionsBoxComponent, deps: [{ token: ChatClientService }, { token: NotificationService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2280
- MessageActionsBoxComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: { 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__namespace, 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 <stream-message-input\n [message]=\"message\"\n (messageUpdate)=\"modalClosed()\"\n ></stream-message-input>\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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1__namespace.TranslatePipe } });
2337
+ MessageActionsBoxComponent.ɵcmp = i0__namespace.ɵɵ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__namespace, 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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1__namespace.TranslatePipe } });
2281
2338
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageActionsBoxComponent, decorators: [{
2282
2339
  type: i0.Component,
2283
2340
  args: [{
@@ -2285,7 +2342,9 @@
2285
2342
  templateUrl: './message-actions-box.component.html',
2286
2343
  styles: [],
2287
2344
  }]
2288
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }]; }, propDecorators: { isOpen: [{
2345
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
2346
+ type: i0.Input
2347
+ }], isOpen: [{
2289
2348
  type: i0.Input
2290
2349
  }], isMine: [{
2291
2350
  type: i0.Input
@@ -2391,7 +2450,16 @@
2391
2450
  var _this = this;
2392
2451
  this.channelService = channelService;
2393
2452
  this.channelListToggleService = channelListToggleService;
2394
- this.channelService.activeChannel$.subscribe(function (c) { return (_this.activeChannel = c); });
2453
+ this.channelService.activeChannel$.subscribe(function (c) {
2454
+ var _a, _b;
2455
+ _this.activeChannel = c;
2456
+ var capabilities = (_b = (_a = _this.activeChannel) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.own_capabilities;
2457
+ if (!capabilities) {
2458
+ return;
2459
+ }
2460
+ _this.canReceiveConnectEvents =
2461
+ capabilities.indexOf('connect-events') !== -1;
2462
+ });
2395
2463
  }
2396
2464
  ChannelHeaderComponent.prototype.toggleMenu = function (event) {
2397
2465
  event.stopPropagation();
@@ -2416,7 +2484,7 @@
2416
2484
  return ChannelHeaderComponent;
2417
2485
  }());
2418
2486
  ChannelHeaderComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelHeaderComponent, deps: [{ token: ChannelService }, { token: ChannelListToggleService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2419
- ChannelHeaderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0__namespace, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n </div>\n <stream-avatar\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar>\n <div class=\"str-chat__header-livestream-left\">\n <p class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{'streamChat.{{ watcherCount }} online' | translate:watcherCountParam}}\n </p>\n </div>\n</div>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i1__namespace.TranslatePipe } });
2487
+ ChannelHeaderComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelHeaderComponent, selector: "stream-channel-header", ngImport: i0__namespace, template: "<div class=\"str-chat__header-livestream\">\n <div\n class=\"str-chat__header-hamburger\"\n (click)=\"toggleMenu($event)\"\n (keyup.enter)=\"toggleMenu($event)\"\n >\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n <span class=\"str-chat__header-hamburger--line\"></span>\n </div>\n <stream-avatar\n imageUrl=\"{{ activeChannel?.data?.image }}\"\n name=\"{{ activeChannel?.data?.name }}\"\n ></stream-avatar>\n <div class=\"str-chat__header-livestream-left\">\n <p data-testid=\"name\" class=\"str-chat__header-livestream-left--title\">\n {{ activeChannel?.data?.name }}\n </p>\n <p data-testid=\"info\" class=\"str-chat__header-livestream-left--members\">\n {{'streamChat.{{ memberCount }} members' | translate:memberCountParam}}\n {{canReceiveConnectEvents ? ('streamChat.{{ watcherCount }} online' |\n translate:watcherCountParam) : ''}}\n </p>\n </div>\n</div>\n", components: [{ type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }], pipes: { "translate": i1__namespace.TranslatePipe } });
2420
2488
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelHeaderComponent, decorators: [{
2421
2489
  type: i0.Component,
2422
2490
  args: [{
@@ -2433,21 +2501,25 @@
2433
2501
  this.isUnread = false;
2434
2502
  this.latestMessage = 'Nothing yet...';
2435
2503
  this.subscriptions = [];
2504
+ this.canSendReadEvents = true;
2436
2505
  }
2437
2506
  ChannelPreviewComponent.prototype.ngOnInit = function () {
2438
2507
  var _this = this;
2439
- var _a, _b;
2508
+ var _a, _b, _c, _d;
2440
2509
  this.subscriptions.push(this.channelService.activeChannel$.subscribe(function (activeChannel) { var _a; return (_this.isActive = (activeChannel === null || activeChannel === void 0 ? void 0 : activeChannel.id) === ((_a = _this.channel) === null || _a === void 0 ? void 0 : _a.id)); }));
2441
2510
  var messages = (_b = (_a = this.channel) === null || _a === void 0 ? void 0 : _a.state) === null || _b === void 0 ? void 0 : _b.messages;
2442
2511
  if (messages && messages.length > 0) {
2443
2512
  this.setLatestMessage(messages[messages.length - 1]);
2444
2513
  }
2445
- this.isUnread = !!this.channel.countUnread();
2514
+ this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
2515
+ var capabilities = ((_d = (_c = this.channel) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.own_capabilities) || [];
2516
+ this.canSendReadEvents = capabilities.indexOf('read-events') !== -1;
2446
2517
  this.subscriptions.push(this.channel.on('message.new', this.handleMessageEvent.bind(this)));
2447
2518
  this.subscriptions.push(this.channel.on('message.updated', this.handleMessageEvent.bind(this)));
2448
2519
  this.subscriptions.push(this.channel.on('message.deleted', this.handleMessageEvent.bind(this)));
2449
2520
  this.subscriptions.push(this.channel.on('channel.truncated', this.handleMessageEvent.bind(this)));
2450
- this.subscriptions.push(this.channel.on('message.read', function () { return (_this.isUnread = !!_this.channel.countUnread()); }));
2521
+ this.subscriptions.push(this.channel.on('message.read', function () { return (_this.isUnread =
2522
+ !!_this.channel.countUnread() && _this.canSendReadEvents); }));
2451
2523
  };
2452
2524
  ChannelPreviewComponent.prototype.ngOnDestroy = function () {
2453
2525
  this.subscriptions.forEach(function (s) { return s.unsubscribe(); });
@@ -2490,7 +2562,7 @@
2490
2562
  return;
2491
2563
  }
2492
2564
  this.setLatestMessage(event.message);
2493
- this.isUnread = !!this.channel.countUnread();
2565
+ this.isUnread = !!this.channel.countUnread() && this.canSendReadEvents;
2494
2566
  };
2495
2567
  ChannelPreviewComponent.prototype.setLatestMessage = function (message) {
2496
2568
  if (message === null || message === void 0 ? void 0 : message.deleted_at) {
@@ -2973,7 +3045,7 @@
2973
3045
  return MessageComponent;
2974
3046
  }());
2975
3047
  MessageComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2976
- MessageComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0__namespace, 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 *ngIf=\"isMessageDeliveredAndRead; else deliveredStatus\">\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 ></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 [innerHTML]=\"\n message?.html || message?.text\n | highlightMentions: message?.mentioned_users\n \"\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: ["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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1__namespace.TranslatePipe, "highlightMentions": HighlightMentionsPipe } });
3048
+ MessageComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { messageInputTemplate: "messageInputTemplate", message: "message", enabledMessageActions: "enabledMessageActions", areReactionsEnabled: "areReactionsEnabled", canReactToMessage: "canReactToMessage", isLastSentMessage: "isLastSentMessage", canReceiveReadEvents: "canReceiveReadEvents" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0__namespace, 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 [innerHTML]=\"\n message?.html || message?.text\n | highlightMentions: message?.mentioned_users\n \"\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__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i1__namespace.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i1__namespace.TranslatePipe, "highlightMentions": HighlightMentionsPipe } });
2977
3049
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageComponent, decorators: [{
2978
3050
  type: i0.Component,
2979
3051
  args: [{
@@ -2981,7 +3053,9 @@
2981
3053
  templateUrl: './message.component.html',
2982
3054
  styles: [],
2983
3055
  }]
2984
- }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }]; }, propDecorators: { message: [{
3056
+ }], ctorParameters: function () { return [{ type: ChatClientService }, { type: ChannelService }]; }, propDecorators: { messageInputTemplate: [{
3057
+ type: i0.Input
3058
+ }], message: [{
2985
3059
  type: i0.Input
2986
3060
  }], enabledMessageActions: [{
2987
3061
  type: i0.Input
@@ -2991,6 +3065,8 @@
2991
3065
  type: i0.Input
2992
3066
  }], isLastSentMessage: [{
2993
3067
  type: i0.Input
3068
+ }], canReceiveReadEvents: [{
3069
+ type: i0.Input
2994
3070
  }], container: [{
2995
3071
  type: i0.ViewChild,
2996
3072
  args: ['container']
@@ -3278,6 +3354,7 @@
3278
3354
  var capabilites = (_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.own_capabilities;
3279
3355
  if (capabilites) {
3280
3356
  _this.canReactToMessage = capabilites.indexOf('send-reaction') !== -1;
3357
+ _this.canReceiveReadEvents = capabilites.indexOf('read-events') !== -1;
3281
3358
  _this.authorizedMessageActions = [];
3282
3359
  if (capabilites.indexOf('flag-message') !== -1) {
3283
3360
  _this.authorizedMessageActions.push('flag');
@@ -3410,7 +3487,7 @@
3410
3487
  return MessageListComponent;
3411
3488
  }());
3412
3489
  MessageListComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageListComponent, deps: [{ token: ChannelService }, { token: ChatClientService }, { token: ImageLoadService }], target: i0__namespace.ɵɵFactoryTarget.Component });
3413
- MessageListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { messageTemplate: "messageTemplate", areReactionsEnabled: "areReactionsEnabled", enabledMessageActionsInput: ["enabledMessageActions", "enabledMessageActionsInput"] }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container *ngIf=\"messageTemplate; else defaultMessageTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate;\n context: {\n message: message,\n areReactionsEnabled: areReactionsEnabled,\n canReactToMessage: canReactToMessage,\n lastSentMessageId: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n )\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMessageTemplate>\n <stream-message\n [message]=\"message\"\n [areReactionsEnabled]=\"areReactionsEnabled\"\n [canReactToMessage]=\"canReactToMessage\"\n [isLastSentMessage]=\"\n !!(lastSentMessageId && message?.id === lastSentMessageId)\n \"\n [enabledMessageActions]=\"enabledMessageActions\"\n ></stream-message>\n </ng-template>\n </li>\n </ul>\n </div>\n</div>\n<div class=\"str-chat__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n", components: [{ type: MessageComponent, selector: "stream-message", inputs: ["message", "enabledMessageActions", "areReactionsEnabled", "canReactToMessage", "isLastSentMessage"] }], directives: [{ type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe } });
3490
+ MessageListComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageListComponent, selector: "stream-message-list", inputs: { messageTemplate: "messageTemplate", messageInputTemplate: "messageInputTemplate", areReactionsEnabled: "areReactionsEnabled", enabledMessageActionsInput: ["enabledMessageActions", "enabledMessageActionsInput"] }, host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n #scrollContainer\n data-testid=\"scroll-container\"\n class=\"str-chat__list\"\n (scroll)=\"scrolled()\"\n>\n <div class=\"str-chat__reverse-infinite-scroll\">\n <ul class=\"str-chat__ul\">\n <li\n data-testclass=\"message\"\n *ngFor=\"\n let message of messages$ | async;\n let i = index;\n trackBy: trackByMessageId\n \"\n class=\"str-chat__li str-chat__li--{{ groupStyles[i] }}\"\n >\n <ng-container *ngIf=\"messageTemplate; else defaultMessageTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n messageTemplate;\n context: {\n message: message,\n areReactionsEnabled: areReactionsEnabled,\n canReactToMessage: canReactToMessage,\n lastSentMessageId: !!(\n lastSentMessageId && message?.id === lastSentMessageId\n ),\n canReceiveReadEvents: canReceiveReadEvents,\n messageInputTemplate: messageInputTemplate\n }\n \"\n ></ng-container>\n </ng-container>\n <ng-template #defaultMessageTemplate>\n <stream-message\n [message]=\"message\"\n [areReactionsEnabled]=\"areReactionsEnabled\"\n [canReactToMessage]=\"canReactToMessage\"\n [isLastSentMessage]=\"\n !!(lastSentMessageId && message?.id === lastSentMessageId)\n \"\n [enabledMessageActions]=\"enabledMessageActions\"\n [canReceiveReadEvents]=\"canReceiveReadEvents\"\n [messageInputTemplate]=\"messageInputTemplate\"\n ></stream-message>\n </ng-template>\n </li>\n </ul>\n </div>\n</div>\n<div class=\"str-chat__list-notifications\">\n <button\n data-testid=\"scroll-to-bottom\"\n *ngIf=\"isUserScrolledUp\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-right\n str-chat__message-notification-scroll-down\n \"\n (keyup.enter)=\"scrollToBottom()\"\n (click)=\"scrollToBottom()\"\n >\n <div\n *ngIf=\"unreadMessageCount > 0\"\n class=\"\n str-chat__message-notification\n str-chat__message-notification-scroll-down-unread-count\n \"\n >\n {{ unreadMessageCount }}\n </div>\n </button>\n</div>\n", components: [{ type: MessageComponent, selector: "stream-message", inputs: ["messageInputTemplate", "message", "enabledMessageActions", "areReactionsEnabled", "canReactToMessage", "isLastSentMessage", "canReceiveReadEvents"] }], directives: [{ type: i3__namespace.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i3__namespace.AsyncPipe } });
3414
3491
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageListComponent, decorators: [{
3415
3492
  type: i0.Component,
3416
3493
  args: [{
@@ -3420,6 +3497,8 @@
3420
3497
  }]
3421
3498
  }], ctorParameters: function () { return [{ type: ChannelService }, { type: ChatClientService }, { type: ImageLoadService }]; }, propDecorators: { messageTemplate: [{
3422
3499
  type: i0.Input
3500
+ }], messageInputTemplate: [{
3501
+ type: i0.Input
3423
3502
  }], areReactionsEnabled: [{
3424
3503
  type: i0.Input
3425
3504
  }], enabledMessageActionsInput: [{