feature(theme-shared): add loader-bar and error 500 component

pull/1562/head
mehmet-erim 6 years ago
parent a2d00356ac
commit 5e9d4d67ec

@ -0,0 +1,15 @@
.error {
position: fixed;
top: 0;
background-color: #fff;
width: 100vw;
height: 100vh;
z-index: 999999;
}
.centered {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

@ -0,0 +1,33 @@
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngxs/store';
@Component({
selector: 'abp-error-500',
template: `
<div class="error">
<div class="row centered">
<div class="col-md-12">
<div class="error-template">
<h1>
Oops!
</h1>
<div class="error-details">
Sorry, an error has occured.
</div>
<div class="error-actions">
<a routerLink="/" class="btn btn-primary btn-md mt-2"
><span class="glyphicon glyphicon-home"></span> Take Me Home
</a>
</div>
</div>
</div>
</div>
</div>
`,
styleUrls: ['error-500.component.scss'],
})
export class Error500Component implements OnInit {
constructor(private store: Store) {}
ngOnInit(): void {}
}

@ -0,0 +1,23 @@
.abp-loader-bar {
left: 0;
opacity: 0;
position: fixed;
top: 0;
transition: opacity 0.4s linear 0.4s;
z-index: 99999;
&.is-loading {
opacity: 1;
transition: none;
}
.abp-progress {
background: #77b6ff;
box-shadow: 0 0 10px rgba(119, 182, 255, 0.7);
height: 2px;
left: 0;
position: fixed;
top: 0;
transition: width 0.4s ease;
}
}

@ -0,0 +1,73 @@
import { Component, OnInit, Input } from '@angular/core';
import { Actions, ofActionSuccessful } from '@ngxs/store';
import { LoaderStart, LoaderStop } from '@abp/ng.core';
import { filter } from 'rxjs/operators';
@Component({
selector: 'abp-loader-bar',
template: `
<div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading">
<div [ngClass]="progressClass" [style.width.vw]="progressLevel"></div>
</div>
`,
styleUrls: ['./loader-bar.component.scss'],
})
export class LoaderBarComponent {
@Input()
containerClass: string = 'abp-loader-bar';
@Input()
progressClass: string = 'abp-progress';
@Input()
isLoading: boolean = false;
@Input()
filter = (action: LoaderStart | LoaderStop) => action.payload.url.indexOf('openid-configuration') < 0;
progressLevel: number = 0;
interval: any;
constructor(private actions: Actions) {
actions
.pipe(
ofActionSuccessful(LoaderStart, LoaderStop),
filter(this.filter),
)
.subscribe(action => {
if (action instanceof LoaderStart) {
this.startLoading();
} else {
this.stopLoading();
}
});
}
startLoading() {
this.isLoading = true;
const interval = setInterval(() => {
if (this.progressLevel < 75) {
this.progressLevel += Math.random() * 10;
} else if (this.progressLevel < 90) {
this.progressLevel += 0.4;
} else if (this.progressLevel < 100) {
this.progressLevel += 0.1;
} else {
clearInterval(interval);
}
}, 300);
this.interval = interval;
}
stopLoading() {
clearInterval(this.interval);
this.progressLevel = 100;
this.isLoading = false;
setTimeout(() => {
this.progressLevel = 0;
}, 800);
}
}

@ -1,11 +1,22 @@
import { RestOccurError } from '@abp/ng.core';
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import {
Injectable,
ApplicationRef,
ComponentFactoryResolver,
RendererFactory2,
Inject,
ReflectiveInjector,
Injector,
EmbeddedViewRef,
} from '@angular/core';
import { Navigate, RouterState } from '@ngxs/router-plugin';
import { Actions, ofActionSuccessful, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { Toaster } from '../models/toaster';
import { ConfirmationService } from '../services/confirmation.service';
import { DOCUMENT } from '@angular/common';
import { Error500Component } from '../components/errors/error-500.component';
const DEFAULTS = {
defaultError: {
@ -31,7 +42,15 @@ const DEFAULTS = {
@Injectable({ providedIn: 'root' })
export class ErrorHandler {
constructor(private actions: Actions, private store: Store, private confirmationService: ConfirmationService) {
constructor(
private actions: Actions,
private store: Store,
private confirmationService: ConfirmationService,
private appRef: ApplicationRef,
private cfRes: ComponentFactoryResolver,
private rendererFactory: RendererFactory2,
private injector: Injector,
) {
actions.pipe(ofActionSuccessful(RestOccurError)).subscribe(res => {
const { payload: err = {} as HttpErrorResponse | any } = res;
const body = (err as HttpErrorResponse).error.error;
@ -57,6 +76,14 @@ export class ErrorHandler {
case 404:
this.showError(DEFAULTS.defaultError404.details, DEFAULTS.defaultError404.message);
break;
case 500:
this.show500Component();
break;
case 0:
if ((err as HttpErrorResponse).statusText === 'Unknown Error') {
this.show500Component();
}
break;
default:
this.showError(DEFAULTS.defaultError.details, DEFAULTS.defaultError.message);
break;
@ -88,4 +115,12 @@ export class ErrorHandler {
}),
);
}
private show500Component() {
const renderer = this.rendererFactory.createRenderer(null, null);
const host = renderer.selectRootElement('app-root', true);
const componentRef = this.cfRes.resolveComponentFactory(Error500Component).create(this.injector);
this.appRef.attachView(componentRef.hostView);
renderer.appendChild(host, (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0]);
}
}

@ -11,6 +11,9 @@ import { ModalComponent } from './components/modal/modal.component';
import { ToastComponent } from './components/toast/toast.component';
import styles from './contants/styles';
import { ErrorHandler } from './handlers/error.handler';
import { Error500Component } from './components/errors/error-500.component';
import { LoaderBarComponent } from './components/loader-bar/loader-bar.component';
import { Options } from './models/options';
export function appendScript(injector: Injector) {
const fn = function() {
@ -39,11 +42,12 @@ export function appendScript(injector: Injector) {
targetSelector: '.form-group',
}),
],
declarations: [ConfirmationComponent, ToastComponent, ModalComponent],
exports: [NgbModalModule, ConfirmationComponent, ToastComponent, ModalComponent],
declarations: [ConfirmationComponent, ToastComponent, ModalComponent, Error500Component, LoaderBarComponent],
exports: [NgbModalModule, ConfirmationComponent, ToastComponent, ModalComponent, LoaderBarComponent],
entryComponents: [Error500Component],
})
export class ThemeSharedModule {
static forRoot(): ModuleWithProviders {
static forRoot(options = {} as Options): ModuleWithProviders {
return {
ngModule: ThemeSharedModule,
providers: [

Loading…
Cancel
Save