Skip to content

Commit d1326ab

Browse files
committed
feat: recoverState method to allow SDK components to initiate state recovery
1 parent d101694 commit d1326ab

File tree

8 files changed

+205
-83
lines changed

8 files changed

+205
-83
lines changed

projects/stream-chat-angular/src/assets/i18n/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,6 @@ export const en = {
131131
'You currently have {{count}} attachments, the maximum is {{max}}':
132132
'You currently have {{count}} attachments, the maximum is {{max}}',
133133
'and others': 'and others',
134+
'Reload channels': 'Reload channels',
134135
},
135136
};

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,13 @@
4646
</div>
4747
} @else {
4848
@if (isError$ | async) {
49-
<div data-testid="chatdown-container" class="str-chat__down">
50-
<ng-container *ngTemplateOutlet="loadingChannels" />
49+
<div
50+
data-testid="chatdown-container"
51+
class="str-chat__dow str-chat__channel-list-empty"
52+
>
53+
<button (click)="recoverState()" class="str-chat__cta-button">
54+
{{ "streamChat.Reload channels" | translate }}
55+
</button>
5156
</div>
5257
}
5358
@if (isInitializing$ | async) {

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,7 @@ describe('ChannelListComponent', () => {
8484
it('should display error indicator, if error happened', () => {
8585
expect(queryChatdownContainer()).toBeNull();
8686

87-
channelServiceMock.channelQueryState$.next({
88-
state: 'error',
89-
error: new Error('error'),
90-
});
87+
channelServiceMock.shouldRecoverState$.next(true);
9188
fixture.detectChanges();
9289

9390
expect(queryChatdownContainer()).not.toBeNull();

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ export class ChannelListComponent implements OnDestroy {
3333
this.theme$ = this.themeService.theme$;
3434
this.channels$ = this.channelService.channels$;
3535
this.hasMoreChannels$ = this.channelService.hasMoreChannels$;
36-
this.isError$ = this.channelService.channelQueryState$.pipe(
37-
map((s) => !this.isLoadingMoreChannels && s?.state === 'error'),
38-
);
36+
this.isError$ = this.channelService.shouldRecoverState$;
3937
this.isInitializing$ = this.channelService.channelQueryState$.pipe(
4038
map((s) => !this.isLoadingMoreChannels && s?.state === 'in-progress'),
4139
);
@@ -56,6 +54,10 @@ export class ChannelListComponent implements OnDestroy {
5654
this.isLoadingMoreChannels = false;
5755
}
5856

57+
recoverState() {
58+
void this.channelService.recoverState();
59+
}
60+
5961
trackByChannelId(_: number, item: Channel<DefaultStreamChatGenerics>) {
6062
return item.cid;
6163
}

projects/stream-chat-angular/src/lib/channel-preview/channel-preview.component.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input, NgZone, OnDestroy, OnInit } from '@angular/core';
1+
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
22
import { Subscription } from 'rxjs';
33
import { filter } from 'rxjs/operators';
44
import { Channel, Event, FormatMessageResponse } from 'stream-chat';
@@ -41,7 +41,6 @@ export class ChannelPreviewComponent implements OnInit, OnDestroy {
4141

4242
constructor(
4343
private channelService: ChannelService,
44-
private ngZone: NgZone,
4544
private chatClientService: ChatClientService,
4645
messageService: MessageService,
4746
public customTemplatesService: CustomTemplatesService,

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,9 @@ describe('ChannelService', () => {
18411841
});
18421842

18431843
it('should reset state after connection recovered', async () => {
1844+
const spy = jasmine.createSpy();
1845+
service.shouldRecoverState$.subscribe(spy);
1846+
spy.calls.reset();
18441847
await init();
18451848
mockChatClient.queryChannels.calls.reset();
18461849
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
@@ -1851,6 +1854,8 @@ describe('ChannelService', () => {
18511854
jasmine.any(Object),
18521855
jasmine.any(Object),
18531856
);
1857+
1858+
expect(spy).not.toHaveBeenCalled();
18541859
});
18551860

18561861
it(`shouldn't do duplicate state reset after connection recovered`, async () => {
@@ -2414,4 +2419,52 @@ describe('ChannelService', () => {
24142419

24152420
expect(activeChannel.markRead).toHaveBeenCalledTimes(2);
24162421
});
2422+
2423+
it('should signal if state recovery is needed - initial load', async () => {
2424+
const spy = jasmine.createSpy();
2425+
service.shouldRecoverState$.subscribe(spy);
2426+
2427+
expect(spy).toHaveBeenCalledWith(false);
2428+
spy.calls.reset();
2429+
const error = 'there was an error';
2430+
2431+
await expectAsync(
2432+
init(undefined, undefined, undefined, () =>
2433+
mockChatClient.queryChannels.and.rejectWith(error),
2434+
),
2435+
).toBeRejectedWith(error);
2436+
2437+
expect(spy).toHaveBeenCalledWith(true);
2438+
2439+
spy.calls.reset();
2440+
mockChatClient.queryChannels.and.resolveTo([]);
2441+
await service.recoverState();
2442+
2443+
expect(spy).toHaveBeenCalledWith(false);
2444+
});
2445+
2446+
it('should signal if state recovery is needed - failed state recover after connection.recovered', fakeAsync(() => {
2447+
void init();
2448+
tick();
2449+
const spy = jasmine.createSpy();
2450+
service.shouldRecoverState$.subscribe(spy);
2451+
spy.calls.reset();
2452+
mockChatClient.queryChannels.and.rejectWith(
2453+
new Error('there was an error'),
2454+
);
2455+
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
2456+
2457+
tick();
2458+
flush();
2459+
2460+
expect(spy).toHaveBeenCalledWith(true);
2461+
2462+
spy.calls.reset();
2463+
mockChatClient.queryChannels.and.resolveTo([]);
2464+
void service.recoverState();
2465+
tick();
2466+
flush();
2467+
2468+
expect(spy).toHaveBeenCalledWith(false);
2469+
}));
24172470
});

0 commit comments

Comments
 (0)