Skip to content

Commit

Permalink
Re-add error page
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-va committed May 22, 2024
1 parent 2b73ce1 commit 1544c53
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 86 deletions.
33 changes: 23 additions & 10 deletions apps/client-asset-sg/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
<asset-sg-app-bar>
<ng-template [cdkPortalOutlet]="appPortalService.appBarPortalContent$ | push"></ng-template>
</asset-sg-app-bar>
<asset-sg-menu-bar />
<div class="router-outlet">
<router-outlet></router-outlet>
</div>
<div class="drawer-portal">
<ng-template [cdkPortalOutlet]="appPortalService.drawerPortalContent$ | push"></ng-template>
</div>
<ng-container *ngIf="errorService.onMessage | async as error; else content">
<asset-sg-app-bar />
<div class="error">
<span>{{error}}</span>
<button asset-sg-warn (click)="authService.logOut()">
Logout
</button>
</div>
</ng-container>

<ng-template #content>
<asset-sg-app-bar>
<ng-template [cdkPortalOutlet]="appPortalService.appBarPortalContent$ | push"></ng-template>
</asset-sg-app-bar>
<asset-sg-menu-bar />
<div class="router-outlet">
<router-outlet></router-outlet>
</div>
<div class="drawer-portal">
<ng-template [cdkPortalOutlet]="appPortalService.drawerPortalContent$ | push"></ng-template>
</div>
</ng-template>

<div class="alerts">
<ul app-alert-list></ul>
</div>
16 changes: 16 additions & 0 deletions apps/client-asset-sg/src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@use 'styles/variables';
@use '@angular/material' as mat;
@use '../theme' as *;

$app-bar-height: 88px;
$menu-bar-width: 80px;
Expand Down Expand Up @@ -44,6 +46,20 @@ asset-sg-menu-bar {
}
}

.error {
display: flex;
flex-direction: column;
gap: 20px;
grid-column: 1 / -1;
padding: 40px;
align-items: center;
font-size: 24px;
font-weight: bolder;

color: mat.get-contrast-color-from-palette($asset-sg-warn, 500);
background-color: mat.get-color-from-palette($asset-sg-warn, 600);
}

.alerts {
position: fixed;
width: min(30rem, 95vw);
Expand Down
6 changes: 5 additions & 1 deletion apps/client-asset-sg/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { debounceTime, fromEvent, map, startWith } from 'rxjs';
import { assert } from 'tsafe';

import { AuthService } from '@asset-sg/auth';
import { ErrorService } from '@asset-sg/auth';
import { AppPortalService, appSharedStateActions, setCssCustomProperties } from '@asset-sg/client-shared';

import { AppState } from './state/app-state';
Expand All @@ -25,7 +26,10 @@ export class AppComponent {
private _httpClient = inject(HttpClient);
public appPortalService = inject(AppPortalService);
private store = inject(Store<AppState>);
public readonly router: Router = inject(Router);

readonly router: Router = inject(Router);
readonly errorService = inject(ErrorService);
readonly authService = inject(AuthService);

constructor(private readonly _authService: AuthService) {
this._httpClient
Expand Down
2 changes: 2 additions & 0 deletions apps/client-asset-sg/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { LetModule } from '@rx-angular/template/let';
import { PushModule } from '@rx-angular/template/push';

import { AuthInterceptor, AuthModule } from '@asset-sg/auth';
import { ErrorService } from '@asset-sg/auth';
import {
AnchorComponent,
ButtonComponent,
Expand Down Expand Up @@ -114,6 +115,7 @@ registerLocaleData(locale_deCH, 'de-CH');
],
providers: [
provideSvgIcons(icons),
ErrorService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'fill', floatLabel: 'auto' } },
{ provide: CURRENT_LANG, useFactory: currentLangFactory },
Expand Down
1 change: 1 addition & 0 deletions libs/auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './lib/auth.module';
export * from './lib/services/auth.interceptor';
export * from './lib/services/auth.service';
export * from './lib/services/error.service';
7 changes: 6 additions & 1 deletion libs/auth/src/lib/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { OAuthModule } from 'angular-oauth2-oidc';

import { AnchorComponent, ButtonComponent, icons } from '@asset-sg/client-shared';

import { ErrorService } from './services/error.service';


@NgModule({
imports: [
Expand Down Expand Up @@ -44,6 +46,9 @@ import { AnchorComponent, ButtonComponent, icons } from '@asset-sg/client-shared
}),
],
exports: [OAuthModule],
providers: [provideSvgIcons(icons)],
providers: [
provideSvgIcons(icons),
ErrorService,
],
})
export class AuthModule {}
8 changes: 6 additions & 2 deletions libs/auth/src/lib/services/auth.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { EMPTY, Observable, catchError } from 'rxjs';

import { AlertType, showAlert } from '@asset-sg/client-shared';

import { ErrorService } from './error.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
private _oauthService = inject(OAuthService);
private _router: Router = inject(Router);
private readonly store = inject(Store);
private readonly errorService = inject(ErrorService);

intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
const token = sessionStorage.getItem('access_token');
Expand All @@ -34,7 +37,9 @@ export class AuthInterceptor implements HttpInterceptor {
} else {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401 || error.status === 403) {
if (error.status === 403) {
this.errorService.updateMessage(error.error.error);
} else if (error.status === 401) {
this.store.dispatch(showAlert({
alert: {
id: `auth-error-${error.status}`,
Expand All @@ -44,7 +49,6 @@ export class AuthInterceptor implements HttpInterceptor {
},
}));
} else {
console.log(error);
this.store.dispatch(showAlert({
alert: {
id: `request-error-${error.status}-${error.url}`,
Expand Down
19 changes: 19 additions & 0 deletions libs/auth/src/lib/services/error.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class ErrorService {
private message$ = new BehaviorSubject<string | null>(null);

get onMessage(): Observable<string | null> {
return this.message$.asObservable();
}

updateMessage(message: string) {
this.message$.next(message);
}

clear(): void {
this.message$.next(null);
}
}
144 changes: 72 additions & 72 deletions libs/client-shared/src/lib/components/button/button.component.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,72 @@
import { FocusMonitor } from '@angular/cdk/a11y';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostBinding,
Input,
OnDestroy,
inject,
} from '@angular/core';

@Component({
standalone: true,
selector:
// eslint-disable-next-line @angular-eslint/component-selector
'button[asset-sg-reset], button[asset-sg-icon-button], button[asset-sg-primary], button[asset-sg-secondary], button[asset-sg-icon-button-tw]',
template: '<ng-content></ng-content>',
styleUrls: ['./button.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ButtonComponent implements AfterViewInit, OnDestroy {
protected _host = inject<ElementRef<HTMLElement>>(ElementRef);
private _focusMonitor = inject(FocusMonitor);
private _cd = inject(ChangeDetectorRef);

constructor() {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'attributes') {
if (this._host.nativeElement.attributes.getNamedItem('asset-sg-icon-button-tw')) {
this._classes = 'bg-white';
this._cd.detectChanges();
}
}
});
});

observer.observe(this._host.nativeElement, {
attributes: true, //configure it to listen to attribute changes
});
// console.log(this._host.nativeElement.attributes);
}

@HostBinding('class')
private _classes: string | undefined;

private _disabled: true | undefined;
@HostBinding('[attr.disabled]')
@HostBinding('[attr.aria-disabled]')
@Input()
get disabled(): true | false | undefined {
return this._disabled;
}
set disabled(value: BooleanInput) {
this._disabled = coerceBooleanProperty(value) || undefined;
}

@HostBinding('attr.type')
@Input()
public type = this._host.nativeElement.tagName === 'BUTTON' ? 'button' : undefined;

ngAfterViewInit() {
this._focusMonitor.monitor(this._host, false);
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._host);
}
}
import { FocusMonitor } from '@angular/cdk/a11y';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostBinding,
Input,
OnDestroy,
inject,
} from '@angular/core';

@Component({
standalone: true,
selector:
// eslint-disable-next-line @angular-eslint/component-selector
'button[asset-sg-reset], button[asset-sg-icon-button], button[asset-sg-primary], button[asset-sg-warn], button[asset-sg-secondary], button[asset-sg-icon-button-tw]',
template: '<ng-content></ng-content>',
styleUrls: ['./button.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ButtonComponent implements AfterViewInit, OnDestroy {
protected _host = inject<ElementRef<HTMLElement>>(ElementRef);
private _focusMonitor = inject(FocusMonitor);
private _cd = inject(ChangeDetectorRef);

constructor() {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'attributes') {
if (this._host.nativeElement.attributes.getNamedItem('asset-sg-icon-button-tw')) {
this._classes = 'bg-white';
this._cd.detectChanges();
}
}
});
});

observer.observe(this._host.nativeElement, {
attributes: true, //configure it to listen to attribute changes
});
// console.log(this._host.nativeElement.attributes);
}

@HostBinding('class')
private _classes: string | undefined;

private _disabled: true | undefined;
@HostBinding('[attr.disabled]')
@HostBinding('[attr.aria-disabled]')
@Input()
get disabled(): true | false | undefined {
return this._disabled;
}
set disabled(value: BooleanInput) {
this._disabled = coerceBooleanProperty(value) || undefined;
}

@HostBinding('attr.type')
@Input()
public type = this._host.nativeElement.tagName === 'BUTTON' ? 'button' : undefined;

ngAfterViewInit() {
this._focusMonitor.monitor(this._host, false);
}

ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._host);
}
}

0 comments on commit 1544c53

Please sign in to comment.