Skip to content

Commit d81fa19

Browse files
committed
feat: Add loading indicator to message list
1 parent cb79823 commit d81fa19

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
replies' | translate:replyCountParam)}}
2424
</div>
2525
</li>
26+
<stream-loading-indicator
27+
data-testid="top-loading-indicator"
28+
*ngIf="isLoading && direction === 'bottom-to-top'"
29+
></stream-loading-indicator>
2630
<li
2731
tabindex="0"
2832
data-testclass="message"
@@ -41,6 +45,10 @@
4145
"
4246
></ng-container>
4347
</li>
48+
<stream-loading-indicator
49+
data-testid="bottom-loading-indicator"
50+
*ngIf="isLoading && direction === 'top-to-bottom'"
51+
></stream-loading-indicator>
4452
</ul>
4553
<ng-template #defaultTypingIndicator let-usersTyping$="usersTyping$">
4654
<!-- eslint-disable-next-line @angular-eslint/template/no-any -->

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ describe('MessageListComponent', () => {
4040
let queryParentMessageReplyCount: () => HTMLElement | null;
4141
let queryTypingIndicator: () => HTMLElement | null;
4242
let queryTypingUsers: () => HTMLElement | null;
43+
let queryLoadingIndicator: (pos: 'top' | 'bottom') => HTMLElement | null;
4344

4445
beforeEach(() => {
4546
channelServiceMock = mockChannelService();
@@ -90,6 +91,8 @@ describe('MessageListComponent', () => {
9091
nativeElement.querySelector('[data-testid="typing-users"]');
9192
queryParentMessageReplyCount = () =>
9293
nativeElement.querySelector('[data-testid="reply-count"]');
94+
queryLoadingIndicator = (pos: 'top' | 'bottom') =>
95+
nativeElement.querySelector(`[data-testid="${pos}-loading-indicator"]`);
9396
TestBed.inject(StreamI18nService).setTranslation('en');
9497
fixture.detectChanges();
9598
const scrollContainer = queryScrollContainer()!;
@@ -870,4 +873,41 @@ describe('MessageListComponent', () => {
870873
);
871874
});
872875
});
876+
877+
it('should set isLoading flag', () => {
878+
expect(component.isLoading).toBeFalse();
879+
880+
const scrollContainer = queryScrollContainer()!;
881+
scrollContainer.scrollTo({ top: 0 });
882+
scrollContainer.dispatchEvent(new Event('scroll'));
883+
fixture.detectChanges();
884+
885+
expect(component.isLoading).toBeTrue();
886+
887+
channelServiceMock.activeChannelMessages$.next(generateMockMessages());
888+
889+
expect(component.isLoading).toBeFalse();
890+
});
891+
892+
it('should display loading indicator', () => {
893+
component.isLoading = false;
894+
fixture.detectChanges();
895+
896+
expect(queryLoadingIndicator('top')).toBeNull();
897+
expect(queryLoadingIndicator('bottom')).toBeNull();
898+
899+
component.direction = 'top-to-bottom';
900+
component.isLoading = true;
901+
fixture.detectChanges();
902+
903+
expect(queryLoadingIndicator('top')).toBeNull();
904+
expect(queryLoadingIndicator('bottom')).not.toBeNull();
905+
906+
component.direction = 'bottom-to-top';
907+
component.isLoading = true;
908+
fixture.detectChanges();
909+
910+
expect(queryLoadingIndicator('top')).not.toBeNull();
911+
expect(queryLoadingIndicator('bottom')).toBeNull();
912+
});
873913
});

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export class MessageListComponent
5858
lastSentMessageId: string | undefined;
5959
parentMessage: StreamMessage | undefined;
6060
highlightedMessageId: string | undefined;
61+
isLoading = false;
6162
@ViewChild('scrollContainer')
6263
private scrollContainer!: ElementRef<HTMLElement>;
6364
@ViewChild('parentMessageElement')
@@ -276,6 +277,7 @@ export class MessageListComponent
276277
this.mode === 'main'
277278
? void this.channelService.loadMoreMessages(direction)
278279
: void this.channelService.loadMoreThreadReplies(direction);
280+
this.isLoading = true;
279281
}
280282
this.prevScrollTop = this.scrollContainer.nativeElement.scrollTop;
281283
}
@@ -346,6 +348,7 @@ export class MessageListComponent
346348
: this.channelService.activeThreadMessages$
347349
).pipe(
348350
tap((messages) => {
351+
this.isLoading = false;
349352
if (messages.length === 0) {
350353
return;
351354
}

0 commit comments

Comments
 (0)