stream-chat-react-native-core 6.3.1 → 6.4.0-beta.2

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 (179) hide show
  1. package/lib/commonjs/components/Attachment/AudioAttachment.js +255 -216
  2. package/lib/commonjs/components/Attachment/AudioAttachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js +11 -11
  4. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Gallery.js +9 -0
  6. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  7. package/lib/commonjs/components/ChannelList/ChannelList.js +23 -0
  8. package/lib/commonjs/components/ChannelList/ChannelList.js.map +1 -1
  9. package/lib/commonjs/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js +31 -8
  10. package/lib/commonjs/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js.map +1 -1
  11. package/lib/commonjs/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js +75 -0
  12. package/lib/commonjs/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js.map +1 -0
  13. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js +21 -10
  14. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  15. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessageNotification.js +23 -7
  16. package/lib/commonjs/components/ChannelList/hooks/listeners/useNewMessageNotification.js.map +1 -1
  17. package/lib/commonjs/components/ChannelList/hooks/useChannelMembershipState.js +17 -0
  18. package/lib/commonjs/components/ChannelList/hooks/useChannelMembershipState.js.map +1 -0
  19. package/lib/commonjs/components/ChannelList/hooks/useSelectedChannelState.js +32 -0
  20. package/lib/commonjs/components/ChannelList/hooks/useSelectedChannelState.js.map +1 -0
  21. package/lib/commonjs/components/ChannelList/hooks/utils/index.js +102 -0
  22. package/lib/commonjs/components/ChannelList/hooks/utils/index.js.map +1 -0
  23. package/lib/commonjs/components/ChannelList/utils.js +23 -11
  24. package/lib/commonjs/components/ChannelList/utils.js.map +1 -1
  25. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessenger.js +1 -2
  26. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessenger.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +24 -13
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  29. package/lib/commonjs/components/Message/Message.js.map +1 -1
  30. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +35 -23
  31. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  32. package/lib/commonjs/components/ProgressControl/ProgressControl.js +57 -54
  33. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -1
  34. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js +52 -52
  35. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js.map +1 -1
  36. package/lib/commonjs/components/index.js +22 -0
  37. package/lib/commonjs/components/index.js.map +1 -1
  38. package/lib/commonjs/contexts/themeContext/utils/theme.js +1 -0
  39. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  40. package/lib/commonjs/hooks/useAudioPlayer.js +158 -0
  41. package/lib/commonjs/hooks/useAudioPlayer.js.map +1 -0
  42. package/lib/commonjs/icons/Archieve.js +33 -0
  43. package/lib/commonjs/icons/Archieve.js.map +1 -0
  44. package/lib/commonjs/icons/Pause.js +2 -2
  45. package/lib/commonjs/icons/Pause.js.map +1 -1
  46. package/lib/commonjs/icons/Play.js +2 -2
  47. package/lib/commonjs/icons/Play.js.map +1 -1
  48. package/lib/commonjs/icons/index.js +11 -0
  49. package/lib/commonjs/icons/index.js.map +1 -1
  50. package/lib/commonjs/native.js.map +1 -1
  51. package/lib/commonjs/types/types.js.map +1 -1
  52. package/lib/commonjs/version.json +1 -1
  53. package/lib/module/components/Attachment/AudioAttachment.js +255 -216
  54. package/lib/module/components/Attachment/AudioAttachment.js.map +1 -1
  55. package/lib/module/components/Attachment/FileAttachmentGroup.js +11 -11
  56. package/lib/module/components/Attachment/FileAttachmentGroup.js.map +1 -1
  57. package/lib/module/components/Attachment/Gallery.js +9 -0
  58. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  59. package/lib/module/components/ChannelList/ChannelList.js +23 -0
  60. package/lib/module/components/ChannelList/ChannelList.js.map +1 -1
  61. package/lib/module/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js +31 -8
  62. package/lib/module/components/ChannelList/hooks/listeners/useAddedToChannelNotification.js.map +1 -1
  63. package/lib/module/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js +75 -0
  64. package/lib/module/components/ChannelList/hooks/listeners/useChannelMemberUpdated.js.map +1 -0
  65. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js +21 -10
  66. package/lib/module/components/ChannelList/hooks/listeners/useNewMessage.js.map +1 -1
  67. package/lib/module/components/ChannelList/hooks/listeners/useNewMessageNotification.js +23 -7
  68. package/lib/module/components/ChannelList/hooks/listeners/useNewMessageNotification.js.map +1 -1
  69. package/lib/module/components/ChannelList/hooks/useChannelMembershipState.js +17 -0
  70. package/lib/module/components/ChannelList/hooks/useChannelMembershipState.js.map +1 -0
  71. package/lib/module/components/ChannelList/hooks/useSelectedChannelState.js +32 -0
  72. package/lib/module/components/ChannelList/hooks/useSelectedChannelState.js.map +1 -0
  73. package/lib/module/components/ChannelList/hooks/utils/index.js +102 -0
  74. package/lib/module/components/ChannelList/hooks/utils/index.js.map +1 -0
  75. package/lib/module/components/ChannelList/utils.js +23 -11
  76. package/lib/module/components/ChannelList/utils.js.map +1 -1
  77. package/lib/module/components/ChannelPreview/ChannelPreviewMessenger.js +1 -2
  78. package/lib/module/components/ChannelPreview/ChannelPreviewMessenger.js.map +1 -1
  79. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +24 -13
  80. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  81. package/lib/module/components/Message/Message.js.map +1 -1
  82. package/lib/module/components/MessageInput/FileUploadPreview.js +35 -23
  83. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  84. package/lib/module/components/ProgressControl/ProgressControl.js +57 -54
  85. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -1
  86. package/lib/module/components/ProgressControl/WaveProgressBar.js +52 -52
  87. package/lib/module/components/ProgressControl/WaveProgressBar.js.map +1 -1
  88. package/lib/module/components/index.js +22 -0
  89. package/lib/module/components/index.js.map +1 -1
  90. package/lib/module/contexts/themeContext/utils/theme.js +1 -0
  91. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  92. package/lib/module/hooks/useAudioPlayer.js +158 -0
  93. package/lib/module/hooks/useAudioPlayer.js.map +1 -0
  94. package/lib/module/icons/Archieve.js +33 -0
  95. package/lib/module/icons/Archieve.js.map +1 -0
  96. package/lib/module/icons/Pause.js +2 -2
  97. package/lib/module/icons/Pause.js.map +1 -1
  98. package/lib/module/icons/Play.js +2 -2
  99. package/lib/module/icons/Play.js.map +1 -1
  100. package/lib/module/icons/index.js +11 -0
  101. package/lib/module/icons/index.js.map +1 -1
  102. package/lib/module/native.js.map +1 -1
  103. package/lib/module/types/types.js.map +1 -1
  104. package/lib/module/version.json +1 -1
  105. package/lib/typescript/components/Attachment/AudioAttachment.d.ts +2 -2
  106. package/lib/typescript/components/Attachment/AudioAttachment.d.ts.map +1 -1
  107. package/lib/typescript/components/Attachment/FileAttachmentGroup.d.ts.map +1 -1
  108. package/lib/typescript/components/Attachment/Gallery.d.ts.map +1 -1
  109. package/lib/typescript/components/ChannelList/ChannelList.d.ts +20 -6
  110. package/lib/typescript/components/ChannelList/ChannelList.d.ts.map +1 -1
  111. package/lib/typescript/components/ChannelList/hooks/listeners/useAddedToChannelNotification.d.ts +4 -3
  112. package/lib/typescript/components/ChannelList/hooks/listeners/useAddedToChannelNotification.d.ts.map +1 -1
  113. package/lib/typescript/components/ChannelList/hooks/listeners/useChannelMemberUpdated.d.ts +12 -0
  114. package/lib/typescript/components/ChannelList/hooks/listeners/useChannelMemberUpdated.d.ts.map +1 -0
  115. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessage.d.ts +4 -3
  116. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessage.d.ts.map +1 -1
  117. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessageNotification.d.ts +4 -3
  118. package/lib/typescript/components/ChannelList/hooks/listeners/useNewMessageNotification.d.ts.map +1 -1
  119. package/lib/typescript/components/ChannelList/hooks/useChannelMembershipState.d.ts +5 -0
  120. package/lib/typescript/components/ChannelList/hooks/useChannelMembershipState.d.ts.map +1 -0
  121. package/lib/typescript/components/ChannelList/hooks/useSelectedChannelState.d.ts +13 -0
  122. package/lib/typescript/components/ChannelList/hooks/useSelectedChannelState.d.ts.map +1 -0
  123. package/lib/typescript/components/ChannelList/hooks/utils/index.d.ts +22 -0
  124. package/lib/typescript/components/ChannelList/hooks/utils/index.d.ts.map +1 -0
  125. package/lib/typescript/components/ChannelList/utils.d.ts +10 -4
  126. package/lib/typescript/components/ChannelList/utils.d.ts.map +1 -1
  127. package/lib/typescript/components/ChannelPreview/ChannelPreviewMessenger.d.ts.map +1 -1
  128. package/lib/typescript/components/ImageGallery/components/ImageGalleryVideoControl.d.ts.map +1 -1
  129. package/lib/typescript/components/Message/Message.d.ts +22 -11
  130. package/lib/typescript/components/Message/Message.d.ts.map +1 -1
  131. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts.map +1 -1
  132. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +35 -2
  133. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts.map +1 -1
  134. package/lib/typescript/components/ProgressControl/WaveProgressBar.d.ts +27 -0
  135. package/lib/typescript/components/ProgressControl/WaveProgressBar.d.ts.map +1 -1
  136. package/lib/typescript/components/index.d.ts +2 -0
  137. package/lib/typescript/components/index.d.ts.map +1 -1
  138. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +1 -0
  139. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  140. package/lib/typescript/hooks/useAudioPlayer.d.ts +16 -0
  141. package/lib/typescript/hooks/useAudioPlayer.d.ts.map +1 -0
  142. package/lib/typescript/icons/Archieve.d.ts +4 -0
  143. package/lib/typescript/icons/Archieve.d.ts.map +1 -0
  144. package/lib/typescript/icons/Pause.d.ts.map +1 -1
  145. package/lib/typescript/icons/index.d.ts +1 -0
  146. package/lib/typescript/icons/index.d.ts.map +1 -1
  147. package/lib/typescript/native.d.ts +10 -3
  148. package/lib/typescript/native.d.ts.map +1 -1
  149. package/lib/typescript/types/types.d.ts +5 -1
  150. package/lib/typescript/types/types.d.ts.map +1 -1
  151. package/package.json +4 -2
  152. package/src/components/Attachment/AudioAttachment.tsx +173 -137
  153. package/src/components/Attachment/FileAttachmentGroup.tsx +9 -16
  154. package/src/components/Attachment/Gallery.tsx +3 -0
  155. package/src/components/ChannelList/ChannelList.tsx +38 -3
  156. package/src/components/ChannelList/hooks/listeners/useAddedToChannelNotification.ts +32 -3
  157. package/src/components/ChannelList/hooks/listeners/useChannelMemberUpdated.ts +116 -0
  158. package/src/components/ChannelList/hooks/listeners/useNewMessage.ts +46 -17
  159. package/src/components/ChannelList/hooks/listeners/useNewMessageNotification.ts +18 -3
  160. package/src/components/ChannelList/hooks/useChannelMembershipState.ts +22 -0
  161. package/src/components/ChannelList/hooks/useSelectedChannelState.ts +57 -0
  162. package/src/components/ChannelList/hooks/utils/index.ts +130 -0
  163. package/src/components/ChannelList/utils.ts +50 -14
  164. package/src/components/ChannelPreview/ChannelPreviewMessenger.tsx +1 -2
  165. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +23 -13
  166. package/src/components/Message/Message.tsx +26 -4
  167. package/src/components/MessageInput/FileUploadPreview.tsx +29 -28
  168. package/src/components/ProgressControl/ProgressControl.tsx +115 -92
  169. package/src/components/ProgressControl/WaveProgressBar.tsx +96 -59
  170. package/src/components/index.ts +2 -0
  171. package/src/contexts/themeContext/utils/theme.ts +2 -0
  172. package/src/hooks/useAudioPlayer.ts +59 -0
  173. package/src/icons/Archieve.tsx +10 -0
  174. package/src/icons/Pause.tsx +2 -5
  175. package/src/icons/Play.tsx +2 -2
  176. package/src/icons/index.ts +1 -0
  177. package/src/native.ts +11 -3
  178. package/src/types/types.ts +14 -1
  179. package/src/version.json +1 -1
@@ -12,6 +12,7 @@ import { ChannelListMessenger, ChannelListMessengerProps } from './ChannelListMe
12
12
  import { useAddedToChannelNotification } from './hooks/listeners/useAddedToChannelNotification';
13
13
  import { useChannelDeleted } from './hooks/listeners/useChannelDeleted';
14
14
  import { useChannelHidden } from './hooks/listeners/useChannelHidden';
15
+ import { useChannelMemberUpdated } from './hooks/listeners/useChannelMemberUpdated';
15
16
  import { useChannelTruncated } from './hooks/listeners/useChannelTruncated';
16
17
  import { useChannelUpdated } from './hooks/listeners/useChannelUpdated';
17
18
  import { useChannelVisible } from './hooks/listeners/useChannelVisible';
@@ -29,7 +30,7 @@ import {
29
30
  } from '../../contexts/channelsContext/ChannelsContext';
30
31
  import { useChatContext } from '../../contexts/chatContext/ChatContext';
31
32
  import { upsertCidsForQuery } from '../../store/apis/upsertCidsForQuery';
32
- import type { DefaultStreamChatGenerics } from '../../types/types';
33
+ import type { ChannelListEventListenerOptions, DefaultStreamChatGenerics } from '../../types/types';
33
34
  import { ChannelPreviewMessenger } from '../ChannelPreview/ChannelPreviewMessenger';
34
35
  import { EmptyStateIndicator as EmptyStateIndicatorDefault } from '../Indicators/EmptyStateIndicator';
35
36
  import { LoadingErrorIndicator as LoadingErrorIndicatorDefault } from '../Indicators/LoadingErrorIndicator';
@@ -89,12 +90,15 @@ export type ChannelListProps<
89
90
  *
90
91
  * @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
91
92
  * @param event An [Event Object](https://getstream.io/chat/docs/event_object) corresponding to `notification.added_to_channel` event
93
+ * @param filters Channel filters
94
+ * @param sort Channel sort options
92
95
  *
93
96
  * @overrideType Function
94
97
  * */
95
98
  onAddedToChannel?: (
96
99
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
97
100
  event: Event<StreamChatGenerics>,
101
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
98
102
  ) => void;
99
103
  /**
100
104
  * Function that overrides default behavior when a channel gets deleted. In absence of this prop, the channel will be removed from the list.
@@ -120,6 +124,21 @@ export type ChannelListProps<
120
124
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
121
125
  event: Event<StreamChatGenerics>,
122
126
  ) => void;
127
+ /**
128
+ * Function that overrides default behavior when a channel member.updated event is triggered
129
+ * @param lockChannelOrder If set to true, channels won't dynamically sort by most recent message, defaults to false
130
+ * @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
131
+ * @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `member.updated` event
132
+ * @param filters Channel filters
133
+ * @param sort Channel sort options
134
+ * @overrideType Function
135
+ */
136
+ onChannelMemberUpdated?: (
137
+ lockChannelOrder: boolean,
138
+ setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
139
+ event: Event<StreamChatGenerics>,
140
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
141
+ ) => void;
123
142
  /**
124
143
  * Function to customize behavior when a channel gets truncated
125
144
  *
@@ -163,13 +182,16 @@ export type ChannelListProps<
163
182
  * @param lockChannelOrder If set to true, channels won't dynamically sort by most recent message, defaults to false
164
183
  * @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
165
184
  * @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `message.new` event
166
- *
185
+ * @param considerArchivedChannels If set to true, archived channels will be considered while updating the list of channels
186
+ * @param filters Channel filters
187
+ * @param sort Channel sort options
167
188
  * @overrideType Function
168
189
  * */
169
190
  onNewMessage?: (
170
191
  lockChannelOrder: boolean,
171
192
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
172
193
  event: Event<StreamChatGenerics>,
194
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
173
195
  ) => void;
174
196
  /**
175
197
  * Override the default listener/handler for event `notification.message_new`
@@ -177,13 +199,15 @@ export type ChannelListProps<
177
199
  *
178
200
  * @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
179
201
  * @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `notification.message_new` event
180
- *
202
+ * @param filters Channel filters
181
203
  * @overrideType Function
182
204
  * */
183
205
  onNewMessageNotification?: (
184
206
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
185
207
  event: Event<StreamChatGenerics>,
208
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
186
209
  ) => void;
210
+
187
211
  /**
188
212
  * Function that overrides default behavior when a user gets removed from a channel
189
213
  *
@@ -244,6 +268,7 @@ export const ChannelList = <
244
268
  onAddedToChannel,
245
269
  onChannelDeleted,
246
270
  onChannelHidden,
271
+ onChannelMemberUpdated,
247
272
  onChannelTruncated,
248
273
  onChannelUpdated,
249
274
  onChannelVisible,
@@ -289,6 +314,7 @@ export const ChannelList = <
289
314
  // Setup event listeners
290
315
  useAddedToChannelNotification({
291
316
  onAddedToChannel,
317
+ options: { filters, sort },
292
318
  setChannels,
293
319
  });
294
320
 
@@ -302,6 +328,13 @@ export const ChannelList = <
302
328
  setChannels,
303
329
  });
304
330
 
331
+ useChannelMemberUpdated({
332
+ lockChannelOrder,
333
+ onChannelMemberUpdated,
334
+ options: { filters, sort },
335
+ setChannels,
336
+ });
337
+
305
338
  useChannelTruncated({
306
339
  onChannelTruncated,
307
340
  refreshList,
@@ -322,11 +355,13 @@ export const ChannelList = <
322
355
  useNewMessage({
323
356
  lockChannelOrder,
324
357
  onNewMessage,
358
+ options: { filters, sort },
325
359
  setChannels,
326
360
  });
327
361
 
328
362
  useNewMessageNotification({
329
363
  onNewMessageNotification,
364
+ options: { filters, sort },
330
365
  setChannels,
331
366
  });
332
367
 
@@ -6,8 +6,12 @@ import type { Channel, Event } from 'stream-chat';
6
6
 
7
7
  import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
8
8
 
9
- import type { DefaultStreamChatGenerics } from '../../../../types/types';
9
+ import type {
10
+ ChannelListEventListenerOptions,
11
+ DefaultStreamChatGenerics,
12
+ } from '../../../../types/types';
10
13
  import { getChannel } from '../../utils';
14
+ import { findLastPinnedChannelIndex, findPinnedAtSortOrder } from '../utils';
11
15
 
12
16
  type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
13
17
  {
@@ -15,13 +19,16 @@ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultSt
15
19
  onAddedToChannel?: (
16
20
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
17
21
  event: Event<StreamChatGenerics>,
22
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
18
23
  ) => void;
24
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>;
19
25
  };
20
26
 
21
27
  export const useAddedToChannelNotification = <
22
28
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
23
29
  >({
24
30
  onAddedToChannel,
31
+ options,
25
32
  setChannels,
26
33
  }: Parameters<StreamChatGenerics>) => {
27
34
  const { client } = useChatContext<StreamChatGenerics>();
@@ -29,15 +36,37 @@ export const useAddedToChannelNotification = <
29
36
  useEffect(() => {
30
37
  const handleEvent = async (event: Event<StreamChatGenerics>) => {
31
38
  if (typeof onAddedToChannel === 'function') {
32
- onAddedToChannel(setChannels, event);
39
+ onAddedToChannel(setChannels, event, options);
33
40
  } else {
41
+ if (!options) return;
42
+ const { sort } = options;
34
43
  if (event.channel?.id && event.channel?.type) {
35
44
  const channel = await getChannel<StreamChatGenerics>({
36
45
  client,
37
46
  id: event.channel.id,
38
47
  type: event.channel.type,
39
48
  });
40
- setChannels((channels) => (channels ? uniqBy([channel, ...channels], 'cid') : channels));
49
+
50
+ const pinnedAtSort = findPinnedAtSortOrder({ sort });
51
+
52
+ setChannels((channels) => {
53
+ if (!channels) return channels;
54
+
55
+ // handle pinning
56
+ let lastPinnedChannelIndex: number | null = null;
57
+
58
+ const newChannels = [...channels];
59
+ if (pinnedAtSort === 1 || pinnedAtSort === -1) {
60
+ lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });
61
+ const newTargetChannelIndex =
62
+ typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0;
63
+
64
+ newChannels.splice(newTargetChannelIndex, 0, channel);
65
+ return newChannels;
66
+ }
67
+
68
+ return uniqBy([channel, ...channels], 'cid');
69
+ });
41
70
  }
42
71
  }
43
72
  };
@@ -0,0 +1,116 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import type { Channel, Event } from 'stream-chat';
4
+
5
+ import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
6
+
7
+ import type {
8
+ ChannelListEventListenerOptions,
9
+ DefaultStreamChatGenerics,
10
+ } from '../../../../types/types';
11
+ import {
12
+ findLastPinnedChannelIndex,
13
+ findPinnedAtSortOrder,
14
+ isChannelArchived,
15
+ isChannelPinned,
16
+ shouldConsiderArchivedChannels,
17
+ shouldConsiderPinnedChannels,
18
+ } from '../utils';
19
+
20
+ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
21
+ {
22
+ lockChannelOrder: boolean;
23
+ setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>;
24
+ onChannelMemberUpdated?: (
25
+ lockChannelOrder: boolean,
26
+ setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
27
+ event: Event<StreamChatGenerics>,
28
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
29
+ ) => void;
30
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>;
31
+ };
32
+
33
+ export const useChannelMemberUpdated = <
34
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
35
+ >({
36
+ lockChannelOrder,
37
+ onChannelMemberUpdated,
38
+ options,
39
+ setChannels,
40
+ }: Parameters<StreamChatGenerics>) => {
41
+ const { client } = useChatContext<StreamChatGenerics>();
42
+
43
+ useEffect(() => {
44
+ const handleEvent = (event: Event<StreamChatGenerics>) => {
45
+ if (typeof onChannelMemberUpdated === 'function') {
46
+ onChannelMemberUpdated(lockChannelOrder, setChannels, event, options);
47
+ } else {
48
+ if (!options) return;
49
+ const { filters, sort } = options;
50
+ if (!event.member?.user || event.member.user.id !== client.userID || !event.channel_type) {
51
+ return;
52
+ }
53
+ const channelType = event.channel_type;
54
+ const channelId = event.channel_id;
55
+
56
+ const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
57
+ const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
58
+ const pinnedAtSort = findPinnedAtSortOrder({ sort });
59
+
60
+ setChannels((currentChannels) => {
61
+ if (!currentChannels) return currentChannels;
62
+
63
+ const targetChannel = client.channel(channelType, channelId);
64
+ // assumes that channel instances are not changing
65
+ const targetChannelIndex = currentChannels.indexOf(targetChannel);
66
+ const targetChannelExistsWithinList = targetChannelIndex >= 0;
67
+
68
+ const isTargetChannelPinned = isChannelPinned(targetChannel);
69
+ const isTargetChannelArchived = isChannelArchived(targetChannel);
70
+
71
+ if (!considerPinnedChannels || lockChannelOrder) {
72
+ return currentChannels;
73
+ }
74
+
75
+ const newChannels = [...currentChannels];
76
+
77
+ if (targetChannelExistsWithinList) {
78
+ newChannels.splice(targetChannelIndex, 1);
79
+ }
80
+
81
+ // handle archiving (remove channel)
82
+ if (
83
+ // When archived filter true, and channel is unarchived
84
+ (considerArchivedChannels && !isTargetChannelArchived && filters?.archived) ||
85
+ // When archived filter false, and channel is archived
86
+ (considerArchivedChannels && isTargetChannelArchived && !filters?.archived)
87
+ ) {
88
+ return newChannels;
89
+ }
90
+
91
+ // handle pinning
92
+ let lastPinnedChannelIndex: number | null = null;
93
+
94
+ if (pinnedAtSort === 1 || (pinnedAtSort === -1 && !isTargetChannelPinned)) {
95
+ lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });
96
+ }
97
+ const newTargetChannelIndex =
98
+ typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0;
99
+
100
+ // skip re-render if the position of the channel does not change
101
+ if (currentChannels[newTargetChannelIndex] === targetChannel) {
102
+ return currentChannels;
103
+ }
104
+
105
+ newChannels.splice(newTargetChannelIndex, 0, targetChannel);
106
+
107
+ return newChannels;
108
+ });
109
+ }
110
+ };
111
+
112
+ const listener = client?.on('member.updated', handleEvent);
113
+ return () => listener?.unsubscribe();
114
+ // eslint-disable-next-line react-hooks/exhaustive-deps
115
+ }, []);
116
+ };
@@ -4,8 +4,17 @@ import type { Channel, Event } from 'stream-chat';
4
4
 
5
5
  import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
6
6
 
7
- import type { DefaultStreamChatGenerics } from '../../../../types/types';
7
+ import type {
8
+ ChannelListEventListenerOptions,
9
+ DefaultStreamChatGenerics,
10
+ } from '../../../../types/types';
8
11
  import { moveChannelUp } from '../../utils';
12
+ import {
13
+ isChannelArchived,
14
+ isChannelPinned,
15
+ shouldConsiderArchivedChannels,
16
+ shouldConsiderPinnedChannels,
17
+ } from '../utils';
9
18
 
10
19
  type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
11
20
  {
@@ -15,7 +24,9 @@ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultSt
15
24
  lockChannelOrder: boolean,
16
25
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
17
26
  event: Event<StreamChatGenerics>,
27
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
18
28
  ) => void;
29
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>;
19
30
  };
20
31
 
21
32
  export const useNewMessage = <
@@ -23,6 +34,7 @@ export const useNewMessage = <
23
34
  >({
24
35
  lockChannelOrder,
25
36
  onNewMessage,
37
+ options,
26
38
  setChannels,
27
39
  }: Parameters<StreamChatGenerics>) => {
28
40
  const { client } = useChatContext<StreamChatGenerics>();
@@ -30,27 +42,44 @@ export const useNewMessage = <
30
42
  useEffect(() => {
31
43
  const handleEvent = (event: Event<StreamChatGenerics>) => {
32
44
  if (typeof onNewMessage === 'function') {
33
- onNewMessage(lockChannelOrder, setChannels, event);
45
+ onNewMessage(lockChannelOrder, setChannels, event, options);
34
46
  } else {
47
+ if (!options) return;
48
+ const { filters, sort } = options;
49
+ const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
50
+ const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
51
+
52
+ const channelType = event.channel_type;
53
+ const channelId = event.channel_id;
54
+
55
+ if (!channelType || !channelId) return;
56
+
35
57
  setChannels((channels) => {
36
58
  if (!channels) return channels;
37
- const channelInList = channels.filter((channel) => channel.cid === event.cid).length > 0;
38
-
39
- if (!channelInList && event.channel_type && event.channel_id) {
40
- // If channel doesn't exist in existing list, check in activeChannels as well.
41
- // It may happen that channel was hidden using channel.hide(). In that case
42
- // We remove it from `channels` state, but its still being watched and exists in client.activeChannels.
43
- const channel = client.channel(event.channel_type, event.channel_id);
44
- return [channel, ...channels];
45
- }
59
+ const targetChannel = client.channel(channelType, channelId);
60
+ const targetChannelIndex = channels.indexOf(targetChannel);
61
+
62
+ const isTargetChannelArchived = isChannelArchived(targetChannel);
63
+ const isTargetChannelPinned = isChannelPinned(targetChannel);
46
64
 
47
- if (!lockChannelOrder && event.cid)
48
- return moveChannelUp<StreamChatGenerics>({
49
- channels,
50
- cid: event.cid,
51
- });
65
+ if (
66
+ // When archived filter false, and channel is archived
67
+ (considerArchivedChannels && isTargetChannelArchived && !filters?.archived) ||
68
+ // When archived filter true, and channel is unarchived
69
+ (considerArchivedChannels && !isTargetChannelArchived && filters?.archived) ||
70
+ // If the channel is pinned and we are not considering pinned channels
71
+ (isTargetChannelPinned && considerPinnedChannels) ||
72
+ lockChannelOrder
73
+ ) {
74
+ return [...channels];
75
+ }
52
76
 
53
- return [...channels];
77
+ return moveChannelUp<StreamChatGenerics>({
78
+ channels,
79
+ channelToMove: targetChannel,
80
+ channelToMoveIndexWithinChannels: targetChannelIndex,
81
+ sort,
82
+ });
54
83
  });
55
84
  }
56
85
  };
@@ -6,23 +6,29 @@ import type { Channel, Event } from 'stream-chat';
6
6
 
7
7
  import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
8
8
 
9
- import type { DefaultStreamChatGenerics } from '../../../../types/types';
9
+ import type {
10
+ ChannelListEventListenerOptions,
11
+ DefaultStreamChatGenerics,
12
+ } from '../../../../types/types';
10
13
  import { getChannel } from '../../utils';
14
+ import { isChannelArchived } from '../utils';
11
15
 
12
16
  type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
13
17
  {
14
18
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>;
15
-
16
19
  onNewMessageNotification?: (
17
20
  setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
18
21
  event: Event<StreamChatGenerics>,
22
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>,
19
23
  ) => void;
24
+ options?: ChannelListEventListenerOptions<StreamChatGenerics>;
20
25
  };
21
26
 
22
27
  export const useNewMessageNotification = <
23
28
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
24
29
  >({
25
30
  onNewMessageNotification,
31
+ options,
26
32
  setChannels,
27
33
  }: Parameters<StreamChatGenerics>) => {
28
34
  const { client } = useChatContext<StreamChatGenerics>();
@@ -30,14 +36,23 @@ export const useNewMessageNotification = <
30
36
  useEffect(() => {
31
37
  const handleEvent = async (event: Event<StreamChatGenerics>) => {
32
38
  if (typeof onNewMessageNotification === 'function') {
33
- onNewMessageNotification(setChannels, event);
39
+ onNewMessageNotification(setChannels, event, options);
34
40
  } else {
41
+ if (!options) return;
42
+ const { filters } = options;
35
43
  if (event.channel?.id && event.channel?.type) {
36
44
  const channel = await getChannel({
37
45
  client,
38
46
  id: event.channel.id,
39
47
  type: event.channel.type,
40
48
  });
49
+
50
+ // Handle archived channels
51
+ const considerArchivedChannels = filters && filters.archived === false;
52
+ if (isChannelArchived(channel) && considerArchivedChannels) {
53
+ return;
54
+ }
55
+
41
56
  setChannels((channels) => (channels ? uniqBy([channel, ...channels], 'cid') : channels));
42
57
  }
43
58
  }
@@ -0,0 +1,22 @@
1
+ import { Channel, ChannelMemberResponse, EventTypes } from 'stream-chat';
2
+
3
+ import { useSelectedChannelState } from './useSelectedChannelState';
4
+
5
+ import { DefaultStreamChatGenerics } from '../../../types/types';
6
+
7
+ const selector = <StreamChatGenerics extends DefaultStreamChatGenerics>(
8
+ channel: Channel<StreamChatGenerics>,
9
+ ) => channel.state.membership;
10
+ const keys: EventTypes[] = ['member.updated'];
11
+
12
+ export function useChannelMembershipState<StreamChatGenerics extends DefaultStreamChatGenerics>(
13
+ channel: Channel<StreamChatGenerics>,
14
+ ): ChannelMemberResponse<StreamChatGenerics>;
15
+ export function useChannelMembershipState<StreamChatGenerics extends DefaultStreamChatGenerics>(
16
+ channel?: Channel<StreamChatGenerics>,
17
+ ): ChannelMemberResponse<StreamChatGenerics> | undefined;
18
+ export function useChannelMembershipState<StreamChatGenerics extends DefaultStreamChatGenerics>(
19
+ channel?: Channel<StreamChatGenerics>,
20
+ ) {
21
+ return useSelectedChannelState({ channel, selector, stateChangeEventKeys: keys });
22
+ }
@@ -0,0 +1,57 @@
1
+ import { useCallback } from 'react';
2
+
3
+ import type { Channel, EventTypes } from 'stream-chat';
4
+ import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
+
6
+ import { DefaultStreamChatGenerics } from '../../../types/types';
7
+
8
+ const noop = () => {};
9
+
10
+ export function useSelectedChannelState<
11
+ StreamChatGenerics extends DefaultStreamChatGenerics,
12
+ O,
13
+ >(_: {
14
+ channel: Channel<StreamChatGenerics>;
15
+ selector: (channel: Channel<StreamChatGenerics>) => O;
16
+ stateChangeEventKeys?: EventTypes[];
17
+ }): O;
18
+ export function useSelectedChannelState<
19
+ StreamChatGenerics extends DefaultStreamChatGenerics,
20
+ O,
21
+ >(_: {
22
+ selector: (channel: Channel<StreamChatGenerics>) => O;
23
+ channel?: Channel<StreamChatGenerics> | undefined;
24
+ stateChangeEventKeys?: EventTypes[];
25
+ }): O | undefined;
26
+ export function useSelectedChannelState<StreamChatGenerics extends DefaultStreamChatGenerics, O>({
27
+ channel,
28
+ selector,
29
+ stateChangeEventKeys = ['all'],
30
+ }: {
31
+ selector: (channel: Channel<StreamChatGenerics>) => O;
32
+ channel?: Channel<StreamChatGenerics>;
33
+ stateChangeEventKeys?: EventTypes[];
34
+ }): O | undefined {
35
+ const subscribe = useCallback(
36
+ (onStoreChange: (value: O) => void) => {
37
+ if (!channel) return noop;
38
+
39
+ const subscriptions = stateChangeEventKeys.map((et) =>
40
+ channel.on(et, () => {
41
+ onStoreChange(selector(channel));
42
+ }),
43
+ );
44
+
45
+ return () => subscriptions.forEach((subscription) => subscription.unsubscribe());
46
+ },
47
+ [channel, selector, stateChangeEventKeys],
48
+ );
49
+
50
+ const getSnapshot = useCallback(() => {
51
+ if (!channel) return undefined;
52
+
53
+ return selector(channel);
54
+ }, [channel, selector]);
55
+
56
+ return useSyncExternalStore(subscribe, getSnapshot);
57
+ }
@@ -0,0 +1,130 @@
1
+ import { Channel, ChannelSortBase } from 'stream-chat';
2
+
3
+ import { DefaultStreamChatGenerics } from '../../../../types/types';
4
+ import { ChannelListProps } from '../../ChannelList';
5
+
6
+ export const isChannelPinned = <
7
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
8
+ >(
9
+ channel: Channel<StreamChatGenerics>,
10
+ ) => {
11
+ if (!channel) return false;
12
+
13
+ const member = channel.state.membership;
14
+
15
+ return !!member?.pinned_at;
16
+ };
17
+
18
+ export const isChannelArchived = <
19
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
20
+ >(
21
+ channel: Channel<StreamChatGenerics>,
22
+ ) => {
23
+ if (!channel) return false;
24
+
25
+ const member = channel.state.membership;
26
+
27
+ return !!member?.archived_at;
28
+ };
29
+
30
+ export const shouldConsiderArchivedChannels = <
31
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
32
+ >(
33
+ filters: ChannelListProps<StreamChatGenerics>['filters'],
34
+ ) => {
35
+ if (!filters) return false;
36
+
37
+ return typeof filters.archived === 'boolean';
38
+ };
39
+
40
+ export const extractSortValue = <
41
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
42
+ >({
43
+ atIndex,
44
+ sort,
45
+ targetKey,
46
+ }: {
47
+ atIndex: number;
48
+ targetKey: keyof ChannelSortBase<StreamChatGenerics>;
49
+ sort?: ChannelListProps<StreamChatGenerics>['sort'];
50
+ }) => {
51
+ if (!sort) return null;
52
+ let option: null | ChannelSortBase<StreamChatGenerics> = null;
53
+
54
+ if (Array.isArray(sort)) {
55
+ option = sort[atIndex] ?? null;
56
+ } else {
57
+ let index = 0;
58
+ for (const key in sort) {
59
+ if (index !== atIndex) {
60
+ index++;
61
+ continue;
62
+ }
63
+
64
+ if (key !== targetKey) {
65
+ return null;
66
+ }
67
+
68
+ option = sort;
69
+
70
+ break;
71
+ }
72
+ }
73
+
74
+ return option?.[targetKey] ?? null;
75
+ };
76
+
77
+ /**
78
+ * Returns true only if `{ pinned_at: -1 }` or `{ pinned_at: 1 }` option is first within the `sort` array.
79
+ */
80
+ export const shouldConsiderPinnedChannels = <
81
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
82
+ >(
83
+ sort: ChannelListProps<StreamChatGenerics>['sort'],
84
+ ) => {
85
+ const value = extractSortValue({
86
+ atIndex: 0,
87
+ sort,
88
+ targetKey: 'pinned_at',
89
+ });
90
+
91
+ if (typeof value !== 'number') return false;
92
+
93
+ return Math.abs(value) === 1;
94
+ };
95
+
96
+ export function findPinnedAtSortOrder<
97
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
98
+ >({ sort }: { sort: ChannelListProps<StreamChatGenerics>['sort'] }) {
99
+ if (!sort) return null;
100
+
101
+ if (Array.isArray(sort)) {
102
+ const [option] = sort;
103
+
104
+ if (!option?.pinned_at) return null;
105
+
106
+ return option.pinned_at;
107
+ } else {
108
+ if (!sort.pinned_at) return null;
109
+
110
+ return sort.pinned_at;
111
+ }
112
+ }
113
+
114
+ export function findLastPinnedChannelIndex<
115
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
116
+ >({ channels }: { channels: Channel<StreamChatGenerics>[] }) {
117
+ let lastPinnedChannelIndex: number | null = null;
118
+
119
+ for (const channel of channels) {
120
+ if (!isChannelPinned(channel)) break;
121
+
122
+ if (typeof lastPinnedChannelIndex === 'number') {
123
+ lastPinnedChannelIndex++;
124
+ } else {
125
+ lastPinnedChannelIndex = 0;
126
+ }
127
+ }
128
+
129
+ return lastPinnedChannelIndex;
130
+ }