Skip to content

Commit d83a6e0

Browse files
Allow integrators to shape their ChannelLists however they want with more freedom
1 parent b68b916 commit d83a6e0

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 = {};
@@ -167,15 +157,13 @@ export type ChannelListProps<
167157
watchers?: { limit?: number; offset?: number };
168158
};
169159

170-
const UnMemoizedChannelList = <
171-
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
172-
>(
173-
props: ChannelListProps<StreamChatGenerics>,
160+
const UnMemoizedChannelList = <SCG extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(
161+
props: ChannelListProps<SCG>,
174162
) => {
175163
const {
176164
additionalChannelSearchProps,
177165
Avatar = DefaultAvatar,
178-
allowNewMessagesFromUnfilteredChannels,
166+
allowNewMessagesFromUnfilteredChannels = true,
179167
channelRenderFilterFn,
180168
ChannelSearch = DefaultChannelSearch,
181169
customActiveChannel,
@@ -186,7 +174,7 @@ const UnMemoizedChannelList = <
186174
LoadingErrorIndicator = NullComponent,
187175
LoadingIndicator = LoadingChannels,
188176
List = ChannelListMessenger,
189-
lockChannelOrder,
177+
lockChannelOrder = false,
190178
onAddedToChannel,
191179
onChannelDeleted,
192180
onChannelHidden,
@@ -218,7 +206,7 @@ const UnMemoizedChannelList = <
218206
setActiveChannel,
219207
theme,
220208
useImageFlagEmojisOnWindows,
221-
} = useChatContext<StreamChatGenerics>('ChannelList');
209+
} = useChatContext<SCG>('ChannelList');
222210

223211
const channelListRef = useRef<HTMLDivElement>(null);
224212
const [channelUpdateCount, setChannelUpdateCount] = useState(0);
@@ -228,8 +216,8 @@ const UnMemoizedChannelList = <
228216
* If customActiveChannel prop is absent, then set the first channel in list as active channel.
229217
*/
230218
const activeChannelHandler = async (
231-
channels: Array<Channel<StreamChatGenerics>>,
232-
setChannels: React.Dispatch<React.SetStateAction<Array<Channel<StreamChatGenerics>>>>,
219+
channels: Array<Channel<SCG>>,
220+
setChannels: React.Dispatch<React.SetStateAction<Array<Channel<SCG>>>>,
233221
) => {
234222
if (!channels.length || channels.length > (options?.limit || MAX_QUERY_CHANNELS_LIMIT)) {
235223
return;
@@ -269,17 +257,11 @@ const UnMemoizedChannelList = <
269257
* For some events, inner properties on the channel will update but the shallow comparison will not
270258
* force a re-render. Incrementing this dummy variable ensures the channel previews update.
271259
*/
272-
const forceUpdate = useCallback(
273-
() => setChannelUpdateCount((count) => count + 1),
274-
[setChannelUpdateCount],
275-
);
260+
const forceUpdate = useCallback(() => setChannelUpdateCount((count) => count + 1), []);
276261

277262
const onSearch = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
278-
if (!event.target.value) {
279-
setSearchActive(false);
280-
} else {
281-
setSearchActive(true);
282-
}
263+
setSearchActive(!!event.target.value);
264+
283265
additionalChannelSearchProps?.onSearch?.(event);
284266
// eslint-disable-next-line react-hooks/exhaustive-deps
285267
}, []);
@@ -302,43 +284,35 @@ const UnMemoizedChannelList = <
302284

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

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

309-
useMessageNewListener(
310-
setChannels,
311-
onMessageNewHandler,
312-
lockChannelOrder,
289+
const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
290+
291+
const { customFn, defaultFn } = usePrepareShapeHandlers<SCG>({
313292
allowNewMessagesFromUnfilteredChannels,
314-
// TODO: adjust accordingly (consider sort option)
315293
considerPinnedChannels,
316-
);
317-
useNotificationMessageNewListener(
318-
setChannels,
319-
onMessageNew,
320-
allowNewMessagesFromUnfilteredChannels,
321-
);
322-
useNotificationAddedToChannelListener(
323-
setChannels,
294+
lockChannelOrder,
324295
onAddedToChannel,
325-
allowNewMessagesFromUnfilteredChannels,
326-
);
327-
useMemberUpdatedListener({
328-
considerPinnedChannels,
296+
onChannelDeleted,
297+
onChannelHidden,
298+
onChannelTruncated,
299+
onChannelUpdated,
300+
onChannelVisible,
301+
onMessageNew,
302+
onMessageNewHandler,
303+
onRemovedFromChannel,
329304
setChannels,
305+
// TODO: implement
306+
// customHandleChannelListShape
330307
});
331-
useNotificationRemovedFromChannelListener(setChannels, onRemovedFromChannel);
332-
useChannelDeletedListener(setChannels, onChannelDeleted);
333-
useChannelHiddenListener(setChannels, onChannelHidden);
334-
useChannelVisibleListener(setChannels, onChannelVisible);
335-
useChannelTruncatedListener(setChannels, onChannelTruncated, forceUpdate);
336-
useChannelUpdatedListener(setChannels, onChannelUpdated, forceUpdate);
308+
309+
useChannelListShape<SCG>(customFn ?? defaultFn);
310+
311+
// TODO: maybe move this too
337312
useConnectionRecoveredListener(forceUpdate);
338-
useUserPresenceChangedListener(setChannels);
339313

340314
useEffect(() => {
341-
const handleEvent = (event: Event<StreamChatGenerics>) => {
315+
const handleEvent = (event: Event<SCG>) => {
342316
if (event.cid === channel?.cid) {
343317
setActiveChannel();
344318
}
@@ -354,7 +328,7 @@ const UnMemoizedChannelList = <
354328
// eslint-disable-next-line react-hooks/exhaustive-deps
355329
}, [channel?.cid]);
356330

357-
const renderChannel = (item: Channel<StreamChatGenerics>) => {
331+
const renderChannel = (item: Channel<SCG>) => {
358332
const previewProps = {
359333
activeChannel: channel,
360334
Avatar,

0 commit comments

Comments
 (0)