@sendbird/uikit-chat-hooks 2.4.1 → 2.5.0-rc.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 (134) hide show
  1. package/README.md +2 -2
  2. package/lib/commonjs/channel/useChannelMessagesReducer.js +153 -0
  3. package/lib/commonjs/channel/useChannelMessagesReducer.js.map +1 -0
  4. package/lib/commonjs/channel/useGroupChannel.js +0 -4
  5. package/lib/commonjs/channel/useGroupChannel.js.map +1 -1
  6. package/lib/commonjs/channel/useGroupChannelList/index.js +0 -5
  7. package/lib/commonjs/channel/useGroupChannelList/index.js.map +1 -1
  8. package/lib/commonjs/channel/useGroupChannelList/reducer.js +12 -29
  9. package/lib/commonjs/channel/useGroupChannelList/reducer.js.map +1 -1
  10. package/lib/commonjs/channel/useGroupChannelList/useGroupChannelListWithCollection.js +1 -22
  11. package/lib/commonjs/channel/useGroupChannelList/useGroupChannelListWithCollection.js.map +1 -1
  12. package/lib/commonjs/channel/useGroupChannelList/useGroupChannelListWithQuery.js +1 -18
  13. package/lib/commonjs/channel/useGroupChannelList/useGroupChannelListWithQuery.js.map +1 -1
  14. package/lib/commonjs/channel/useGroupChannelMessages/index.js +0 -5
  15. package/lib/commonjs/channel/useGroupChannelMessages/index.js.map +1 -1
  16. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js +172 -131
  17. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js.map +1 -1
  18. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js +76 -73
  19. package/lib/commonjs/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js.map +1 -1
  20. package/lib/commonjs/channel/useOpenChannel.js +0 -4
  21. package/lib/commonjs/channel/useOpenChannel.js.map +1 -1
  22. package/lib/commonjs/channel/useOpenChannelList/index.js +0 -3
  23. package/lib/commonjs/channel/useOpenChannelList/index.js.map +1 -1
  24. package/lib/commonjs/channel/useOpenChannelList/reducer.js +2 -21
  25. package/lib/commonjs/channel/useOpenChannelList/reducer.js.map +1 -1
  26. package/lib/commonjs/channel/useOpenChannelList/useOpenChannelListWithQuery.js +1 -22
  27. package/lib/commonjs/channel/useOpenChannelList/useOpenChannelListWithQuery.js.map +1 -1
  28. package/lib/commonjs/channel/useOpenChannelMessages/index.js +0 -3
  29. package/lib/commonjs/channel/useOpenChannelMessages/index.js.map +1 -1
  30. package/lib/commonjs/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js +128 -57
  31. package/lib/commonjs/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js.map +1 -1
  32. package/lib/commonjs/common/useAppFeatures.js +0 -3
  33. package/lib/commonjs/common/useAppFeatures.js.map +1 -1
  34. package/lib/commonjs/common/useMessageOutgoingStatus.js +0 -11
  35. package/lib/commonjs/common/useMessageOutgoingStatus.js.map +1 -1
  36. package/lib/commonjs/common/usePushTrigger.js +0 -6
  37. package/lib/commonjs/common/usePushTrigger.js.map +1 -1
  38. package/lib/commonjs/common/useTotalUnreadMessageCount.js +0 -7
  39. package/lib/commonjs/common/useTotalUnreadMessageCount.js.map +1 -1
  40. package/lib/commonjs/common/useUserList.js +5 -20
  41. package/lib/commonjs/common/useUserList.js.map +1 -1
  42. package/lib/commonjs/handler/useChannelHandler.js +15 -41
  43. package/lib/commonjs/handler/useChannelHandler.js.map +1 -1
  44. package/lib/commonjs/handler/useConnectionHandler.js +14 -11
  45. package/lib/commonjs/handler/useConnectionHandler.js.map +1 -1
  46. package/lib/commonjs/handler/useUserEventHandler.js +0 -8
  47. package/lib/commonjs/handler/useUserEventHandler.js.map +1 -1
  48. package/lib/commonjs/index.js +0 -23
  49. package/lib/commonjs/index.js.map +1 -1
  50. package/lib/commonjs/model/CustomQuery.js +0 -6
  51. package/lib/commonjs/model/CustomQuery.js.map +1 -1
  52. package/lib/commonjs/types.js.map +1 -1
  53. package/lib/module/channel/useChannelMessagesReducer.js +146 -0
  54. package/lib/module/channel/useChannelMessagesReducer.js.map +1 -0
  55. package/lib/module/channel/useGroupChannel.js.map +1 -1
  56. package/lib/module/channel/useGroupChannelList/index.js.map +1 -1
  57. package/lib/module/channel/useGroupChannelList/reducer.js +12 -26
  58. package/lib/module/channel/useGroupChannelList/reducer.js.map +1 -1
  59. package/lib/module/channel/useGroupChannelList/useGroupChannelListWithCollection.js +1 -15
  60. package/lib/module/channel/useGroupChannelList/useGroupChannelListWithCollection.js.map +1 -1
  61. package/lib/module/channel/useGroupChannelList/useGroupChannelListWithQuery.js +1 -11
  62. package/lib/module/channel/useGroupChannelList/useGroupChannelListWithQuery.js.map +1 -1
  63. package/lib/module/channel/useGroupChannelMessages/index.js.map +1 -1
  64. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js +174 -125
  65. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.js.map +1 -1
  66. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js +78 -70
  67. package/lib/module/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.js.map +1 -1
  68. package/lib/module/channel/useOpenChannel.js.map +1 -1
  69. package/lib/module/channel/useOpenChannelList/index.js.map +1 -1
  70. package/lib/module/channel/useOpenChannelList/reducer.js +2 -18
  71. package/lib/module/channel/useOpenChannelList/reducer.js.map +1 -1
  72. package/lib/module/channel/useOpenChannelList/useOpenChannelListWithQuery.js +1 -17
  73. package/lib/module/channel/useOpenChannelList/useOpenChannelListWithQuery.js.map +1 -1
  74. package/lib/module/channel/useOpenChannelMessages/index.js.map +1 -1
  75. package/lib/module/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js +129 -53
  76. package/lib/module/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.js.map +1 -1
  77. package/lib/module/common/useAppFeatures.js.map +1 -1
  78. package/lib/module/common/useMessageOutgoingStatus.js +0 -6
  79. package/lib/module/common/useMessageOutgoingStatus.js.map +1 -1
  80. package/lib/module/common/usePushTrigger.js.map +1 -1
  81. package/lib/module/common/useTotalUnreadMessageCount.js +0 -1
  82. package/lib/module/common/useTotalUnreadMessageCount.js.map +1 -1
  83. package/lib/module/common/useUserList.js +5 -15
  84. package/lib/module/common/useUserList.js.map +1 -1
  85. package/lib/module/handler/useChannelHandler.js +15 -35
  86. package/lib/module/handler/useChannelHandler.js.map +1 -1
  87. package/lib/module/handler/useConnectionHandler.js +15 -6
  88. package/lib/module/handler/useConnectionHandler.js.map +1 -1
  89. package/lib/module/handler/useUserEventHandler.js +0 -2
  90. package/lib/module/handler/useUserEventHandler.js.map +1 -1
  91. package/lib/module/index.js +0 -1
  92. package/lib/module/index.js.map +1 -1
  93. package/lib/module/model/CustomQuery.js +0 -4
  94. package/lib/module/model/CustomQuery.js.map +1 -1
  95. package/lib/module/types.js.map +1 -1
  96. package/lib/typescript/src/channel/useChannelMessagesReducer.d.ts +18 -0
  97. package/lib/typescript/src/channel/useGroupChannelList/reducer.d.ts +1 -1
  98. package/lib/typescript/src/common/useUserList.d.ts +1 -1
  99. package/lib/typescript/src/handler/useChannelHandler.d.ts +1 -1
  100. package/lib/typescript/src/handler/useConnectionHandler.d.ts +1 -2
  101. package/lib/typescript/src/index.d.ts +0 -1
  102. package/lib/typescript/src/types.d.ts +51 -20
  103. package/package.json +15 -10
  104. package/src/channel/useChannelMessagesReducer.ts +143 -0
  105. package/src/channel/useGroupChannelList/reducer.ts +11 -7
  106. package/src/channel/useGroupChannelList/useGroupChannelListWithCollection.ts +1 -1
  107. package/src/channel/useGroupChannelList/useGroupChannelListWithQuery.ts +1 -1
  108. package/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithCollection.ts +174 -105
  109. package/src/channel/useGroupChannelMessages/useGroupChannelMessagesWithQuery.ts +90 -63
  110. package/src/channel/useOpenChannelList/useOpenChannelListWithQuery.ts +1 -5
  111. package/src/channel/useOpenChannelMessages/useOpenChannelMessagesWithQuery.ts +143 -26
  112. package/src/common/useUserList.ts +4 -4
  113. package/src/handler/useChannelHandler.ts +11 -24
  114. package/src/handler/useConnectionHandler.ts +11 -5
  115. package/src/index.ts +0 -1
  116. package/src/types.ts +58 -20
  117. package/lib/commonjs/channel/useGroupChannelMessages/reducer.js +0 -154
  118. package/lib/commonjs/channel/useGroupChannelMessages/reducer.js.map +0 -1
  119. package/lib/commonjs/channel/useOpenChannelMessages/reducer.js +0 -154
  120. package/lib/commonjs/channel/useOpenChannelMessages/reducer.js.map +0 -1
  121. package/lib/commonjs/common/useTotalUnreadChannelCount.js +0 -29
  122. package/lib/commonjs/common/useTotalUnreadChannelCount.js.map +0 -1
  123. package/lib/module/channel/useGroupChannelMessages/reducer.js +0 -144
  124. package/lib/module/channel/useGroupChannelMessages/reducer.js.map +0 -1
  125. package/lib/module/channel/useOpenChannelMessages/reducer.js +0 -144
  126. package/lib/module/channel/useOpenChannelMessages/reducer.js.map +0 -1
  127. package/lib/module/common/useTotalUnreadChannelCount.js +0 -17
  128. package/lib/module/common/useTotalUnreadChannelCount.js.map +0 -1
  129. package/lib/typescript/src/channel/useGroupChannelMessages/reducer.d.ts +0 -15
  130. package/lib/typescript/src/channel/useOpenChannelMessages/reducer.d.ts +0 -15
  131. package/lib/typescript/src/common/useTotalUnreadChannelCount.d.ts +0 -6
  132. package/src/channel/useGroupChannelMessages/reducer.ts +0 -125
  133. package/src/channel/useOpenChannelMessages/reducer.ts +0 -125
  134. package/src/common/useTotalUnreadChannelCount.ts +0 -26
@@ -1,4 +1,4 @@
1
- import { useCallback, useRef } from 'react';
1
+ import { useRef } from 'react';
2
2
 
3
3
  import type {
4
4
  SendbirdBaseChannel,
@@ -6,17 +6,20 @@ 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,
16
+ useFreshCallback,
14
17
  useUniqHandlerId,
15
18
  } from '@sendbird/uikit-utils';
16
19
 
17
20
  import { useChannelHandler } from '../../handler/useChannelHandler';
18
21
  import type { UseGroupChannelMessages, UseGroupChannelMessagesOptions } from '../../types';
19
- import { useGroupChannelMessagesReducer } from './reducer';
22
+ import { useChannelMessagesReducer } from '../useChannelMessagesReducer';
20
23
 
21
24
  const createMessageQuery = (
22
25
  channel: SendbirdGroupChannel,
@@ -39,15 +42,14 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
39
42
  loading,
40
43
  refreshing,
41
44
  messages,
42
- nextMessages,
43
- newMessagesFromMembers,
45
+ newMessages,
44
46
  updateMessages,
45
- updateNextMessages,
46
- deleteNextMessages,
47
47
  deleteMessages,
48
+ updateNewMessages,
49
+ deleteNewMessages,
48
50
  updateLoading,
49
51
  updateRefreshing,
50
- } = useGroupChannelMessagesReducer(userId, options?.sortComparator);
52
+ } = useChannelMessagesReducer(options?.sortComparator);
51
53
 
52
54
  const channelMarkAsRead = async () => {
53
55
  try {
@@ -57,20 +59,18 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
57
59
  }
58
60
  };
59
61
 
60
- const init = useCallback(
61
- async (uid?: string) => {
62
- if (uid) {
63
- queryRef.current = createMessageQuery(channel, options?.queryCreator);
64
- channelMarkAsRead();
65
- if (queryRef.current?.hasNext) {
66
- const list = await queryRef.current?.load();
67
- updateMessages(list, true, sdk.currentUser.userId);
68
- }
69
- updateNextMessages([], true, sdk.currentUser.userId);
62
+ const init = useFreshCallback(async (uid?: string) => {
63
+ if (uid) {
64
+ channelMarkAsRead();
65
+ updateNewMessages([], true, sdk.currentUser.userId);
66
+
67
+ queryRef.current = createMessageQuery(channel, options?.queryCreator);
68
+ if (queryRef.current?.hasNext) {
69
+ const list = await queryRef.current?.load();
70
+ updateMessages(list, true, sdk.currentUser.userId);
70
71
  }
71
- },
72
- [sdk, channel.url, options?.queryCreator],
73
- );
72
+ }
73
+ });
74
74
 
75
75
  const channelUpdater = (channel: SendbirdBaseChannel) => {
76
76
  if (channel.isGroupChannel() && !isDifferentChannel(channel, channel)) {
@@ -82,17 +82,42 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
82
82
  // Messages
83
83
  onMessageReceived(eventChannel, message) {
84
84
  if (isDifferentChannel(channel, eventChannel)) return;
85
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
86
+
85
87
  channelMarkAsRead();
86
- 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
+ }
87
96
  },
88
97
  onMessageUpdated(eventChannel, message) {
89
98
  if (isDifferentChannel(channel, eventChannel)) return;
99
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
100
+
90
101
  updateMessages([message], false, sdk.currentUser.userId);
91
102
  },
92
103
  onMessageDeleted(eventChannel, messageId) {
93
104
  if (isDifferentChannel(channel, eventChannel)) return;
94
105
  deleteMessages([messageId], []);
95
- 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);
96
121
  },
97
122
  // Channels
98
123
  onChannelChanged: channelUpdater,
@@ -130,95 +155,90 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
130
155
  updateLoading(true);
131
156
  await init(userId);
132
157
  updateLoading(false);
133
- }, [init, userId]);
158
+ }, [channel.url, userId]);
134
159
 
135
- const refresh: ReturnType<UseGroupChannelMessages>['refresh'] = useCallback(async () => {
160
+ const refresh: ReturnType<UseGroupChannelMessages>['refresh'] = useFreshCallback(async () => {
136
161
  updateRefreshing(true);
137
162
  await init(userId);
138
163
  updateRefreshing(false);
139
- }, [init, userId]);
164
+ });
140
165
 
141
- const prev: ReturnType<UseGroupChannelMessages>['prev'] = useCallback(async () => {
166
+ const prev: ReturnType<UseGroupChannelMessages>['prev'] = useFreshCallback(async () => {
142
167
  if (queryRef.current && queryRef.current?.hasNext) {
143
168
  const list = await queryRef.current?.load();
144
169
  updateMessages(list, false, sdk.currentUser.userId);
145
170
  }
146
- }, []);
171
+ });
172
+ const hasPrev: ReturnType<UseGroupChannelMessages>['hasPrev'] = useFreshCallback(
173
+ () => queryRef.current?.hasNext ?? false,
174
+ );
147
175
 
148
- const next: ReturnType<UseGroupChannelMessages>['next'] = useCallback(async () => {
149
- if (nextMessages.length > 0) {
150
- updateMessages(nextMessages, false, sdk.currentUser.userId);
151
- updateNextMessages([], true, sdk.currentUser.userId);
152
- }
153
- }, [nextMessages.length]);
176
+ const next: ReturnType<UseGroupChannelMessages>['next'] = useFreshCallback(ASYNC_NOOP);
177
+ const hasNext: ReturnType<UseGroupChannelMessages>['hasNext'] = useFreshCallback(() => false);
154
178
 
155
- const sendUserMessage: ReturnType<UseGroupChannelMessages>['sendUserMessage'] = useCallback(
179
+ const sendUserMessage: ReturnType<UseGroupChannelMessages>['sendUserMessage'] = useFreshCallback(
156
180
  (params, onPending) => {
157
181
  return new Promise((resolve, reject) => {
158
182
  channel
159
183
  .sendUserMessage(params)
160
184
  .onPending((pendingMessage) => {
161
185
  if (pendingMessage.isUserMessage()) {
162
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
186
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
163
187
  onPending?.(pendingMessage);
164
188
  }
165
189
  })
166
190
  .onSucceeded((sentMessage) => {
167
191
  if (sentMessage.isUserMessage()) {
168
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
192
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
169
193
  resolve(sentMessage);
170
194
  }
171
195
  })
172
196
  .onFailed((err, sentMessage) => {
173
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
197
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
174
198
  reject(err);
175
199
  });
176
200
  });
177
201
  },
178
- [channel],
179
202
  );
180
- const sendFileMessage: ReturnType<UseGroupChannelMessages>['sendFileMessage'] = useCallback(
203
+ const sendFileMessage: ReturnType<UseGroupChannelMessages>['sendFileMessage'] = useFreshCallback(
181
204
  (params, onPending) => {
182
205
  return new Promise((resolve, reject) => {
183
206
  channel
184
207
  .sendFileMessage(params)
185
208
  .onPending((pendingMessage) => {
186
209
  if (pendingMessage.isFileMessage()) {
187
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
210
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
188
211
  onPending?.(pendingMessage);
189
212
  }
190
213
  })
191
214
  .onSucceeded((sentMessage) => {
192
215
  if (sentMessage.isFileMessage()) {
193
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
216
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
194
217
  resolve(sentMessage);
195
218
  }
196
219
  })
197
220
  .onFailed((err, sentMessage) => {
198
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
221
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
199
222
  reject(err);
200
223
  });
201
224
  });
202
225
  },
203
- [channel],
204
226
  );
205
- const updateUserMessage: ReturnType<UseGroupChannelMessages>['updateUserMessage'] = useCallback(
227
+ const updateUserMessage: ReturnType<UseGroupChannelMessages>['updateUserMessage'] = useFreshCallback(
206
228
  async (messageId, params) => {
207
229
  const updatedMessage = await channel.updateUserMessage(messageId, params);
208
230
  updateMessages([updatedMessage], false, sdk.currentUser.userId);
209
231
  return updatedMessage;
210
232
  },
211
- [channel],
212
233
  );
213
- const updateFileMessage: ReturnType<UseGroupChannelMessages>['updateFileMessage'] = useCallback(
234
+ const updateFileMessage: ReturnType<UseGroupChannelMessages>['updateFileMessage'] = useFreshCallback(
214
235
  async (messageId, params) => {
215
236
  const updatedMessage = await channel.updateFileMessage(messageId, params);
216
237
  updateMessages([updatedMessage], false, sdk.currentUser.userId);
217
238
  return updatedMessage;
218
239
  },
219
- [channel],
220
240
  );
221
- const resendMessage: ReturnType<UseGroupChannelMessages>['resendMessage'] = useCallback(
241
+ const resendMessage: ReturnType<UseGroupChannelMessages>['resendMessage'] = useFreshCallback(
222
242
  async (failedMessage) => {
223
243
  const message = await (() => {
224
244
  if (failedMessage.isUserMessage()) return channel.resendUserMessage(failedMessage);
@@ -226,36 +246,43 @@ export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, c
226
246
  return null;
227
247
  })();
228
248
 
229
- if (message) updateNextMessages([message], false, sdk.currentUser.userId);
249
+ if (message) updateMessages([message], false, sdk.currentUser.userId);
230
250
  },
231
- [channel],
232
- );
233
- const deleteMessage: ReturnType<UseGroupChannelMessages>['deleteMessage'] = useCallback(
234
- async (message) => {
235
- if (message.sendingStatus === 'succeeded') {
236
- if (message.isUserMessage()) await channel.deleteMessage(message);
237
- if (message.isFileMessage()) await channel.deleteMessage(message);
238
- } else {
239
- deleteMessages([message.messageId], [message.reqId]);
240
- }
241
- },
242
- [channel],
243
251
  );
252
+ const deleteMessage: ReturnType<UseGroupChannelMessages>['deleteMessage'] = useFreshCallback(async (message) => {
253
+ if (message.sendingStatus === 'succeeded') {
254
+ if (message.isUserMessage()) await channel.deleteMessage(message);
255
+ if (message.isFileMessage()) await channel.deleteMessage(message);
256
+ } else {
257
+ deleteMessages([message.messageId], [message.reqId]);
258
+ }
259
+ });
260
+ const resetNewMessages: ReturnType<UseGroupChannelMessages>['resetNewMessages'] = useFreshCallback(() => {
261
+ updateNewMessages([], true, sdk.currentUser.userId);
262
+ });
244
263
 
245
264
  return {
246
265
  loading,
247
266
  refreshing,
248
267
  refresh,
249
268
  messages,
250
- nextMessages,
251
- newMessagesFromMembers,
269
+ newMessages,
270
+ resetNewMessages,
252
271
  next,
272
+ hasNext,
253
273
  prev,
274
+ hasPrev,
254
275
  sendUserMessage,
255
276
  sendFileMessage,
256
277
  updateUserMessage,
257
278
  updateFileMessage,
258
279
  resendMessage,
259
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,
260
287
  };
261
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)) {
@@ -79,7 +75,7 @@ export const useOpenChannelListWithQuery: UseOpenChannelList = (sdk, userId, opt
79
75
  } finally {
80
76
  updateLoading(false);
81
77
  }
82
- }, [init, userId]);
78
+ }, [userId]);
83
79
 
84
80
  const refresh = useFreshCallback(async () => {
85
81
  updateRefreshing(true);
@@ -1,9 +1,16 @@
1
1
  import { useRef } from 'react';
2
2
 
3
- import type { SendbirdBaseChannel, SendbirdOpenChannel, SendbirdPreviousMessageListQuery } from '@sendbird/uikit-utils';
3
+ import type {
4
+ SendbirdBaseChannel,
5
+ SendbirdBaseMessage,
6
+ SendbirdOpenChannel,
7
+ SendbirdPreviousMessageListQuery,
8
+ } from '@sendbird/uikit-utils';
4
9
  import {
10
+ ASYNC_NOOP,
5
11
  NOOP,
6
12
  isDifferentChannel,
13
+ isMyMessage,
7
14
  useAsyncEffect,
8
15
  useForceUpdate,
9
16
  useFreshCallback,
@@ -11,8 +18,9 @@ import {
11
18
  } from '@sendbird/uikit-utils';
12
19
 
13
20
  import { useChannelHandler } from '../../handler/useChannelHandler';
21
+ import { useConnectionHandler } from '../../handler/useConnectionHandler';
14
22
  import type { UseOpenChannelMessages, UseOpenChannelMessagesOptions } from '../../types';
15
- import { useOpenChannelMessagesReducer } from './reducer';
23
+ import { useChannelMessagesReducer } from '../useChannelMessagesReducer';
16
24
 
17
25
  const createMessageQuery = (channel: SendbirdOpenChannel, creator?: UseOpenChannelMessagesOptions['queryCreator']) => {
18
26
  if (creator) return creator();
@@ -31,15 +39,14 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
31
39
  loading,
32
40
  refreshing,
33
41
  messages,
34
- nextMessages,
35
- newMessagesFromMembers,
42
+ newMessages,
36
43
  updateMessages,
37
- updateNextMessages,
38
- deleteNextMessages,
44
+ updateNewMessages,
45
+ deleteNewMessages,
39
46
  deleteMessages,
40
47
  updateLoading,
41
48
  updateRefreshing,
42
- } = useOpenChannelMessagesReducer(userId, options?.sortComparator);
49
+ } = useChannelMessagesReducer(options?.sortComparator);
43
50
 
44
51
  const init = useFreshCallback(async (uid?: string) => {
45
52
  if (uid) {
@@ -49,7 +56,7 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
49
56
 
50
57
  updateMessages(list, true, sdk.currentUser.userId);
51
58
  }
52
- updateNextMessages([], true, sdk.currentUser.userId);
59
+ updateNewMessages([], true, sdk.currentUser.userId);
53
60
  }
54
61
  });
55
62
 
@@ -59,6 +66,99 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
59
66
  }
60
67
  };
61
68
 
69
+ useConnectionHandler(sdk, handlerId, {
70
+ async onReconnectSucceeded() {
71
+ const lastMessage = messages[0];
72
+ if (!lastMessage) return;
73
+
74
+ const messageContext = {
75
+ updatedMessages: [] as SendbirdBaseMessage[],
76
+ addedMessages: [] as SendbirdBaseMessage[],
77
+ deletedMessageIds: [] as number[],
78
+ };
79
+ const changeLogsContext = {
80
+ hasMore: false,
81
+ token: '',
82
+ };
83
+ const messageQueryContext = {
84
+ hasMore: false,
85
+ timestamp: lastMessage.createdAt,
86
+ };
87
+
88
+ // Updated & Deleted messages
89
+ const changelogsParams = {
90
+ replyType: queryRef.current?.replyType,
91
+ includeMetaArray: queryRef.current?.includeMetaArray,
92
+ includeReactions: queryRef.current?.includeReactions,
93
+ includeThreadInfo: queryRef.current?.includeThreadInfo,
94
+ includeParentMessageInfo: queryRef.current?.includeParentMessageInfo,
95
+ };
96
+
97
+ const changeLogsByTS = await channel.getMessageChangeLogsSinceTimestamp(lastMessage.createdAt);
98
+ changeLogsContext.token = changeLogsByTS.token;
99
+ changeLogsContext.hasMore = changeLogsByTS.hasMore;
100
+ messageContext.updatedMessages.push(...changeLogsByTS.updatedMessages);
101
+ messageContext.deletedMessageIds.push(...changeLogsByTS.deletedMessageIds);
102
+
103
+ while (changeLogsContext.hasMore) {
104
+ const changeLogsByToken = await channel.getMessageChangeLogsSinceToken(changeLogsByTS.token, changelogsParams);
105
+ changeLogsContext.token = changeLogsByToken.token;
106
+ changeLogsContext.hasMore = changeLogsByToken.hasMore;
107
+ messageContext.updatedMessages.push(...changeLogsByToken.updatedMessages);
108
+ messageContext.deletedMessageIds.push(...changeLogsByToken.deletedMessageIds);
109
+ }
110
+
111
+ // Added messages
112
+ const messageQueryParams = {
113
+ prevResultSize: 0,
114
+ nextResultSize: queryRef.current?.limit ?? 100,
115
+ reverse: queryRef.current?.reverse,
116
+ includeParentMessageInfo: queryRef.current?.includeParentMessageInfo,
117
+ includeThreadInfo: queryRef.current?.includeThreadInfo,
118
+ includeReactions: queryRef.current?.includeReactions,
119
+ includeMetaArray: queryRef.current?.includeMetaArray,
120
+ replyType: queryRef.current?.replyType,
121
+ customTypesFilter: queryRef.current?.customTypesFilter,
122
+ messageTypeFilter: queryRef.current?.messageTypeFilter,
123
+ senderUserIdsFilter: queryRef.current?.senderUserIdsFilter,
124
+ showSubchannelMessagesOnly: queryRef.current?.showSubchannelMessagesOnly,
125
+ };
126
+
127
+ const queriedMessages = await channel.getMessagesByTimestamp(lastMessage.createdAt, messageQueryParams);
128
+ messageQueryContext.hasMore = queriedMessages.length > 0;
129
+ if (messageQueryContext.hasMore) {
130
+ messageQueryContext.timestamp = queriedMessages[0].createdAt;
131
+ messageContext.addedMessages.unshift(...queriedMessages);
132
+ }
133
+
134
+ while (messageQueryContext.hasMore) {
135
+ const queriedMessages = await channel.getMessagesByTimestamp(messageQueryContext.timestamp, messageQueryParams);
136
+ messageQueryContext.hasMore = queriedMessages.length > 0;
137
+ if (messageQueryContext.hasMore) {
138
+ messageQueryContext.timestamp = queriedMessages[0].createdAt;
139
+ messageContext.addedMessages.unshift(...queriedMessages);
140
+ }
141
+ }
142
+
143
+ // Update to View
144
+ updateMessages(
145
+ [...messageContext.addedMessages, ...messageContext.updatedMessages],
146
+ false,
147
+ sdk.currentUser.userId,
148
+ );
149
+ deleteMessages(messageContext.deletedMessageIds, []);
150
+
151
+ if (messageContext.addedMessages.length > 0) {
152
+ if (options?.shouldCountNewMessages?.()) {
153
+ updateNewMessages(messageContext.addedMessages, false, sdk.currentUser.userId);
154
+ }
155
+ if (options?.onMessagesReceived) {
156
+ options.onMessagesReceived(messageContext.addedMessages);
157
+ }
158
+ }
159
+ },
160
+ });
161
+
62
162
  useChannelHandler(
63
163
  sdk,
64
164
  handlerId,
@@ -66,16 +166,26 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
66
166
  // Messages
67
167
  onMessageReceived(eventChannel, message) {
68
168
  if (isDifferentChannel(channel, eventChannel)) return;
69
- updateNextMessages([message], false, sdk.currentUser.userId);
169
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
170
+
171
+ updateMessages([message], false, sdk.currentUser.userId);
172
+ if (options?.shouldCountNewMessages?.()) {
173
+ updateNewMessages([message], false, sdk.currentUser.userId);
174
+ }
175
+ if (options?.onMessagesReceived) {
176
+ options.onMessagesReceived([message]);
177
+ }
70
178
  },
71
179
  onMessageUpdated(eventChannel, message) {
72
180
  if (isDifferentChannel(channel, eventChannel)) return;
181
+ if (isMyMessage(message, sdk.currentUser.userId)) return;
182
+
73
183
  updateMessages([message], false, sdk.currentUser.userId);
74
184
  },
75
185
  onMessageDeleted(eventChannel, messageId) {
76
186
  if (isDifferentChannel(channel, eventChannel)) return;
77
187
  deleteMessages([messageId], []);
78
- deleteNextMessages([messageId], []);
188
+ deleteNewMessages([messageId], []);
79
189
  },
80
190
  // Channels
81
191
  onChannelChanged: channelUpdater,
@@ -124,7 +234,7 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
124
234
  return () => {
125
235
  channel.exit().catch(NOOP);
126
236
  };
127
- }, [init, userId]);
237
+ }, [channel.url, userId]);
128
238
 
129
239
  const refresh: ReturnType<UseOpenChannelMessages>['refresh'] = useFreshCallback(async () => {
130
240
  updateRefreshing(true);
@@ -138,13 +248,12 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
138
248
  updateMessages(list, false, sdk.currentUser.userId);
139
249
  }
140
250
  });
251
+ const hasPrev: ReturnType<UseOpenChannelMessages>['hasPrev'] = useFreshCallback(
252
+ () => queryRef.current?.hasNext ?? false,
253
+ );
141
254
 
142
- const next: ReturnType<UseOpenChannelMessages>['next'] = useFreshCallback(async () => {
143
- if (nextMessages.length > 0) {
144
- updateMessages(nextMessages, false, sdk.currentUser.userId);
145
- updateNextMessages([], true, sdk.currentUser.userId);
146
- }
147
- });
255
+ const next: ReturnType<UseOpenChannelMessages>['next'] = useFreshCallback(ASYNC_NOOP);
256
+ const hasNext: ReturnType<UseOpenChannelMessages>['hasNext'] = useFreshCallback(() => false);
148
257
 
149
258
  const sendUserMessage: ReturnType<UseOpenChannelMessages>['sendUserMessage'] = useFreshCallback(
150
259
  (params, onPending) => {
@@ -153,18 +262,18 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
153
262
  .sendUserMessage(params)
154
263
  .onPending((pendingMessage) => {
155
264
  if (pendingMessage.isUserMessage()) {
156
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
265
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
157
266
  onPending?.(pendingMessage);
158
267
  }
159
268
  })
160
269
  .onSucceeded((sentMessage) => {
161
270
  if (sentMessage.isUserMessage()) {
162
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
271
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
163
272
  resolve(sentMessage);
164
273
  }
165
274
  })
166
275
  .onFailed((err, sentMessage) => {
167
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
276
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
168
277
  reject(err);
169
278
  });
170
279
  });
@@ -178,18 +287,18 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
178
287
  .sendFileMessage(params)
179
288
  .onPending((pendingMessage) => {
180
289
  if (pendingMessage.isFileMessage()) {
181
- updateNextMessages([pendingMessage], false, sdk.currentUser.userId);
290
+ updateMessages([pendingMessage], false, sdk.currentUser.userId);
182
291
  onPending?.(pendingMessage);
183
292
  }
184
293
  })
185
294
  .onSucceeded((sentMessage) => {
186
295
  if (sentMessage.isFileMessage()) {
187
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
296
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
188
297
  resolve(sentMessage);
189
298
  }
190
299
  })
191
300
  .onFailed((err, sentMessage) => {
192
- updateNextMessages([sentMessage], false, sdk.currentUser.userId);
301
+ updateMessages([sentMessage], false, sdk.currentUser.userId);
193
302
  reject(err);
194
303
  });
195
304
  });
@@ -217,7 +326,7 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
217
326
  return null;
218
327
  })();
219
328
 
220
- if (message) updateNextMessages([message], false, sdk.currentUser.userId);
329
+ if (message) updateMessages([message], false, sdk.currentUser.userId);
221
330
  });
222
331
  const deleteMessage: ReturnType<UseOpenChannelMessages>['deleteMessage'] = useFreshCallback(async (message) => {
223
332
  if (message.sendingStatus === 'succeeded') {
@@ -227,21 +336,29 @@ export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, cha
227
336
  deleteMessages([message.messageId], [message.reqId]);
228
337
  }
229
338
  });
339
+ const resetNewMessages: ReturnType<UseOpenChannelMessages>['resetNewMessages'] = useFreshCallback(() => {
340
+ updateNewMessages([], true, sdk.currentUser.userId);
341
+ });
230
342
 
231
343
  return {
232
344
  loading,
233
345
  refreshing,
234
346
  refresh,
235
347
  messages,
236
- nextMessages,
237
- newMessagesFromMembers,
348
+ newMessages,
238
349
  next,
350
+ hasNext,
239
351
  prev,
352
+ hasPrev,
240
353
  sendUserMessage,
241
354
  sendFileMessage,
242
355
  updateUserMessage,
243
356
  updateFileMessage,
244
357
  resendMessage,
245
358
  deleteMessage,
359
+ resetNewMessages,
360
+
361
+ nextMessages: newMessages,
362
+ newMessagesFromMembers: newMessages,
246
363
  };
247
364
  };
@@ -36,7 +36,7 @@ const createUserQuery = <User extends UserStruct>(
36
36
  * ```
37
37
  * */
38
38
  export const useUserList = <
39
- Options extends UseUserListOptions<QueriedUser>,
39
+ Options extends UseUserListOptions<UserStruct>,
40
40
  QueriedUser extends UserStruct = Options['queryCreator'] extends Optional<
41
41
  () => CustomQueryInterface<infer User extends UserStruct>
42
42
  >
@@ -44,7 +44,7 @@ export const useUserList = <
44
44
  : SendbirdUser,
45
45
  >(
46
46
  sdk: SendbirdChatSDK,
47
- options?: Options,
47
+ options?: UseUserListOptions<QueriedUser>,
48
48
  ): UseUserListReturn<QueriedUser> => {
49
49
  const query = useRef<CustomQueryInterface<QueriedUser>>();
50
50
 
@@ -85,7 +85,7 @@ export const useUserList = <
85
85
  if (query.current?.hasNext) {
86
86
  const users = await query.current?.next().catch((e) => {
87
87
  Logger.error(e);
88
- if (e.code === SBErrorCode.NON_AUTHORIZED) Logger.warn(SBErrorMessage.ACL);
88
+ if (e.code === SBErrorCode.UNAUTHORIZED_REQUEST) Logger.warn(SBErrorMessage.ACL);
89
89
  throw e;
90
90
  });
91
91
  updateUsers(users, true);
@@ -122,7 +122,7 @@ export const useUserList = <
122
122
  if (query.current && query.current?.hasNext) {
123
123
  const nextUsers = await query.current.next().catch((e) => {
124
124
  Logger.error(e);
125
- if (e.code === SBErrorCode.NON_AUTHORIZED) Logger.warn(SBErrorMessage.ACL);
125
+ if (e.code === SBErrorCode.UNAUTHORIZED_REQUEST) Logger.warn(SBErrorMessage.ACL);
126
126
  throw e;
127
127
  });
128
128
  updateUsers(nextUsers, false);