Skip to content

Commit 66ea7c9

Browse files
Allow integrators to shape their ChannelLists however they want with more freedom
1 parent 3703c16 commit 66ea7c9

File tree

3 files changed

+577
-62
lines changed

3 files changed

+577
-62
lines changed

src/components/ChannelList/ChannelList.tsx

Lines changed: 31 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,9 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
22
import clsx from 'clsx';
33

44
import { ChannelListMessenger, ChannelListMessengerProps } from './ChannelListMessenger';
5-
import { useChannelDeletedListener } from './hooks/useChannelDeletedListener';
6-
import { useChannelHiddenListener } from './hooks/useChannelHiddenListener';
7-
import { useChannelTruncatedListener } from './hooks/useChannelTruncatedListener';
8-
import { useChannelUpdatedListener } from './hooks/useChannelUpdatedListener';
9-
import { useChannelVisibleListener } from './hooks/useChannelVisibleListener';
105
import { useConnectionRecoveredListener } from './hooks/useConnectionRecoveredListener';
11-
import { useMessageNewListener } from './hooks/useMessageNewListener';
126
import { useMobileNavigation } from './hooks/useMobileNavigation';
13-
import { useNotificationAddedToChannelListener } from './hooks/useNotificationAddedToChannelListener';
14-
import { useNotificationMessageNewListener } from './hooks/useNotificationMessageNewListener';
15-
import { useNotificationRemovedFromChannelListener } from './hooks/useNotificationRemovedFromChannelListener';
167
import { CustomQueryChannelsFn, usePaginatedChannels } from './hooks/usePaginatedChannels';
17-
import { useUserPresenceChangedListener } from './hooks/useUserPresenceChangedListener';
18-
import { useMemberUpdatedListener } from './hooks/useMemberUpdatedListener';
198
import {
209
MAX_QUERY_CHANNELS_LIMIT,
2110
moveChannelUpwards,
@@ -43,6 +32,7 @@ import type { Channel, ChannelFilters, ChannelOptions, ChannelSort, Event } from
4332
import type { ChannelAvatarProps } from '../Avatar';
4433
import type { TranslationContextValue } from '../../context/TranslationContext';
4534
import type { DefaultStreamChatGenerics, PaginatorProps } from '../../types/types';
35+
import { useChannelListShape, usePrepareShapeHandlers } from './hooks/useChannelListShape';
4636

4737
const DEFAULT_FILTERS = {};
4838
const DEFAULT_OPTIONS = {};
@@ -166,15 +156,13 @@ export type ChannelListProps<
166156
watchers?: { limit?: number; offset?: number };
167157
};
168158

169-
const UnMemoizedChannelList = <
170-
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
171-
>(
172-
props: ChannelListProps<StreamChatGenerics>,
159+
const UnMemoizedChannelList = <SCG extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(
160+
props: ChannelListProps<SCG>,
173161
) => {
174162
const {
175163
additionalChannelSearchProps,
176164
Avatar = DefaultAvatar,
177-
allowNewMessagesFromUnfilteredChannels,
165+
allowNewMessagesFromUnfilteredChannels = true,
178166
channelRenderFilterFn,
179167
ChannelSearch = DefaultChannelSearch,
180168
customActiveChannel,
@@ -185,7 +173,7 @@ const UnMemoizedChannelList = <
185173
LoadingErrorIndicator = NullComponent,
186174
LoadingIndicator = LoadingChannels,
187175
List = ChannelListMessenger,
188-
lockChannelOrder,
176+
lockChannelOrder = false,
189177
onAddedToChannel,
190178
onChannelDeleted,
191179
onChannelHidden,
@@ -217,7 +205,7 @@ const UnMemoizedChannelList = <
217205
setActiveChannel,
218206
theme,
219207
useImageFlagEmojisOnWindows,
220-
} = useChatContext<StreamChatGenerics>('ChannelList');
208+
} = useChatContext<SCG>('ChannelList');
221209

222210
const channelListRef = useRef<HTMLDivElement>(null);
223211
const [channelUpdateCount, setChannelUpdateCount] = useState(0);
@@ -227,8 +215,8 @@ const UnMemoizedChannelList = <
227215
* If customActiveChannel prop is absent, then set the first channel in list as active channel.
228216
*/
229217
const activeChannelHandler = async (
230-
channels: Array<Channel<StreamChatGenerics>>,
231-
setChannels: React.Dispatch<React.SetStateAction<Array<Channel<StreamChatGenerics>>>>,
218+
channels: Array<Channel<SCG>>,
219+
setChannels: React.Dispatch<React.SetStateAction<Array<Channel<SCG>>>>,
232220
) => {
233221
if (!channels.length || channels.length > (options?.limit || MAX_QUERY_CHANNELS_LIMIT)) {
234222
return;
@@ -268,17 +256,11 @@ const UnMemoizedChannelList = <
268256
* For some events, inner properties on the channel will update but the shallow comparison will not
269257
* force a re-render. Incrementing this dummy variable ensures the channel previews update.
270258
*/
271-
const forceUpdate = useCallback(
272-
() => setChannelUpdateCount((count) => count + 1),
273-
[setChannelUpdateCount],
274-
);
259+
const forceUpdate = useCallback(() => setChannelUpdateCount((count) => count + 1), []);
275260

276261
const onSearch = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
277-
if (!event.target.value) {
278-
setSearchActive(false);
279-
} else {
280-
setSearchActive(true);
281-
}
262+
setSearchActive(!!event.target.value);
263+
282264
additionalChannelSearchProps?.onSearch?.(event);
283265
// eslint-disable-next-line react-hooks/exhaustive-deps
284266
}, []);
@@ -301,43 +283,35 @@ const UnMemoizedChannelList = <
301283

302284
const loadedChannels = channelRenderFilterFn ? channelRenderFilterFn(channels) : channels;
303285

304-
const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
305-
306286
useMobileNavigation(channelListRef, navOpen, closeMobileNav);
307287

308-
useMessageNewListener(
309-
setChannels,
310-
onMessageNewHandler,
311-
lockChannelOrder,
288+
const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
289+
290+
const { customFn, defaultFn } = usePrepareShapeHandlers<SCG>({
312291
allowNewMessagesFromUnfilteredChannels,
313-
// TODO: adjust accordingly (consider sort option)
314292
considerPinnedChannels,
315-
);
316-
useNotificationMessageNewListener(
317-
setChannels,
318-
onMessageNew,
319-
allowNewMessagesFromUnfilteredChannels,
320-
);
321-
useNotificationAddedToChannelListener(
322-
setChannels,
293+
lockChannelOrder,
323294
onAddedToChannel,
324-
allowNewMessagesFromUnfilteredChannels,
325-
);
326-
useMemberUpdatedListener({
327-
considerPinnedChannels,
295+
onChannelDeleted,
296+
onChannelHidden,
297+
onChannelTruncated,
298+
onChannelUpdated,
299+
onChannelVisible,
300+
onMessageNew,
301+
onMessageNewHandler,
302+
onRemovedFromChannel,
328303
setChannels,
304+
// TODO: implement
305+
// customHandleChannelListShape
329306
});
330-
useNotificationRemovedFromChannelListener(setChannels, onRemovedFromChannel);
331-
useChannelDeletedListener(setChannels, onChannelDeleted);
332-
useChannelHiddenListener(setChannels, onChannelHidden);
333-
useChannelVisibleListener(setChannels, onChannelVisible);
334-
useChannelTruncatedListener(setChannels, onChannelTruncated, forceUpdate);
335-
useChannelUpdatedListener(setChannels, onChannelUpdated, forceUpdate);
307+
308+
useChannelListShape<SCG>(customFn ?? defaultFn);
309+
310+
// TODO: maybe move this too
336311
useConnectionRecoveredListener(forceUpdate);
337-
useUserPresenceChangedListener(setChannels);
338312

339313
useEffect(() => {
340-
const handleEvent = (event: Event<StreamChatGenerics>) => {
314+
const handleEvent = (event: Event<SCG>) => {
341315
if (event.cid === channel?.cid) {
342316
setActiveChannel();
343317
}
@@ -353,7 +327,7 @@ const UnMemoizedChannelList = <
353327
// eslint-disable-next-line react-hooks/exhaustive-deps
354328
}, [channel?.cid]);
355329

356-
const renderChannel = (item: Channel<StreamChatGenerics>) => {
330+
const renderChannel = (item: Channel<SCG>) => {
357331
const previewProps = {
358332
activeChannel: channel,
359333
Avatar,

0 commit comments

Comments
 (0)