Skip to content

Commit 5ecc331

Browse files
committed
fix: delay jumping to last read message to allow precedence to channelService.jumpToMessage
1 parent b00c85b commit 5ecc331

File tree

5 files changed

+40
-10
lines changed

5 files changed

+40
-10
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ describe('ChannelService', () => {
357357
service.usersTypingInChannel$.subscribe(typingUsersSpy);
358358
const typingUsersInThreadSpy = jasmine.createSpy();
359359
service.usersTypingInThread$.subscribe(typingUsersInThreadSpy);
360+
service.isMessageLoadingInProgress = true;
360361
messagesSpy.calls.reset();
361362
activeChannelSpy.calls.reset();
362363
messageToQuoteSpy.calls.reset();
@@ -386,6 +387,7 @@ describe('ChannelService', () => {
386387
(activeChannel as MockChannel).handleEvent('message.new', mockMessage());
387388

388389
expect(messagesSpy).not.toHaveBeenCalled();
390+
expect(service.isMessageLoadingInProgress).toBeFalse();
389391
});
390392

391393
it('should tell if user #hasMoreChannels$', async () => {
@@ -2177,7 +2179,11 @@ describe('ChannelService', () => {
21772179
service.activeChannelMessages$.subscribe(messagesSpy);
21782180
messagesSpy.calls.reset();
21792181
const messageId = '1232121123';
2180-
await service.jumpToMessage(messageId);
2182+
const response = service.jumpToMessage(messageId);
2183+
2184+
expect(service.isMessageLoadingInProgress).toBeTrue();
2185+
2186+
await response;
21812187

21822188
expect(jumpToMessageIdSpy).toHaveBeenCalledWith({
21832189
id: messageId,
@@ -2187,6 +2193,7 @@ describe('ChannelService', () => {
21872193
expect(messagesSpy).toHaveBeenCalledWith(
21882194
jasmine.arrayContaining([jasmine.objectContaining({ id: messageId })])
21892195
);
2196+
expect(service.isMessageLoadingInProgress).toBeFalse();
21902197
});
21912198

21922199
it(`should display error notification if message couldn't be loaded`, async () => {
@@ -2211,6 +2218,7 @@ describe('ChannelService', () => {
22112218
expect(notificationService.addTemporaryNotification).toHaveBeenCalledWith(
22122219
'streamChat.Message not found'
22132220
);
2221+
expect(service.isMessageLoadingInProgress).toBeFalse();
22142222
});
22152223

22162224
it('should pin message', async () => {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ export class ChannelService<
315315
* @internal
316316
*/
317317
static readonly MAX_MESSAGE_REACTIONS_TO_FETCH = 1200;
318+
/**
319+
* @internal
320+
*/
321+
isMessageLoadingInProgress = false;
318322
messagePageSize = 25;
319323
private channelsSubject = new BehaviorSubject<Channel<T>[] | undefined>(
320324
undefined
@@ -568,6 +572,7 @@ export class ChannelService<
568572
this.stopWatchForActiveChannelEvents(prevActiveChannel);
569573
this.flushMarkReadQueue();
570574
this.areReadEventsPaused = false;
575+
this.isMessageLoadingInProgress = false;
571576
const readState =
572577
channel.state.read[this.chatClientService.chatClient.user?.id || ''];
573578
this.activeChannelLastReadMessageId = readState?.last_read_message_id;
@@ -613,6 +618,7 @@ export class ChannelService<
613618
this.activeChannelLastReadMessageId = undefined;
614619
this.activeChannelUnreadCount = undefined;
615620
this.areReadEventsPaused = false;
621+
this.isMessageLoadingInProgress = false;
616622
}
617623

618624
/**
@@ -1268,6 +1274,7 @@ export class ChannelService<
12681274
* @param parentMessageId The ID of the parent message if we want to load a thread message
12691275
*/
12701276
async jumpToMessage(messageId: string, parentMessageId?: string) {
1277+
this.isMessageLoadingInProgress = true;
12711278
const activeChannel = this.activeChannelSubject.getValue();
12721279
try {
12731280
await activeChannel?.state.loadMessageIntoState(
@@ -1289,6 +1296,8 @@ export class ChannelService<
12891296
'streamChat.Message not found'
12901297
);
12911298
throw error;
1299+
} finally {
1300+
this.isMessageLoadingInProgress = false;
12921301
}
12931302
}
12941303

projects/stream-chat-angular/src/lib/message-list/message-list.component.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,7 @@ describe('MessageListComponent', () => {
10871087
expect(component['resetScrollState']).not.toHaveBeenCalled();
10881088
});
10891089

1090-
it('should jump to first unread message if openMessageListAt specifies', () => {
1090+
it('should jump to first unread message if openMessageListAt specifies', fakeAsync(() => {
10911091
component.openMessageListAt = 'last-read-message';
10921092

10931093
const channel = generateMockChannels()[0];
@@ -1097,6 +1097,7 @@ describe('MessageListComponent', () => {
10971097
messages[messages.length - 2].id;
10981098
channelServiceMock.activeChannel$.next(channel);
10991099
channelServiceMock.activeChannelMessages$.next(messages);
1100+
tick();
11001101

11011102
expect(component.lastReadMessageId).toBe(messages[messages.length - 2].id);
11021103

@@ -1105,7 +1106,7 @@ describe('MessageListComponent', () => {
11051106
);
11061107

11071108
expect(component.isJumpingToLatestUnreadMessage).toBeTrue();
1108-
});
1109+
}));
11091110

11101111
it('should display new message indicator - new mesage is the first on the given day', () => {
11111112
component.openMessageListAt = 'last-read-message';

projects/stream-chat-angular/src/lib/message-list/message-list.component.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,9 @@ export class MessageListComponent
197197
);
198198
this.subscriptions.push(
199199
this.channelService.activeChannel$.subscribe((channel) => {
200-
let isNewChannel = false;
200+
let wasChannelSwitch = false;
201201
if (this.channelId !== channel?.id) {
202-
isNewChannel = true;
202+
wasChannelSwitch = true;
203203
if (this.checkIfUnreadNotificationIsVisibleTimeout) {
204204
clearTimeout(this.checkIfUnreadNotificationIsVisibleTimeout);
205205
}
@@ -227,9 +227,18 @@ export class MessageListComponent
227227
) {
228228
this.lastReadMessageId = lastReadMessageId;
229229
this.unreadCount = unreadCount || 0;
230-
if (isNewChannel && this.lastReadMessageId) {
230+
if (wasChannelSwitch && this.lastReadMessageId) {
231+
// Delay jumping to last read message in case we need to give precedence to channelService.jumpToMessage
231232
if (this.openMessageListAt === 'last-read-message') {
232-
this.jumpToFirstUnreadMessage();
233+
setTimeout(() => {
234+
// Don't jump if a jump to a message was already started (using channelService.jumpToMessage)
235+
if (
236+
!this.isJumpingToMessage &&
237+
!this.channelService.isMessageLoadingInProgress
238+
) {
239+
this.jumpToFirstUnreadMessage();
240+
}
241+
}, 0);
233242
} else {
234243
// Wait till messages and the unread banner is rendered
235244
// If unread banner isn't visible on the screen, we display the unread notificaion
@@ -702,8 +711,9 @@ export class MessageListComponent
702711
const lastReadIndex = messages.findIndex(
703712
(m) => m.id === this.lastReadMessageId
704713
);
705-
this.firstUnreadMessageId =
706-
messages[lastReadIndex + 1]?.id || this.lastReadMessageId;
714+
if (lastReadIndex !== -1) {
715+
this.firstUnreadMessageId = messages[lastReadIndex + 1]?.id;
716+
}
707717
}
708718
}),
709719
tap(

projects/stream-chat-angular/src/lib/mocks/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,9 @@ export const mockChannelService = (): MockChannelService => {
310310
channel;
311311
};
312312

313-
const jumpToMessage = () => {};
313+
const jumpToMessage = () => {
314+
activeChannelMessages$.next(activeChannelMessages$.getValue());
315+
};
314316

315317
const clearMessageJump = () => {};
316318

0 commit comments

Comments
 (0)