Skip to content

Commit d0c5298

Browse files
author
Abigail Cabascango
committed
TTA-115 implement a stable, slow or offline connection warning
1 parent 399ac39 commit d0c5298

10 files changed

+258
-0
lines changed

src/app/app.component.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,13 @@
1+
<app-internet-connection-status listen="true">
2+
3+
<ng-container *fast>
4+
</ng-container>
5+
6+
<ng-container *slow>
7+
</ng-container>
8+
9+
<ng-container *offline>
10+
</ng-container>
11+
12+
</app-internet-connection-status>
113
<router-outlet></router-outlet>

src/app/app.module.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ import { SearchUserComponent } from './modules/shared/components/search-user/sea
9797
import { TimeRangeCustomComponent } from './modules/reports/components/time-range-custom/time-range-custom.component';
9898
import { TimeRangeHeaderComponent } from './modules/reports/components/time-range-custom/time-range-header/time-range-header.component';
9999
import { TimeRangeOptionsComponent } from './modules/reports/components/time-range-custom/time-range-options/time-range-options.component';
100+
import { InternetConnectionStatusComponent } from './modules/internet-connection-status/internet-connection-status.component';
101+
import { FastDirective} from './modules/internet-connection-status/internet-connection-directives/fast.directive';
102+
import { SlowDirective} from './modules/internet-connection-status/internet-connection-directives/slow.directive';
103+
import { OfflineDirective} from './modules/internet-connection-status/internet-connection-directives/offline.directive';
104+
import { ConnectionDirective } from './modules/internet-connection-status/internet-connection-directives/connection.directive';
105+
100106

101107
const maskConfig: Partial<IConfig> = {
102108
validation: false,
@@ -156,6 +162,11 @@ const maskConfig: Partial<IConfig> = {
156162
TimeRangeCustomComponent,
157163
TimeRangeHeaderComponent,
158164
TimeRangeOptionsComponent,
165+
InternetConnectionStatusComponent,
166+
SlowDirective,
167+
FastDirective,
168+
OfflineDirective,
169+
ConnectionDirective
159170
],
160171
imports: [
161172
NgxMaskModule.forRoot(maskConfig),
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Directive, Attribute, ElementRef, OnInit } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[appConnection]'
5+
})
6+
7+
export class ConnectionDirective implements OnInit {
8+
constructor(
9+
@Attribute('slowSrc') private slowSrc,
10+
@Attribute('fastSrc') private fastSrc,
11+
@Attribute('offlineSrc') private offlineSrc,
12+
private host: ElementRef<HTMLImageElement>
13+
) {
14+
}
15+
16+
ngOnInit() {
17+
const { effectiveType } = navigator.connection;
18+
let src;
19+
if (/\fast-5g|3g|4g/.test(effectiveType)) {
20+
src = this.fastSrc;
21+
}else if (/\slow-2g|2g/.test(effectiveType)) {
22+
src = this.slowSrc;
23+
}else {
24+
src = this.offlineSrc;
25+
}
26+
this.host.nativeElement.setAttribute('src', src);
27+
}
28+
29+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Directive, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[appFast]'
5+
})
6+
7+
export class FastDirective {
8+
9+
constructor(public tpl: TemplateRef<any>) { }
10+
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Directive, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[appOffline]'
5+
})
6+
7+
export class OfflineDirective {
8+
9+
constructor(public tpl: TemplateRef<any>) { }
10+
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Directive, TemplateRef } from '@angular/core';
2+
3+
@Directive({
4+
selector: '[appSlow]'
5+
})
6+
7+
export class SlowDirective {
8+
9+
constructor(public tpl: TemplateRef<any>) { }
10+
11+
}

src/app/modules/internet-connection-status/internet-connection-status.component.html

Whitespace-only changes.

src/app/modules/internet-connection-status/internet-connection-status.component.scss

Whitespace-only changes.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { InternetConnectionStatusComponent } from './internet-connection-status.component';
3+
import { ToastrService } from 'ngx-toastr';
4+
import { of } from 'rxjs';
5+
6+
describe('InternetConnectionStatusComponent', () => {
7+
let component: InternetConnectionStatusComponent;
8+
let fixture: ComponentFixture<InternetConnectionStatusComponent>;
9+
const toastrServiceStub = {
10+
error: () => {
11+
return 'test error';
12+
},
13+
warning: () => {
14+
return 'warning error';
15+
},
16+
success: () => {
17+
return 'success error';
18+
}
19+
};
20+
21+
beforeEach(async () => {
22+
await TestBed.configureTestingModule({
23+
declarations: [ InternetConnectionStatusComponent ],
24+
providers: [{ provide: ToastrService, useValue: toastrServiceStub }]
25+
})
26+
.compileComponents();
27+
});
28+
29+
beforeEach(() => {
30+
fixture = TestBed.createComponent(InternetConnectionStatusComponent);
31+
component = fixture.componentInstance;
32+
fixture.detectChanges();
33+
});
34+
35+
it('should show a stable connection warning', () => {
36+
component.connection$ = of('4g');
37+
fixture.detectChanges();
38+
component.ngOnInit();
39+
expect(component.isFast).toBe(true);
40+
});
41+
42+
it('should show a slow connection warning', () => {
43+
component.connection$ = of('2g');
44+
fixture.detectChanges();
45+
component.ngOnInit();
46+
expect(component.isFast).toBe(false);
47+
});
48+
49+
it('should show offline warning', () => {
50+
component.connection$ = of('Offline');
51+
fixture.detectChanges();
52+
component.ngOnInit();
53+
expect(component.isFast).toBe(false);
54+
});
55+
56+
it('should change the network type', () => {
57+
component.connection$ = of('5g');
58+
fixture.detectChanges();
59+
component.ngOnInit();
60+
component.connection$.subscribe((networkType: string) => {
61+
expect(networkType).toEqual('5g');
62+
});
63+
64+
jasmine.clock().install();
65+
jasmine.clock().tick(300);
66+
67+
component.connection$ = of('2g');
68+
fixture.detectChanges();
69+
console.log(window.navigator);
70+
component.connection$.subscribe((networkType: string) => {
71+
expect(networkType).toEqual('2g');
72+
});
73+
74+
jasmine.clock().uninstall();
75+
});
76+
77+
it('should return when window.navigator.connection is undefined', () => {
78+
const attributeCustome = '__defineGetter__';
79+
window.navigator[attributeCustome]('connection', () => {
80+
return undefined;
81+
});
82+
fixture = TestBed.createComponent(InternetConnectionStatusComponent);
83+
component = fixture.componentInstance;
84+
fixture.detectChanges();
85+
const statusInit = component.ngOnInit();
86+
expect(statusInit).toEqual(undefined);
87+
});
88+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { Component, OnInit, ContentChild, Attribute, OnDestroy} from '@angular/core';
2+
import { FastDirective} from '../../modules/internet-connection-status/internet-connection-directives/fast.directive';
3+
import { SlowDirective} from '../../modules/internet-connection-status/internet-connection-directives/slow.directive';
4+
import { OfflineDirective} from '../../modules/internet-connection-status/internet-connection-directives/offline.directive';
5+
import { Observable, of, Subscription } from 'rxjs';
6+
import { take, map } from 'rxjs/operators';
7+
import { ToastrService } from 'ngx-toastr';
8+
9+
type Connection = {
10+
effectiveType: string;
11+
};
12+
13+
declare global {
14+
interface Navigator {
15+
connection: {
16+
effectiveType: string;
17+
addEventListener: (a: any, b: any) => {};
18+
removeEventListener: (a: any, b: any) => {};
19+
};
20+
}
21+
}
22+
23+
24+
@Component({
25+
selector: 'app-internet-connection-status',
26+
templateUrl: './internet-connection-status.component.html',
27+
styleUrls: ['./internet-connection-status.component.scss']
28+
})
29+
export class InternetConnectionStatusComponent implements OnInit {
30+
isFast = true;
31+
connectionType: string;
32+
networkType: string;
33+
@ContentChild(FastDirective) fast: FastDirective;
34+
@ContentChild(SlowDirective) slow: SlowDirective;
35+
@ContentChild(OfflineDirective) offline: OfflineDirective;
36+
37+
private subscription: Subscription;
38+
39+
constructor(@Attribute('listen') private withChanges: boolean, private toastrService: ToastrService) {
40+
}
41+
42+
connection$ = new Observable((observer) => {
43+
const { effectiveType } = navigator.connection;
44+
observer.next(effectiveType);
45+
46+
const onConnectionChange = () => {
47+
this.networkType = navigator.connection.effectiveType;
48+
observer.next(this.networkType);
49+
};
50+
51+
navigator.connection.addEventListener('change', onConnectionChange);
52+
53+
return () => {
54+
navigator.connection.removeEventListener('change', onConnectionChange);
55+
observer.complete();
56+
};
57+
});
58+
59+
ngOnInit() {
60+
const connection = navigator.connection;
61+
console.log('navigator component', connection);
62+
if (!connection || !connection.effectiveType) {
63+
return;
64+
}
65+
66+
this.subscription = this.connection$
67+
.pipe(take(this.withChanges ? Number.POSITIVE_INFINITY : 1))
68+
.subscribe((effectiveType: string) => {
69+
70+
this.connectionType = effectiveType;
71+
72+
if (/\fast-5g|3g|4g/.test(effectiveType)){
73+
this.toastrService.success('You have a good connection');
74+
this.isFast = true;
75+
}else if (/\slow-2g|2g/.test(effectiveType)) {
76+
this.toastrService.warning('Caution your connection is slow');
77+
this.isFast = false;
78+
} else {
79+
this.toastrService.error('You are offline');
80+
this.isFast = false;
81+
}
82+
});
83+
}
84+
85+
}

0 commit comments

Comments
 (0)