[frontend] Add initial design for dashboard

This commit is contained in:
Cathy Hu 2020-08-24 15:36:23 +02:00
parent 75df2e8cf6
commit 7ce824ea8e
39 changed files with 460 additions and 64 deletions

View file

@ -19,6 +19,7 @@ import { ReactiveFormsModule } from '@angular/forms';
import { AuthTokenInterceptor } from './core/auth/auth-token.interceptor';
import { ConfirmComponent } from './auth/confirm/confirm.component';
import { ErrorInterceptor } from './core/auth/error.interceptor';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [
@ -39,6 +40,7 @@ import { ErrorInterceptor } from './core/auth/error.interceptor';
ApiModule,
HttpClientModule,
ReactiveFormsModule,
BrowserAnimationsModule,
],
providers: [
{ provide: BASE_PATH, useValue: environment.API_BASE_PATH },

View file

@ -4,6 +4,7 @@ import {
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse,
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { LoginService } from './login.service';
@ -19,10 +20,15 @@ export class ErrorInterceptor implements HttpInterceptor {
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((err) => {
if (err.status === 401) {
catchError((err: HttpErrorResponse) => {
if (err.error instanceof ProgressEvent) {
// TODO Add spinner/overlay in app to prevent user input
console.log('Networkerror');
} else if (err.status === 401) {
this.loginService.logout();
location.reload(true);
} else if (err.status === 404) {
this.router.navigate(['/404']);
}
const error = err.error.message || err.statusText;
return throwError(error);

View file

@ -0,0 +1,18 @@
<div class="dashboard">
<mat-card>
<mat-card-title> Dashboard: {{ (hood$ | async).name }} </mat-card-title>
<mat-card-subtitle>Lorem ipsum</mat-card-subtitle>
</mat-card>
<mat-tab-group>
<mat-tab label="Overview">
<app-hoodsettings [hoodId]="hoodId"> </app-hoodsettings>
</mat-tab>
<mat-tab label="Platforms">
<app-platforms></app-platforms>
</mat-tab>
<mat-tab label="Hoodpage">
<app-hoodpage></app-hoodpage>
</mat-tab>
</mat-tab-group>
</div>

View file

@ -0,0 +1,7 @@
.mat-card {
box-shadow: none;
}
.dashboard {
margin: 10px;
}

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BoardComponent } from './board.component';
describe('BoardComponent', () => {
let component: BoardComponent;
let fixture: ComponentFixture<BoardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [BoardComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BoardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HoodsService, BodyHood } from 'src/app/core/api';
import { first } from 'rxjs/operators';
import { Observable } from 'rxjs';
@Component({
selector: 'app-board',
templateUrl: './board.component.html',
styleUrls: ['./board.component.scss'],
})
export class BoardComponent implements OnInit {
hoodId: number;
hood$: Observable<BodyHood>;
constructor(
private route: ActivatedRoute,
private hoodService: HoodsService
) {}
ngOnInit(): void {
this.hoodId = this.route.snapshot.params['id'];
this.hood$ = this.hoodService.getHood(this.hoodId);
}
}

View file

@ -0,0 +1 @@
<p>hoodpage works!</p>

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HoodpageComponent } from './hoodpage.component';
describe('HoodpageComponent', () => {
let component: HoodpageComponent;
let fixture: ComponentFixture<HoodpageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HoodpageComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HoodpageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-hoodpage',
templateUrl: './hoodpage.component.html',
styleUrls: ['./hoodpage.component.scss'],
})
export class HoodpageComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View file

@ -0,0 +1,11 @@
<mat-card>
<mat-card-title>Badwords</mat-card-title>
<mat-card-subtitle
>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</mat-card-subtitle
>
<mat-card-content>
<div>
<app-option-card></app-option-card>
</div>
</mat-card-content>
</mat-card>

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BadwordsComponent } from './badwords.component';
describe('BadwordsComponent', () => {
let component: BadwordsComponent;
let fixture: ComponentFixture<BadwordsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [BadwordsComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BadwordsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,19 @@
import { Component, OnInit, Input } from '@angular/core';
import { BadwordsService, BodyBadWord } from 'src/app/core/api';
import { Observable } from 'rxjs';
@Component({
selector: 'app-badwords',
templateUrl: './badwords.component.html',
styleUrls: ['./badwords.component.scss'],
})
export class BadwordsComponent implements OnInit {
@Input() hoodId;
badwords$: Observable<BodyBadWord>;
constructor(private badwordService: BadwordsService) {}
ngOnInit(): void {
//this.badwords$ = this.badwordService.getBadwords(this.hoodId);
}
}

View file

@ -0,0 +1,35 @@
<div class="settings">
<div class="explanation">
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>info</mat-icon>
</mat-panel-title>
<mat-panel-description>
How to use triggers and badwords to filter messages
</mat-panel-description>
</mat-expansion-panel-header>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin nisi
enim, semper at metus dapibus, mattis rutrum risus. Nam sit amet
venenatis ipsum. Nulla accumsan blandit est, vel dignissim nisl
consectetur in. Phasellus pretium vulputate lorem, ornare lobortis est
euismod ut. Nullam sit amet malesuada diam. Sed condimentum felis eu
scelerisque fringilla. Mauris vel sapien et nisl faucibus rutrum. Ut
dictum erat nec mattis tristique. Suspendisse ultrices tempus
facilisis. Fusce ac quam tempus sapien commodo vehicula. Suspendisse
viverra accumsan nunc, lacinia sagittis augue porttitor non. Cras
auctor, lorem sed convallis bibendum, odio sapien blandit nisl, sed
pulvinar augue risus a ligula. In dui massa, fringilla eu dolor eu,
volutpat varius lorem. Vivamus et molestie eros.
</p>
</mat-expansion-panel>
</mat-accordion>
</div>
<div class="container">
<app-trigger class="container-item"></app-trigger>
<app-badwords class="container-item"></app-badwords>
</div>
</div>

View file

@ -0,0 +1,21 @@
.container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
@media (max-width: 600px) {
grid-template-columns: 1fr;
}
}
.container-item {
align-items: center;
}
.settings {
margin: 1%;
}
.explanation {
margin-top: 10px;
margin-bottom: 10px;
}

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HoodsettingsComponent } from './hoodsettings.component';
describe('HoodsettingsComponent', () => {
let component: HoodsettingsComponent;
let fixture: ComponentFixture<HoodsettingsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HoodsettingsComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HoodsettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,14 @@
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-hoodsettings',
templateUrl: './hoodsettings.component.html',
styleUrls: ['./hoodsettings.component.scss'],
})
export class HoodsettingsComponent implements OnInit {
@Input() hoodId;
constructor() {}
ngOnInit(): void {}
}

View file

@ -0,0 +1,11 @@
<mat-card>
<mat-card-title>Triggers</mat-card-title>
<mat-card-subtitle
>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</mat-card-subtitle
>
<mat-card-content>
<div>
<app-option-card></app-option-card>
</div>
</mat-card-content>
</mat-card>

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TriggerComponent } from './trigger.component';
describe('TriggerComponent', () => {
let component: TriggerComponent;
let fixture: ComponentFixture<TriggerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [TriggerComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TriggerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-trigger',
templateUrl: './trigger.component.html',
styleUrls: ['./trigger.component.scss'],
})
export class TriggerComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View file

@ -0,0 +1 @@
<p>platforms works!</p>

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PlatformsComponent } from './platforms.component';
describe('PlatformsComponent', () => {
let component: PlatformsComponent;
let fixture: ComponentFixture<PlatformsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PlatformsComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PlatformsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,12 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-platforms',
templateUrl: './platforms.component.html',
styleUrls: ['./platforms.component.scss'],
})
export class PlatformsComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
}

View file

@ -2,8 +2,8 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard.component';
import { HoodsComponent } from './hoods/hoods.component';
import { SettingspageComponent } from './settingspage/settingspage.component';
import { AuthGuard } from '../core/auth/auth.guard';
import { BoardComponent } from './board/board.component';
const routes: Routes = [
{
@ -11,7 +11,7 @@ const routes: Routes = [
component: DashboardComponent,
children: [
{ path: '', component: HoodsComponent },
{ path: 'settings', component: SettingspageComponent },
{ path: 'hoods/:id', component: BoardComponent },
],
canActivate: [AuthGuard],
},

View file

@ -1,12 +1,28 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HoodsComponent } from './hoods/hoods.component';
import { SettingspageComponent } from './settingspage/settingspage.component';
import { DashboardComponent } from './dashboard.component';
import { DashboardRoutingModule } from './dashboard-routing.module';
import { HoodsettingsComponent } from './board/hoodsettings/hoodsettings.component';
import { PlatformsComponent } from './board/platforms/platforms.component';
import { HoodpageComponent } from './board/hoodpage/hoodpage.component';
import { BoardComponent } from './board/board.component';
import { MaterialModule } from '../shared/material/material.module';
import { TriggerComponent } from './board/hoodsettings/trigger/trigger.component';
import { BadwordsComponent } from './board/hoodsettings/badwords/badwords.component';
import { SharedModule } from '../shared/shared.module';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [HoodsComponent, SettingspageComponent, DashboardComponent],
imports: [CommonModule, DashboardRoutingModule],
declarations: [
HoodsComponent,
DashboardComponent,
HoodsettingsComponent,
PlatformsComponent,
HoodpageComponent,
BoardComponent,
TriggerComponent,
BadwordsComponent,
],
imports: [DashboardRoutingModule, MaterialModule, SharedModule, CommonModule],
})
export class DashboardModule {}

View file

@ -1,2 +1,2 @@
<p>hoods works!</p>
<div *ngFor="let item of hoods$ | async">{{ item.name }}</div>
<!--<div *ngFor="let item of hoods$ | async">{{ item.name }}</div>-->

View file

@ -1 +0,0 @@
<p>settingspage works!</p>

View file

@ -1,25 +0,0 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SettingspageComponent } from './settingspage.component';
describe('SettingspageComponent', () => {
let component: SettingspageComponent;
let fixture: ComponentFixture<SettingspageComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SettingspageComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SettingspageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -1,15 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-settingspage',
templateUrl: './settingspage.component.html',
styleUrls: ['./settingspage.component.scss']
})
export class SettingspageComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View file

@ -14,23 +14,18 @@ export class HoodpageComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private router: Router,
private readonly hoodService: HoodsService
private readonly hoodsService: HoodsService
) {}
ngOnInit(): void {
const hoodId = this.route.snapshot.params['id'];
if (hoodId) {
this.hoodService
this.hoodsService
.getHood(hoodId)
.pipe(first())
.subscribe(
(data) => {
this.hood = data;
},
(error) => {
this.router.navigate(['/404']);
}
);
.subscribe((data) => {
this.hood = data;
});
}
}
}

View file

@ -3,10 +3,29 @@ import { MatToolbarModule } from '@angular/material/toolbar';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatTabsModule } from '@angular/material/tabs';
import { MatCardModule } from '@angular/material/card';
import { MatExpansionModule } from '@angular/material/expansion';
@NgModule({
declarations: [],
imports: [MatButtonModule, MatIconModule, MatMenuModule, MatToolbarModule],
exports: [MatButtonModule, MatIconModule, MatMenuModule, MatToolbarModule],
imports: [
MatButtonModule,
MatIconModule,
MatMenuModule,
MatToolbarModule,
MatTabsModule,
MatCardModule,
MatExpansionModule,
],
exports: [
MatButtonModule,
MatIconModule,
MatMenuModule,
MatToolbarModule,
MatTabsModule,
MatCardModule,
MatExpansionModule,
],
})
export class MaterialModule {}

View file

@ -0,0 +1,12 @@
<p>option-card works!</p>
<mat-card>
test
<button mat-icon-button color="primary" aria-label="Edit">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn" aria-label="Delete">
<mat-icon>delete</mat-icon>
</button>
</mat-card>

View file

@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OptionCardComponent } from './option-card.component';
describe('OptionCardComponent', () => {
let component: OptionCardComponent;
let fixture: ComponentFixture<OptionCardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [OptionCardComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OptionCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,14 @@
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-option-card',
templateUrl: './option-card.component.html',
styleUrls: ['./option-card.component.scss'],
})
export class OptionCardComponent implements OnInit {
@Input() option;
constructor() {}
ngOnInit(): void {}
}

View file

@ -2,10 +2,16 @@ import { NgModule } from '@angular/core';
import { ToolbarComponent } from './toolbar/toolbar.component';
import { MaterialModule } from './material/material.module';
import { NotFoundComponent } from './not-found/not-found.component';
import { OptionCardComponent } from './option-card/option-card.component';
@NgModule({
declarations: [ToolbarComponent, NotFoundComponent],
declarations: [ToolbarComponent, NotFoundComponent, OptionCardComponent],
imports: [MaterialModule],
exports: [ToolbarComponent, NotFoundComponent, MaterialModule],
exports: [
ToolbarComponent,
NotFoundComponent,
OptionCardComponent,
MaterialModule,
],
})
export class SharedModule {}