Skip to content

Commit 4797266

Browse files
committed
feat: channel archiving
1 parent 4fadc2e commit 4797266

File tree

6 files changed

+67
-37
lines changed

6 files changed

+67
-37
lines changed

examples/TypeScriptMessaging/App.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
MessageInput,
1313
MessageList,
1414
OverlayProvider,
15-
SqliteClient,
1615
Streami18n,
1716
Thread,
1817
ThreadContextValue,
@@ -68,11 +67,16 @@ const user = {
6867
id: 'luke_skywalker',
6968
};
7069
const filters = {
71-
archived: true,
70+
archived: false,
7271
members: { $in: ['luke_skywalker'] },
7372
type: 'messaging',
7473
};
75-
const sort: ChannelSort<StreamChatGenerics> = { last_updated: -1 };
74+
75+
const sort: ChannelSort<StreamChatGenerics> = [
76+
{ pinned_at: 1 },
77+
{ last_message_at: -1 },
78+
{ updated_at: -1 },
79+
];
7680

7781
/**
7882
* Start playing with streami18n instance here:

package/src/components/ChannelList/ChannelList.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import type { DefaultStreamChatGenerics } from '../../types/types';
3333
import { ChannelPreviewMessenger } from '../ChannelPreview/ChannelPreviewMessenger';
3434
import { EmptyStateIndicator as EmptyStateIndicatorDefault } from '../Indicators/EmptyStateIndicator';
3535
import { LoadingErrorIndicator as LoadingErrorIndicatorDefault } from '../Indicators/LoadingErrorIndicator';
36-
import { shouldConsiderArchivedChannels } from './hooks/utils';
3736
import { useChannelMemberUpdated } from './hooks/listeners/useMemberUpdated';
3837

3938
export type ChannelListProps<
@@ -166,27 +165,28 @@ export type ChannelListProps<
166165
* @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
167166
* @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `message.new` event
168167
* @param considerArchivedChannels If set to true, archived channels will be considered while updating the list of channels
168+
* @param filters Channel filters
169169
* @overrideType Function
170170
* */
171171
onNewMessage?: (
172172
lockChannelOrder: boolean,
173173
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
174174
event: Event<StreamChatGenerics>,
175-
considerArchivedChannels?: boolean,
175+
filters?: ChannelFilters<StreamChatGenerics>,
176176
) => void;
177177
/**
178178
* Override the default listener/handler for event `notification.message_new`
179179
* This event is received on channel, which is not being watched.
180180
*
181181
* @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
182182
* @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `notification.message_new` event
183-
*
183+
* @param filters Channel filters
184184
* @overrideType Function
185185
* */
186186
onNewMessageNotification?: (
187187
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
188188
event: Event<StreamChatGenerics>,
189-
considerArchivedChannels?: boolean,
189+
filters?: ChannelFilters<StreamChatGenerics>,
190190
) => void;
191191
/**
192192
* Function that overrides default behavior when a user gets removed from a channel
@@ -200,6 +200,23 @@ export type ChannelListProps<
200200
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
201201
event: Event<StreamChatGenerics>,
202202
) => void;
203+
204+
/**
205+
* Function that overrides default behavior when a channel member.updated event is triggered
206+
* @param lockChannelOrder If set to true, channels won't dynamically sort by most recent message, defaults to false
207+
* @param setChannels Setter for internal state property - `channels`. It's created from useState() hook.
208+
* @param event An [Event object](https://getstream.io/chat/docs/event_object) corresponding to `member.updated` event
209+
* @param filters Channel filters
210+
* @param sort Channel sort options
211+
* @overrideType Function
212+
*/
213+
onChannelMemberUpdated?: (
214+
lockChannelOrder: boolean,
215+
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
216+
event: Event<StreamChatGenerics>,
217+
filters?: ChannelFilters<StreamChatGenerics>,
218+
sort?: ChannelSort<StreamChatGenerics>,
219+
) => void;
203220
/**
204221
* Object containing channel query options
205222
* @see See [Channel query documentation](https://getstream.io/chat/docs/query_channels) for a list of available option fields
@@ -248,6 +265,7 @@ export const ChannelList = <
248265
onAddedToChannel,
249266
onChannelDeleted,
250267
onChannelHidden,
268+
onChannelMemberUpdated,
251269
onChannelTruncated,
252270
onChannelUpdated,
253271
onChannelVisible,
@@ -290,8 +308,6 @@ export const ChannelList = <
290308
sort,
291309
});
292310

293-
const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
294-
295311
// Setup event listeners
296312
useAddedToChannelNotification({
297313
onAddedToChannel,
@@ -329,13 +345,13 @@ export const ChannelList = <
329345
lockChannelOrder,
330346
onNewMessage,
331347
setChannels,
332-
considerArchivedChannels,
348+
filters,
333349
});
334350

335351
useNewMessageNotification({
336352
onNewMessageNotification,
337353
setChannels,
338-
considerArchivedChannels,
354+
filters,
339355
});
340356

341357
useRemovedFromChannelNotification({
@@ -349,7 +365,11 @@ export const ChannelList = <
349365
});
350366

351367
useChannelMemberUpdated({
368+
lockChannelOrder,
352369
setChannels,
370+
onChannelMemberUpdated,
371+
filters,
372+
sort,
353373
});
354374

355375
const channelIdsStr = channels?.reduce((acc, channel) => `${acc}${channel.cid}`, '');

package/src/components/ChannelList/hooks/listeners/useMemberUpdated.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
11
import { useEffect } from 'react';
22

3-
import type { Channel, Event } from 'stream-chat';
3+
import type { Channel, ChannelFilters, ChannelSort, Event } from 'stream-chat';
44

55
import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
66

77
import type { DefaultStreamChatGenerics } from '../../../../types/types';
88

99
type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
1010
{
11+
lockChannelOrder: boolean;
1112
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>;
1213
onChannelMemberUpdated?: (
14+
lockChannelOrder: boolean,
1315
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
1416
event: Event<StreamChatGenerics>,
17+
filters?: ChannelFilters<StreamChatGenerics>,
18+
sort?: ChannelSort<StreamChatGenerics>,
1519
) => void;
20+
filters?: ChannelFilters<StreamChatGenerics>;
21+
sort?: ChannelSort<StreamChatGenerics>;
1622
};
1723

1824
export const useChannelMemberUpdated = <
1925
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
2026
>({
27+
lockChannelOrder,
2128
onChannelMemberUpdated,
2229
setChannels,
30+
filters,
31+
sort,
2332
}: Parameters<StreamChatGenerics>) => {
2433
const { client } = useChatContext<StreamChatGenerics>();
2534

2635
useEffect(() => {
2736
const handleEvent = async (event: Event<StreamChatGenerics>) => {
2837
if (typeof onChannelMemberUpdated === 'function') {
29-
onChannelMemberUpdated(setChannels, event);
38+
onChannelMemberUpdated(lockChannelOrder, setChannels, event, filters, sort);
3039
} else {
3140
if (!event.member?.user || event.member.user.id !== client.userID || !event.channel_type) {
3241
return;
@@ -43,14 +52,21 @@ export const useChannelMemberUpdated = <
4352
const targetChannelIndex = currentChannels.indexOf(targetChannel);
4453
const targetChannelExistsWithinList = targetChannelIndex >= 0;
4554

55+
if (lockChannelOrder) {
56+
return currentChannels;
57+
}
58+
4659
const newChannels = [...currentChannels];
4760

4861
if (targetChannelExistsWithinList) {
4962
newChannels.splice(targetChannelIndex, 1);
5063
}
5164

5265
// handle archiving (remove channel)
53-
if (typeof member.archived_at === 'string') {
66+
if (
67+
typeof member.archived_at === 'string' ||
68+
(filters && filters.archived === true && member.archived_at === null)
69+
) {
5470
return newChannels;
5571
}
5672
return currentChannels;

package/src/components/ChannelList/hooks/listeners/useNewMessage.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect } from 'react';
22

3-
import type { Channel, Event } from 'stream-chat';
3+
import type { Channel, ChannelFilters, Event } from 'stream-chat';
44

55
import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
66

@@ -16,9 +16,9 @@ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultSt
1616
lockChannelOrder: boolean,
1717
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
1818
event: Event<StreamChatGenerics>,
19-
considerArchivedChannels?: boolean,
19+
filters?: ChannelFilters<StreamChatGenerics>,
2020
) => void;
21-
considerArchivedChannels?: boolean;
21+
filters?: ChannelFilters<StreamChatGenerics>;
2222
};
2323

2424
export const useNewMessage = <
@@ -27,14 +27,14 @@ export const useNewMessage = <
2727
lockChannelOrder,
2828
onNewMessage,
2929
setChannels,
30-
considerArchivedChannels = false,
30+
filters,
3131
}: Parameters<StreamChatGenerics>) => {
3232
const { client } = useChatContext<StreamChatGenerics>();
3333

3434
useEffect(() => {
3535
const handleEvent = (event: Event<StreamChatGenerics>) => {
3636
if (typeof onNewMessage === 'function') {
37-
onNewMessage(lockChannelOrder, setChannels, event, considerArchivedChannels);
37+
onNewMessage(lockChannelOrder, setChannels, event, filters);
3838
} else {
3939
setChannels((channels) => {
4040
if (!channels) return channels;
@@ -46,6 +46,8 @@ export const useNewMessage = <
4646

4747
const isTargetChannelArchived = isChannelArchived(targetChannel);
4848

49+
const considerArchivedChannels = filters && filters.archived === false;
50+
4951
// If channel is archived and we don't want to consider archived channels, return existing list
5052
if (isTargetChannelArchived && considerArchivedChannels) {
5153
return channels;

package/src/components/ChannelList/hooks/listeners/useNewMessageNotification.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
22

33
import uniqBy from 'lodash/uniqBy';
44

5-
import type { Channel, Event } from 'stream-chat';
5+
import type { Channel, ChannelFilters, Event } from 'stream-chat';
66

77
import { useChatContext } from '../../../../contexts/chatContext/ChatContext';
88

@@ -16,23 +16,24 @@ type Parameters<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultSt
1616
onNewMessageNotification?: (
1717
setChannels: React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[] | null>>,
1818
event: Event<StreamChatGenerics>,
19+
filters?: ChannelFilters<StreamChatGenerics>,
1920
) => void;
20-
considerArchivedChannels?: boolean;
21+
filters?: ChannelFilters<StreamChatGenerics>;
2122
};
2223

2324
export const useNewMessageNotification = <
2425
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
2526
>({
26-
considerArchivedChannels = false,
2727
onNewMessageNotification,
2828
setChannels,
29+
filters,
2930
}: Parameters<StreamChatGenerics>) => {
3031
const { client } = useChatContext<StreamChatGenerics>();
3132

3233
useEffect(() => {
3334
const handleEvent = async (event: Event<StreamChatGenerics>) => {
3435
if (typeof onNewMessageNotification === 'function') {
35-
onNewMessageNotification(setChannels, event);
36+
onNewMessageNotification(setChannels, event, filters);
3637
} else {
3738
if (event.channel?.id && event.channel?.type) {
3839
const channel = await getChannel({
@@ -42,6 +43,7 @@ export const useNewMessageNotification = <
4243
});
4344

4445
// Handle archived channels
46+
const considerArchivedChannels = filters && filters.archived === false;
4547
if (isChannelArchived(channel) && considerArchivedChannels) {
4648
return;
4749
}

package/src/components/ChannelList/hooks/utils/index.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
import { Channel } from 'stream-chat';
22
import { DefaultStreamChatGenerics } from '../../../../types/types';
3-
import { ChannelListProps } from '../../ChannelList';
4-
5-
/**
6-
* Returns `true` only if `archived` property is set to `false` within `filters`.
7-
*/
8-
export const shouldConsiderArchivedChannels = <
9-
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
10-
>(
11-
filters: ChannelListProps<StreamChatGenerics>['filters'],
12-
) => {
13-
if (!filters) return false;
14-
15-
return !filters.archived;
16-
};
173

184
export const isChannelPinned = <
195
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,

0 commit comments

Comments
 (0)