@sendbird/uikit-chat-hooks 2.4.2 → 2.5.0-rc.1

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 (46) hide show
  1. package/lib/commonjs/channel/{useGroupChannelMessages/reducer.js → useChannelMessagesReducer.js} +39 -30
  2. package/lib/commonjs/channel/useChannelMessagesReducer.js.map +1 -0
  3. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js +169 -99
  4. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js.map +1 -1
  5. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js +56 -25
  6. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js.map +1 -1
  7. package/lib/commonjs/channel/useOpenChannelList/useOpenChannelListWithQuery.js +0 -4
  8. package/lib/commonjs/channel/useOpenChannelList/useOpenChannelListWithQuery.js.map +1 -1
  9. package/lib/commonjs/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js +128 -28
  10. package/lib/commonjs/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js.map +1 -1
  11. package/lib/commonjs/common/useUserList.js +2 -2
  12. package/lib/commonjs/common/useUserList.js.map +1 -1
  13. package/lib/commonjs/types.js.map +1 -1
  14. package/lib/module/channel/{useGroupChannelMessages/reducer.js → useChannelMessagesReducer.js} +38 -29
  15. package/lib/module/channel/useChannelMessagesReducer.js.map +1 -0
  16. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js +170 -100
  17. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js.map +1 -1
  18. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js +57 -26
  19. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js.map +1 -1
  20. package/lib/module/channel/useOpenChannelList/useOpenChannelListWithQuery.js +0 -4
  21. package/lib/module/channel/useOpenChannelList/useOpenChannelListWithQuery.js.map +1 -1
  22. package/lib/module/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js +129 -29
  23. package/lib/module/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js.map +1 -1
  24. package/lib/module/common/useUserList.js +2 -2
  25. package/lib/module/common/useUserList.js.map +1 -1
  26. package/lib/module/types.js.map +1 -1
  27. package/lib/typescript/src/channel/useChannelMessagesReducer.d.ts +18 -0
  28. package/lib/typescript/src/types.d.ts +51 -20
  29. package/package.json +4 -5
  30. package/src/channel/useChannelMessagesReducer.ts +143 -0
  31. package/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.ts +168 -96
  32. package/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.ts +62 -25
  33. package/src/channel/useOpenChannelList/useOpenChannelListWithQuery.ts +0 -4
  34. package/src/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.ts +142 -25
  35. package/src/common/useUserList.ts +2 -2
  36. package/src/types.ts +58 -20
  37. package/lib/commonjs/channel/useGroupChannelMessages/reducer.js.map +0 -1
  38. package/lib/commonjs/channel/useOpenChannelMessages/reducer.js +0 -144
  39. package/lib/commonjs/channel/useOpenChannelMessages/reducer.js.map +0 -1
  40. package/lib/module/channel/useGroupChannelMessages/reducer.js.map +0 -1
  41. package/lib/module/channel/useOpenChannelMessages/reducer.js +0 -137
  42. package/lib/module/channel/useOpenChannelMessages/reducer.js.map +0 -1
  43. package/lib/typescript/src/channel/useGroupChannelMessages/reducer.d.ts +0 -15
  44. package/lib/typescript/src/channel/useOpenChannelMessages/reducer.d.ts +0 -15
  45. package/src/channel/useGroupChannelMessages/reducer.ts +0 -126
  46. package/src/channel/useOpenChannelMessages/reducer.ts +0 -126
@@ -1,16 +1,12 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
 
3
3
  import { MessageCollectionInitPolicy, MessageEventSource, MessageFilter } from '@sendbird/chat/groupChannel';
4
- import type {
5
- SendbirdBaseMessage,
6
- SendbirdFileMessage,
7
- SendbirdGroupChannel,
8
- SendbirdMessageCollection,
9
- } from '@sendbird/uikit-utils';
4
+ import type { SendbirdFileMessage, SendbirdGroupChannel, SendbirdMessageCollection } from '@sendbird/uikit-utils';
10
5
  import {
11
6
  Logger,
12
7
  confirmAndMarkAsRead,
13
8
  isDifferentChannel,
9
+ isMyMessage,
14
10
  useForceUpdate,
15
11
  useFreshCallback,
16
12
  useUniqHandlerId,
@@ -18,35 +14,49 @@ import {
18
14
 
19
15
  import { useChannelHandler } from '../../handler/useChannelHandler';
20
16
  import type { UseGroupChannelMessages, UseGroupChannelMessagesOptions } from '../../types';
21
- import { useGroupChannelMessagesReducer } from './reducer';
17
+ import { useChannelMessagesReducer } from '../useChannelMessagesReducer';
18
+
19
+ const MESSAGE_LIMIT = {
20
+ DEFAULT: 50,
21
+ SEARCH: 20,
22
+ };
22
23
 
23
24
  const createMessageCollection = (
24
25
  channel: SendbirdGroupChannel,
25
- creator?: UseGroupChannelMessagesOptions['collectionCreator'],
26
+ limit: number,
27
+ options?: UseGroupChannelMessagesOptions,
26
28
  ) => {
27
- if (creator) return creator();
29
+ if (options?.collectionCreator) return options?.collectionCreator({ startingPoint: options?.startingPoint });
28
30
  const filter = new MessageFilter();
29
- return channel.createMessageCollection({ filter, limit: 100 });
31
+ return channel.createMessageCollection({ filter, limit, startingPoint: options?.startingPoint });
30
32
  };
31
33
 
34
+ function isNotEmpty(arr?: unknown[]): arr is unknown[] {
35
+ if (!arr) return false;
36
+ return arr.length !== 0;
37
+ }
38
+
32
39
  export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (sdk, channel, userId, options) => {
40
+ const initialStartingPoint = options?.startingPoint ?? Number.MAX_SAFE_INTEGER;
41
+ const initialLimit = typeof options?.startingPoint === 'number' ? MESSAGE_LIMIT.SEARCH : MESSAGE_LIMIT.DEFAULT;
42
+
33
43
  const forceUpdate = useForceUpdate();
34
44
  const collectionRef = useRef<SendbirdMessageCollection>();
45
+ const collectionInitializedRef = useRef(false);
35
46
  const handlerId = useUniqHandlerId('useGroupChannelMessagesWithCollection');
36
47
 
37
48
  const {
38
49
  loading,
39
50
  refreshing,
40
51
  messages,
41
- nextMessages,
42
- newMessagesFromMembers,
52
+ newMessages,
43
53
  updateMessages,
44
- updateNextMessages,
45
- deleteNextMessages,
54
+ updateNewMessages,
55
+ deleteNewMessages,
46
56
  deleteMessages,
47
57
  updateLoading,
48
58
  updateRefreshing,
49
- } = useGroupChannelMessagesReducer(userId, options?.sortComparator);
59
+ } = useChannelMessagesReducer(options?.sortComparator);
50
60
 
51
61
  const channelMarkAsRead = async (source?: MessageEventSource) => {
52
62
  try {
@@ -63,81 +73,120 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
63
73
  }
64
74
  };
65
75
 
66
- const init = useFreshCallback(async (uid?: string, callback?: () => void) => {
76
+ const updateUnsendMessages = () => {
77
+ const { pendingMessages, failedMessages } = collectionRef.current ?? {};
78
+ if (isNotEmpty(pendingMessages)) updateMessages(pendingMessages, false, sdk.currentUser.userId);
79
+ if (isNotEmpty(failedMessages)) updateMessages(failedMessages, false, sdk.currentUser.userId);
80
+ };
81
+
82
+ const init = useFreshCallback(async (startingPoint: number, limit: number, callback?: () => void) => {
67
83
  if (collectionRef.current) collectionRef.current?.dispose();
68
84
 
69
- if (uid) {
70
- collectionRef.current = createMessageCollection(channel, options?.collectionCreator);
71
- updateNextMessages([], true, sdk.currentUser.userId);
72
- channelMarkAsRead();
85
+ channelMarkAsRead();
86
+ updateNewMessages([], true, sdk.currentUser.userId);
73
87
 
74
- collectionRef.current?.setMessageCollectionHandler({
75
- onMessagesAdded: (_, __, messages) => {
76
- channelMarkAsRead(_.source);
77
- updateNextMessages(messages, false, sdk.currentUser.userId);
78
- },
79
- onMessagesUpdated: (_, __, messages) => {
80
- channelMarkAsRead(_.source);
88
+ collectionInitializedRef.current = false;
89
+ collectionRef.current = createMessageCollection(channel, limit, {
90
+ collectionCreator: options?.collectionCreator,
91
+ startingPoint,
92
+ });
81
93
 
82
- // NOTE: admin message is not added via onMessagesAdded handler, not checked yet is this a bug.
83
- if (_.source === MessageEventSource.EVENT_MESSAGE_RECEIVED) {
84
- const nextMessageIds = nextMessages.map((it) => it.messageId);
85
- const nonAddedMessagesFromReceivedEvent = messages.filter(
86
- (it) => nextMessageIds.indexOf(it.messageId) === -1,
87
- );
88
- updateNextMessages(nonAddedMessagesFromReceivedEvent, false, sdk.currentUser.userId);
89
- }
94
+ collectionRef.current?.setMessageCollectionHandler({
95
+ onMessagesAdded: (_, __, messages) => {
96
+ channelMarkAsRead(_.source);
90
97
 
91
- // NOTE: v4 MESSAGE_RECEIVED is called twice from onMessagesAdded and onMessagesUpdated when receiving new message.
92
- // This is not intended behavior but not bugs.
93
- if (_.source !== MessageEventSource.EVENT_MESSAGE_RECEIVED) {
94
- updateMessages(messages, false, sdk.currentUser.userId);
98
+ const incomingMessages = messages.filter((it) => {
99
+ switch (_.source) {
100
+ case MessageEventSource.EVENT_MESSAGE_SENT_PENDING:
101
+ case MessageEventSource.EVENT_MESSAGE_SENT_SUCCESS:
102
+ case MessageEventSource.EVENT_MESSAGE_SENT_FAILED:
103
+ return !isMyMessage(it, sdk.currentUser.userId);
104
+ default:
105
+ return true;
95
106
  }
96
- },
97
- onMessagesDeleted: (_, __, messageIds) => {
98
- deleteMessages(messageIds, []);
99
- deleteNextMessages(messageIds, []);
100
- },
101
- onChannelDeleted: () => {
102
- options?.onChannelDeleted?.();
103
- },
104
- onChannelUpdated: (_, eventChannel) => {
105
- if (eventChannel.isGroupChannel() && !isDifferentChannel(eventChannel, channel)) {
106
- forceUpdate();
107
- }
108
- },
109
- onHugeGapDetected: () => {
110
- init(uid);
111
- },
112
- });
107
+ });
113
108
 
114
- collectionRef.current
115
- .initialize(MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API)
116
- .onCacheResult((err, messages) => {
117
- if (err) sdk.isCacheEnabled && Logger.error('[useGroupChannelMessagesWithCollection/onCacheResult]', err);
118
- else {
119
- Logger.debug('[useGroupChannelMessagesWithCollection/onCacheResult]', 'message length:', messages.length);
109
+ if (incomingMessages.length > 0) {
110
+ updateMessages(incomingMessages, false, sdk.currentUser.userId);
120
111
 
121
- updateMessages(messages, true, sdk.currentUser.userId);
122
- updateMessages(collectionRef.current?.pendingMessages ?? [], false, sdk.currentUser.userId);
123
- updateMessages(collectionRef.current?.failedMessages ?? [], false, sdk.currentUser.userId);
112
+ if (options?.shouldCountNewMessages?.()) {
113
+ updateNewMessages(incomingMessages, false, sdk.currentUser.userId);
124
114
  }
125
- callback?.();
126
- })
127
- .onApiResult((err, messages) => {
128
- if (err) Logger.warn('[useGroupChannelMessagesWithCollection/onApiResult]', err);
129
- else {
130
- Logger.debug('[useGroupChannelMessagesWithCollection/onApiResult]', 'message length:', messages.length);
131
-
132
- updateMessages(messages, true, sdk.currentUser.userId);
133
- if (sdk.isCacheEnabled) {
134
- updateMessages(collectionRef.current?.pendingMessages ?? [], false, sdk.currentUser.userId);
135
- updateMessages(collectionRef.current?.failedMessages ?? [], false, sdk.currentUser.userId);
115
+
116
+ switch (_.source) {
117
+ case MessageEventSource.EVENT_MESSAGE_RECEIVED:
118
+ case MessageEventSource.SYNC_MESSAGE_FILL: {
119
+ options?.onMessagesReceived?.(incomingMessages);
136
120
  }
137
121
  }
138
- callback?.();
122
+ }
123
+ },
124
+ onMessagesUpdated: (_, __, messages) => {
125
+ channelMarkAsRead(_.source);
126
+
127
+ const incomingMessages = messages.filter((it) => {
128
+ switch (_.source) {
129
+ case MessageEventSource.EVENT_MESSAGE_UPDATED:
130
+ return !isMyMessage(it, sdk.currentUser.userId);
131
+ default:
132
+ return true;
133
+ }
139
134
  });
140
- }
135
+
136
+ if (incomingMessages.length > 0) {
137
+ // NOTE: admin message is not added via onMessagesAdded handler, not checked yet is this a bug.
138
+ updateMessages(messages, false, sdk.currentUser.userId);
139
+
140
+ if (options?.shouldCountNewMessages?.()) {
141
+ if (_.source === MessageEventSource.EVENT_MESSAGE_RECEIVED) {
142
+ updateNewMessages(messages, false, sdk.currentUser.userId);
143
+ }
144
+ }
145
+ }
146
+ },
147
+ onMessagesDeleted: (_, __, messageIds) => {
148
+ deleteMessages(messageIds, []);
149
+ deleteNewMessages(messageIds, []);
150
+ },
151
+ onChannelDeleted: () => {
152
+ options?.onChannelDeleted?.();
153
+ },
154
+ onChannelUpdated: (_, eventChannel) => {
155
+ if (eventChannel.isGroupChannel() && !isDifferentChannel(eventChannel, channel)) {
156
+ forceUpdate();
157
+ }
158
+ },
159
+ onHugeGapDetected: () => {
160
+ init(Number.MAX_SAFE_INTEGER, MESSAGE_LIMIT.DEFAULT);
161
+ },
162
+ });
163
+
164
+ collectionRef.current
165
+ .initialize(MessageCollectionInitPolicy.CACHE_AND_REPLACE_BY_API)
166
+ .onCacheResult((err, messages) => {
167
+ if (err) sdk.isCacheEnabled && Logger.error('[useGroupChannelMessagesWithCollection/onCacheResult]', err);
168
+ else {
169
+ Logger.debug('[useGroupChannelMessagesWithCollection/onCacheResult]', 'message length:', messages.length);
170
+
171
+ updateMessages(messages, true, sdk.currentUser.userId);
172
+ updateUnsendMessages();
173
+ }
174
+
175
+ callback?.();
176
+ })
177
+ .onApiResult((err, messages) => {
178
+ if (err) Logger.warn('[useGroupChannelMessagesWithCollection/onApiResult]', err);
179
+ else {
180
+ Logger.debug('[useGroupChannelMessagesWithCollection/onApiResult]', 'message length:', messages.length);
181
+
182
+ updateMessages(messages, true, sdk.currentUser.userId);
183
+ if (!options?.startingPoint) options?.onMessagesReceived?.(messages);
184
+ if (sdk.isCacheEnabled) updateUnsendMessages();
185
+ }
186
+
187
+ collectionInitializedRef.current = true;
188
+ callback?.();
189
+ });
141
190
  });
142
191
 
143
192
  useChannelHandler(sdk, handlerId, {
@@ -156,7 +205,7 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
156
205
  // NOTE: Cache read is heavy task, and it prevents smooth ui transition
157
206
  setTimeout(async () => {
158
207
  updateLoading(true);
159
- init(userId, () => updateLoading(false));
208
+ init(initialStartingPoint, initialLimit, () => updateLoading(false));
160
209
  }, 0);
161
210
  }, [channel.url, userId]);
162
211
 
@@ -168,7 +217,7 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
168
217
 
169
218
  const refresh: ReturnType<UseGroupChannelMessages>['refresh'] = useFreshCallback(async () => {
170
219
  updateRefreshing(true);
171
- init(userId, () => updateRefreshing(false));
220
+ init(Number.MAX_SAFE_INTEGER, MESSAGE_LIMIT.DEFAULT, () => updateRefreshing(false));
172
221
  });
173
222
 
174
223
  const prev: ReturnType<UseGroupChannelMessages>['prev'] = useFreshCallback(async () => {
@@ -180,23 +229,28 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
180
229
  }
181
230
  });
182
231
 
183
- const next: ReturnType<UseGroupChannelMessages>['next'] = useFreshCallback(async () => {
184
- const messageCandidates: SendbirdBaseMessage[] = [];
232
+ const hasPrev: ReturnType<UseGroupChannelMessages>['hasPrev'] = useFreshCallback(() => {
233
+ if (collectionInitializedRef.current && collectionRef.current) {
234
+ return collectionRef.current.hasPrevious;
235
+ } else {
236
+ return false;
237
+ }
238
+ });
185
239
 
240
+ const next: ReturnType<UseGroupChannelMessages>['next'] = useFreshCallback(async () => {
186
241
  if (collectionRef.current && collectionRef.current?.hasNext) {
187
242
  try {
188
243
  const fetchedList = await collectionRef.current?.loadNext();
189
- messageCandidates.push(...fetchedList);
244
+ updateMessages(fetchedList, false, sdk.currentUser.userId);
190
245
  } catch {}
191
246
  }
247
+ });
192
248
 
193
- if (nextMessages.length > 0) {
194
- messageCandidates.push(...nextMessages);
195
- }
196
-
197
- if (messageCandidates.length > 0) {
198
- updateMessages(messageCandidates, false, sdk.currentUser.userId);
199
- updateNextMessages([], true, sdk.currentUser.userId);
249
+ const hasNext: ReturnType<UseGroupChannelMessages>['hasNext'] = useFreshCallback(() => {
250
+ if (collectionInitializedRef.current && collectionRef.current) {
251
+ return collectionRef.current.hasNext;
252
+ } else {
253
+ return false;
200
254
  }
201
255
  });
202
256
 
@@ -217,8 +271,8 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
217
271
  resolve(sentMessage);
218
272
  }
219
273
  })
220
- .onFailed((err, _failedMessage) => {
221
- // updateMessages([failedMessage], false, sdk.currentUser.userId);
274
+ .onFailed((err, failedMessage) => {
275
+ updateMessages([failedMessage], false, sdk.currentUser.userId);
222
276
  reject(err);
223
277
  });
224
278
  });
@@ -241,8 +295,8 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
241
295
  resolve(sentMessage as SendbirdFileMessage);
242
296
  }
243
297
  })
244
- .onFailed((err, _failedMessage) => {
245
- // updateMessages([failedMessage], false, sdk.currentUser.userId);
298
+ .onFailed((err, failedMessage) => {
299
+ updateMessages([failedMessage], false, sdk.currentUser.userId);
246
300
  reject(err);
247
301
  });
248
302
  });
@@ -285,21 +339,39 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
285
339
  }
286
340
  }
287
341
  });
342
+ const resetNewMessages: ReturnType<UseGroupChannelMessages>['resetNewMessages'] = useFreshCallback(() => {
343
+ updateNewMessages([], true, sdk.currentUser.userId);
344
+ });
345
+ const resetWithStartingPoint: ReturnType<UseGroupChannelMessages>['resetWithStartingPoint'] = useFreshCallback(
346
+ (startingPoint, callback) => {
347
+ updateLoading(true);
348
+ updateMessages([], true, sdk.currentUser.userId);
349
+ init(startingPoint, MESSAGE_LIMIT.DEFAULT, () => {
350
+ updateLoading(false);
351
+ callback?.();
352
+ });
353
+ },
354
+ );
288
355
 
289
356
  return {
290
357
  loading,
291
358
  refreshing,
292
359
  refresh,
293
360
  messages,
294
- nextMessages,
295
- newMessagesFromMembers,
296
361
  next,
362
+ hasNext,
297
363
  prev,
364
+ hasPrev,
365
+ newMessages,
366
+ resetNewMessages,
298
367
  sendUserMessage,
299
368
  sendFileMessage,
300
369
  updateUserMessage,
301
370
  updateFileMessage,
302
371
  resendMessage,
303
372
  deleteMessage,
373
+ resetWithStartingPoint,
374
+ nextMessages: newMessages,
375
+ newMessagesFromMembers: newMessages,
304
376
  };
305
377
  };
@@ -6,9 +6,11 @@ import type {
6
6
  SendbirdPreviousMessageListQuery,
7
7
  } from '@sendbird/uikit-utils';
8
8
  import {
9
+ ASYNC_NOOP,
9
10
  Logger,
10
11
  confirmAndMarkAsRead,
11
12
  isDifferentChannel,
13
+ isMyMessage,
12
14
  useAsyncEffect,
13
15
  useForceUpdate,
14
16
  useFreshCallback,
@@ -17,7 +19,7 @@ import {
17
19
 
18
20
  import { useChannelHandler } from '../../handler/useChannelHandler';
19
21
  import type { UseGroupChannelMessages, UseGroupChannelMessagesOptions } from '../../types';
20
- import { useGroupChannelMessagesReducer } from './reducer';
22
+ import { useChannelMessagesReducer } from '../useChannelMessagesReducer';
21
23
 
22
24
  const createMessageQuery = (
23
25
  channel: SendbirdGroupChannel,
@@ -40,15 +42,14 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
40
42
  loading,
41
43
  refreshing,
42
44
  messages,
43
- nextMessages,
44
- newMessagesFromMembers,
45
+ newMessages,
45
46
  updateMessages,
46
- updateNextMessages,
47
- deleteNextMessages,
48
47
  deleteMessages,
48
+ updateNewMessages,
49
+ deleteNewMessages,
49
50
  updateLoading,
50
51
  updateRefreshing,
51
- } = useGroupChannelMessagesReducer(userId, options?.sortComparator);
52
+ } = useChannelMessagesReducer(options?.sortComparator);
52
53
 
53
54
  const channelMarkAsRead = async () => {
54
55
  try {
@@ -60,13 +61,14 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
60
61
 
61
62
  const init = useFreshCallback(async (uid?: string) => {
62
63
  if (uid) {
63
- queryRef.current = createMessageQuery(channel, options?.queryCreator);
64
64
  channelMarkAsRead();
65
+ updateNewMessages([], true, sdk.currentUser.userId);
66
+
67
+ queryRef.current = createMessageQuery(channel, options?.queryCreator);
65
68
  if (queryRef.current?.hasNext) {
66
69
  const list = await queryRef.current?.load();
67
70
  updateMessages(list, true, sdk.currentUser.userId);
68
71
  }
69
- updateNextMessages([], true, sdk.currentUser.userId);
70
72
  }
71
73
  });
72
74
 
@@ -80,17 +82,42 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
80
82
  // Messages
81
83
  onMessageReceived(eventChannel, message) {
82
84
  if (isDifferentChannel(channel, eventChannel)) return;
85
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
86
+
83
87
  channelMarkAsRead();
84
- updateNextMessages([message], false, sdk.currentUser.userId);
88
+
89
+ updateMessages([message], false, sdk.currentUser.userId);
90
+ if (options?.shouldCountNewMessages?.()) {
91
+ updateNewMessages([message], false, sdk.currentUser.userId);
92
+ }
93
+ if (options?.onMessagesReceived) {
94
+ options.onMessagesReceived([message]);
95
+ }
85
96
  },
86
97
  onMessageUpdated(eventChannel, message) {
87
98
  if (isDifferentChannel(channel, eventChannel)) return;
99
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
100
+
88
101
  updateMessages([message], false, sdk.currentUser.userId);
89
102
  },
90
103
  onMessageDeleted(eventChannel, messageId) {
91
104
  if (isDifferentChannel(channel, eventChannel)) return;
92
105
  deleteMessages([messageId], []);
93
- deleteNextMessages([messageId], []);
106
+ deleteNewMessages([messageId], []);
107
+ },
108
+ async onReactionUpdated(eventChannel, reactionEvent) {
109
+ if (isDifferentChannel(channel, eventChannel)) return;
110
+
111
+ const message = await sdk.message.getMessage({
112
+ messageId: reactionEvent.messageId,
113
+ includeReactions: true,
114
+ includeParentMessageInfo: true,
115
+ includeThreadInfo: true,
116
+ includeMetaArray: true,
117
+ channelUrl: channel.url,
118
+ channelType: channel.channelType,
119
+ });
120
+ updateMessages([message], false, sdk.currentUser.userId);
94
121
  },
95
122
  // Channels
96
123
  onChannelChanged: channelUpdater,
@@ -142,13 +169,12 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
142
169
  updateMessages(list, false, sdk.currentUser.userId);
143
170
  }
144
171
  });
172
+ const hasPrev: ReturnType<UseGroupChannelMessages>['hasPrev'] = useFreshCallback(
173
+ () => queryRef.current?.hasNext ?? false,
174
+ );
145
175
 
146
- const next: ReturnType<UseGroupChannelMessages>['next'] = useFreshCallback(async () => {
147
- if (nextMessages.length > 0) {
148
- updateMessages(nextMessages, false, sdk.currentUser.userId);
149
- updateNextMessages([], true, sdk.currentUser.userId);
150
- }
151
- });
176
+ const next: ReturnType<UseGroupChannelMessages>['next'] = useFreshCallback(ASYNC_NOOP);
177
+ const hasNext: ReturnType<UseGroupChannelMessages>['hasNext'] = useFreshCallback(() => false);
152
178
 
153
179
  const sendUserMessage: ReturnType<UseGroupChannelMessages>['sendUserMessage'] = useFreshCallback(
154
180
  (params, onPending) => {
@@ -157,18 +183,18 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
157
183
  .sendUserMessage(params)
158
184
  .onPending((pendingMessage) => {
159
185
  if (pendingMessage.isUserMessage()) {
160
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
186
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
161
187
  onPending?.(pendingMessage);
162
188
  }
163
189
  })
164
190
  .onSucceeded((sentMessage) => {
165
191
  if (sentMessage.isUserMessage()) {
166
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
192
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
167
193
  resolve(sentMessage);
168
194
  }
169
195
  })
170
196
  .onFailed((err, sentMessage) => {
171
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
197
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
172
198
  reject(err);
173
199
  });
174
200
  });
@@ -181,18 +207,18 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
181
207
  .sendFileMessage(params)
182
208
  .onPending((pendingMessage) => {
183
209
  if (pendingMessage.isFileMessage()) {
184
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
210
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
185
211
  onPending?.(pendingMessage);
186
212
  }
187
213
  })
188
214
  .onSucceeded((sentMessage) => {
189
215
  if (sentMessage.isFileMessage()) {
190
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
216
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
191
217
  resolve(sentMessage);
192
218
  }
193
219
  })
194
220
  .onFailed((err, sentMessage) => {
195
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
221
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
196
222
  reject(err);
197
223
  });
198
224
  });
@@ -220,7 +246,7 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
220
246
  return null;
221
247
  })();
222
248
 
223
- if (message) updateNextMessages([message], false, sdk.currentUser.userId);
249
+ if (message) updateMessages([message], false, sdk.currentUser.userId);
224
250
  },
225
251
  );
226
252
  const deleteMessage: ReturnType<UseGroupChannelMessages>['deleteMessage'] = useFreshCallback(async (message) => {
@@ -231,21 +257,32 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
231
257
  deleteMessages([message.messageId], [message.reqId]);
232
258
  }
233
259
  });
260
+ const resetNewMessages: ReturnType<UseGroupChannelMessages>['resetNewMessages'] = useFreshCallback(() => {
261
+ updateNewMessages([], true, sdk.currentUser.userId);
262
+ });
234
263
 
235
264
  return {
236
265
  loading,
237
266
  refreshing,
238
267
  refresh,
239
268
  messages,
240
- nextMessages,
241
- newMessagesFromMembers,
269
+ newMessages,
270
+ resetNewMessages,
242
271
  next,
272
+ hasNext,
243
273
  prev,
274
+ hasPrev,
244
275
  sendUserMessage,
245
276
  sendFileMessage,
246
277
  updateUserMessage,
247
278
  updateFileMessage,
248
279
  resendMessage,
249
280
  deleteMessage,
281
+ resetWithStartingPoint() {
282
+ Logger.warn('resetWithStartingPoint is not supported in Query, please use Collection instead.');
283
+ },
284
+
285
+ nextMessages: newMessages,
286
+ newMessagesFromMembers: newMessages,
250
287
  };
251
288
  };
@@ -53,10 +53,6 @@ export const useOpenChannelListWithQuery: UseOpenChannelList = (sdk, userId, opt
53
53
  onChannelFrozen: updateChannel,
54
54
  onChannelUnfrozen: updateChannel,
55
55
  onChannelDeleted: (url) => deleteChannels([url]),
56
- onUserBanned(channel, user) {
57
- const isMe = user.userId === userId;
58
- if (isMe && channel.isOpenChannel()) deleteChannels([channel.url]);
59
- },
60
56
  onUserEntered: (channel, user) => {
61
57
  const isMe = user.userId === userId;
62
58
  if (isMe && channel.isOpenChannel() && !openChannels.find((it) => it.url === channel.url)) {