stream-chat-angular 2.15.0 → 2.16.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.
@@ -354,7 +354,7 @@
354
354
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
355
355
  }
356
356
 
357
- var version = '2.15.0';
357
+ var version = '2.16.0';
358
358
 
359
359
  /**
360
360
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -635,6 +635,7 @@
635
635
  this.activeChannelSubscriptions = [];
636
636
  this.activeParentMessageIdSubject = new rxjs.BehaviorSubject(undefined);
637
637
  this.activeThreadMessagesSubject = new rxjs.BehaviorSubject([]);
638
+ this.latestMessageDateByUserByChannelsSubject = new rxjs.BehaviorSubject({});
638
639
  this.messagePageSize = 25;
639
640
  this.messageToQuoteSubject = new rxjs.BehaviorSubject(undefined);
640
641
  this.usersTypingInChannelSubject = new rxjs.BehaviorSubject([]);
@@ -667,8 +668,8 @@
667
668
  this.activeParentMessage$ = rxjs.combineLatest([
668
669
  this.activeChannelMessages$,
669
670
  this.activeParentMessageId$,
670
- ]).pipe(operators.map(function (_f) {
671
- var _g = __read(_f, 2), messages = _g[0], parentMessageId = _g[1];
671
+ ]).pipe(operators.map(function (_h) {
672
+ var _j = __read(_h, 2), messages = _j[0], parentMessageId = _j[1];
672
673
  if (!parentMessageId) {
673
674
  return undefined;
674
675
  }
@@ -685,6 +686,8 @@
685
686
  this.usersTypingInChannel$ =
686
687
  this.usersTypingInChannelSubject.asObservable();
687
688
  this.usersTypingInThread$ = this.usersTypingInThreadSubject.asObservable();
689
+ this.latestMessageDateByUserByChannels$ =
690
+ this.latestMessageDateByUserByChannelsSubject.asObservable();
688
691
  }
689
692
  /**
690
693
  * Sets the given `channel` as active.
@@ -714,8 +717,8 @@
714
717
  var _a;
715
718
  return __awaiter(this, void 0, void 0, function () {
716
719
  var messageToQuote, activeChannel, result;
717
- return __generator(this, function (_f) {
718
- switch (_f.label) {
720
+ return __generator(this, function (_h) {
721
+ switch (_h.label) {
719
722
  case 0:
720
723
  messageToQuote = this.messageToQuoteSubject.getValue();
721
724
  if (messageToQuote && !!messageToQuote.parent_id) {
@@ -732,9 +735,9 @@
732
735
  limit: (_a = this.options) === null || _a === void 0 ? void 0 : _a.message_limit,
733
736
  }))];
734
737
  case 2:
735
- result = _f.sent();
738
+ result = _h.sent();
736
739
  this.activeThreadMessagesSubject.next((result === null || result === void 0 ? void 0 : result.messages) || []);
737
- _f.label = 3;
740
+ _h.label = 3;
738
741
  case 3: return [2 /*return*/];
739
742
  }
740
743
  });
@@ -747,8 +750,8 @@
747
750
  var _a, _b, _c, _d, _e;
748
751
  return __awaiter(this, void 0, void 0, function () {
749
752
  var activeChnannel, lastMessageId;
750
- return __generator(this, function (_f) {
751
- switch (_f.label) {
753
+ return __generator(this, function (_h) {
754
+ switch (_h.label) {
752
755
  case 0:
753
756
  activeChnannel = this.activeChannelSubject.getValue();
754
757
  lastMessageId = (_a = this.activeChannelMessagesSubject.getValue()[0]) === null || _a === void 0 ? void 0 : _a.id;
@@ -758,7 +761,7 @@
758
761
  watchers: { limit: 0 },
759
762
  }))];
760
763
  case 1:
761
- _f.sent();
764
+ _h.sent();
762
765
  if (((_c = activeChnannel === null || activeChnannel === void 0 ? void 0 : activeChnannel.data) === null || _c === void 0 ? void 0 : _c.id) ===
763
766
  ((_e = (_d = this.activeChannelSubject.getValue()) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.id)) {
764
767
  this.activeChannelMessagesSubject.next(__spreadArray([], __read(activeChnannel.state.messages)));
@@ -775,8 +778,8 @@
775
778
  var _a, _b;
776
779
  return __awaiter(this, void 0, void 0, function () {
777
780
  var activeChnannel, parentMessageId, lastMessageId;
778
- return __generator(this, function (_f) {
779
- switch (_f.label) {
781
+ return __generator(this, function (_h) {
782
+ switch (_h.label) {
780
783
  case 0:
781
784
  activeChnannel = this.activeChannelSubject.getValue();
782
785
  parentMessageId = this.activeParentMessageIdSubject.getValue();
@@ -789,7 +792,7 @@
789
792
  id_lt: lastMessageId,
790
793
  }))];
791
794
  case 1:
792
- _f.sent();
795
+ _h.sent();
793
796
  this.activeThreadMessagesSubject.next((activeChnannel === null || activeChnannel === void 0 ? void 0 : activeChnannel.state.threads[parentMessageId]) || []);
794
797
  return [2 /*return*/];
795
798
  }
@@ -805,8 +808,8 @@
805
808
  ChannelService.prototype.init = function (filters, sort, options) {
806
809
  return __awaiter(this, void 0, void 0, function () {
807
810
  var _this = this;
808
- return __generator(this, function (_f) {
809
- switch (_f.label) {
811
+ return __generator(this, function (_h) {
812
+ switch (_h.label) {
810
813
  case 0:
811
814
  this.filters = filters;
812
815
  this.options = options || {
@@ -820,7 +823,7 @@
820
823
  this.sort = sort || { last_message_at: -1, updated_at: -1 };
821
824
  return [4 /*yield*/, this.queryChannels()];
822
825
  case 1:
823
- _f.sent();
826
+ _h.sent();
824
827
  this.chatClientService.notification$.subscribe(function (notification) { return void _this.handleNotification(notification); });
825
828
  return [2 /*return*/];
826
829
  }
@@ -836,6 +839,7 @@
836
839
  this.activeParentMessageIdSubject.next(undefined);
837
840
  this.activeThreadMessagesSubject.next([]);
838
841
  this.channelsSubject.next(undefined);
842
+ this.latestMessageDateByUserByChannelsSubject.next({});
839
843
  this.selectMessageToQuote(undefined);
840
844
  };
841
845
  /**
@@ -843,13 +847,13 @@
843
847
  */
844
848
  ChannelService.prototype.loadMoreChannels = function () {
845
849
  return __awaiter(this, void 0, void 0, function () {
846
- return __generator(this, function (_f) {
847
- switch (_f.label) {
850
+ return __generator(this, function (_h) {
851
+ switch (_h.label) {
848
852
  case 0:
849
853
  this.options.offset = this.channels.length;
850
854
  return [4 /*yield*/, this.queryChannels()];
851
855
  case 1:
852
- _f.sent();
856
+ _h.sent();
853
857
  return [2 /*return*/];
854
858
  }
855
859
  });
@@ -863,13 +867,13 @@
863
867
  ChannelService.prototype.addReaction = function (messageId, reactionType) {
864
868
  var _a;
865
869
  return __awaiter(this, void 0, void 0, function () {
866
- return __generator(this, function (_f) {
867
- switch (_f.label) {
870
+ return __generator(this, function (_h) {
871
+ switch (_h.label) {
868
872
  case 0: return [4 /*yield*/, ((_a = this.activeChannelSubject.getValue()) === null || _a === void 0 ? void 0 : _a.sendReaction(messageId, {
869
873
  type: reactionType,
870
874
  }))];
871
875
  case 1:
872
- _f.sent();
876
+ _h.sent();
873
877
  return [2 /*return*/];
874
878
  }
875
879
  });
@@ -883,12 +887,12 @@
883
887
  ChannelService.prototype.removeReaction = function (messageId, reactionType) {
884
888
  var _a;
885
889
  return __awaiter(this, void 0, void 0, function () {
886
- return __generator(this, function (_f) {
887
- switch (_f.label) {
890
+ return __generator(this, function (_h) {
891
+ switch (_h.label) {
888
892
  case 0: return [4 /*yield*/, ((_a = this.activeChannelSubject
889
893
  .getValue()) === null || _a === void 0 ? void 0 : _a.deleteReaction(messageId, reactionType))];
890
894
  case 1:
891
- _f.sent();
895
+ _h.sent();
892
896
  return [2 /*return*/];
893
897
  }
894
898
  });
@@ -909,8 +913,8 @@
909
913
  if (quotedMessageId === void 0) { quotedMessageId = undefined; }
910
914
  return __awaiter(this, void 0, void 0, function () {
911
915
  var preview, channel;
912
- return __generator(this, function (_f) {
913
- switch (_f.label) {
916
+ return __generator(this, function (_h) {
917
+ switch (_h.label) {
914
918
  case 0:
915
919
  preview = createMessagePreview(this.chatClientService.chatClient.user, text, attachments, mentionedUsers, parentId, quotedMessageId);
916
920
  channel = this.activeChannelSubject.getValue();
@@ -918,7 +922,7 @@
918
922
  channel.state.addMessageSorted(preview, true);
919
923
  return [4 /*yield*/, this.sendMessageRequest(preview)];
920
924
  case 1:
921
- _f.sent();
925
+ _h.sent();
922
926
  return [2 /*return*/];
923
927
  }
924
928
  });
@@ -931,14 +935,14 @@
931
935
  ChannelService.prototype.resendMessage = function (message) {
932
936
  return __awaiter(this, void 0, void 0, function () {
933
937
  var channel;
934
- return __generator(this, function (_f) {
935
- switch (_f.label) {
938
+ return __generator(this, function (_h) {
939
+ switch (_h.label) {
936
940
  case 0:
937
941
  channel = this.activeChannelSubject.getValue();
938
942
  channel.state.addMessageSorted(Object.assign(Object.assign({}, message), { errorStatusCode: undefined, status: 'sending' }), true);
939
943
  return [4 /*yield*/, this.sendMessageRequest(message)];
940
944
  case 1:
941
- _f.sent();
945
+ _h.sent();
942
946
  return [2 /*return*/];
943
947
  }
944
948
  });
@@ -950,11 +954,11 @@
950
954
  */
951
955
  ChannelService.prototype.updateMessage = function (message) {
952
956
  return __awaiter(this, void 0, void 0, function () {
953
- return __generator(this, function (_f) {
954
- switch (_f.label) {
957
+ return __generator(this, function (_h) {
958
+ switch (_h.label) {
955
959
  case 0: return [4 /*yield*/, this.chatClientService.chatClient.updateMessage(message)];
956
960
  case 1:
957
- _f.sent();
961
+ _h.sent();
958
962
  return [2 /*return*/];
959
963
  }
960
964
  });
@@ -966,11 +970,11 @@
966
970
  */
967
971
  ChannelService.prototype.deleteMessage = function (message) {
968
972
  return __awaiter(this, void 0, void 0, function () {
969
- return __generator(this, function (_f) {
970
- switch (_f.label) {
973
+ return __generator(this, function (_h) {
974
+ switch (_h.label) {
971
975
  case 0: return [4 /*yield*/, this.chatClientService.chatClient.deleteMessage(message.id)];
972
976
  case 1:
973
- _f.sent();
977
+ _h.sent();
974
978
  return [2 /*return*/];
975
979
  }
976
980
  });
@@ -984,8 +988,8 @@
984
988
  ChannelService.prototype.uploadAttachments = function (uploads) {
985
989
  return __awaiter(this, void 0, void 0, function () {
986
990
  var result, channel, uploadResults;
987
- return __generator(this, function (_f) {
988
- switch (_f.label) {
991
+ return __generator(this, function (_h) {
992
+ switch (_h.label) {
989
993
  case 0:
990
994
  result = [];
991
995
  channel = this.activeChannelSubject.getValue();
@@ -993,7 +997,7 @@
993
997
  ? channel.sendImage(upload.file)
994
998
  : channel.sendFile(upload.file); }))];
995
999
  case 1:
996
- uploadResults = _f.sent();
1000
+ uploadResults = _h.sent();
997
1001
  uploadResults.forEach(function (uploadResult, i) {
998
1002
  var file = uploads[i].file;
999
1003
  var type = uploads[i].type;
@@ -1021,15 +1025,15 @@
1021
1025
  ChannelService.prototype.deleteAttachment = function (attachmentUpload) {
1022
1026
  return __awaiter(this, void 0, void 0, function () {
1023
1027
  var channel;
1024
- return __generator(this, function (_f) {
1025
- switch (_f.label) {
1028
+ return __generator(this, function (_h) {
1029
+ switch (_h.label) {
1026
1030
  case 0:
1027
1031
  channel = this.activeChannelSubject.getValue();
1028
1032
  return [4 /*yield*/, (attachmentUpload.type === 'image'
1029
1033
  ? channel.deleteImage(attachmentUpload.url)
1030
1034
  : channel.deleteFile(attachmentUpload.url))];
1031
1035
  case 1:
1032
- _f.sent();
1036
+ _h.sent();
1033
1037
  return [2 /*return*/];
1034
1038
  }
1035
1039
  });
@@ -1044,8 +1048,8 @@
1044
1048
  return __awaiter(this, void 0, void 0, function () {
1045
1049
  var activeChannel, result;
1046
1050
  var _this = this;
1047
- return __generator(this, function (_f) {
1048
- switch (_f.label) {
1051
+ return __generator(this, function (_h) {
1052
+ switch (_h.label) {
1049
1053
  case 0:
1050
1054
  activeChannel = this.activeChannelSubject.getValue();
1051
1055
  if (!activeChannel) {
@@ -1062,7 +1066,7 @@
1062
1066
  id: { $ne: this.chatClientService.chatClient.userID },
1063
1067
  })];
1064
1068
  case 2:
1065
- result = _f.sent();
1069
+ result = _h.sent();
1066
1070
  return [2 /*return*/, Object.values(result.members)];
1067
1071
  }
1068
1072
  });
@@ -1076,13 +1080,13 @@
1076
1080
  ChannelService.prototype.sendAction = function (messageId, formData) {
1077
1081
  return __awaiter(this, void 0, void 0, function () {
1078
1082
  var channel, response, isThreadReply;
1079
- return __generator(this, function (_f) {
1080
- switch (_f.label) {
1083
+ return __generator(this, function (_h) {
1084
+ switch (_h.label) {
1081
1085
  case 0:
1082
1086
  channel = this.activeChannelSubject.getValue();
1083
1087
  return [4 /*yield*/, channel.sendAction(messageId, formData)];
1084
1088
  case 1:
1085
- response = _f.sent();
1089
+ response = _h.sent();
1086
1090
  if (response === null || response === void 0 ? void 0 : response.message) {
1087
1091
  channel.state.addMessageSorted(Object.assign(Object.assign({}, response.message), { status: 'received' }));
1088
1092
  isThreadReply = !!response.message.parent_id;
@@ -1119,17 +1123,17 @@
1119
1123
  var _a;
1120
1124
  return __awaiter(this, void 0, void 0, function () {
1121
1125
  var channel, isThreadReply, response, error_1, stringError, parsedError;
1122
- return __generator(this, function (_f) {
1123
- switch (_f.label) {
1126
+ return __generator(this, function (_h) {
1127
+ switch (_h.label) {
1124
1128
  case 0:
1125
1129
  channel = this.activeChannelSubject.getValue();
1126
1130
  isThreadReply = !!preview.parent_id;
1127
1131
  isThreadReply
1128
1132
  ? this.activeThreadMessagesSubject.next(__spreadArray([], __read(channel.state.threads[preview.parent_id])))
1129
1133
  : this.activeChannelMessagesSubject.next(__spreadArray([], __read(channel.state.messages)));
1130
- _f.label = 1;
1134
+ _h.label = 1;
1131
1135
  case 1:
1132
- _f.trys.push([1, 3, , 4]);
1136
+ _h.trys.push([1, 3, , 4]);
1133
1137
  return [4 /*yield*/, channel.sendMessage({
1134
1138
  text: preview.text,
1135
1139
  attachments: preview.attachments,
@@ -1139,7 +1143,7 @@
1139
1143
  quoted_message_id: preview.quoted_message_id,
1140
1144
  })];
1141
1145
  case 2:
1142
- response = _f.sent();
1146
+ response = _h.sent();
1143
1147
  if (response === null || response === void 0 ? void 0 : response.message) {
1144
1148
  channel.state.addMessageSorted(Object.assign(Object.assign({}, response.message), { status: 'received' }), true);
1145
1149
  isThreadReply
@@ -1148,7 +1152,7 @@
1148
1152
  }
1149
1153
  return [3 /*break*/, 4];
1150
1154
  case 3:
1151
- error_1 = _f.sent();
1155
+ error_1 = _h.sent();
1152
1156
  stringError = JSON.stringify(error_1);
1153
1157
  parsedError = stringError
1154
1158
  ? JSON.parse(stringError)
@@ -1165,53 +1169,53 @@
1165
1169
  };
1166
1170
  ChannelService.prototype.handleNotification = function (notification) {
1167
1171
  return __awaiter(this, void 0, void 0, function () {
1168
- var _f;
1172
+ var _h;
1169
1173
  var _this = this;
1170
- return __generator(this, function (_g) {
1171
- switch (_g.label) {
1174
+ return __generator(this, function (_j) {
1175
+ switch (_j.label) {
1172
1176
  case 0:
1173
- _f = notification.eventType;
1174
- switch (_f) {
1177
+ _h = notification.eventType;
1178
+ switch (_h) {
1175
1179
  case 'notification.message_new': return [3 /*break*/, 1];
1176
1180
  case 'notification.added_to_channel': return [3 /*break*/, 3];
1177
1181
  case 'notification.removed_from_channel': return [3 /*break*/, 5];
1178
1182
  }
1179
1183
  return [3 /*break*/, 6];
1180
1184
  case 1: return [4 /*yield*/, this.ngZone.run(function () { return __awaiter(_this, void 0, void 0, function () {
1181
- return __generator(this, function (_f) {
1182
- switch (_f.label) {
1185
+ return __generator(this, function (_h) {
1186
+ switch (_h.label) {
1183
1187
  case 0:
1184
1188
  if (!this.customNewMessageNotificationHandler) return [3 /*break*/, 1];
1185
1189
  this.customNewMessageNotificationHandler(notification, this.channelListSetter);
1186
1190
  return [3 /*break*/, 3];
1187
1191
  case 1: return [4 /*yield*/, this.handleNewMessageNotification(notification)];
1188
1192
  case 2:
1189
- _f.sent();
1190
- _f.label = 3;
1193
+ _h.sent();
1194
+ _h.label = 3;
1191
1195
  case 3: return [2 /*return*/];
1192
1196
  }
1193
1197
  });
1194
1198
  }); })];
1195
1199
  case 2:
1196
- _g.sent();
1200
+ _j.sent();
1197
1201
  return [3 /*break*/, 6];
1198
1202
  case 3: return [4 /*yield*/, this.ngZone.run(function () { return __awaiter(_this, void 0, void 0, function () {
1199
- return __generator(this, function (_f) {
1200
- switch (_f.label) {
1203
+ return __generator(this, function (_h) {
1204
+ switch (_h.label) {
1201
1205
  case 0:
1202
1206
  if (!this.customAddedToChannelNotificationHandler) return [3 /*break*/, 1];
1203
1207
  this.customAddedToChannelNotificationHandler(notification, this.channelListSetter);
1204
1208
  return [3 /*break*/, 3];
1205
1209
  case 1: return [4 /*yield*/, this.handleAddedToChannelNotification(notification)];
1206
1210
  case 2:
1207
- _f.sent();
1208
- _f.label = 3;
1211
+ _h.sent();
1212
+ _h.label = 3;
1209
1213
  case 3: return [2 /*return*/];
1210
1214
  }
1211
1215
  });
1212
1216
  }); })];
1213
1217
  case 4:
1214
- _g.sent();
1218
+ _j.sent();
1215
1219
  return [3 /*break*/, 6];
1216
1220
  case 5:
1217
1221
  {
@@ -1224,7 +1228,7 @@
1224
1228
  }
1225
1229
  });
1226
1230
  }
1227
- _g.label = 6;
1231
+ _j.label = 6;
1228
1232
  case 6: return [2 /*return*/];
1229
1233
  }
1230
1234
  });
@@ -1236,11 +1240,11 @@
1236
1240
  };
1237
1241
  ChannelService.prototype.handleNewMessageNotification = function (notification) {
1238
1242
  return __awaiter(this, void 0, void 0, function () {
1239
- return __generator(this, function (_f) {
1240
- switch (_f.label) {
1243
+ return __generator(this, function (_h) {
1244
+ switch (_h.label) {
1241
1245
  case 0: return [4 /*yield*/, this.addChannelFromNotification(notification)];
1242
1246
  case 1:
1243
- _f.sent();
1247
+ _h.sent();
1244
1248
  return [2 /*return*/];
1245
1249
  }
1246
1250
  });
@@ -1248,11 +1252,11 @@
1248
1252
  };
1249
1253
  ChannelService.prototype.handleAddedToChannelNotification = function (notification) {
1250
1254
  return __awaiter(this, void 0, void 0, function () {
1251
- return __generator(this, function (_f) {
1252
- switch (_f.label) {
1255
+ return __generator(this, function (_h) {
1256
+ switch (_h.label) {
1253
1257
  case 0: return [4 /*yield*/, this.addChannelFromNotification(notification)];
1254
1258
  case 1:
1255
- _f.sent();
1259
+ _h.sent();
1256
1260
  return [2 /*return*/];
1257
1261
  }
1258
1262
  });
@@ -1262,13 +1266,13 @@
1262
1266
  var _a, _b;
1263
1267
  return __awaiter(this, void 0, void 0, function () {
1264
1268
  var channel;
1265
- return __generator(this, function (_f) {
1266
- switch (_f.label) {
1269
+ return __generator(this, function (_h) {
1270
+ switch (_h.label) {
1267
1271
  case 0:
1268
1272
  channel = this.chatClientService.chatClient.channel((_a = notification.event.channel) === null || _a === void 0 ? void 0 : _a.type, (_b = notification.event.channel) === null || _b === void 0 ? void 0 : _b.id);
1269
1273
  return [4 /*yield*/, channel.watch()];
1270
1274
  case 1:
1271
- _f.sent();
1275
+ _h.sent();
1272
1276
  this.watchForChannelEvents(channel);
1273
1277
  this.channelsSubject.next(__spreadArray([
1274
1278
  channel
@@ -1299,6 +1303,7 @@
1299
1303
  void (c === null || c === void 0 ? void 0 : c.markRead());
1300
1304
  }
1301
1305
  });
1306
+ _this.updateLatestMessages(event);
1302
1307
  });
1303
1308
  }));
1304
1309
  this.activeChannelSubscriptions.push(channel.on('message.updated', function (event) { return _this.messageUpdated(event); }));
@@ -1329,13 +1334,13 @@
1329
1334
  ChannelService.prototype.typingStarted = function (parentId) {
1330
1335
  return __awaiter(this, void 0, void 0, function () {
1331
1336
  var activeChannel;
1332
- return __generator(this, function (_f) {
1333
- switch (_f.label) {
1337
+ return __generator(this, function (_h) {
1338
+ switch (_h.label) {
1334
1339
  case 0:
1335
1340
  activeChannel = this.activeChannelSubject.getValue();
1336
1341
  return [4 /*yield*/, (activeChannel === null || activeChannel === void 0 ? void 0 : activeChannel.keystroke(parentId))];
1337
1342
  case 1:
1338
- _f.sent();
1343
+ _h.sent();
1339
1344
  return [2 /*return*/];
1340
1345
  }
1341
1346
  });
@@ -1348,13 +1353,13 @@
1348
1353
  ChannelService.prototype.typingStopped = function (parentId) {
1349
1354
  return __awaiter(this, void 0, void 0, function () {
1350
1355
  var activeChannel;
1351
- return __generator(this, function (_f) {
1352
- switch (_f.label) {
1356
+ return __generator(this, function (_h) {
1357
+ switch (_h.label) {
1353
1358
  case 0:
1354
1359
  activeChannel = this.activeChannelSubject.getValue();
1355
1360
  return [4 /*yield*/, (activeChannel === null || activeChannel === void 0 ? void 0 : activeChannel.stopTyping(parentId))];
1356
1361
  case 1:
1357
- _f.sent();
1362
+ _h.sent();
1358
1363
  return [2 /*return*/];
1359
1364
  }
1360
1365
  });
@@ -1427,13 +1432,13 @@
1427
1432
  return __awaiter(this, void 0, void 0, function () {
1428
1433
  var channels, prevChannels, error_2;
1429
1434
  var _this = this;
1430
- return __generator(this, function (_f) {
1431
- switch (_f.label) {
1435
+ return __generator(this, function (_h) {
1436
+ switch (_h.label) {
1432
1437
  case 0:
1433
- _f.trys.push([0, 2, , 3]);
1438
+ _h.trys.push([0, 2, , 3]);
1434
1439
  return [4 /*yield*/, this.chatClientService.chatClient.queryChannels(this.filters, this.sort, this.options)];
1435
1440
  case 1:
1436
- channels = _f.sent();
1441
+ channels = _h.sent();
1437
1442
  channels.forEach(function (c) { return _this.watchForChannelEvents(c); });
1438
1443
  prevChannels = this.channelsSubject.getValue() || [];
1439
1444
  this.channelsSubject.next(__spreadArray(__spreadArray([], __read(prevChannels)), __read(channels)));
@@ -1443,7 +1448,7 @@
1443
1448
  this.hasMoreChannelsSubject.next(channels.length >= this.options.limit);
1444
1449
  return [3 /*break*/, 3];
1445
1450
  case 2:
1446
- error_2 = _f.sent();
1451
+ error_2 = _h.sent();
1447
1452
  this.channelsSubject.error(error_2);
1448
1453
  return [3 /*break*/, 3];
1449
1454
  case 3: return [2 /*return*/];
@@ -1554,7 +1559,6 @@
1554
1559
  }
1555
1560
  }
1556
1561
  };
1557
- // truncate active thread as well
1558
1562
  ChannelService.prototype.handleChannelTruncate = function (event) {
1559
1563
  var _a, _b;
1560
1564
  var channelIndex = this.channels.findIndex(function (c) { return c.cid === event.channel.cid; });
@@ -1640,6 +1644,26 @@
1640
1644
  return;
1641
1645
  }
1642
1646
  };
1647
+ ChannelService.prototype.updateLatestMessages = function (event) {
1648
+ var _a, _b, _c, _d, _e, _f, _g;
1649
+ if (((_b = (_a = event.message) === null || _a === void 0 ? void 0 : _a.user) === null || _b === void 0 ? void 0 : _b.id) !== ((_d = (_c = this.chatClientService) === null || _c === void 0 ? void 0 : _c.chatClient.user) === null || _d === void 0 ? void 0 : _d.id)) {
1650
+ return;
1651
+ }
1652
+ var latestMessages = this.latestMessageDateByUserByChannelsSubject.getValue();
1653
+ if (!((_e = event.message) === null || _e === void 0 ? void 0 : _e.created_at)) {
1654
+ return;
1655
+ }
1656
+ var channelId = (_f = event === null || event === void 0 ? void 0 : event.message) === null || _f === void 0 ? void 0 : _f.cid;
1657
+ if (!channelId) {
1658
+ return;
1659
+ }
1660
+ var messageDate = new Date(event.message.created_at);
1661
+ if (!latestMessages[channelId] ||
1662
+ ((_g = latestMessages[channelId]) === null || _g === void 0 ? void 0 : _g.getTime()) < messageDate.getTime()) {
1663
+ latestMessages[channelId] = messageDate;
1664
+ this.latestMessageDateByUserByChannelsSubject.next(Object.assign({}, latestMessages));
1665
+ }
1666
+ };
1643
1667
  return ChannelService;
1644
1668
  }());
1645
1669
  ChannelService.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: ChannelService, deps: [{ token: ChatClientService }, { token: i0__namespace.NgZone }], target: i0__namespace.ɵɵFactoryTarget.Injectable });
@@ -2551,6 +2575,7 @@
2551
2575
  this.textareaValue = '';
2552
2576
  this.mentionedUsers = [];
2553
2577
  this.typingStart$ = new rxjs.Subject();
2578
+ this.isCooldownInProgress = false;
2554
2579
  this.subscriptions = [];
2555
2580
  this.isViewInited = false;
2556
2581
  this.subscriptions.push(this.attachmentService.attachmentUploadInProgressCounter$.subscribe(function (counter) {
@@ -2594,6 +2619,30 @@
2594
2619
  this.configService.commandAutocompleteItemTemplate;
2595
2620
  this.emojiPickerTemplate = this.configService.emojiPickerTemplate;
2596
2621
  this.subscriptions.push(this.typingStart$.subscribe(function () { return void _this.channelService.typingStarted(_this.parentMessageId); }));
2622
+ this.subscriptions.push(rxjs.combineLatest([
2623
+ this.channelService.latestMessageDateByUserByChannels$,
2624
+ this.channelService.activeChannel$,
2625
+ ])
2626
+ .pipe(operators.map(function (_12) {
2627
+ var _13 = __read(_12, 2), latestMessages = _13[0], channel = _13[1];
2628
+ return [latestMessages[(channel === null || channel === void 0 ? void 0 : channel.cid) || ''], channel];
2629
+ }))
2630
+ .subscribe(function (_12) {
2631
+ var _13 = __read(_12, 2), latestMessageDate = _13[0], channel = _13[1];
2632
+ var _a, _b, _c;
2633
+ var cooldown = ((_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.cooldown) &&
2634
+ latestMessageDate &&
2635
+ Math.round(((_b = channel === null || channel === void 0 ? void 0 : channel.data) === null || _b === void 0 ? void 0 : _b.cooldown) -
2636
+ (new Date().getTime() - latestMessageDate.getTime()) / 1000);
2637
+ if (cooldown &&
2638
+ cooldown > 0 &&
2639
+ ((_c = channel === null || channel === void 0 ? void 0 : channel.data) === null || _c === void 0 ? void 0 : _c.own_capabilities).includes('slow-mode')) {
2640
+ _this.startCooldown(cooldown);
2641
+ }
2642
+ else if (_this.isCooldownInProgress) {
2643
+ _this.stopCooldown();
2644
+ }
2645
+ }));
2597
2646
  }
2598
2647
  MessageInputComponent.prototype.ngAfterViewInit = function () {
2599
2648
  this.isViewInited = true;
@@ -2725,6 +2774,21 @@
2725
2774
  enumerable: false,
2726
2775
  configurable: true
2727
2776
  });
2777
+ Object.defineProperty(MessageInputComponent.prototype, "disabledTextareaText", {
2778
+ get: function () {
2779
+ if (!this.canSendMessages) {
2780
+ return this.mode === 'thread'
2781
+ ? "streamChat.You can't send thread replies in this channel"
2782
+ : "streamChat.You can't send messages in this channel";
2783
+ }
2784
+ else if (this.cooldown$) {
2785
+ return 'streamChat.Slow Mode ON';
2786
+ }
2787
+ return '';
2788
+ },
2789
+ enumerable: false,
2790
+ configurable: true
2791
+ });
2728
2792
  MessageInputComponent.prototype.filesSelected = function (fileList) {
2729
2793
  return __awaiter(this, void 0, void 0, function () {
2730
2794
  return __generator(this, function (_12) {
@@ -2853,10 +2917,28 @@
2853
2917
  enumerable: false,
2854
2918
  configurable: true
2855
2919
  });
2920
+ MessageInputComponent.prototype.startCooldown = function (cooldown) {
2921
+ var _this = this;
2922
+ this.isCooldownInProgress = true;
2923
+ this.cooldown$ = rxjs.timer(0, 1000).pipe(operators.take(cooldown + 1), operators.map(function (v) { return cooldown - v; }), operators.tap(function (v) {
2924
+ if (v === 0) {
2925
+ _this.stopCooldown();
2926
+ }
2927
+ }));
2928
+ };
2929
+ MessageInputComponent.prototype.stopCooldown = function () {
2930
+ var _this = this;
2931
+ this.cooldown$ = undefined;
2932
+ this.isCooldownInProgress = false;
2933
+ // the anchor directive will be recreated because of *ngIf, so we will have to reinit the textarea as well
2934
+ this.textareaRef = undefined;
2935
+ // we can only create the textarea after the anchor was recreated, so we will have to wait a change detection cycle with setTimeout
2936
+ setTimeout(function () { return _this.initTextarea(); });
2937
+ };
2856
2938
  return MessageInputComponent;
2857
2939
  }());
2858
2940
  MessageInputComponent.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0__namespace.ComponentFactoryResolver }, { token: i0__namespace.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }], target: i0__namespace.ɵɵFactoryTarget.Component });
2859
- MessageInputComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", commandAutocompleteItemTemplate: "commandAutocompleteItemTemplate", emojiPickerTemplate: "emojiPickerTemplate", mode: "mode", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div\n data-testid=\"quoted-message-container\"\n class=\"quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon\n icon=\"close-no-outline\"\n style=\"font-size: 10px; line-height: 10px\"\n ></stream-icon>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n ></stream-avatar>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container *ngIf=\"emojiPickerTemplate\">\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: { emojiInput$: emojiInputService.emojiInput$ }\n \"\n ></ng-container>\n </div>\n </ng-container>\n <ng-template\n *ngIf=\"canSendMessages; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [commandAutocompleteItemTemplate]=\"commandAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"\n (mode === 'thread'\n ? 'You can\\'t send thread replies in this channel'\n : 'streamChat.You can\\'t send messages in this channel'\n ) | translate\n \"\n class=\"rta__textarea str-chat__textarea__textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }], directives: [{ type: i6__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "commandAutocompleteItemTemplate", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i6__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
2941
+ MessageInputComponent.ɵcmp = i0__namespace.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mentionAutocompleteItemTemplate: "mentionAutocompleteItemTemplate", commandAutocompleteItemTemplate: "commandAutocompleteItemTemplate", emojiPickerTemplate: "emojiPickerTemplate", mode: "mode", acceptedFileTypes: "acceptedFileTypes", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message" }, outputs: { messageUpdate: "messageUpdate" }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0__namespace, template: "<div\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div\n data-testid=\"quoted-message-container\"\n class=\"quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon\n icon=\"close-no-outline\"\n style=\"font-size: 10px; line-height: 10px\"\n ></stream-icon>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n ></stream-avatar>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <stream-attachment-preview-list\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container\n *ngIf=\"emojiPickerTemplate && !isCooldownInProgress\"\n data-testid=\"emoji-picker\"\n >\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: { emojiInput$: emojiInputService.emojiInput$ }\n \"\n ></ng-container>\n </div>\n </ng-container>\n <div\n class=\"str-chat__input-flat-cooldown str-chat-angular__cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n {{ cooldown$ | async }}\n </div>\n <ng-template\n *ngIf=\"canSendMessages && !isCooldownInProgress; else notAllowed\"\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionAutocompleteItemTemplate]=\"mentionAutocompleteItemTemplate\"\n [commandAutocompleteItemTemplate]=\"commandAutocompleteItemTemplate\"\n [mentionScope]=\"mentionScope\"\n ></ng-template>\n <ng-template #notAllowed>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"disabledTextareaText | translate\"\n class=\"rta__textarea str-chat__textarea__textarea\"\n data-testid=\"disabled-textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"\n isFileUploadEnabled &&\n isFileUploadAuthorized &&\n canSendMessages &&\n !isCooldownInProgress\n \"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [accept]=\"accept\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon icon=\"file-upload\"></stream-icon>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon icon=\"send\"></stream-icon>\n </button>\n </div>\n</div>\n", components: [{ type: IconComponent, selector: "stream-icon", inputs: ["icon", "size"] }, { type: AvatarComponent, selector: "stream-avatar", inputs: ["name", "imageUrl", "size"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list" }], directives: [{ type: i6__namespace.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6__namespace.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionAutocompleteItemTemplate", "mentionScope", "commandAutocompleteItemTemplate", "value"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i6__namespace.AsyncPipe, "translate": i2__namespace.TranslatePipe } });
2860
2942
  i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: MessageInputComponent, decorators: [{
2861
2943
  type: i0.Component,
2862
2944
  args: [{