Skip to content

Commit d43a3aa

Browse files
authored
Merge pull request #480 from GetStream/empty-channel-last-read-message
fix: notification.removed_from_channel immediately removes event hand…
2 parents 9a9c245 + 046de8c commit d43a3aa

File tree

2 files changed

+86
-25
lines changed

2 files changed

+86
-25
lines changed

projects/stream-chat-angular/src/lib/channel.service.spec.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,9 @@ describe('ChannelService', () => {
684684
let channels = spy.calls.mostRecent().args[0] as Channel[];
685685

686686
expect(channels.find((c) => c.cid === channel.cid)).toBeUndefined();
687-
expect(channel.stopWatching).toHaveBeenCalledWith();
687+
expect(channel.stopWatching).not.toHaveBeenCalledWith();
688688

689-
(channel as MockChannel).handleEvent('channel.hidden', {
689+
(channel as MockChannel).handleEvent('channel.visible', {
690690
type: 'channel.visible',
691691
channel,
692692
});
@@ -899,10 +899,15 @@ describe('ChannelService', () => {
899899

900900
it('should watch for channel events', async () => {
901901
const channel = generateMockChannels(1)[0];
902-
spyOn(channel, 'on').and.callThrough();
903-
await init([channel]);
902+
const unsubscribeSpy = jasmine.createSpy();
903+
spyOn(channel, 'on').and.returnValue({ unsubscribe: unsubscribeSpy });
904+
await init([channel], undefined, undefined, undefined, false);
904905

905906
expect(channel.on).toHaveBeenCalledWith(jasmine.any(Function));
907+
908+
service.reset();
909+
910+
expect(unsubscribeSpy).toHaveBeenCalledWith();
906911
});
907912

908913
it('should add the new channel to the top of the list, and start watching it, if user is added to a channel', fakeAsync(async () => {
@@ -993,16 +998,27 @@ describe('ChannelService', () => {
993998
mockChatClient.activeChannels[channel.cid] = channel;
994999
spyOn(channel, 'stopWatching');
9951000
spyOn(service, 'setAsActiveChannel');
1001+
9961002
events$.next({
9971003
eventType: 'notification.removed_from_channel',
9981004
event: { channel: channel } as any as Event<DefaultStreamChatGenerics>,
9991005
});
10001006

1001-
const channels = spy.calls.mostRecent().args[0] as Channel[];
1007+
let channels = spy.calls.mostRecent().args[0] as Channel[];
10021008

10031009
expect(channels.find((c) => c.cid === channel.cid)).toBeUndefined();
10041010
expect(service.setAsActiveChannel).not.toHaveBeenCalled();
10051011
expect(channel.stopWatching).toHaveBeenCalledWith();
1012+
1013+
// Check that new messages won't readd the channel to the list
1014+
(channel as MockChannel).handleEvent('message.new', {
1015+
id: 'new-message',
1016+
type: 'message.new',
1017+
});
1018+
1019+
channels = spy.calls.mostRecent().args[0] as Channel[];
1020+
1021+
expect(channels.find((c) => c.cid === channel.cid)).toBeUndefined();
10061022
});
10071023

10081024
it('should remove channel form the list if user is removed from channel, and emit new active channel', async () => {

projects/stream-chat-angular/src/lib/channel.service.ts

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -137,29 +137,41 @@ export class ChannelService<
137137
*/
138138
customNewMessageNotificationHandler?: (
139139
clientEvent: ClientEvent,
140-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void
140+
channelListSetter: (
141+
channels: (Channel<T> | ChannelResponse<T>)[],
142+
shouldStopWatchingRemovedChannels?: boolean
143+
) => void
141144
) => void;
142145
/**
143146
* Custom event handler to call when the user is added to a channel, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels)
144147
*/
145148
customAddedToChannelNotificationHandler?: (
146149
clientEvent: ClientEvent,
147-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void
150+
channelListSetter: (
151+
channels: (Channel<T> | ChannelResponse<T>)[],
152+
shouldStopWatchingRemovedChannels?: boolean
153+
) => void
148154
) => void;
149155
/**
150156
* Custom event handler to call when the user is removed from a channel, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels)
151157
*/
152158
customRemovedFromChannelNotificationHandler?: (
153159
clientEvent: ClientEvent,
154-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void
160+
channelListSetter: (
161+
channels: (Channel<T> | ChannelResponse<T>)[],
162+
shouldStopWatchingRemovedChannels?: boolean
163+
) => void
155164
) => void;
156165
/**
157166
* Custom event handler to call when a channel is deleted, provide an event handler if you want to override the [default channel list ordering](./ChannelService.mdx/#channels)
158167
*/
159168
customChannelDeletedHandler?: (
160169
event: Event,
161170
channel: Channel<T>,
162-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
171+
channelListSetter: (
172+
channels: (Channel<T> | ChannelResponse<T>)[],
173+
shouldStopWatchingRemovedChannels?: boolean
174+
) => void,
163175
messageListSetter: (messages: StreamMessage<T>[]) => void,
164176
threadListSetter: (messages: StreamMessage<T>[]) => void,
165177
parentMessageSetter: (message: StreamMessage<T> | undefined) => void
@@ -170,7 +182,10 @@ export class ChannelService<
170182
customChannelUpdatedHandler?: (
171183
event: Event,
172184
channel: Channel<T>,
173-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
185+
channelListSetter: (
186+
channels: (Channel<T> | ChannelResponse<T>)[],
187+
shouldStopWatchingRemovedChannels?: boolean
188+
) => void,
174189
messageListSetter: (messages: StreamMessage[]) => void,
175190
threadListSetter: (messages: StreamMessage[]) => void,
176191
parentMessageSetter: (message: StreamMessage | undefined) => void
@@ -181,7 +196,10 @@ export class ChannelService<
181196
customChannelTruncatedHandler?: (
182197
event: Event,
183198
channel: Channel<T>,
184-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
199+
channelListSetter: (
200+
channels: (Channel<T> | ChannelResponse<T>)[],
201+
shouldStopWatchingRemovedChannels?: boolean
202+
) => void,
185203
messageListSetter: (messages: StreamMessage<T>[]) => void,
186204
threadListSetter: (messages: StreamMessage<T>[]) => void,
187205
parentMessageSetter: (message: StreamMessage<T> | undefined) => void
@@ -192,7 +210,10 @@ export class ChannelService<
192210
customChannelHiddenHandler?: (
193211
event: Event,
194212
channel: Channel<T>,
195-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
213+
channelListSetter: (
214+
channels: (Channel<T> | ChannelResponse<T>)[],
215+
shouldStopWatchingRemovedChannels?: boolean
216+
) => void,
196217
messageListSetter: (messages: StreamMessage<T>[]) => void,
197218
threadListSetter: (messages: StreamMessage<T>[]) => void,
198219
parentMessageSetter: (message: StreamMessage<T> | undefined) => void
@@ -203,7 +224,10 @@ export class ChannelService<
203224
customChannelVisibleHandler?: (
204225
event: Event,
205226
channel: Channel<T>,
206-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
227+
channelListSetter: (
228+
channels: (Channel<T> | ChannelResponse<T>)[],
229+
shouldStopWatchingRemovedChannels?: boolean
230+
) => void,
207231
messageListSetter: (messages: StreamMessage<T>[]) => void,
208232
threadListSetter: (messages: StreamMessage<T>[]) => void,
209233
parentMessageSetter: (message: StreamMessage<T> | undefined) => void
@@ -214,7 +238,10 @@ export class ChannelService<
214238
customNewMessageHandler?: (
215239
event: Event,
216240
channel: Channel<T>,
217-
channelListSetter: (channels: (Channel<T> | ChannelResponse<T>)[]) => void,
241+
channelListSetter: (
242+
channels: (Channel<T> | ChannelResponse<T>)[],
243+
shouldStopWatchingRemovedChannels?: boolean
244+
) => void,
218245
messageListSetter: (messages: StreamMessage<T>[]) => void,
219246
threadListSetter: (messages: StreamMessage<T>[]) => void,
220247
parentMessageSetter: (message: StreamMessage<T> | undefined) => void
@@ -258,6 +285,7 @@ export class ChannelService<
258285
>([]);
259286
private hasMoreChannelsSubject = new ReplaySubject<boolean>(1);
260287
private activeChannelSubscriptions: { unsubscribe: () => void }[] = [];
288+
private channelSubscriptions: { [key: string]: () => void } = {};
261289
private activeParentMessageIdSubject = new BehaviorSubject<
262290
string | undefined
263291
>(undefined);
@@ -295,7 +323,8 @@ export class ChannelService<
295323
>(undefined);
296324

297325
private channelListSetter = (
298-
channels: (Channel<T> | ChannelResponse<T>)[]
326+
channels: (Channel<T> | ChannelResponse<T>)[],
327+
shouldStopWatchingRemovedChannels = true
299328
) => {
300329
const currentChannels = this.channelsSubject.getValue() || [];
301330
const newChannels = channels.filter(
@@ -305,7 +334,10 @@ export class ChannelService<
305334
(c) => !channels?.find((channel) => channel.cid === c.cid)
306335
);
307336
void this.addChannelsFromNotification(newChannels as ChannelResponse<T>[]);
308-
this.removeChannelsFromChannelList(deletedChannels.map((c) => c.cid));
337+
this.removeChannelsFromChannelList(
338+
deletedChannels.map((c) => c.cid),
339+
shouldStopWatchingRemovedChannels
340+
);
309341
};
310342

311343
private messageListSetter = (messages: StreamMessage<T>[]) => {
@@ -602,6 +634,10 @@ export class ChannelService<
602634
this.clientEventsSubscription?.unsubscribe();
603635
this.dismissErrorNotification?.();
604636
this.dismissErrorNotification = undefined;
637+
Object.keys(this.channelSubscriptions).forEach((cid) => {
638+
this.channelSubscriptions[cid]();
639+
});
640+
this.channelSubscriptions = {};
605641
}
606642

607643
/**
@@ -1074,7 +1110,7 @@ export class ChannelService<
10741110

10751111
private handleRemovedFromChannelNotification(clientEvent: ClientEvent<T>) {
10761112
const channelIdToBeRemoved = clientEvent.event.channel!.cid;
1077-
this.removeChannelsFromChannelList([channelIdToBeRemoved]);
1113+
this.removeChannelsFromChannelList([channelIdToBeRemoved], true);
10781114
}
10791115

10801116
private handleNewMessageNotification(clientEvent: ClientEvent<T>) {
@@ -1113,14 +1149,22 @@ export class ChannelService<
11131149
}
11141150
}
11151151

1116-
private removeChannelsFromChannelList(cids: string[]) {
1152+
private removeChannelsFromChannelList(
1153+
cids: string[],
1154+
shouldStopWatching: boolean
1155+
) {
11171156
const channels = this.channels.filter((c) => !cids.includes(c.cid || ''));
1118-
cids.forEach(
1119-
(cid) =>
1157+
if (shouldStopWatching) {
1158+
cids.forEach((cid) => {
1159+
if (this.channelSubscriptions[cid]) {
1160+
this.channelSubscriptions[cid]();
1161+
delete this.channelSubscriptions.cid;
1162+
}
11201163
void this.chatClientService.chatClient.activeChannels[
11211164
cid
1122-
]?.stopWatching()
1123-
);
1165+
]?.stopWatching();
1166+
});
1167+
}
11241168
if (channels.length < this.channels.length) {
11251169
this.channelsSubject.next(channels);
11261170
if (cids.includes(this.activeChannelSubject.getValue()?.cid || '')) {
@@ -1370,7 +1414,7 @@ export class ChannelService<
13701414
}
13711415

13721416
private watchForChannelEvents(channel: Channel<T>) {
1373-
channel.on((event: Event<T>) => {
1417+
const unsubscribe = channel.on((event: Event<T>) => {
13741418
switch (event.type) {
13751419
case 'message.new': {
13761420
this.ngZone.run(() => {
@@ -1476,6 +1520,7 @@ export class ChannelService<
14761520
}
14771521
}
14781522
});
1523+
this.channelSubscriptions[channel.cid] = unsubscribe.unsubscribe;
14791524
}
14801525

14811526
private handleNewMessage(_: Event, channel: Channel<T>) {
@@ -1485,11 +1530,11 @@ export class ChannelService<
14851530
}
14861531

14871532
private handleChannelHidden(event: Event) {
1488-
this.removeChannelsFromChannelList([event.channel!.cid]);
1533+
this.removeChannelsFromChannelList([event.channel!.cid], false);
14891534
}
14901535

14911536
private handleChannelDeleted(event: Event) {
1492-
this.removeChannelsFromChannelList([event.channel!.cid]);
1537+
this.removeChannelsFromChannelList([event.channel!.cid], true);
14931538
}
14941539

14951540
private handleChannelVisible(event: Event, channel: Channel<T>) {

0 commit comments

Comments
 (0)