Initial commit
This commit is contained in:
15
src/app/app-view/app-view.component.html
Normal file
15
src/app/app-view/app-view.component.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<mat-tab-nav-panel id="outlet" #tp>
|
||||
<div id="scrollable">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-tab-nav-panel>
|
||||
<nav mat-tab-nav-bar id="bot-navigation" [tabPanel]="tp" color="primary">
|
||||
@for (link of LINKS; track link) {
|
||||
<a mat-tab-link [routerLink]="link.href" routerLinkActive #rla="routerLinkActive" [active]="rla.isActive">
|
||||
<div>
|
||||
<div><mat-icon>{{link.icon}}</mat-icon></div>
|
||||
<div>{{link.title}}</div>
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
</nav>
|
||||
26
src/app/app-view/app-view.component.scss
Normal file
26
src/app/app-view/app-view.component.scss
Normal file
@@ -0,0 +1,26 @@
|
||||
#bot-navigation {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#outlet {
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#scrollable {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:host {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration-line: none;
|
||||
}
|
||||
38
src/app/app-view/app-view.component.spec.ts
Normal file
38
src/app/app-view/app-view.component.spec.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AppViewComponent } from './app-view.component';
|
||||
import { AuthClient } from '../services/auth.client';
|
||||
import { SwPush } from '@angular/service-worker';
|
||||
import { UpdatesService } from '../services/updates.service';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('AppViewComponent', () => {
|
||||
let component: AppViewComponent;
|
||||
let fixture: ComponentFixture<AppViewComponent>;
|
||||
let authClient: jasmine.SpyObj<AuthClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
const authSpy = jasmine.createSpyObj('AuthClient', ['check'])
|
||||
const pushSpy = jasmine.createSpyObj('SwPush', ['requestSubscription'])
|
||||
const updatesSpy = jasmine.createSpyObj('UpdatesService', ['postNotif'])
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppViewComponent],
|
||||
providers: [{provide: AuthClient, useValue: authSpy},
|
||||
{provide: SwPush, useValue: pushSpy},
|
||||
{provide: UpdatesService, useValue: updatesSpy}],
|
||||
imports: [MatTabsModule, RouterModule.forRoot([]), MatIconModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(AppViewComponent);
|
||||
component = fixture.componentInstance;
|
||||
authClient = TestBed.inject(AuthClient) as jasmine.SpyObj<AuthClient>
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
59
src/app/app-view/app-view.component.ts
Normal file
59
src/app/app-view/app-view.component.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AuthClient } from '../services/auth.client';
|
||||
import { SwPush } from '@angular/service-worker';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { UpdatesService } from '../services/updates.service';
|
||||
import { Link } from '../types/link';
|
||||
import { LocalStorageService } from '../services/local-storage.service';
|
||||
import { interval } from 'rxjs';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-app-view',
|
||||
templateUrl: './app-view.component.html',
|
||||
styleUrls: ['./app-view.component.scss']
|
||||
})
|
||||
export class AppViewComponent implements OnInit {
|
||||
readonly VAPID_PUK = environment.vapid.pubkey
|
||||
private readonly _LINKS: Link[] = [
|
||||
{ title: "Jadłospis", href: "menu", icon: "restaurant_menu", enabled: this.ls.capCheck(2) },
|
||||
{ title: "Wiadomości", href: "news", icon: "newspaper", enabled: this.ls.capCheck(1) },
|
||||
{ title: "Konto", href: "grades", icon: "account_circle", enabled: true }
|
||||
];
|
||||
|
||||
public get LINKS() {
|
||||
return this._LINKS.filter((v) => {
|
||||
return v.enabled
|
||||
});
|
||||
}
|
||||
|
||||
constructor (private ac: AuthClient, readonly swPush: SwPush, private us: UpdatesService, private ls: LocalStorageService, private sb: MatSnackBar) {}
|
||||
|
||||
subscribeToNotif() {
|
||||
if (this.swPush.isEnabled && this.ls.capCheck(4)) {
|
||||
this.swPush.requestSubscription({
|
||||
serverPublicKey: this.VAPID_PUK
|
||||
}).then(sub => {
|
||||
this.us.postNotif(sub)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.subscribeToNotif()
|
||||
this.ac.check()
|
||||
this.newsCheck()
|
||||
interval(1000 * 60 * 15).subscribe(this.newsCheck)
|
||||
}
|
||||
|
||||
newsCheck() {
|
||||
if (this.ls.newsflag) return;
|
||||
this.us.newsCheck().subscribe((s) => {
|
||||
if (s.hash != this.ls.newsCheck.hash) {
|
||||
this.ls.newsflag = this.ls.newsCheck.count - s.count
|
||||
this.ls.newsCheck = s
|
||||
this.sb.open("Nowe wiadomości", "Zamknij", {duration: 5000, verticalPosition: 'bottom'})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
10
src/app/app-view/menu/allergens/allergens.component.html
Normal file
10
src/app/app-view/menu/allergens/allergens.component.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<h2><b>Alergeny</b></h2>
|
||||
<ol>
|
||||
<!-- Make non-static -->
|
||||
<li>Nabiał</li>
|
||||
<li>Gluten</li>
|
||||
<li>Seler</li>
|
||||
<li>Jaja</li>
|
||||
<li>Ryby</li>
|
||||
<li>Sezam / Orzechy</li>
|
||||
</ol>
|
||||
3
src/app/app-view/menu/allergens/allergens.component.scss
Normal file
3
src/app/app-view/menu/allergens/allergens.component.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
ol>li::marker {
|
||||
font-weight: bold;
|
||||
}
|
||||
21
src/app/app-view/menu/allergens/allergens.component.spec.ts
Normal file
21
src/app/app-view/menu/allergens/allergens.component.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AllergensComponent } from './allergens.component';
|
||||
|
||||
describe('AllergensComponent', () => {
|
||||
let component: AllergensComponent;
|
||||
let fixture: ComponentFixture<AllergensComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AllergensComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(AllergensComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
10
src/app/app-view/menu/allergens/allergens.component.ts
Normal file
10
src/app/app-view/menu/allergens/allergens.component.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-allergens',
|
||||
templateUrl: './allergens.component.html',
|
||||
styleUrls: ['./allergens.component.scss']
|
||||
})
|
||||
export class AllergensComponent {
|
||||
|
||||
}
|
||||
60
src/app/app-view/menu/menu.component.html
Normal file
60
src/app/app-view/menu/menu.component.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<div id="cards">
|
||||
<mat-spinner *ngIf="loading"></mat-spinner>
|
||||
<mat-card *ngIf="gettitle">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{gettitle}}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content></mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="getsn">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Śniadanie</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<ul>
|
||||
<li *ngFor="let i of ls.defaultItems.sn">{{i}}</li>
|
||||
<li *ngFor="let i of getsn.fancy">{{i.charAt(0).toUpperCase()+i.substring(1)}}</li>
|
||||
</ul>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="getob">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Obiad</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<ul>
|
||||
<li *ngIf="getob.soup">Z: {{getob.soup}}</li>
|
||||
<li *ngIf="getob.vege" style="color: #43A047">V: {{getob.vege}}</li>
|
||||
<li *ngIf="getob.meal">{{getob.meal}}</li>
|
||||
<li *ngFor="let i of getob.condiments">{{i}}</li>
|
||||
<li *ngIf="getob.drink">{{getob.drink}}</li>
|
||||
<li *ngFor="let i of getob.other">{{i}}</li>
|
||||
</ul>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-icon-button (click)="vote('ob', '+')"><mat-icon [color]="menu!.obv == '+' ? 'primary' : null">thumb_up</mat-icon></button>
|
||||
<span *ngIf="menu?.stat?.ob != 'NaN'">{{menu?.stat?.ob}}%</span>
|
||||
<button mat-icon-button (click)="vote('ob', '-')"><mat-icon [color]="menu!.obv == '-' ? 'warn' : null">thumb_down</mat-icon></button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="getkol">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Kolacja</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<ul [innerHTML]="getkol"></ul>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-icon-button (click)="vote('kol', '+')"><mat-icon [color]="menu!.kolv == '+' ? 'primary' : null">thumb_up</mat-icon></button>
|
||||
<span *ngIf="menu?.stat?.kol != 'NaN'">{{menu?.stat?.kol}}%</span>
|
||||
<button mat-icon-button (click)="vote('kol', '-')"><mat-icon [color]="menu!.kolv == '-' ? 'warn' : null">thumb_down</mat-icon></button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
<mat-card *ngIf="!(getkol || getob || getsn || loading)">
|
||||
<mat-card-content id="no-data">
|
||||
Brak danych, wybierz inny dzień.
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<button id="alrg" mat-icon-button (click)="alrg()"><mat-icon color="primary">info</mat-icon></button>
|
||||
</div>
|
||||
<app-date-selector [(date)]="day" [filter]="filter"></app-date-selector>
|
||||
41
src/app/app-view/menu/menu.component.scss
Normal file
41
src/app/app-view/menu/menu.component.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#alrg {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
mat-spinner {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
mat-card {
|
||||
margin: 15px;
|
||||
padding: 1ch;
|
||||
}
|
||||
|
||||
#no-data {
|
||||
color: #777;
|
||||
@media (prefers-color-scheme: dark) {
|
||||
color: #AAA
|
||||
}
|
||||
}
|
||||
|
||||
mat-card-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
app-date-selector {
|
||||
width: 100%;
|
||||
}
|
||||
45
src/app/app-view/menu/menu.component.spec.ts
Normal file
45
src/app/app-view/menu/menu.component.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MenuComponent } from './menu.component';
|
||||
import { UpdatesService } from 'src/app/services/updates.service';
|
||||
import { DateSelectorComponent } from '../../commonComponents/date-selector/date-selector.component';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
|
||||
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS, MAT_MOMENT_DATE_FORMATS, MomentDateAdapter } from '@angular/material-moment-adapter';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
|
||||
describe('MenuComponent', () => {
|
||||
let component: MenuComponent;
|
||||
let fixture: ComponentFixture<MenuComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const updatesSpy = jasmine.createSpyObj('UpdatesService', ['getMenu'])
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ MenuComponent, DateSelectorComponent],
|
||||
providers: [
|
||||
{provide: UpdatesService, useValue: updatesSpy},
|
||||
{provide: DateAdapter, useClass: MomentDateAdapter},
|
||||
{provide: MAT_DATE_LOCALE, useValue: "pl-PL"},
|
||||
{provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS},
|
||||
{provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: {useUtc: true}},
|
||||
],
|
||||
imports: [MatIconModule, MatFormFieldModule, MatDatepickerModule, MatCardModule, ReactiveFormsModule, MatInputModule, BrowserAnimationsModule, MatBottomSheetModule]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MenuComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
65
src/app/app-view/menu/menu.component.ts
Normal file
65
src/app/app-view/menu/menu.component.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { UpdatesService } from '../../services/updates.service';
|
||||
import { Menu } from '../../types/menu';
|
||||
import * as moment from 'moment';
|
||||
import { MatBottomSheet } from '@angular/material/bottom-sheet';
|
||||
import { AllergensComponent } from './allergens/allergens.component';
|
||||
import { weekendFilter } from "../../fd.da";
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-menu',
|
||||
templateUrl: './menu.component.html',
|
||||
styleUrls: ['./menu.component.scss']
|
||||
})
|
||||
export class MenuComponent {
|
||||
constructor(private uc:UpdatesService, readonly bs: MatBottomSheet, readonly ls: LocalStorageService) {
|
||||
this.day = moment.utc()
|
||||
}
|
||||
loading = true
|
||||
|
||||
public filter = weekendFilter
|
||||
|
||||
private _day!: moment.Moment;
|
||||
public get day(): moment.Moment {
|
||||
return this._day;
|
||||
}
|
||||
public set day(value: moment.Moment) {
|
||||
// if (value.isAfter(moment.utc("19:15:00", "HH:mm:ss"))) value.add(1, "day")
|
||||
if (!this.filter(value)) value.isoWeekday(8);
|
||||
this._day = moment.utc(value).startOf('day');
|
||||
this.updateMenu()
|
||||
}
|
||||
|
||||
menu?: Menu;
|
||||
get getsn() {return (this.menu && this.menu.sn) ? this.menu.sn : null}
|
||||
get getob() {return (this.menu && this.menu.ob) ? this.menu.ob : null}
|
||||
get getkol() {return (this.menu && this.menu.kol) ? this.menu.kol : null}
|
||||
get gettitle() {return (this.menu && this.menu.dayTitle && this.menu.dayTitle != "") ? this.menu.dayTitle : null}
|
||||
|
||||
updateMenu(silent?: boolean) {
|
||||
this.loading = !silent
|
||||
if (!silent) this.menu = undefined
|
||||
this.uc.getMenu(this.day).subscribe(m => {
|
||||
this.loading = false
|
||||
this.menu = m
|
||||
})
|
||||
}
|
||||
|
||||
alrg() {
|
||||
this.bs.open(AllergensComponent)
|
||||
}
|
||||
|
||||
protected vegeColor(text: string) {
|
||||
if (text.startsWith("V: ")) {
|
||||
return "#43A047"
|
||||
}
|
||||
return "inherit"
|
||||
}
|
||||
|
||||
vote(type: "ob" | "kol", vote: "-" | "+" | "n") {
|
||||
this.uc.postVote(this.menu!.day, type, vote).subscribe((data) => {
|
||||
this.updateMenu(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
12
src/app/app-view/news/news.component.html
Normal file
12
src/app/app-view/news/news.component.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<mat-spinner *ngIf="loading"></mat-spinner>
|
||||
<mat-card *ngFor="let item of news">
|
||||
<mat-card-header>
|
||||
<mat-icon *ngIf="item.pinned">push_pin</mat-icon>
|
||||
<mat-card-title>{{item.title}}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content [innerHTML]="item.content">
|
||||
</mat-card-content>
|
||||
<mat-card-footer>
|
||||
<p>{{item.date | date:'d-LL-yyyy HH:mm'}}</p>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
31
src/app/app-view/news/news.component.scss
Normal file
31
src/app/app-view/news/news.component.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
mat-card {
|
||||
margin: 15px;
|
||||
padding: 1ch;
|
||||
}
|
||||
|
||||
mat-spinner {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
mat-card-title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
mat-card-footer p {
|
||||
font-size: 0.8rem;
|
||||
color: #4a4a4a;
|
||||
@media (prefers-color-scheme: dark) {
|
||||
color: #999999
|
||||
}
|
||||
margin-bottom: 0;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
mat-card-content p {
|
||||
white-space: pre-line;
|
||||
}
|
||||
31
src/app/app-view/news/news.component.spec.ts
Normal file
31
src/app/app-view/news/news.component.spec.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NewsComponent } from './news.component';
|
||||
import { UpdatesService } from 'src/app/services/updates.service';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('NewsComponent', () => {
|
||||
let component: NewsComponent;
|
||||
let fixture: ComponentFixture<NewsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const updatesMock = jasmine.createSpyObj('UpdatesService', {
|
||||
getNews: of()
|
||||
})
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ NewsComponent ],
|
||||
providers: [
|
||||
{provide: UpdatesService, useValue: updatesMock}
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(NewsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
30
src/app/app-view/news/news.component.ts
Normal file
30
src/app/app-view/news/news.component.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { UpdatesService } from '../../services/updates.service';
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service';
|
||||
import { News } from 'src/app/types/news';
|
||||
import { marked } from 'marked';
|
||||
|
||||
@Component({
|
||||
selector: 'app-news',
|
||||
templateUrl: './news.component.html',
|
||||
styleUrls: ['./news.component.scss'],
|
||||
})
|
||||
export class NewsComponent implements OnInit {
|
||||
news:Array<News> = new Array<News>
|
||||
loading = true
|
||||
constructor(private newsapi:UpdatesService, private ls: LocalStorageService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.ls.newsflag = false
|
||||
this.loading = true
|
||||
this.news = this.ls.news
|
||||
this.newsapi.getNews().subscribe(data => {
|
||||
this.loading = false
|
||||
this.news = data.map(v => {
|
||||
v.content = marked.parse(v.content, {breaks: true}).toString()
|
||||
return v
|
||||
});
|
||||
this.ls.news = this.news
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<form [formGroup]="form" (ngSubmit)="changePass()">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Aktualne hasło</mat-label>
|
||||
<input type="password" matInput formControlName="oldPass">
|
||||
</mat-form-field><br>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Nowe hasło</mat-label>
|
||||
<input type="password" matInput formControlName="newPass">
|
||||
</mat-form-field><br>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Powtórz nowe hasło</mat-label>
|
||||
<input type="password" matInput formControlName="newPassRepeat">
|
||||
<mat-error *ngIf="form.errors?.['noMatch']">Hasła muszą się zgadzać</mat-error>
|
||||
</mat-form-field><br>
|
||||
<button mat-stroked-button>Zmień hasło</button><br>
|
||||
<p *ngIf="error" style="color: red;">{{error}}</p>
|
||||
</form>
|
||||
@@ -0,0 +1,10 @@
|
||||
mat-error {
|
||||
font-size: 10pt;
|
||||
}
|
||||
form {
|
||||
margin: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: fit-content;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ChangePasswordDialogComponent } from './change-password-dialog.component';
|
||||
import { AuthClient } from 'src/app/services/auth.client';
|
||||
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('ChangePasswordDialogComponent', () => {
|
||||
let component: ChangePasswordDialogComponent;
|
||||
let fixture: ComponentFixture<ChangePasswordDialogComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
const authMock = jasmine.createSpyObj('AuthClient', ['chpass'])
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ChangePasswordDialogComponent],
|
||||
providers: [
|
||||
{provide: AuthClient, useValue: authMock},
|
||||
{provide: MatDialogRef, useValue: {}}
|
||||
],
|
||||
imports: [MatDialogModule, MatFormFieldModule, ReactiveFormsModule, MatInputModule, BrowserAnimationsModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(ChangePasswordDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AuthClient } from '../../../services/auth.client';
|
||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { catchError, throwError } from 'rxjs';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { Router } from '@angular/router';
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-change-password-dialog',
|
||||
templateUrl: './change-password-dialog.component.html',
|
||||
styleUrls: ['./change-password-dialog.component.scss']
|
||||
})
|
||||
export class ChangePasswordDialogComponent {
|
||||
error: string | null = null;
|
||||
form: FormGroup;
|
||||
constructor (private ac: AuthClient, public dr: MatDialogRef<ChangePasswordDialogComponent>, private router: Router, private ls: LocalStorageService) {
|
||||
this.form = new FormGroup({
|
||||
oldPass: new FormControl(),
|
||||
newPass: new FormControl(),
|
||||
newPassRepeat: new FormControl(),
|
||||
}, {validators: [this.matchpass(), Validators.required]})
|
||||
}
|
||||
|
||||
private matchpass() : ValidatorFn {
|
||||
return (control: AbstractControl) : ValidationErrors | null => {
|
||||
const newpass = control.get('newPass')
|
||||
const newpassrepeat = control.get("newPassRepeat")
|
||||
if (newpass?.value != newpassrepeat?.value) {
|
||||
const err = {noMatch: true}
|
||||
newpassrepeat?.setErrors(err)
|
||||
return err
|
||||
}
|
||||
newpassrepeat?.setErrors(null)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
protected changePass() {
|
||||
if (this.form.errors) {
|
||||
return;
|
||||
}
|
||||
this.ac.chpass(this.form.get('oldPass')?.value, this.form.get('newPass')?.value).pipe(catchError((err)=>{
|
||||
if (err.status == 401) {
|
||||
this.error = "Niepoprawne dane"
|
||||
return throwError(() => new Error(err.message))
|
||||
}
|
||||
this.error = "Nieznany błąd"
|
||||
return throwError(() => new Error(err.message))
|
||||
})).subscribe((data) => {
|
||||
if (this.error == null) {
|
||||
this.dr.close()
|
||||
this.ls.logOut()
|
||||
this.router.navigateByUrl("/login")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
18
src/app/app-view/personal/clean/clean.component.html
Normal file
18
src/app/app-view/personal/clean/clean.component.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<h1 mat-dialog-title>Czystość</h1>
|
||||
<mat-dialog-content>
|
||||
@if (grade) {
|
||||
<h1>Twoja ocena: <span [ngStyle]="gradeColor()">{{grade}}</span></h1>
|
||||
}
|
||||
@else {
|
||||
<h1>Nie oceniono</h1>
|
||||
}
|
||||
<p *ngIf="notes.length > 0">Uwagi:</p>
|
||||
<ul>
|
||||
<li *ngFor="let i of notes">{{i.label}}<span *ngIf="i.weight > 1"> ({{i.weight}})</span></li>
|
||||
</ul>
|
||||
<p>{{tips}}</p>
|
||||
<app-date-selector [(date)]="day" [filter]="filter"/>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-icon-button mat-dialog-close><mat-icon>close</mat-icon></button>
|
||||
</mat-dialog-actions>
|
||||
23
src/app/app-view/personal/clean/clean.component.spec.ts
Normal file
23
src/app/app-view/personal/clean/clean.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CleanComponent } from './clean.component';
|
||||
|
||||
describe('CleanComponent', () => {
|
||||
let component: CleanComponent;
|
||||
let fixture: ComponentFixture<CleanComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CleanComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CleanComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
67
src/app/app-view/personal/clean/clean.component.ts
Normal file
67
src/app/app-view/personal/clean/clean.component.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
import { weekendFilter } from 'src/app/fd.da';
|
||||
import { UpdatesService } from 'src/app/services/updates.service';
|
||||
import { CleanNote } from 'src/app/types/clean-note';
|
||||
|
||||
@Component({
|
||||
selector: 'app-clean',
|
||||
templateUrl: './clean.component.html',
|
||||
styleUrl: './clean.component.scss'
|
||||
})
|
||||
export class CleanComponent implements OnInit {
|
||||
private _day: moment.Moment = moment()
|
||||
public get day(): moment.Moment {
|
||||
return this._day;
|
||||
}
|
||||
public set day(value: moment.Moment) {
|
||||
if (!this.filter(value)) value.isoWeekday(5);
|
||||
this._day = moment.utc(value).startOf('day');
|
||||
this.update()
|
||||
}
|
||||
grade: number | null = null
|
||||
notes: CleanNote[] = []
|
||||
tips: string = ""
|
||||
filter = weekendFilter
|
||||
|
||||
constructor (private updates: UpdatesService) {
|
||||
this.day = moment.utc();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.update()
|
||||
}
|
||||
|
||||
update() {
|
||||
this.updates.getClean(this.day).subscribe((v) => {
|
||||
if (v) {
|
||||
this.grade = v.grade
|
||||
this.notes = v.notes
|
||||
this.tips = v.tips
|
||||
} else {
|
||||
this.grade = null
|
||||
this.notes = []
|
||||
this.tips = ""
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected gradeColor() {
|
||||
switch (this.grade) {
|
||||
case 1:
|
||||
return { color: "red" }
|
||||
case 2:
|
||||
return { color: "darkorange" }
|
||||
case 3:
|
||||
return { color: "orange" }
|
||||
case 4:
|
||||
return { color: "olive" }
|
||||
case 5:
|
||||
return { color: "green" }
|
||||
case 6:
|
||||
return { color: "springgreen" }
|
||||
default:
|
||||
return { color: "inherit" }
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/app/app-view/personal/key/key.component.html
Normal file
14
src/app/app-view/personal/key/key.component.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<h1 mat-dialog-title>Klucze</h1>
|
||||
<mat-dialog-content>
|
||||
@for (item of keys; track $index) {
|
||||
@if (item.taken) {
|
||||
<div>{{item.room}}: Zajęte</div>
|
||||
}
|
||||
@else {
|
||||
<div class="free">{{item.room}}: Wolne</div>
|
||||
}
|
||||
}
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-icon-button mat-dialog-close><mat-icon>close</mat-icon></button>
|
||||
</mat-dialog-actions>
|
||||
6
src/app/app-view/personal/key/key.component.scss
Normal file
6
src/app/app-view/personal/key/key.component.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
.free {
|
||||
color: black;
|
||||
@media (prefers-color-scheme: dark) {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
23
src/app/app-view/personal/key/key.component.spec.ts
Normal file
23
src/app/app-view/personal/key/key.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { KeyComponent } from './key.component';
|
||||
|
||||
describe('KeyComponent', () => {
|
||||
let component: KeyComponent;
|
||||
let fixture: ComponentFixture<KeyComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [KeyComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(KeyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
21
src/app/app-view/personal/key/key.component.ts
Normal file
21
src/app/app-view/personal/key/key.component.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { UpdatesService } from 'src/app/services/updates.service';
|
||||
import { UKey } from 'src/app/types/key';
|
||||
|
||||
@Component({
|
||||
selector: 'app-key',
|
||||
templateUrl: './key.component.html',
|
||||
styleUrl: './key.component.scss'
|
||||
})
|
||||
export class KeyComponent implements OnInit {
|
||||
|
||||
constructor (private us: UpdatesService){}
|
||||
|
||||
keys!: UKey[]
|
||||
|
||||
ngOnInit(): void {
|
||||
this.us.getKeys().subscribe((v) => {
|
||||
this.keys = v
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<mat-dialog-content>
|
||||
Czy na pewno chcesz się wylogować?
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button [mat-dialog-close]="true">Tak</button>
|
||||
<button mat-button mat-dialog-close>Nie</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LogoutConfirmationComponent } from './logout-confirmation.component';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
|
||||
describe('LogoutConfirmationComponent', () => {
|
||||
let component: LogoutConfirmationComponent;
|
||||
let fixture: ComponentFixture<LogoutConfirmationComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LogoutConfirmationComponent],
|
||||
imports: [MatDialogModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(LogoutConfirmationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-logout-confirmation',
|
||||
templateUrl: './logout-confirmation.component.html',
|
||||
styleUrls: ['./logout-confirmation.component.scss']
|
||||
})
|
||||
export class LogoutConfirmationComponent {
|
||||
|
||||
}
|
||||
33
src/app/app-view/personal/personal.component.html
Normal file
33
src/app/app-view/personal/personal.component.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<mat-action-list>
|
||||
<button mat-list-item (click)="logout()">
|
||||
<mat-icon matListItemIcon color="primary">logout</mat-icon>
|
||||
<div matListItemTitle>Wyloguj</div>
|
||||
</button>
|
||||
<button mat-list-item (click)="openPassChange()">
|
||||
<mat-icon matListItemIcon color="primary">manage_accounts</mat-icon>
|
||||
<div matListItemTitle>Zmiana hasła</div>
|
||||
</button>
|
||||
<button mat-list-item (click)="checkUpdate()">
|
||||
<div matListItemIcon [ngSwitch]="checking">
|
||||
<mat-spinner diameter="25" *ngSwitchCase="true"></mat-spinner>
|
||||
<mat-icon *ngSwitchCase="false">update</mat-icon>
|
||||
<mat-icon *ngSwitchCase="'err'" color="warn">error</mat-icon>
|
||||
<mat-icon *ngSwitchCase="'aval'">upgrade</mat-icon>
|
||||
</div>
|
||||
<div matListItemTitle>Sprawdź dostępność aktualizacji</div>
|
||||
<div matListItemLine>Aktualna wersja: {{version}}</div>
|
||||
</button>
|
||||
<button mat-list-item (click)="openKey()" *ngIf="ls.capCheck(32)">
|
||||
<mat-icon matListItemIcon>key</mat-icon>
|
||||
<div matListItemTitle>Klucze</div>
|
||||
</button>
|
||||
<button mat-list-item *ngIf="ls.capCheck(16) && ls.hasRoom()" (click)="openClean()">
|
||||
<mat-icon matListItemIcon>cleaning_services</mat-icon>
|
||||
<div matListItemTitle>Oceny za czystość</div>
|
||||
</button>
|
||||
<button mat-list-item (click)="goToAdmin()" *ngIf="ls.admin">
|
||||
<mat-icon matListItemIcon color="accent">admin_panel_settings</mat-icon>
|
||||
<div matListItemTitle>Panel administracyjny</div>
|
||||
<div matListItemLine>Poprzednio Tryb edycji</div>
|
||||
</button>
|
||||
</mat-action-list>
|
||||
0
src/app/app-view/personal/personal.component.scss
Normal file
0
src/app/app-view/personal/personal.component.scss
Normal file
32
src/app/app-view/personal/personal.component.spec.ts
Normal file
32
src/app/app-view/personal/personal.component.spec.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PersonalComponent } from './personal.component';
|
||||
import { AuthClient } from 'src/app/services/auth.client';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('PersonalComponent', () => {
|
||||
let component: PersonalComponent;
|
||||
let fixture: ComponentFixture<PersonalComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
const authMock = jasmine.createSpyObj('AuthClient', ['s'])
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PersonalComponent],
|
||||
providers: [
|
||||
{provide: AuthClient, useValue: authMock},
|
||||
],
|
||||
imports: [MatDialogModule, MatSnackBarModule, MatListModule, BrowserAnimationsModule]
|
||||
});
|
||||
fixture = TestBed.createComponent(PersonalComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
64
src/app/app-view/personal/personal.component.ts
Normal file
64
src/app/app-view/personal/personal.component.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AuthClient } from '../../services/auth.client';
|
||||
import { Router } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ChangePasswordDialogComponent } from './change-password-dialog/change-password-dialog.component';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { LogoutConfirmationComponent } from './logout-confirmation/logout-confirmation.component';
|
||||
import { AppUpdateService } from 'src/app/services/app-update.service';
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service';
|
||||
import { KeyComponent } from './key/key.component';
|
||||
import { CleanComponent } from './clean/clean.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-personal',
|
||||
templateUrl: './personal.component.html',
|
||||
styleUrls: ['./personal.component.scss']
|
||||
})
|
||||
export class PersonalComponent {
|
||||
updateaval: boolean | unknown = false
|
||||
checking: boolean | "err" | "aval" = false
|
||||
constructor (private ac: AuthClient, private router: Router, private dialog: MatDialog, readonly update: AppUpdateService, protected ls: LocalStorageService) {}
|
||||
public version: any = environment.version;
|
||||
protected logout() {
|
||||
let dialogRef = this.dialog.open(LogoutConfirmationComponent)
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.ac.logout().subscribe(() => {
|
||||
this.router.navigateByUrl("/login")
|
||||
this.ls.logOut()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected openPassChange() {
|
||||
this.dialog.open(ChangePasswordDialogComponent)
|
||||
}
|
||||
|
||||
protected openKey() {
|
||||
this.dialog.open(KeyComponent)
|
||||
}
|
||||
|
||||
protected openClean() {
|
||||
this.dialog.open(CleanComponent)
|
||||
}
|
||||
|
||||
protected goToAdmin() {
|
||||
this.router.navigateByUrl("admin")
|
||||
}
|
||||
|
||||
protected async checkUpdate() {
|
||||
this.checking = true
|
||||
this.update.checkForUpdate().subscribe({
|
||||
next: (v) => {
|
||||
this.checking = false
|
||||
if (v) {
|
||||
this.checking = "aval"
|
||||
}
|
||||
},
|
||||
error: () => this.checking = "err"
|
||||
})
|
||||
this.ac.check()
|
||||
}
|
||||
}
|
||||
12
src/app/app-view/start/start.component.html
Normal file
12
src/app/app-view/start/start.component.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<div>
|
||||
<h1>Witamy w aplikacji!</h1>
|
||||
<p>Dostępne funkcje:</p>
|
||||
<mat-nav-list>
|
||||
@for (link of LINKS; track $index) {
|
||||
<mat-list-item [routerLink]="link.href">
|
||||
<a matListItemTitle>{{link.title}}</a>
|
||||
<mat-icon matListItemIcon>{{link.icon}}</mat-icon>
|
||||
</mat-list-item>
|
||||
}
|
||||
</mat-nav-list>
|
||||
</div>
|
||||
6
src/app/app-view/start/start.component.scss
Normal file
6
src/app/app-view/start/start.component.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
:host {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
23
src/app/app-view/start/start.component.spec.ts
Normal file
23
src/app/app-view/start/start.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StartComponent } from './start.component';
|
||||
|
||||
describe('StartComponent', () => {
|
||||
let component: StartComponent;
|
||||
let fixture: ComponentFixture<StartComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [StartComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(StartComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
27
src/app/app-view/start/start.component.ts
Normal file
27
src/app/app-view/start/start.component.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service';
|
||||
import { Link } from 'src/app/types/link';
|
||||
|
||||
@Component({
|
||||
selector: 'app-start',
|
||||
templateUrl: './start.component.html',
|
||||
styleUrl: './start.component.scss'
|
||||
})
|
||||
export class StartComponent {
|
||||
private readonly _LINKS: Link[] = [
|
||||
{ title: "Jadłospis (z funkcją głosowania)", href: "menu", icon: "restaurant_menu", enabled: this.ls.capCheck(2) },
|
||||
{ title: "Wiadomości", href: "news", icon: "newspaper", enabled: this.ls.capCheck(1) },
|
||||
{ title: "Ustawienia konta", href: "grades", icon: "settings_account_box", enabled: true },
|
||||
{ title: "Klucze do sal", href: "grades", icon: "key", enabled: this.ls.capCheck(32) },
|
||||
{ title: "Oceny za czystość", href: "grades", icon: "cleaning_services", enabled: this.ls.capCheck(16) },
|
||||
{ title: "Administracja", href: "grades", icon: "admin_panel_settings", enabled: this.ls.admin != 0 },
|
||||
];
|
||||
public get LINKS(): Link[] {
|
||||
return this._LINKS.filter(v => v.enabled);
|
||||
}
|
||||
constructor(private r: Router, private readonly route: ActivatedRoute, private ls: LocalStorageService) { }
|
||||
protected redirect(link: any) {
|
||||
this.r.navigate([link], { relativeTo: this.route })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user