Skip to content

Commit

Permalink
Add alerts
Browse files Browse the repository at this point in the history
Replace error page navigation with alerts

Move alert feature into `client-shared` library

Remove duplicate material styles

Fix http response errors being displayed as empty text

Fix alert icons getting smaller on long error messages

Fix lint errors
  • Loading branch information
daniel-va committed May 16, 2024
1 parent 3ffb4f1 commit ae42ebe
Show file tree
Hide file tree
Showing 28 changed files with 496 additions and 118 deletions.
16 changes: 0 additions & 16 deletions apps/client-asset-sg/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,6 @@
{
"files": ["*.ts"],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "assetSg",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "asset-sg",
"style": "kebab-case"
}
],
"no-restricted-imports": [
"error",
{
Expand Down
9 changes: 6 additions & 3 deletions apps/client-asset-sg/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<asset-sg-app-bar>
<ng-template *ngIf="!router.url.includes('/error')" [cdkPortalOutlet]="appPortalService.appBarPortalContent$ | push"></ng-template>
<ng-template [cdkPortalOutlet]="appPortalService.appBarPortalContent$ | push"></ng-template>
</asset-sg-app-bar>
<asset-sg-menu-bar *ngIf="!router.url.includes('/error')"/>
<asset-sg-menu-bar />
<div class="router-outlet">
<router-outlet></router-outlet>
</div>
<div class="drawer-portal" *ngIf="!router.url.includes('/error')">
<div class="drawer-portal">
<ng-template [cdkPortalOutlet]="appPortalService.drawerPortalContent$ | push"></ng-template>
</div>
<div class="alerts">
<ul app-alert-list></ul>
</div>
14 changes: 14 additions & 0 deletions apps/client-asset-sg/src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,17 @@ asset-sg-menu-bar {
--viewport-width: min(calc(100vw - #{$menu-bar-width}), calc(1920px - #{$menu-bar-width}));
}
}

.alerts {
position: fixed;
width: min(30rem, 95vw);

bottom: 2rem;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;

/// angular-cdk-overlay is at 1000, so we go to 1500.
z-index: 1500;
}
18 changes: 2 additions & 16 deletions apps/client-asset-sg/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-transla
import { ForModule } from '@rx-angular/template/for';
import { LetModule } from '@rx-angular/template/let';
import { PushModule } from '@rx-angular/template/push';
import * as O from 'fp-ts/Option';
import * as C from 'io-ts/Codec';

import { AuthInterceptor, AuthModule } from '@asset-sg/auth';
import {
Expand All @@ -28,6 +26,7 @@ import {
currentLangFactory,
icons,
} from '@asset-sg/client-shared';
import { AlertModule } from '@asset-sg/client-shared/lib/features/alert/alert.module';
import { storeLogger } from '@asset-sg/core';

import { environment } from '../environments/environment';
Expand All @@ -36,7 +35,6 @@ import { adminGuard, editorGuard } from './app-guards';
import { assetsPageMatcher } from './app-matchers';
import { AppComponent } from './app.component';
import { AppBarComponent, MenuBarComponent, NotFoundComponent, RedirectToLangComponent } from './components';
import { ErrorComponent } from './components/error/error.component';
import { appTranslations } from './i18n';
import { AppSharedStateEffects } from './state';
import { appSharedStateReducer } from './state/app-shared.reducer';
Expand All @@ -50,7 +48,6 @@ registerLocaleData(locale_deCH, 'de-CH');
NotFoundComponent,
AppBarComponent,
MenuBarComponent,
ErrorComponent,
],
imports: [
BrowserModule,
Expand All @@ -75,10 +72,6 @@ registerLocaleData(locale_deCH, 'de-CH');
loadChildren: () => import('@asset-sg/asset-editor').then(m => m.AssetEditorModule),
canActivate: [editorGuard],
},
{
path: ':lang/error',
component: ErrorComponent,
},
{
matcher: assetsPageMatcher,
loadChildren: () => import('@asset-sg/asset-viewer').then(m => m.AssetViewerModule),
Expand Down Expand Up @@ -117,6 +110,7 @@ registerLocaleData(locale_deCH, 'de-CH');
DialogModule,
A11yModule,
AuthModule,
AlertModule,
],
providers: [
provideSvgIcons(icons),
Expand All @@ -137,11 +131,3 @@ export class AppModule {
export interface Encoder<O, A> {
readonly encode: (a: A) => O;
}

function optionFromNullable<O, A>(encoder: Encoder<O, A>): Encoder<O | null, O.Option<A>> {
return {
encode: O.fold(() => null, encoder.encode),
};
}

const foooobar = optionFromNullable(C.string);

This file was deleted.

13 changes: 0 additions & 13 deletions apps/client-asset-sg/src/app/components/error/error.component.scss

This file was deleted.

24 changes: 0 additions & 24 deletions apps/client-asset-sg/src/app/components/error/error.component.ts

This file was deleted.

26 changes: 3 additions & 23 deletions apps/client-asset-sg/src/mat-styles.scss
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
@use 'app/styles/variables';
@use 'app/styles/mixins' as mixins;
@use '@angular/material' as mat;
@use 'sass:map';

@include mat.core();

$asset-sg-palette: map.set(mat.$indigo-palette, 500, variables.$cyan-03);
@import 'theme';

$asset-sg-primary: mat.define-palette($asset-sg-palette);
$asset-sg-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
$asset-sg-warn: mat.define-palette(mat.$red-palette);
@include mat.core();

$asset-sg-theme: mat.define-light-theme(
(
color: (
primary: $asset-sg-primary,
accent: $asset-sg-accent,
warn: $asset-sg-warn,
),
)
);
@include mat.all-component-themes($asset-sg-theme);

@include mat.select-theme($asset-sg-theme);
.mat-mdc-select-value {
color: variables.$grey-09;
}
Expand Down Expand Up @@ -112,7 +98,6 @@ mat-option.mat-mdc-option {
}
}

@include mat.legacy-autocomplete-theme($asset-sg-theme);
.mat-autocomplete-panel .mat-option.mat-selected:not(.mat-active):not(:hover):not(.mat-option-disabled) {
color: inherit;
background-color: variables.$grey-01;
Expand All @@ -137,7 +122,6 @@ mat-option.mat-option {
}
}

@include mat.form-field-theme($asset-sg-theme);
.mat-mdc-form-field {
&:hover,
&.mat-focused {
Expand Down Expand Up @@ -230,7 +214,6 @@ mat-option.mat-option {
}
}

@include mat.datepicker-theme($asset-sg-theme);
button.mat-icon-button {
border-radius: 0;
background-color: white;
Expand Down Expand Up @@ -266,8 +249,6 @@ mat-datepicker-content.mat-datepicker-content .mat-calendar {
height: 24.5rem;
}

@include mat.progress-bar-theme($asset-sg-theme);
@include mat.radio-theme($asset-sg-theme);
.mat-mdc-radio-button.mat-accent {
--mdc-radio-selected-focus-icon-color: #{variables.$dark-red};
--mdc-radio-selected-hover-icon-color: #{variables.$dark-red};
Expand All @@ -276,7 +257,6 @@ mat-datepicker-content.mat-datepicker-content .mat-calendar {
--mat-mdc-radio-checked-ripple-color: #{variables.$dark-red};
}

@include mat.menu-theme($asset-sg-theme);
.mat-mdc-menu-item:hover:not([disabled]),
.mat-mdc-menu-item.cdk-program-focused:not([disabled]),
.mat-mdc-menu-item.cdk-keyboard-focused:not([disabled]),
Expand Down
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@use 'app/styles/variables';
@use './open-layers';


@font-face {
font-family: 'Inter';
font-style: normal;
Expand Down
21 changes: 21 additions & 0 deletions apps/client-asset-sg/src/theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@use 'app/styles/variables';
@use 'app/styles/mixins' as mixins;
@use '@angular/material' as mat;
@use 'sass:map';

$asset-sg-palette: map.set(mat.$indigo-palette, 500, variables.$cyan-03);

$asset-sg-primary: mat.define-palette($asset-sg-palette);
$asset-sg-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
$asset-sg-warn: mat.define-palette(mat.$red-palette);

$asset-sg-theme: mat.define-light-theme(
(
color: (
primary: $asset-sg-primary,
accent: $asset-sg-accent,
warn: $asset-sg-warn,
),
)
);

27 changes: 26 additions & 1 deletion libs/auth/src/lib/services/auth.interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { OAuthService } from 'angular-oauth2-oidc';
import { ResponseError } from 'ol/net';

Check warning on line 6 in libs/auth/src/lib/services/auth.interceptor.ts

View workflow job for this annotation

GitHub Actions / lint

'ResponseError' is defined but never used
import { EMPTY, Observable, catchError } from 'rxjs';

import { showAlert } from '@asset-sg/client-shared/lib/features/alert/alert.actions';
import { AlertType } from '@asset-sg/client-shared/lib/features/alert/alert.model';

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

intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
const token = sessionStorage.getItem('access_token');
Expand All @@ -30,7 +36,26 @@ export class AuthInterceptor implements HttpInterceptor {
} else {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
this._router.navigate(['de/error'], { state: { errorMessage: error.error.error } });
if (error.status === 401 || error.status === 403) {
this.store.dispatch(showAlert({
alert: {
id: `auth-error-${error.status}`,
text: error.error.error,
type: AlertType.Error,
isPersistent: true,
},
}));
} else {
console.log(error);
this.store.dispatch(showAlert({
alert: {
id: `request-error-${error.status}-${error.url}`,
text: error.error.message,
type: AlertType.Error,
isPersistent: true,
},
}));
}
return EMPTY;
}),
);
Expand Down
16 changes: 0 additions & 16 deletions libs/client-shared/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,6 @@
{
"files": ["*.ts"],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "assetSg",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "asset-sg",
"style": "kebab-case"
}
],
"@angular-eslint/no-host-metadata-property": "off",
"@angular-eslint/no-output-rename": "off",
"@typescript-eslint/member-ordering": "off"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<ng-container *ngFor="let entry of alerts$ | async; trackBy: getAlertId">
<li
app-alert
[alert]="entry.alert"
[metadata]="entry.metadata"
></li>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:host {
display: flex;
flex-direction: column;
gap: 0.5rem;

list-style: none;
margin: 0;
padding: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Component, inject } from '@angular/core';
import { Store } from '@ngrx/store';

import { AlertId } from '../alert.model';
import { AlertEntry, AlertState } from '../alert.reducer';
import { selectAlerts } from '../alert.selectors';

@Component({
selector: 'ul[app-alert-list]',
templateUrl: './alert-list.component.html',
styleUrls: ['./alert-list.component.scss'],
})
export class AlertListComponent {
private readonly store = inject(Store<AlertState>);
readonly alerts$ = this.store.select(selectAlerts);

getAlertId = (_index: number, entry: AlertEntry): AlertId => entry.alert.id;
}
10 changes: 10 additions & 0 deletions libs/client-shared/src/lib/features/alert/alert.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { createAction, props } from '@ngrx/store';

import { Alert, AlertId } from './alert.model';

export const showAlert = createAction('[Alert] Create Alert', props<{ alert: Alert }>());
export const hideAlert = createAction('[Alert] Remove Alert', props<{ id: AlertId }>());

export type AlertAction =
| typeof showAlert
| typeof hideAlert
Loading

0 comments on commit ae42ebe

Please sign in to comment.