stream-chat-angular 4.59.2 → 4.60.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.
Files changed (44) hide show
  1. package/assets/i18n/en.d.ts +2 -0
  2. package/assets/version.d.ts +1 -1
  3. package/bundles/stream-chat-angular.umd.js +347 -173
  4. package/bundles/stream-chat-angular.umd.js.map +1 -1
  5. package/esm2015/assets/i18n/en.js +3 -1
  6. package/esm2015/assets/version.js +2 -2
  7. package/esm2015/lib/channel/channel.component.js +13 -9
  8. package/esm2015/lib/channel.service.js +24 -2
  9. package/esm2015/lib/custom-templates.service.js +9 -1
  10. package/esm2015/lib/edit-message-form/edit-message-form.component.js +87 -0
  11. package/esm2015/lib/message/message.component.js +16 -25
  12. package/esm2015/lib/message-actions-box/message-actions-box.component.js +6 -46
  13. package/esm2015/lib/message-bounce-prompt/message-bounce-prompt.component.js +80 -0
  14. package/esm2015/lib/message-list/message-list.component.js +14 -8
  15. package/esm2015/lib/parse-date.js +2 -2
  16. package/esm2015/lib/stream-chat.module.js +13 -3
  17. package/esm2015/lib/types.js +1 -1
  18. package/esm2015/public-api.js +3 -1
  19. package/fesm2015/stream-chat-angular.js +319 -169
  20. package/fesm2015/stream-chat-angular.js.map +1 -1
  21. package/lib/channel/channel.component.d.ts +3 -1
  22. package/lib/channel.service.d.ts +10 -9
  23. package/lib/custom-templates.service.d.ts +8 -0
  24. package/lib/edit-message-form/edit-message-form.component.d.ts +31 -0
  25. package/lib/message/message.component.d.ts +2 -1
  26. package/lib/message-actions-box/message-actions-box.component.d.ts +2 -11
  27. package/lib/message-bounce-prompt/message-bounce-prompt.component.d.ts +28 -0
  28. package/lib/stream-chat.module.d.ts +7 -5
  29. package/lib/types.d.ts +0 -6
  30. package/package.json +1 -1
  31. package/public-api.d.ts +2 -0
  32. package/src/assets/i18n/en.ts +3 -0
  33. package/src/assets/styles/css/index.css +1 -1
  34. package/src/assets/styles/scss/Message.scss +21 -17
  35. package/src/assets/styles/scss/MessageActions.scss +0 -9
  36. package/src/assets/styles/scss/_base.scss +8 -1
  37. package/src/assets/styles/v2/css/index.css +1 -1
  38. package/src/assets/styles/v2/css/index.layout.css +1 -1
  39. package/src/assets/styles/v2/scss/AttachmentList/AttachmentList-layout.scss +6 -0
  40. package/src/assets/styles/v2/scss/EditMessageForm/EditMessageForm-layout.scss +13 -15
  41. package/src/assets/styles/v2/scss/Message/Message-layout.scss +14 -3
  42. package/src/assets/styles/v2/scss/MessageActionsBox/MessageActionsBox-layout.scss +0 -8
  43. package/src/assets/styles/v2/scss/_utils.scss +0 -1
  44. package/src/assets/version.ts +1 -1
@@ -20,7 +20,7 @@ import transliterate from '@stream-io/transliterate';
20
20
  import * as i8 from 'angular-mentions';
21
21
  import { MentionModule } from 'angular-mentions';
22
22
 
23
- const version = '4.59.2';
23
+ const version = '4.60.0';
24
24
 
25
25
  /**
26
26
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -384,6 +384,7 @@ class ChannelService {
384
384
  const channel = this.activeChannelSubject.getValue();
385
385
  return messages.map((message) => this.transformToStreamMessage(message, channel));
386
386
  }), shareReplay(1));
387
+ this.bouncedMessage$ = new BehaviorSubject(undefined);
387
388
  this.hasMoreChannels$ = this.hasMoreChannelsSubject
388
389
  .asObservable()
389
390
  .pipe(shareReplay(1));
@@ -725,18 +726,39 @@ class ChannelService {
725
726
  if (this.beforeUpdateMessage) {
726
727
  messageToUpdate = yield this.beforeUpdateMessage(messageToUpdate);
727
728
  }
729
+ if (message.moderation_details) {
730
+ return this.resendMessage(message);
731
+ }
728
732
  const response = yield this.chatClientService.chatClient.updateMessage(messageToUpdate);
729
733
  const channel = (_a = this.channelsSubject
730
734
  .getValue()) === null || _a === void 0 ? void 0 : _a.find((c) => c.cid === message.cid);
735
+ if (response.message.type === 'error' &&
736
+ response.message.moderation_details) {
737
+ this.notificationService.addTemporaryNotification('streamChat.This message did not meet our content guidelines');
738
+ return message;
739
+ }
731
740
  return this.transformToStreamMessage(response.message, channel);
732
741
  });
733
742
  }
734
743
  /**
735
744
  * Deletes the message from the active channel
736
745
  * @param message Message to be deleted
746
+ * @param isLocalDelete set this `true` if you want to delete a message that's only part of the local state, not yet saved on the backend
737
747
  */
738
- deleteMessage(message) {
748
+ deleteMessage(message, isLocalDelete = false) {
739
749
  return __awaiter(this, void 0, void 0, function* () {
750
+ if (isLocalDelete && this.activeChannel) {
751
+ const result = this.activeChannel.state.removeMessage({
752
+ id: message.id,
753
+ parent_id: message.parent_id,
754
+ });
755
+ if (result) {
756
+ message.parent_id
757
+ ? this.activeThreadMessagesSubject.next(this.activeChannel.state.threads[message.parent_id])
758
+ : this.activeChannelMessagesSubject.next(this.activeChannel.state.messages);
759
+ }
760
+ return;
761
+ }
740
762
  if (this.messageDeleteConfirmationHandler) {
741
763
  const result = yield this.messageDeleteConfirmationHandler(message);
742
764
  if (result) {
@@ -2449,6 +2471,8 @@ const en = {
2449
2471
  'Unread messages': 'Unread messages',
2450
2472
  '{{count}} unread messages': '{{count}} unread messages',
2451
2473
  '{{count}} unread message': '{{count}} unread message',
2474
+ 'This message did not meet our content guidelines': 'This message did not meet our content guidelines',
2475
+ 'Send Anyway': 'Send Anyway',
2452
2476
  },
2453
2477
  };
2454
2478
 
@@ -2865,6 +2889,14 @@ class CustomTemplatesService {
2865
2889
  * The template to show if the thread message list is empty
2866
2890
  */
2867
2891
  this.emptyThreadMessageListPlaceholder$ = new BehaviorSubject(undefined);
2892
+ /**
2893
+ * The template used to display the [edit message form](../components/EditMessageFormComponent.mdx)
2894
+ */
2895
+ this.editMessageFormTemplate$ = new BehaviorSubject(undefined);
2896
+ /**
2897
+ * The template used to display the [message bounce prompt](../components/MessageBouncePromptComponent.mdx)
2898
+ */
2899
+ this.messageBouncePromptTemplate$ = new BehaviorSubject(undefined);
2868
2900
  }
2869
2901
  }
2870
2902
  CustomTemplatesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: CustomTemplatesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
@@ -3175,6 +3207,137 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
3175
3207
  }]
3176
3208
  }], ctorParameters: function () { return [{ type: ChatClientService }, { type: NotificationService }, { type: ChannelService }]; } });
3177
3209
 
3210
+ /**
3211
+ * The `MessageActionsBox` component displays a list of message actions (i.e edit), that can be opened or closed. You can find the [list of the supported actions](../concepts/message-interactions.mdx) in the message interaction guide.
3212
+ */
3213
+ class MessageActionsBoxComponent {
3214
+ constructor(customTemplatesService, messageActionsService, cdRef) {
3215
+ this.customTemplatesService = customTemplatesService;
3216
+ this.messageActionsService = messageActionsService;
3217
+ this.cdRef = cdRef;
3218
+ /**
3219
+ * Indicates if the list should be opened or closed. Adding a UI element to open and close the list is the parent's component responsibility.
3220
+ * @deprecated No need for this since [theme-v2](../theming/introduction.mdx)
3221
+ */
3222
+ this.isOpen = false;
3223
+ /**
3224
+ * Indicates if the message actions are belonging to a message that was sent by the current user or not.
3225
+ */
3226
+ this.isMine = false;
3227
+ /**
3228
+ * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](../concepts/message-interactions.mdx) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI.
3229
+ */
3230
+ this.enabledActions = [];
3231
+ /**
3232
+ * A list of custom message actions to be displayed in the action box
3233
+ *
3234
+ * In the next major release this will be released with `messageReactionsService.customActions$`
3235
+ *
3236
+ * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
3237
+ */
3238
+ this.customActions = [];
3239
+ /**
3240
+ * The number of authorized actions (it can be less or equal than the number of enabled actions)
3241
+ *
3242
+ * @deprecated components should use `messageReactionsService.getAuthorizedMessageActionsCount` method
3243
+ *
3244
+ * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
3245
+ */
3246
+ this.displayedActionsCount = new EventEmitter();
3247
+ /**
3248
+ * An event which emits `true` if the edit message modal is open, and `false` when it is closed.
3249
+ *
3250
+ * @deprecated components should use `messageReactionsService.messageToEdit$` Observable
3251
+ *
3252
+ * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
3253
+ */
3254
+ this.isEditing = new EventEmitter();
3255
+ this.visibleMessageActionItems = [];
3256
+ this.isEditModalOpen = false;
3257
+ this.subscriptions = [];
3258
+ this.isViewInited = false;
3259
+ this.messageActionItems = this.messageActionsService.defaultActions;
3260
+ }
3261
+ ngOnInit() {
3262
+ this.subscriptions.push(this.messageActionsService.messageToEdit$.subscribe((m) => {
3263
+ var _a;
3264
+ let isEditModalOpen = false;
3265
+ if (m && m.id === ((_a = this.message) === null || _a === void 0 ? void 0 : _a.id)) {
3266
+ isEditModalOpen = true;
3267
+ }
3268
+ if (isEditModalOpen !== this.isEditModalOpen) {
3269
+ this.isEditModalOpen = isEditModalOpen;
3270
+ this.isEditing.emit(this.isEditModalOpen);
3271
+ if (this.isViewInited) {
3272
+ this.cdRef.detectChanges();
3273
+ }
3274
+ }
3275
+ }));
3276
+ }
3277
+ ngOnChanges(changes) {
3278
+ if (changes.isMine ||
3279
+ changes.enabledActions ||
3280
+ changes.message ||
3281
+ changes.customActions) {
3282
+ this.setVisibleActions();
3283
+ }
3284
+ }
3285
+ ngAfterViewInit() {
3286
+ this.isViewInited = true;
3287
+ }
3288
+ ngOnDestroy() {
3289
+ this.subscriptions.forEach((s) => s.unsubscribe());
3290
+ }
3291
+ getActionLabel(actionLabelOrTranslationKey) {
3292
+ return typeof actionLabelOrTranslationKey === 'string'
3293
+ ? actionLabelOrTranslationKey
3294
+ : actionLabelOrTranslationKey(this.message);
3295
+ }
3296
+ getMessageActionTemplateContext(item) {
3297
+ return {
3298
+ actionHandler: item.actionHandler,
3299
+ isMine: this.isMine,
3300
+ actionName: item.actionName,
3301
+ message: this.message,
3302
+ actionLabelOrTranslationKey: item.actionLabelOrTranslationKey,
3303
+ };
3304
+ }
3305
+ trackByActionName(_, item) {
3306
+ return item.actionName;
3307
+ }
3308
+ setVisibleActions() {
3309
+ this.visibleMessageActionItems = [
3310
+ ...this.messageActionItems,
3311
+ ...this.customActions,
3312
+ ].filter((item) => item.isVisible(this.enabledActions, this.isMine, this.message));
3313
+ this.displayedActionsCount.emit(this.visibleMessageActionItems.length);
3314
+ }
3315
+ }
3316
+ MessageActionsBoxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, deps: [{ token: CustomTemplatesService }, { token: MessageActionsService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3317
+ MessageActionsBoxComponent.ɵcmp = i0.ɵɵ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", customActions: "customActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, usesOnChanges: true, ngImport: i0, template: "<div\n #actionBox\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box str-chat__message-actions-box-angular\"\n [class.str-chat__message-actions-box--open]=\"true\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <ng-container\n *ngFor=\"let item of visibleMessageActionItems; trackBy: trackByActionName\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageActionsBoxItemTemplate$ | async) ||\n defaultMessageActionItem;\n context: getMessageActionTemplateContext(item)\n \"\n ></ng-container>\n </ng-container>\n </ul>\n</div>\n\n<ng-template\n #defaultMessageActionItem\n let-actionName=\"actionName\"\n let-actionHandler=\"actionHandler\"\n let-actionLabelOrTranslationKey=\"actionLabelOrTranslationKey\"\n>\n <button\n class=\"str-chat__message-actions-list-item-button\"\n [attr.data-testid]=\"actionName + '-action'\"\n (click)=\"actionHandler(message, isMine)\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ getActionLabel(actionLabelOrTranslationKey) | translate }}\n </li>\n </button>\n</ng-template>\n", directives: [{ type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe } });
3318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, decorators: [{
3319
+ type: Component,
3320
+ args: [{
3321
+ selector: 'stream-message-actions-box',
3322
+ templateUrl: './message-actions-box.component.html',
3323
+ styles: [],
3324
+ }]
3325
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: MessageActionsService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { isOpen: [{
3326
+ type: Input
3327
+ }], isMine: [{
3328
+ type: Input
3329
+ }], message: [{
3330
+ type: Input
3331
+ }], enabledActions: [{
3332
+ type: Input
3333
+ }], customActions: [{
3334
+ type: Input
3335
+ }], displayedActionsCount: [{
3336
+ type: Output
3337
+ }], isEditing: [{
3338
+ type: Output
3339
+ }] } });
3340
+
3178
3341
  /**
3179
3342
  * The `Modal` component displays its content in an overlay. The modal can be closed with a close button, if the user clicks outside of the modal content, or if the escape button is pressed. The modal can also be closed from outside.
3180
3343
  */
@@ -4105,113 +4268,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
4105
4268
  }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: NotificationService }, { type: ThemeService }]; } });
4106
4269
 
4107
4270
  /**
4108
- * The `MessageActionsBox` component displays a list of message actions (i.e edit), that can be opened or closed. You can find the [list of the supported actions](../concepts/message-interactions.mdx) in the message interaction guide.
4271
+ * The edit message form displays a modal that's opened when a user edits a message. The component uses the [`MessageActionsService`](../../services/MessageActionsService) to know which message is being edited.
4272
+ *
4273
+ * By default this is displayed within the [`stream-channel` component](../../components/ChannelComponent).
4109
4274
  */
4110
- class MessageActionsBoxComponent {
4111
- constructor(customTemplatesService, messageActionsService, cdRef) {
4275
+ class EditMessageFormComponent {
4276
+ constructor(customTemplatesService, messageActionsService) {
4112
4277
  this.customTemplatesService = customTemplatesService;
4113
4278
  this.messageActionsService = messageActionsService;
4114
- this.cdRef = cdRef;
4115
- /**
4116
- * Indicates if the list should be opened or closed. Adding a UI element to open and close the list is the parent's component responsibility.
4117
- * @deprecated No need for this since [theme-v2](../theming/introduction.mdx)
4118
- */
4119
- this.isOpen = false;
4120
- /**
4121
- * Indicates if the message actions are belonging to a message that was sent by the current user or not.
4122
- */
4123
- this.isMine = false;
4124
- /**
4125
- * The list of [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) that are enabled for the current user, the list of [supported interactions](../concepts/message-interactions.mdx) can be found in our message interaction guide. Unathorized actions won't be displayed on the UI.
4126
- */
4127
- this.enabledActions = [];
4128
- /**
4129
- * A list of custom message actions to be displayed in the action box
4130
- *
4131
- * In the next major release this will be released with `messageReactionsService.customActions$`
4132
- *
4133
- * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
4134
- */
4135
- this.customActions = [];
4136
- /**
4137
- * The number of authorized actions (it can be less or equal than the number of enabled actions)
4138
- *
4139
- * @deprecated components should use `messageReactionsService.getAuthorizedMessageActionsCount` method
4140
- *
4141
- * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
4142
- */
4143
- this.displayedActionsCount = new EventEmitter();
4144
- /**
4145
- * An event which emits `true` if the edit message modal is open, and `false` when it is closed.
4146
- *
4147
- * @deprecated components should use `messageReactionsService.messageToEdit$` Observable
4148
- *
4149
- * More information: https://getstream.io/chat/docs/sdk/angular/services/MessageActionsService
4150
- */
4151
- this.isEditing = new EventEmitter();
4152
- this.isEditModalOpen = false;
4153
- this.visibleMessageActionItems = [];
4279
+ this.class = 'str-chat-angular__edit-message-form';
4280
+ this.isModalOpen = false;
4154
4281
  this.sendMessageSubject = new Subject();
4155
4282
  this.subscriptions = [];
4156
- this.isViewInited = false;
4157
- this.modalClosed = () => {
4158
- this.isEditModalOpen = false;
4159
- this.messageActionsService.messageToEdit$.next(undefined);
4160
- };
4161
- this.messageActionItems = this.messageActionsService.defaultActions;
4162
4283
  this.sendMessage$ = this.sendMessageSubject.asObservable();
4163
4284
  }
4164
4285
  ngOnInit() {
4165
- this.subscriptions.push(this.messageActionsService.messageToEdit$.subscribe((m) => {
4166
- var _a;
4167
- let isEditModalOpen = false;
4168
- if (m && m.id === ((_a = this.message) === null || _a === void 0 ? void 0 : _a.id)) {
4169
- isEditModalOpen = true;
4286
+ this.messageActionsService.messageToEdit$.subscribe((message) => {
4287
+ if ((message && !this.isModalOpen) || (!message && this.isModalOpen)) {
4288
+ this.message = message;
4289
+ this.isModalOpen = !!message;
4170
4290
  }
4171
- if (isEditModalOpen !== this.isEditModalOpen) {
4172
- this.isEditModalOpen = isEditModalOpen;
4173
- this.isEditing.emit(this.isEditModalOpen);
4174
- if (this.isViewInited) {
4175
- this.cdRef.detectChanges();
4176
- }
4177
- }
4178
- }));
4179
- }
4180
- ngOnChanges(changes) {
4181
- if (changes.isMine ||
4182
- changes.enabledActions ||
4183
- changes.message ||
4184
- changes.customActions) {
4185
- this.setVisibleActions();
4186
- }
4187
- }
4188
- ngAfterViewInit() {
4189
- this.isViewInited = true;
4291
+ });
4190
4292
  }
4191
4293
  ngOnDestroy() {
4192
4294
  this.subscriptions.forEach((s) => s.unsubscribe());
4193
4295
  }
4194
- getActionLabel(actionLabelOrTranslationKey) {
4195
- return typeof actionLabelOrTranslationKey === 'string'
4196
- ? actionLabelOrTranslationKey
4197
- : actionLabelOrTranslationKey(this.message);
4198
- }
4199
- getMessageActionTemplateContext(item) {
4296
+ getEditModalContext() {
4200
4297
  return {
4201
- actionHandler: item.actionHandler,
4202
- isMine: this.isMine,
4203
- actionName: item.actionName,
4204
- message: this.message,
4205
- actionLabelOrTranslationKey: item.actionLabelOrTranslationKey,
4298
+ isOpen: this.isModalOpen,
4299
+ isOpenChangeHandler: (isOpen) => {
4300
+ this.isModalOpen = isOpen;
4301
+ if (!this.isModalOpen) {
4302
+ this.dismissed();
4303
+ }
4304
+ },
4305
+ content: this.modalContent,
4206
4306
  };
4207
4307
  }
4208
- sendClicked() {
4209
- this.sendMessageSubject.next();
4210
- }
4211
4308
  getMessageInputContext() {
4212
4309
  return {
4213
4310
  message: this.message,
4214
- messageUpdateHandler: this.modalClosed,
4311
+ messageUpdateHandler: () => {
4312
+ this.dismissed();
4313
+ },
4215
4314
  isFileUploadEnabled: undefined,
4216
4315
  areMentionsEnabled: undefined,
4217
4316
  isMultipleFileUploadEnabled: undefined,
@@ -4220,64 +4319,110 @@ class MessageActionsBoxComponent {
4220
4319
  sendMessage$: this.sendMessage$,
4221
4320
  };
4222
4321
  }
4223
- getEditModalContext() {
4224
- return {
4225
- isOpen: this.isEditModalOpen,
4226
- isOpenChangeHandler: (isOpen) => {
4227
- this.isEditModalOpen = isOpen;
4228
- if (!this.isEditModalOpen) {
4229
- this.modalClosed();
4230
- }
4231
- },
4232
- content: this.modalContent,
4233
- };
4234
- }
4235
- trackByActionName(_, item) {
4236
- return item.actionName;
4322
+ sendClicked() {
4323
+ this.sendMessageSubject.next();
4237
4324
  }
4238
- setVisibleActions() {
4239
- this.visibleMessageActionItems = [
4240
- ...this.messageActionItems,
4241
- ...this.customActions,
4242
- ].filter((item) => item.isVisible(this.enabledActions, this.isMine, this.message));
4243
- this.displayedActionsCount.emit(this.visibleMessageActionItems.length);
4325
+ dismissed() {
4326
+ this.isModalOpen = false;
4327
+ this.message = undefined;
4328
+ this.messageActionsService.messageToEdit$.next(undefined);
4244
4329
  }
4245
4330
  }
4246
- MessageActionsBoxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, deps: [{ token: CustomTemplatesService }, { token: MessageActionsService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
4247
- MessageActionsBoxComponent.ɵcmp = i0.ɵɵ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", customActions: "customActions" }, outputs: { displayedActionsCount: "displayedActionsCount", isEditing: "isEditing" }, viewQueries: [{ propertyName: "modalContent", first: true, predicate: ["modalContent"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #actionBox\n data-testid=\"action-box\"\n class=\"str-chat__message-actions-box str-chat__message-actions-box-angular\"\n [class.str-chat__message-actions-box--open]=\"true\"\n>\n <ul class=\"str-chat__message-actions-list\">\n <ng-container\n *ngFor=\"let item of visibleMessageActionItems; trackBy: trackByActionName\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageActionsBoxItemTemplate$ | async) ||\n defaultMessageActionItem;\n context: getMessageActionTemplateContext(item)\n \"\n ></ng-container>\n </ng-container>\n </ul>\n</div>\n\n<ng-template\n #defaultMessageActionItem\n let-actionName=\"actionName\"\n let-actionHandler=\"actionHandler\"\n let-actionLabelOrTranslationKey=\"actionLabelOrTranslationKey\"\n>\n <button\n class=\"str-chat__message-actions-list-item-button\"\n [attr.data-testid]=\"actionName + '-action'\"\n (click)=\"actionHandler(message, isMine)\"\n >\n <li class=\"str-chat__message-actions-list-item\">\n {{ getActionLabel(actionLabelOrTranslationKey) | translate }}\n </li>\n </button>\n</ng-template>\n\n<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.modalTemplate$ | async) || defaultModal;\n context: getEditModalContext()\n \"\n></ng-container>\n\n<ng-template\n #defaultModal\n let-isOpen=\"isOpen\"\n let-isOpenChangeHandler=\"isOpenChangeHandler\"\n let-content=\"content\"\n>\n <stream-modal\n [isOpen]=\"isOpen\"\n *ngIf=\"isOpen\"\n (isOpenChange)=\"isOpenChangeHandler($event)\"\n [content]=\"content\"\n >\n </stream-modal>\n</ng-template>\n\n<ng-template #modalContent>\n <div class=\"str-chat__edit-message-form\" *ngIf=\"isEditModalOpen\">\n <ng-template\n #defaultInput\n let-messageInput=\"message\"\n let-messageUpdateHandler=\"messageUpdateHandler\"\n let-sendMessage$Input=\"sendMessage$\"\n >\n <stream-message-input\n [message]=\"messageInput\"\n (messageUpdate)=\"messageUpdateHandler()\"\n [sendMessage$]=\"sendMessage$Input\"\n ></stream-message-input>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageInputTemplate$ | async) || defaultInput;\n context: getMessageInputContext()\n \"\n >\n </ng-container>\n\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\n class=\"str-chat__edit-message-cancel\"\n translate\n data-testid=\"cancel-button\"\n (click)=\"modalClosed()\"\n >\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n class=\"str-chat__edit-message-send\"\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</ng-template>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen", "content"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mode", "isMultipleFileUploadEnabled", "message", "sendMessage$", "inputMode", "autoFocus"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe } });
4248
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageActionsBoxComponent, decorators: [{
4331
+ EditMessageFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: EditMessageFormComponent, deps: [{ token: CustomTemplatesService }, { token: MessageActionsService }], target: i0.ɵɵFactoryTarget.Component });
4332
+ EditMessageFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: EditMessageFormComponent, selector: "stream-edit-message-form", host: { properties: { "class": "this.class" } }, viewQueries: [{ propertyName: "modalContent", first: true, predicate: ["editMessageForm"], descendants: true, static: true }], ngImport: i0, template: "<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.modalTemplate$ | async) || defaultModal;\n context: getEditModalContext()\n \"\n></ng-container>\n\n<ng-template\n #defaultModal\n let-isOpen=\"isOpen\"\n let-isOpenChangeHandler=\"isOpenChangeHandler\"\n let-content=\"content\"\n>\n <stream-modal\n [isOpen]=\"isOpen\"\n *ngIf=\"isOpen\"\n (isOpenChange)=\"isOpenChangeHandler($event)\"\n [content]=\"content\"\n >\n </stream-modal>\n</ng-template>\n\n<ng-template #editMessageForm>\n <div class=\"str-chat__edit-message-form\">\n <ng-template\n #defaultInput\n let-messageInput=\"message\"\n let-messageUpdateHandler=\"messageUpdateHandler\"\n let-sendMessage$Input=\"sendMessage$\"\n >\n <stream-message-input\n [message]=\"messageInput\"\n (messageUpdate)=\"messageUpdateHandler()\"\n [sendMessage$]=\"sendMessage$Input\"\n ></stream-message-input>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageInputTemplate$ | async) || defaultInput;\n context: getMessageInputContext()\n \"\n >\n </ng-container>\n\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\n class=\"str-chat__edit-message-cancel\"\n translate\n data-testid=\"cancel-button\"\n (click)=\"dismissed()\"\n >\n streamChat.Cancel\n </button>\n <button\n type=\"submit\"\n translate\n class=\"str-chat__edit-message-send\"\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</ng-template>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen", "content"], outputs: ["isOpenChange"] }, { type: MessageInputComponent, selector: "stream-message-input", inputs: ["isFileUploadEnabled", "areMentionsEnabled", "mentionScope", "mode", "isMultipleFileUploadEnabled", "message", "sendMessage$", "inputMode", "autoFocus"], outputs: ["messageUpdate"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i5.AsyncPipe } });
4333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: EditMessageFormComponent, decorators: [{
4249
4334
  type: Component,
4250
4335
  args: [{
4251
- selector: 'stream-message-actions-box',
4252
- templateUrl: './message-actions-box.component.html',
4336
+ selector: 'stream-edit-message-form',
4337
+ templateUrl: './edit-message-form.component.html',
4253
4338
  styles: [],
4254
4339
  }]
4255
- }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: MessageActionsService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { isOpen: [{
4256
- type: Input
4257
- }], isMine: [{
4258
- type: Input
4259
- }], message: [{
4260
- type: Input
4261
- }], enabledActions: [{
4262
- type: Input
4263
- }], customActions: [{
4264
- type: Input
4265
- }], displayedActionsCount: [{
4266
- type: Output
4267
- }], isEditing: [{
4268
- type: Output
4340
+ }], ctorParameters: function () { return [{ type: CustomTemplatesService }, { type: MessageActionsService }]; }, propDecorators: { class: [{
4341
+ type: HostBinding
4269
4342
  }], modalContent: [{
4270
4343
  type: ViewChild,
4271
- args: ['modalContent', { static: true }]
4344
+ args: ['editMessageForm', { static: true }]
4345
+ }] } });
4346
+
4347
+ /**
4348
+ * The component watches for the [`channelService.bouncedMessage$` stream](../../services/ChannelService/#bouncedmessage) and opens the bounce modal if a message is emitted.
4349
+ *
4350
+ * To bounce messages, you need to set up [semantic filters for moderation](https://getstream.io/automated-moderation/docs/automod_configuration/?q=semantic%20filters).
4351
+ */
4352
+ class MessageBouncePromptComponent {
4353
+ constructor(channelService, customTemplatesService, messageActionsService) {
4354
+ this.channelService = channelService;
4355
+ this.customTemplatesService = customTemplatesService;
4356
+ this.messageActionsService = messageActionsService;
4357
+ this.class = 'str-chat__message-bounce-prompt';
4358
+ this.isModalOpen = false;
4359
+ this.subscriptions = [];
4360
+ this.messageBounceModalOpenChanged = (isOpen) => {
4361
+ this.isModalOpen = isOpen;
4362
+ if (!isOpen) {
4363
+ this.message = undefined;
4364
+ this.channelService.bouncedMessage$.next(undefined);
4365
+ }
4366
+ };
4367
+ this.subscriptions.push(this.channelService.bouncedMessage$.subscribe((m) => {
4368
+ if (m !== this.message) {
4369
+ this.message = m;
4370
+ if (this.message) {
4371
+ this.isModalOpen = true;
4372
+ }
4373
+ }
4374
+ }));
4375
+ }
4376
+ ngOnDestroy() {
4377
+ this.subscriptions.forEach((s) => s.unsubscribe());
4378
+ }
4379
+ resendMessage() {
4380
+ return __awaiter(this, void 0, void 0, function* () {
4381
+ this.isModalOpen = false;
4382
+ yield this.channelService.resendMessage(this.message);
4383
+ this.message = undefined;
4384
+ this.channelService.bouncedMessage$.next(undefined);
4385
+ });
4386
+ }
4387
+ deleteMessage() {
4388
+ return __awaiter(this, void 0, void 0, function* () {
4389
+ if (!this.message) {
4390
+ return;
4391
+ }
4392
+ this.isModalOpen = false;
4393
+ yield this.channelService.deleteMessage(this.message, true);
4394
+ this.message = undefined;
4395
+ this.channelService.bouncedMessage$.next(undefined);
4396
+ });
4397
+ }
4398
+ editMessage() {
4399
+ this.isModalOpen = false;
4400
+ this.messageActionsService.messageToEdit$.next(this.message);
4401
+ this.message = undefined;
4402
+ this.channelService.bouncedMessage$.next(undefined);
4403
+ }
4404
+ }
4405
+ MessageBouncePromptComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageBouncePromptComponent, deps: [{ token: ChannelService }, { token: CustomTemplatesService }, { token: MessageActionsService }], target: i0.ɵɵFactoryTarget.Component });
4406
+ MessageBouncePromptComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageBouncePromptComponent, selector: "stream-message-bounce-prompt", host: { properties: { "class": "this.class" } }, ngImport: i0, template: "<ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.modalTemplate$ | async) || defaultModal;\n context: {\n message: message,\n isOpen: isModalOpen,\n isOpenChangeHandler: messageBounceModalOpenChanged,\n content: modalContent\n }\n \"\n></ng-container>\n\n<ng-template\n #defaultModal\n let-isOpen=\"isOpen\"\n let-isOpenChangeHandler=\"isOpenChangeHandler\"\n let-content=\"content\"\n>\n <stream-modal\n [isOpen]=\"isOpen\"\n *ngIf=\"isOpen\"\n (isOpenChange)=\"isOpenChangeHandler($event)\"\n [content]=\"content\"\n >\n </stream-modal>\n</ng-template>\n\n<ng-template #modalContent>\n <div\n class=\"str-chat__message-bounce-prompt\"\n data-testid=\"message-bounce-prompt\"\n >\n <div class=\"str-chat__message-bounce-prompt-header\">\n {{\n \"streamChat.This message did not meet our content guidelines\"\n | translate\n }}\n </div>\n <div class=\"str-chat__message-bounce-actions\">\n <button\n class=\"str-chat__message-bounce-edit\"\n data-testid=\"message-bounce-edit\"\n (click)=\"editMessage()\"\n (keyup.enter)=\"editMessage()\"\n type=\"button\"\n >\n {{ \"streamChat.Edit Message\" | translate }}\n </button>\n <button\n class=\"str-chat__message-bounce-send\"\n data-testid=\"message-bounce-send\"\n (click)=\"resendMessage()\"\n (keyup.enter)=\"resendMessage()\"\n >\n {{ \"streamChat.Send Anyway\" | translate }}\n </button>\n <button\n class=\"str-chat__message-bounce-delete\"\n data-testid=\"message-bounce-delete\"\n (click)=\"deleteMessage()\"\n (keyup.enter)=\"deleteMessage()\"\n >\n {{ \"streamChat.Delete\" | translate }}\n </button>\n </div>\n </div>\n</ng-template>\n", components: [{ type: ModalComponent, selector: "stream-modal", inputs: ["isOpen", "content"], outputs: ["isOpenChange"] }], directives: [{ type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe } });
4407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageBouncePromptComponent, decorators: [{
4408
+ type: Component,
4409
+ args: [{
4410
+ selector: 'stream-message-bounce-prompt',
4411
+ templateUrl: './message-bounce-prompt.component.html',
4412
+ styles: [],
4413
+ }]
4414
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: CustomTemplatesService }, { type: MessageActionsService }]; }, propDecorators: { class: [{
4415
+ type: HostBinding
4272
4416
  }] } });
4273
4417
 
4274
4418
  /**
4275
4419
  * The `Channel` component is a container component that displays the [`ChannelHeader`](./ChannelHeaderComponent.mdx), [`MessageList`](./MessageListComponent.mdx), [`NotificationList`](./NotificationListComponent.mdx) and [`MessageInput`](./MessageInputComponent.mdx) components. You can also provide the [`Thread`](./ThreadComponent.mdx) component to use message [threads](https://getstream.io/chat/docs/javascript/threads/?language=javascript).
4276
4420
  */
4277
4421
  class ChannelComponent {
4278
- constructor(channelService, themeService) {
4422
+ constructor(channelService, themeService, customTemplatesService) {
4279
4423
  this.channelService = channelService;
4280
4424
  this.themeService = themeService;
4425
+ this.customTemplatesService = customTemplatesService;
4281
4426
  this.subscriptions = [];
4282
4427
  this.isError$ = combineLatest([
4283
4428
  this.channelService.channelQueryState$,
@@ -4296,8 +4441,8 @@ class ChannelComponent {
4296
4441
  this.isActiveChannel$ = this.channelService.activeChannel$.pipe(map((c) => !!c));
4297
4442
  }
4298
4443
  }
4299
- ChannelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelComponent, deps: [{ token: ChannelService }, { token: ThemeService }], target: i0.ɵɵFactoryTarget.Component });
4300
- ChannelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0, template: "<div\n class=\"str-chat str-chat-channel messaging str-chat__channel str-chat__theme-{{\n theme$ | async\n }}\"\n>\n <div\n class=\"str-chat__container\"\n *ngIf=\"\n (isError$ | async) === false &&\n (isInitializing$ | async) === false &&\n (isActiveChannel$ | async) === true;\n else noChannel\n \"\n >\n <div class=\"str-chat__main-panel\">\n <ng-content></ng-content>\n </div>\n <ng-content\n *ngIf=\"isActiveThread$ | async\"\n select='[name=\"thread\"]'\n ></ng-content>\n </div>\n <ng-template #noChannel>\n <div\n class=\"str-chat__empty-channel\"\n *ngIf=\"\n (isInitializing$ | async) === false &&\n ((isError$ | async) === true || (isActiveChannel$ | async) === false)\n \"\n >\n <stream-icon icon=\"chat-bubble\"></stream-icon>\n <p class=\"str-chat__empty-channel-text\">\n {{ \"streamChat.No chats here yet\u2026\" | translate }}\n </p>\n <div class=\"str-chat__empty-channel-notifications\">\n <stream-notification-list></stream-notification-list>\n </div>\n </div>\n <div\n *ngIf=\"\n (isInitializing$ | async) === true &&\n (isError$ | async) === false &&\n (isActiveChannel$ | async) === false\n \"\n class=\"str-chat__loading-channel\"\n >\n <div class=\"str-chat__loading-channel-header\">\n <div class=\"str-chat__loading-channel-header-avatar\"></div>\n <div class=\"str-chat__loading-channel-header-end\">\n <div class=\"str-chat__loading-channel-header-name\"></div>\n <div class=\"str-chat__loading-channel-header-info\"></div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message-list\">\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message-input-row\">\n <div class=\"str-chat__loading-channel-message-input\"></div>\n <div class=\"str-chat__loading-channel-message-send\"></div>\n </div>\n </div>\n </ng-template>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe } });
4444
+ ChannelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelComponent, deps: [{ token: ChannelService }, { token: ThemeService }, { token: CustomTemplatesService }], target: i0.ɵɵFactoryTarget.Component });
4445
+ ChannelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: ChannelComponent, selector: "stream-channel", ngImport: i0, template: "<div\n class=\"str-chat str-chat-channel messaging str-chat__channel str-chat__theme-{{\n theme$ | async\n }}\"\n>\n <div\n class=\"str-chat__container\"\n *ngIf=\"\n (isError$ | async) === false &&\n (isInitializing$ | async) === false &&\n (isActiveChannel$ | async) === true;\n else noChannel\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.editMessageFormTemplate$ | async) ||\n defaultEditMessageForm\n \"\n ></ng-container>\n <ng-template #defaultEditMessageForm>\n <stream-edit-message-form></stream-edit-message-form>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageBouncePromptTemplate$ | async) ||\n defaultMessageBouncePrompt\n \"\n ></ng-container>\n <ng-template #defaultMessageBouncePrompt>\n <stream-message-bounce-prompt></stream-message-bounce-prompt>\n </ng-template>\n <div class=\"str-chat__main-panel\">\n <ng-content></ng-content>\n </div>\n <ng-content\n *ngIf=\"isActiveThread$ | async\"\n select='[name=\"thread\"]'\n ></ng-content>\n </div>\n <ng-template #noChannel>\n <div\n class=\"str-chat__empty-channel\"\n *ngIf=\"\n (isInitializing$ | async) === false &&\n ((isError$ | async) === true || (isActiveChannel$ | async) === false)\n \"\n >\n <stream-icon icon=\"chat-bubble\"></stream-icon>\n <p class=\"str-chat__empty-channel-text\">\n {{ \"streamChat.No chats here yet\u2026\" | translate }}\n </p>\n <div class=\"str-chat__empty-channel-notifications\">\n <stream-notification-list></stream-notification-list>\n </div>\n </div>\n <div\n *ngIf=\"\n (isInitializing$ | async) === true &&\n (isError$ | async) === false &&\n (isActiveChannel$ | async) === false\n \"\n class=\"str-chat__loading-channel\"\n >\n <div class=\"str-chat__loading-channel-header\">\n <div class=\"str-chat__loading-channel-header-avatar\"></div>\n <div class=\"str-chat__loading-channel-header-end\">\n <div class=\"str-chat__loading-channel-header-name\"></div>\n <div class=\"str-chat__loading-channel-header-info\"></div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message-list\">\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message\">\n <div class=\"str-chat__loading-channel-message-avatar\"></div>\n <div class=\"str-chat__loading-channel-message-end\">\n <div class=\"str-chat__loading-channel-message-sender\"></div>\n <div class=\"str-chat__loading-channel-message-last-row\">\n <div class=\"str-chat__loading-channel-message-text\"></div>\n <div class=\"str-chat__loading-channel-message-date\"></div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__loading-channel-message-input-row\">\n <div class=\"str-chat__loading-channel-message-input\"></div>\n <div class=\"str-chat__loading-channel-message-send\"></div>\n </div>\n </div>\n </ng-template>\n</div>\n", components: [{ type: EditMessageFormComponent, selector: "stream-edit-message-form" }, { type: MessageBouncePromptComponent, selector: "stream-message-bounce-prompt" }, { type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: NotificationListComponent, selector: "stream-notification-list" }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe } });
4301
4446
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: ChannelComponent, decorators: [{
4302
4447
  type: Component,
4303
4448
  args: [{
@@ -4305,7 +4450,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
4305
4450
  templateUrl: './channel.component.html',
4306
4451
  styles: [],
4307
4452
  }]
4308
- }], ctorParameters: function () { return [{ type: ChannelService }, { type: ThemeService }]; } });
4453
+ }], ctorParameters: function () { return [{ type: ChannelService }, { type: ThemeService }, { type: CustomTemplatesService }]; } });
4309
4454
 
4310
4455
  const listUsers = (users) => {
4311
4456
  let outStr = '';
@@ -4680,7 +4825,7 @@ const parseDate = (date, format = 'date-time') => {
4680
4825
  nextWeek: 'dddd',
4681
4826
  lastDay: '[Yesterday]',
4682
4827
  lastWeek: '[Last] dddd',
4683
- sameElse: 'DD/MM/YYYY', // Everything else ( 17/10/2011 )
4828
+ sameElse: 'MM/DD/YYYY', // Everything else ( 10/17/2011 )
4684
4829
  });
4685
4830
  };
4686
4831
 
@@ -5091,22 +5236,6 @@ class MessageComponent {
5091
5236
  }
5092
5237
  }
5093
5238
  }));
5094
- this.subscriptions.push(this.messageActionsService.messageToEdit$.subscribe((m) => {
5095
- var _a;
5096
- let isEditing = false;
5097
- if (m && m.id === ((_a = this.message) === null || _a === void 0 ? void 0 : _a.id)) {
5098
- isEditing = true;
5099
- }
5100
- if (isEditing !== this.isEditing) {
5101
- this.isEditing = isEditing;
5102
- if (!this.isEditing) {
5103
- this.isActionBoxOpen = false;
5104
- }
5105
- if (this.isViewInited) {
5106
- this.cdRef.detectChanges();
5107
- }
5108
- }
5109
- }));
5110
5239
  }
5111
5240
  ngOnChanges(changes) {
5112
5241
  var _a, _b, _c, _d, _e, _f, _g;
@@ -5205,9 +5334,6 @@ class MessageComponent {
5205
5334
  }
5206
5335
  }
5207
5336
  messageActionsBoxClicked(popperContent) {
5208
- if (this.isEditing) {
5209
- return;
5210
- }
5211
5337
  popperContent.hide();
5212
5338
  }
5213
5339
  getAttachmentListContext() {
@@ -5249,6 +5375,17 @@ class MessageComponent {
5249
5375
  ownReactions: ((_d = this.message) === null || _d === void 0 ? void 0 : _d.own_reactions) || [],
5250
5376
  };
5251
5377
  }
5378
+ unsentMessageClicked() {
5379
+ var _a, _b, _c, _d;
5380
+ if (((_a = this.message) === null || _a === void 0 ? void 0 : _a.status) === 'failed' &&
5381
+ ((_b = this.message) === null || _b === void 0 ? void 0 : _b.errorStatusCode) !== 403) {
5382
+ this.resendMessage();
5383
+ }
5384
+ else if (((_c = this.message) === null || _c === void 0 ? void 0 : _c.type) === 'error' &&
5385
+ ((_d = this.message) === null || _d === void 0 ? void 0 : _d.moderation_details)) {
5386
+ this.openMessageBouncePrompt();
5387
+ }
5388
+ }
5252
5389
  resendMessage() {
5253
5390
  void this.channelService.resendMessage(this.message);
5254
5391
  }
@@ -5277,10 +5414,6 @@ class MessageComponent {
5277
5414
  // message action box changes UI bindings in parent, so we'll have to rerun change detection
5278
5415
  this.cdRef.detectChanges();
5279
5416
  },
5280
- isEditingChangeHandler: (isEditing) => {
5281
- this.isEditing = isEditing;
5282
- this.isActionBoxOpen = !this.isEditing;
5283
- },
5284
5417
  customActions: this.customActions || [],
5285
5418
  };
5286
5419
  }
@@ -5314,6 +5447,9 @@ class MessageComponent {
5314
5447
  displayOriginalMessage() {
5315
5448
  this.createMessageParts(false);
5316
5449
  }
5450
+ openMessageBouncePrompt() {
5451
+ this.channelService.bouncedMessage$.next(this.message);
5452
+ }
5317
5453
  createMessageParts(shouldTranslate = true) {
5318
5454
  this.messageTextParts = undefined;
5319
5455
  this.messageText = undefined;
@@ -5403,7 +5539,7 @@ class MessageComponent {
5403
5539
  }
5404
5540
  }
5405
5541
  MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }, { token: CustomTemplatesService }, { token: i0.ChangeDetectorRef }, { token: ThemeService }, { token: DateParserService }, { token: i0.NgZone }, { token: MessageService }, { token: MessageActionsService }], target: i0.ɵɵFactoryTarget.Component });
5406
- MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", isLastSentMessage: "isLastSentMessage", mode: "mode", isHighlighted: "isHighlighted", customActions: "customActions" }, 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--other]=\"!isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"hasReactions\"\n [class.str-chat__message--highlighted]=\"isHighlighted\"\n [class.str-chat__message-with-thread-link]=\"shouldDisplayThreadLink\"\n [class.str-chat__message-send-can-be-retried]=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\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 *ngIf=\"themeVersion === '1'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <stream-avatar-placeholder\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n type=\"user\"\n location=\"message-sender\"\n [user]=\"message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions str-chat__message-options\"\n data-testid=\"message-options\"\n [class.str-chat__message-actions-open]=\"isActionBoxOpen\"\n [class.str-chat__message-edit-in-progress]=\"isEditing\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n #messageActionsToggle\n class=\"\n str-chat__message-actions-container\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 [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerClick\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"true\"\n [popperHideOnMouseLeave]=\"false\"\n [popperDisableAnimation]=\"true\"\n (popperOnHidden)=\"isActionBoxOpen = false\"\n >\n <popper-content #popperContent>\n <ng-template\n #defaultMessageActionsBox\n let-isOpen=\"isOpen\"\n let-isMine=\"isMine\"\n let-enabledActions=\"enabledActions\"\n let-messageInput=\"message\"\n let-customActions=\"customActions\"\n >\n <stream-message-actions-box\n (click)=\"messageActionsBoxClicked(popperContent)\"\n *ngIf=\"isOpen\"\n [isOpen]=\"isOpen\"\n [isMine]=\"isMine\"\n [enabledActions]=\"enabledActions\"\n [customActions]=\"customActions\"\n [message]=\"messageInput\"\n ></stream-message-actions-box>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageActionsBoxTemplate$ | async) ||\n defaultMessageActionsBox;\n context: getMessageActionsBoxContext()\n \"\n >\n </ng-container>\n </popper-content>\n <div\n class=\"str-chat__message-actions-box-button\"\n data-testid=\"action-icon\"\n (click)=\"messageActionsClicked()\"\n (keyup.enter)=\"messageActionsClicked()\"\n *ngIf=\"visibleMessageActionsCount > 0\"\n >\n <stream-icon-placeholder\n icon=\"action-icon\"\n class=\"str-chat__message-action-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n str-chat__message-reply-in-thread-button\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reply-in-thread\"\n ></stream-icon-placeholder>\n </div>\n <div\n *ngIf=\"canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n str-chat__message-reactions-button\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reaction-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div class=\"str-chat__message-reactions-host\">\n <ng-template\n #defaultMessageReactions\n let-messageReactionCounts=\"messageReactionCounts\"\n let-latestReactions=\"latestReactions\"\n let-isSelectorOpen=\"isSelectorOpen\"\n let-isSelectorOpenChangeHandler=\"isSelectorOpenChangeHandler\"\n let-messageId=\"messageId\"\n let-ownReactions=\"ownReactions\"\n >\n <stream-message-reactions\n [messageReactionCounts]=\"messageReactionCounts\"\n [latestReactions]=\"latestReactions\"\n [isSelectorOpen]=\"isSelectorOpen\"\n (isSelectorOpenChange)=\"isSelectorOpenChangeHandler($event)\"\n [messageId]=\"messageId\"\n [ownReactions]=\"ownReactions\"\n ></stream-message-reactions>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageReactionsTemplate$ | async) ||\n defaultMessageReactions;\n context: getMessageReactionsContext()\n \"\n ></ng-container>\n </div>\n <!-- transform: translate3d(0, 0, 0) fixes scrolling issues on iOS, see: https://stackoverflow.com/questions/50105780/elements-disappear-when-scrolling-in-safari-webkit-transform-fix-only-works-t/50144295#50144295 -->\n <!-- transform: none is required when image carousel is open in order for the modal to be correctly positioned, see how the transform property changes the behavior of fixed positioned elements https://developer.mozilla.org/en-US/docs/Web/CSS/position -->\n <div\n class=\"str-chat__message-bubble\"\n style=\"transform: {{\n imageAttachmentModalState === 'opened'\n ? 'none'\n : 'translate3d(0, 0, 0)'\n }}\"\n >\n <ng-container *ngIf=\"hasAttachment && !message?.quoted_message\">\n <ng-container\n *ngTemplateOutlet=\"attachmentsTemplate\"\n ></ng-container>\n </ng-container>\n <div\n class=\"str-chat__message-text\"\n tabindex=\"0\"\n *ngIf=\"message?.text || (message?.quoted_message && hasAttachment)\"\n >\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 <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <ng-container *ngIf=\"hasAttachment && message?.quoted_message\">\n <ng-container\n *ngTemplateOutlet=\"attachmentsTemplate\"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\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 data-testid=\"text\">\n <p>\n <ng-container *ngIf=\"messageTextParts; else defaultContent\">\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-template #defaultMention let-content=\"content\">\n <span class=\"str-chat__message-mention\">{{\n content\n }}</span>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.mentionTemplate$ | async) ||\n defaultMention;\n context: getMentionContext(part)\n \"\n ></ng-container>\n </ng-template>\n </ng-container>\n </ng-container>\n <ng-template #defaultContent>\n <ng-container *ngIf=\"displayAs === 'text'; else asHTML\">\n {{ messageText || \"\" }}\n </ng-container>\n <ng-template #asHTML\n ><span\n data-testid=\"html-content\"\n [innerHTML]=\"messageText\"\n ></span\n ></ng-template>\n </ng-template>\n </p>\n </div>\n </div>\n </div>\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-error-icon\"\n icon=\"error\"\n ></stream-icon-placeholder>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'outside-message-bubble', message: message }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'outside-message-bubble' }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n</div>\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 <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.systemMessageTemplate$ | async) ||\n defaultSystemMessage;\n context: getMessageContext()\n \"\n ></ng-container>\n <ng-template #defaultSystemMessage let-messageInput=\"message\">\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>{{ messageInput?.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</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message str-chat__quoted-message-preview\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n (click)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n (keyup.enter)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"message?.quoted_message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-inner str-chat__quoted-message-bubble\">\n <ng-container\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n >\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n let-imageModalStateChangeHandler=\"imageModalStateChangeHandler\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n (imageModalStateChange)=\"imageModalStateChangeHandler($event)\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.attachmentListTemplate$ | async) ||\n defaultAttachments;\n context: getQuotedMessageAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.translation ||\n message?.quoted_message?.html ||\n message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n\n<!-- We need these markups in slightly different positions in theme-v1 and theme-v2, this soultion makes that possible without duplicating the code -->\n<ng-template #messageDateAndSender let-position=\"position\">\n <ng-container\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n >\n <div\n class=\"str-chat__translation-notice\"\n *ngIf=\"shouldDisplayTranslationNotice\"\n data-testid=\"translation-notice\"\n >\n <button\n data-testid=\"see-original\"\n *ngIf=\"displayedMessageTextContent === 'translation'\"\n (click)=\"displayOriginalMessage()\"\n (keyup.enter)=\"displayOriginalMessage()\"\n translate\n >\n streamChat.See original (automatically translated)\n </button>\n <button\n data-testid=\"see-translation\"\n *ngIf=\"displayedMessageTextContent === 'original'\"\n (click)=\"displayTranslatedMessage()\"\n (keyup.enter)=\"displayTranslatedMessage()\"\n translate\n >\n streamChat.See translation\n </button>\n </div>\n <ng-container\n *ngIf=\"customTemplatesService.customMessageMetadataTemplate$ | async\"\n >\n <div class=\"str-chat__custom-message-metadata\">\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.customMessageMetadataTemplate$ | async)!;\n context: getMessageMetadataContext()\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n class=\"\n str-chat__message-data\n str-chat__message-simple-data\n str-chat__message-metadata\n \"\n >\n <ng-container *ngIf=\"themeVersion === '2'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name str-chat__message-sender-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 </ng-container>\n</ng-template>\n\n<ng-template #messageStatus>\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 mode === 'main' && isMessageDeliveredAndRead && canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n <ng-template #deliveredStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.deliveredStatusTemplate$ | async) ||\n defaultDeliveredStatus;\n context: getDeliveredStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultDeliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"delivered-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n </popper-content>\n <stream-icon-placeholder\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon-placeholder>\n </span>\n </ng-template>\n <ng-template #sendingStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.sendingStatusTemplate$ | async) ||\n defaultSendingStatus;\n context: getSendingStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultSendingStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"sending-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n </popper-content>\n <stream-loading-indicator-placeholder\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator-placeholder>\n </span>\n </ng-template>\n <ng-template #readStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.readStatusTemplate$ | async) ||\n defaultReadStatus;\n context: getReadStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultReadStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"read-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div\n class=\"str-chat__tooltip str-chat__tooltip-angular\"\n data-testid=\"read-by-tooltip\"\n >\n {{ readByText }}\n </div>\n </popper-content>\n <stream-avatar-placeholder\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 type=\"user\"\n location=\"message-reader\"\n [user]=\"lastReadUser\"\n ></stream-avatar-placeholder>\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-container>\n</ng-template>\n\n<ng-template #replyCountButton let-position=\"position\">\n <div\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n class=\"\n str-chat__message-simple-reply-button\n str-chat__message-replies-count-button-wrapper\n \"\n >\n <button\n *ngIf=\"shouldDisplayThreadLink\"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '1'\"\n stream-icon-placeholder\n icon=\"reply\"\n ></stream-icon-placeholder>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n</ng-template>\n\n<ng-template #attachmentsTemplate>\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n let-imageModalStateChangeHandler=\"imageModalStateChangeHandler\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n (imageModalStateChange)=\"imageModalStateChangeHandler($event)\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.attachmentListTemplate$ | async) ||\n defaultAttachments;\n context: getAttachmentListContext()\n \"\n ></ng-container>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type", "initialsType", "showOnlineIndicator"] }, { type: i9.NgxPopperjsContentComponent, selector: "popper-content", exportAs: ["ngxPopperjsContent"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions", "customActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"], outputs: ["imageModalStateChange"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i9.NgxPopperjsDirective, selector: "[popper]", inputs: ["popperTimeout", "popperTimeoutAfterShow", "popperApplyClass", "popper", "popperDisabled", "popperPlacement", "popperApplyArrowClass", "popperPreventOverflow", "popperHideOnClickOutside", "popperTrigger", "popperStyles", "popperAriaDescribeBy", "popperAriaRole", "popperBoundaries", "popperCloseOnClickOutside", "popperDisableAnimation", "popperDisableStyle", "popperHideOnMouseLeave", "popperHideOnScroll", "popperAppendTo", "popperModifiers", "popperPositionFixed", "popperDelay", "popperShowOnStart", "popperTarget"], outputs: ["popperOnHidden", "popperOnShown", "popperOnUpdate"], exportAs: ["popper"] }, { type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
5542
+ MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", isLastSentMessage: "isLastSentMessage", mode: "mode", isHighlighted: "isHighlighted", customActions: "customActions" }, 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--other]=\"!isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"hasReactions\"\n [class.str-chat__message--highlighted]=\"isHighlighted\"\n [class.str-chat__message-with-thread-link]=\"shouldDisplayThreadLink\"\n [class.str-chat__message-send-can-be-retried]=\"\n (message?.status === 'failed' && message?.errorStatusCode !== 403) ||\n (message?.type === 'error' && message?.moderation_details)\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 *ngIf=\"themeVersion === '1'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <stream-avatar-placeholder\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n type=\"user\"\n location=\"message-sender\"\n [user]=\"message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions str-chat__message-options\"\n data-testid=\"message-options\"\n [class.str-chat__message-actions-open]=\"isActionBoxOpen\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n #messageActionsToggle\n class=\"\n str-chat__message-actions-container\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerClick\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"true\"\n [popperHideOnMouseLeave]=\"false\"\n [popperDisableAnimation]=\"true\"\n (popperOnHidden)=\"isActionBoxOpen = false\"\n >\n <popper-content #popperContent>\n <ng-template\n #defaultMessageActionsBox\n let-isOpen=\"isOpen\"\n let-isMine=\"isMine\"\n let-enabledActions=\"enabledActions\"\n let-messageInput=\"message\"\n let-customActions=\"customActions\"\n >\n <stream-message-actions-box\n (click)=\"messageActionsBoxClicked(popperContent)\"\n *ngIf=\"isOpen\"\n [isOpen]=\"isOpen\"\n [isMine]=\"isMine\"\n [enabledActions]=\"enabledActions\"\n [customActions]=\"customActions\"\n [message]=\"messageInput\"\n ></stream-message-actions-box>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageActionsBoxTemplate$ | async) ||\n defaultMessageActionsBox;\n context: getMessageActionsBoxContext()\n \"\n >\n </ng-container>\n </popper-content>\n <div\n class=\"str-chat__message-actions-box-button\"\n data-testid=\"action-icon\"\n (click)=\"messageActionsClicked()\"\n (keyup.enter)=\"messageActionsClicked()\"\n *ngIf=\"visibleMessageActionsCount > 0\"\n >\n <stream-icon-placeholder\n icon=\"action-icon\"\n class=\"str-chat__message-action-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n str-chat__message-reply-in-thread-button\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reply-in-thread\"\n ></stream-icon-placeholder>\n </div>\n <div\n *ngIf=\"canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n str-chat__message-reactions-button\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reaction-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div class=\"str-chat__message-reactions-host\">\n <ng-template\n #defaultMessageReactions\n let-messageReactionCounts=\"messageReactionCounts\"\n let-latestReactions=\"latestReactions\"\n let-isSelectorOpen=\"isSelectorOpen\"\n let-isSelectorOpenChangeHandler=\"isSelectorOpenChangeHandler\"\n let-messageId=\"messageId\"\n let-ownReactions=\"ownReactions\"\n >\n <stream-message-reactions\n [messageReactionCounts]=\"messageReactionCounts\"\n [latestReactions]=\"latestReactions\"\n [isSelectorOpen]=\"isSelectorOpen\"\n (isSelectorOpenChange)=\"isSelectorOpenChangeHandler($event)\"\n [messageId]=\"messageId\"\n [ownReactions]=\"ownReactions\"\n ></stream-message-reactions>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.messageReactionsTemplate$ | async) ||\n defaultMessageReactions;\n context: getMessageReactionsContext()\n \"\n ></ng-container>\n </div>\n <!-- transform: translate3d(0, 0, 0) fixes scrolling issues on iOS, see: https://stackoverflow.com/questions/50105780/elements-disappear-when-scrolling-in-safari-webkit-transform-fix-only-works-t/50144295#50144295 -->\n <!-- transform: none is required when image carousel is open in order for the modal to be correctly positioned, see how the transform property changes the behavior of fixed positioned elements https://developer.mozilla.org/en-US/docs/Web/CSS/position -->\n <div\n class=\"str-chat__message-bubble\"\n style=\"transform: {{\n imageAttachmentModalState === 'opened'\n ? 'none'\n : 'translate3d(0, 0, 0)'\n }}\"\n >\n <ng-container *ngIf=\"hasAttachment && !message?.quoted_message\">\n <ng-container\n *ngTemplateOutlet=\"attachmentsTemplate\"\n ></ng-container>\n </ng-container>\n <div\n class=\"str-chat__message-text\"\n tabindex=\"0\"\n *ngIf=\"message?.text || (message?.quoted_message && hasAttachment)\"\n >\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)=\"unsentMessageClicked()\"\n (keyup.enter)=\"unsentMessageClicked()\"\n >\n <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <ng-container *ngIf=\"hasAttachment && message?.quoted_message\">\n <ng-container\n *ngTemplateOutlet=\"attachmentsTemplate\"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n <ng-container *ngIf=\"!message?.moderation_details\">{{\n \"streamChat.Error \u00B7 Unsent\" | translate\n }}</ng-container>\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\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 data-testid=\"text\">\n <p>\n <ng-container *ngIf=\"messageTextParts; else defaultContent\">\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-template #defaultMention let-content=\"content\">\n <span class=\"str-chat__message-mention\">{{\n content\n }}</span>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.mentionTemplate$ | async) ||\n defaultMention;\n context: getMentionContext(part)\n \"\n ></ng-container>\n </ng-template>\n </ng-container>\n </ng-container>\n <ng-template #defaultContent>\n <ng-container *ngIf=\"displayAs === 'text'; else asHTML\">\n {{ messageText || \"\" }}\n </ng-container>\n <ng-template #asHTML\n ><span\n data-testid=\"html-content\"\n [innerHTML]=\"messageText\"\n ></span\n ></ng-template>\n </ng-template>\n </p>\n </div>\n </div>\n </div>\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-error-icon\"\n icon=\"error\"\n ></stream-icon-placeholder>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'outside-message-bubble', message: message }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'outside-message-bubble' }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n</div>\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 <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.systemMessageTemplate$ | async) ||\n defaultSystemMessage;\n context: getMessageContext()\n \"\n ></ng-container>\n <ng-template #defaultSystemMessage let-messageInput=\"message\">\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>{{ messageInput?.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</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message str-chat__quoted-message-preview\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n (click)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n (keyup.enter)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"message?.quoted_message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-inner str-chat__quoted-message-bubble\">\n <ng-container\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n >\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n let-imageModalStateChangeHandler=\"imageModalStateChangeHandler\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n (imageModalStateChange)=\"imageModalStateChangeHandler($event)\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.attachmentListTemplate$ | async) ||\n defaultAttachments;\n context: getQuotedMessageAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.translation ||\n message?.quoted_message?.html ||\n message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n\n<!-- We need these markups in slightly different positions in theme-v1 and theme-v2, this soultion makes that possible without duplicating the code -->\n<ng-template #messageDateAndSender let-position=\"position\">\n <ng-container\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n >\n <div\n class=\"str-chat__translation-notice\"\n *ngIf=\"shouldDisplayTranslationNotice\"\n data-testid=\"translation-notice\"\n >\n <button\n data-testid=\"see-original\"\n *ngIf=\"displayedMessageTextContent === 'translation'\"\n (click)=\"displayOriginalMessage()\"\n (keyup.enter)=\"displayOriginalMessage()\"\n translate\n >\n streamChat.See original (automatically translated)\n </button>\n <button\n data-testid=\"see-translation\"\n *ngIf=\"displayedMessageTextContent === 'original'\"\n (click)=\"displayTranslatedMessage()\"\n (keyup.enter)=\"displayTranslatedMessage()\"\n translate\n >\n streamChat.See translation\n </button>\n </div>\n <ng-container\n *ngIf=\"customTemplatesService.customMessageMetadataTemplate$ | async\"\n >\n <div class=\"str-chat__custom-message-metadata\">\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.customMessageMetadataTemplate$ | async)!;\n context: getMessageMetadataContext()\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n class=\"\n str-chat__message-data\n str-chat__message-simple-data\n str-chat__message-metadata\n \"\n >\n <ng-container *ngIf=\"themeVersion === '2'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name str-chat__message-sender-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 </ng-container>\n</ng-template>\n\n<ng-template #messageStatus>\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 mode === 'main' && isMessageDeliveredAndRead && canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n <ng-template #deliveredStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.deliveredStatusTemplate$ | async) ||\n defaultDeliveredStatus;\n context: getDeliveredStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultDeliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"delivered-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n </popper-content>\n <stream-icon-placeholder\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon-placeholder>\n </span>\n </ng-template>\n <ng-template #sendingStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.sendingStatusTemplate$ | async) ||\n defaultSendingStatus;\n context: getSendingStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultSendingStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"sending-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n </popper-content>\n <stream-loading-indicator-placeholder\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator-placeholder>\n </span>\n </ng-template>\n <ng-template #readStatus>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.readStatusTemplate$ | async) ||\n defaultReadStatus;\n context: getReadStatusContext()\n \"\n ></ng-container>\n </ng-template>\n <ng-template #defaultReadStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"read-indicator\"\n tabindex=\"0\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div\n class=\"str-chat__tooltip str-chat__tooltip-angular\"\n data-testid=\"read-by-tooltip\"\n >\n {{ readByText }}\n </div>\n </popper-content>\n <stream-avatar-placeholder\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 type=\"user\"\n location=\"message-reader\"\n [user]=\"lastReadUser\"\n ></stream-avatar-placeholder>\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-container>\n</ng-template>\n\n<ng-template #replyCountButton let-position=\"position\">\n <div\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n class=\"\n str-chat__message-simple-reply-button\n str-chat__message-replies-count-button-wrapper\n \"\n >\n <button\n *ngIf=\"shouldDisplayThreadLink\"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '1'\"\n stream-icon-placeholder\n icon=\"reply\"\n ></stream-icon-placeholder>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n</ng-template>\n\n<ng-template #attachmentsTemplate>\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n let-imageModalStateChangeHandler=\"imageModalStateChangeHandler\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n (imageModalStateChange)=\"imageModalStateChangeHandler($event)\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n (customTemplatesService.attachmentListTemplate$ | async) ||\n defaultAttachments;\n context: getAttachmentListContext()\n \"\n ></ng-container>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type", "initialsType", "showOnlineIndicator"] }, { type: i9.NgxPopperjsContentComponent, selector: "popper-content", exportAs: ["ngxPopperjsContent"] }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions", "customActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"], outputs: ["imageModalStateChange"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i9.NgxPopperjsDirective, selector: "[popper]", inputs: ["popperTimeout", "popperTimeoutAfterShow", "popperApplyClass", "popper", "popperDisabled", "popperPlacement", "popperApplyArrowClass", "popperPreventOverflow", "popperHideOnClickOutside", "popperTrigger", "popperStyles", "popperAriaDescribeBy", "popperAriaRole", "popperBoundaries", "popperCloseOnClickOutside", "popperDisableAnimation", "popperDisableStyle", "popperHideOnMouseLeave", "popperHideOnScroll", "popperAppendTo", "popperModifiers", "popperPositionFixed", "popperDelay", "popperShowOnStart", "popperTarget"], outputs: ["popperOnHidden", "popperOnShown", "popperOnUpdate"], exportAs: ["popper"] }, { type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "async": i5.AsyncPipe, "translate": i6.TranslatePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
5407
5543
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, decorators: [{
5408
5544
  type: Component,
5409
5545
  args: [{
@@ -6377,8 +6513,8 @@ class MessageListComponent {
6377
6513
  (_d = (_c = this.chatClientService.chatClient) === null || _c === void 0 ? void 0 : _c.logger) === null || _d === void 0 ? void 0 : _d.call(_c, 'info', `Received one or more messages`, {
6378
6514
  tags: `message list ${this.mode}`,
6379
6515
  });
6380
- const currentLatestMessage = messages[messages.length - 1];
6381
- this.newMessageReceived(currentLatestMessage);
6516
+ const currentLatestMessageInState = messages[messages.length - 1];
6517
+ this.newMessageReceived(currentLatestMessageInState);
6382
6518
  const currentOldestMessage = messages[0];
6383
6519
  if (!this.oldestMessage ||
6384
6520
  !messages.find((m) => m.id === this.oldestMessage.id)) {
@@ -6411,7 +6547,8 @@ class MessageListComponent {
6411
6547
  this.isLatestMessageInList =
6412
6548
  !this.latestMessage ||
6413
6549
  messages.length === 0 ||
6414
- messages[messages.length - 1].id === this.latestMessage.id;
6550
+ messages[messages.length - 1].id === this.latestMessage.id ||
6551
+ this.mode === 'thread';
6415
6552
  if (!this.isLatestMessageInList) {
6416
6553
  this.isUserScrolled = true;
6417
6554
  }
@@ -6468,15 +6605,20 @@ class MessageListComponent {
6468
6605
  }
6469
6606
  }
6470
6607
  newMessageReceived(message) {
6471
- var _a, _b, _c, _d, _e, _f;
6608
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
6609
+ const latestMessages = (_b = (_a = this.channelService.activeChannel) === null || _a === void 0 ? void 0 : _a.state) === null || _b === void 0 ? void 0 : _b.latestMessages;
6472
6610
  if (!this.latestMessage ||
6473
- ((_a = this.latestMessage.created_at) === null || _a === void 0 ? void 0 : _a.getTime()) < message.created_at.getTime()) {
6474
- (_c = (_b = this.chatClientService.chatClient) === null || _b === void 0 ? void 0 : _b.logger) === null || _c === void 0 ? void 0 : _c.call(_b, 'info', `Received new message`, { tags: `message list ${this.mode}` });
6611
+ ((_c = this.latestMessage.created_at) === null || _c === void 0 ? void 0 : _c.getTime()) < message.created_at.getTime() ||
6612
+ (this.mode === 'main' &&
6613
+ latestMessages &&
6614
+ this.latestMessage &&
6615
+ ((_d = latestMessages[latestMessages.length - 1]) === null || _d === void 0 ? void 0 : _d.id) !== this.latestMessage.id)) {
6616
+ (_f = (_e = this.chatClientService.chatClient) === null || _e === void 0 ? void 0 : _e.logger) === null || _f === void 0 ? void 0 : _f.call(_e, 'info', `Received new message`, { tags: `message list ${this.mode}` });
6475
6617
  const isNewChannel = !this.latestMessage;
6476
6618
  this.latestMessage = message;
6477
6619
  this.hasNewMessages = true;
6478
6620
  this.isNewMessageSentByUser =
6479
- ((_d = message.user) === null || _d === void 0 ? void 0 : _d.id) === ((_f = (_e = this.chatClientService.chatClient) === null || _e === void 0 ? void 0 : _e.user) === null || _f === void 0 ? void 0 : _f.id);
6621
+ ((_g = message.user) === null || _g === void 0 ? void 0 : _g.id) === ((_j = (_h = this.chatClientService.chatClient) === null || _h === void 0 ? void 0 : _h.user) === null || _j === void 0 ? void 0 : _j.id);
6480
6622
  if (this.isUserScrolled) {
6481
6623
  this.newMessageCountWhileBeingScrolled++;
6482
6624
  }
@@ -6647,7 +6789,9 @@ StreamChatModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", versio
6647
6789
  TextareaDirective,
6648
6790
  ThreadComponent,
6649
6791
  IconPlaceholderComponent,
6650
- LoadingIndicatorPlaceholderComponent], imports: [CommonModule,
6792
+ LoadingIndicatorPlaceholderComponent,
6793
+ EditMessageFormComponent,
6794
+ MessageBouncePromptComponent], imports: [CommonModule,
6651
6795
  TranslateModule,
6652
6796
  StreamAvatarModule,
6653
6797
  NgxPopperjsModule], exports: [ChannelComponent,
@@ -6669,7 +6813,9 @@ StreamChatModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", versio
6669
6813
  StreamAvatarModule,
6670
6814
  ThreadComponent,
6671
6815
  IconPlaceholderComponent,
6672
- LoadingIndicatorPlaceholderComponent] });
6816
+ LoadingIndicatorPlaceholderComponent,
6817
+ EditMessageFormComponent,
6818
+ MessageBouncePromptComponent] });
6673
6819
  StreamChatModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: StreamChatModule, imports: [[
6674
6820
  CommonModule,
6675
6821
  TranslateModule,
@@ -6700,6 +6846,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
6700
6846
  ThreadComponent,
6701
6847
  IconPlaceholderComponent,
6702
6848
  LoadingIndicatorPlaceholderComponent,
6849
+ EditMessageFormComponent,
6850
+ MessageBouncePromptComponent,
6703
6851
  ],
6704
6852
  imports: [
6705
6853
  CommonModule,
@@ -6728,6 +6876,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
6728
6876
  ThreadComponent,
6729
6877
  IconPlaceholderComponent,
6730
6878
  LoadingIndicatorPlaceholderComponent,
6879
+ EditMessageFormComponent,
6880
+ MessageBouncePromptComponent,
6731
6881
  ],
6732
6882
  }]
6733
6883
  }] });
@@ -6790,5 +6940,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
6790
6940
  * Generated bundle index. Do not edit.
6791
6941
  */
6792
6942
 
6793
- export { AttachmentConfigurationService, AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, AvatarPlaceholderComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelListToggleService, ChannelPreviewComponent, ChannelService, ChatClientService, CustomTemplatesService, DateParserService, EmojiInputService, IconComponent, IconPlaceholderComponent, ImageLoadService, LoadingIndicatorComponent, LoadingIndicatorPlaceholderComponent, MessageActionsBoxComponent, MessageActionsService, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, MessageReactionsService, MessageService, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, createMessagePreview, getChannelDisplayText, getGroupStyles, getMessageTranslation, getReadBy, isImageAttachment, isImageFile, listUsers, parseDate, textareaInjectionToken };
6943
+ export { AttachmentConfigurationService, AttachmentListComponent, AttachmentPreviewListComponent, AttachmentService, AutocompleteTextareaComponent, AvatarComponent, AvatarPlaceholderComponent, ChannelComponent, ChannelHeaderComponent, ChannelListComponent, ChannelListToggleService, ChannelPreviewComponent, ChannelService, ChatClientService, CustomTemplatesService, DateParserService, EditMessageFormComponent, EmojiInputService, IconComponent, IconPlaceholderComponent, ImageLoadService, LoadingIndicatorComponent, LoadingIndicatorPlaceholderComponent, MessageActionsBoxComponent, MessageActionsService, MessageBouncePromptComponent, MessageComponent, MessageInputComponent, MessageInputConfigService, MessageListComponent, MessageReactionsComponent, MessageReactionsService, MessageService, ModalComponent, NotificationComponent, NotificationListComponent, NotificationService, StreamAutocompleteTextareaModule, StreamAvatarModule, StreamChatModule, StreamI18nService, StreamTextareaModule, TextareaComponent, TextareaDirective, ThemeService, ThreadComponent, TransliterationService, createMessagePreview, getChannelDisplayText, getGroupStyles, getMessageTranslation, getReadBy, isImageAttachment, isImageFile, listUsers, parseDate, textareaInjectionToken };
6794
6944
  //# sourceMappingURL=stream-chat-angular.js.map