generated from flo/template-frontend
intermediate commit
This commit is contained in:
parent
5dd8aee455
commit
0adf0a9bfc
@ -47,10 +47,11 @@
|
|||||||
"src/favicon.ico"
|
"src/favicon.ico"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": [
|
||||||
|
"node_modules/flowbite/dist/flowbite.min.js"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
@ -110,7 +111,6 @@
|
|||||||
"src/favicon.ico"
|
"src/favicon.ico"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"@angular/material/prebuilt-themes/deeppurple-amber.scss",
|
|
||||||
"src/styles.scss"
|
"src/styles.scss"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
"@angular/compiler": "^15.2.0",
|
"@angular/compiler": "^15.2.0",
|
||||||
"@angular/core": "^15.2.0",
|
"@angular/core": "^15.2.0",
|
||||||
"@angular/forms": "^15.2.0",
|
"@angular/forms": "^15.2.0",
|
||||||
"@angular/material": "^15.2.9",
|
|
||||||
"@angular/platform-browser": "^15.2.0",
|
"@angular/platform-browser": "^15.2.0",
|
||||||
"@angular/platform-browser-dynamic": "^15.2.0",
|
"@angular/platform-browser-dynamic": "^15.2.0",
|
||||||
"@angular/router": "^15.2.0",
|
"@angular/router": "^15.2.0",
|
||||||
|
"flowbite": "^2.5.1",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.12.0"
|
"zone.js": "~0.12.0"
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"karma-coverage": "~2.2.0",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.0.0",
|
"karma-jasmine-html-reporter": "~2.0.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.10",
|
||||||
"typescript": "~4.9.4"
|
"typescript": "~4.9.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { AuthService } from './core/services/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.authService.readUserState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,11 @@ import { RouterModule, Routes } from '@angular/router';
|
|||||||
import { SharedModule } from './shared/shared.module';
|
import { SharedModule } from './shared/shared.module';
|
||||||
import { HomeComponent } from './core/components/home/home.component';
|
import { HomeComponent } from './core/components/home/home.component';
|
||||||
import { CoreModule } from './core/core.module';
|
import { CoreModule } from './core/core.module';
|
||||||
|
import { AuthGuard } from './core/guards/auth.guard';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'home', component: HomeComponent },
|
{ path: 'auth', loadChildren: () => import('./core/auth/auth.module').then(m => m.AuthModule) },
|
||||||
|
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
|
||||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
33
src/app/core/auth/auth.module.ts
Normal file
33
src/app/core/auth/auth.module.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { LoginComponent } from './components/login/login.component';
|
||||||
|
import { RegistrationComponent } from './components/registration/registration.component';
|
||||||
|
import { ConfirmRegistrationComponent } from './components/confirm-registration/confirm-registration.component';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: 'login', component: LoginComponent },
|
||||||
|
{ path: 'registration', component: RegistrationComponent },
|
||||||
|
{ path: 'registration/:id', component: ConfirmRegistrationComponent },
|
||||||
|
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
LoginComponent,
|
||||||
|
RegistrationComponent,
|
||||||
|
ConfirmRegistrationComponent
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
LoginComponent,
|
||||||
|
RegistrationComponent,
|
||||||
|
ConfirmRegistrationComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AuthModule { }
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<p>confirm-registration works!</p>
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-confirm-registration',
|
||||||
|
templateUrl: './confirm-registration.component.html',
|
||||||
|
styleUrls: ['./confirm-registration.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfirmRegistrationComponent {
|
||||||
|
|
||||||
|
}
|
||||||
24
src/app/core/auth/components/login/login.component.html
Normal file
24
src/app/core/auth/components/login/login.component.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<div class="mb-10">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="max-w-sm mx-auto mb-10">
|
||||||
|
<h1 class="font-bold text-center text-skin-accent text-5xl mb-5">
|
||||||
|
Beekeeper
|
||||||
|
</h1>
|
||||||
|
<h1 class="font-bold text-center text-skin-accent text-xl">
|
||||||
|
Anmeldung
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form class="max-w-sm mx-auto" [formGroup]="loginForm">
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="identifier" class="block mb-2 text-sm font-medium text-skin-accent-muted">Benutzername oder E-Mail</label>
|
||||||
|
<input formControlName="identifier" type="text" id="identifier" class="bg-skin-primary border border-gray-300 text-skin-accent-muted text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" placeholder="username72 / your@email.com" required />
|
||||||
|
</div>
|
||||||
|
<div class="mb-5">
|
||||||
|
<label for="password" class="block mb-2 text-sm font-medium text-skin-accent-muted">Passwort</label>
|
||||||
|
<input formControlName="password" type="password" id="password" class="bg-skin-primary border border-gray-300 text-skin-accent-muted text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required />
|
||||||
|
<p id="helper-text-explanation" class="mt-2 text-sm text-skin-accent-muted">Neu hier? <a routerLink="/auth/registration" class="font-medium text-skin-secondary hover:underline">Jetzt registrieren!</a></p>
|
||||||
|
</div>
|
||||||
|
<button (click)="login()" [disabled]="!loginForm.valid" type="submit" class="w-full 9xl:w-auto font-bold text-skin-primary bg-skin-secondary hover:bg-skin-accent rounded-lg text-sm px-5 py-2.5 text-center">Anmelden</button>
|
||||||
|
</form>
|
||||||
35
src/app/core/auth/components/login/login.component.ts
Normal file
35
src/app/core/auth/components/login/login.component.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { filter } from 'rxjs';
|
||||||
|
import { AuthService } from 'src/app/core/services/auth.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrls: ['./login.component.scss']
|
||||||
|
})
|
||||||
|
export class LoginComponent {
|
||||||
|
loginForm = new FormGroup({
|
||||||
|
identifier: new FormControl('', [Validators.required]),
|
||||||
|
password: new FormControl('', [Validators.required]),
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.authService.currentState$.pipe(
|
||||||
|
filter(state => state !== undefined)
|
||||||
|
).subscribe(state => {
|
||||||
|
this.router.navigateByUrl('/home');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
login(): void {
|
||||||
|
this.authService.login({
|
||||||
|
identifier: this.loginForm.value.identifier!,
|
||||||
|
password: this.loginForm.value.password!
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<p>registration works!</p>
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-registration',
|
||||||
|
templateUrl: './registration.component.html',
|
||||||
|
styleUrls: ['./registration.component.scss']
|
||||||
|
})
|
||||||
|
export class RegistrationComponent {
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<app-navigation></app-navigation>
|
<app-navigation></app-navigation>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Home
|
<iframe src="/api/health"></iframe>
|
||||||
</div>
|
</div>
|
||||||
@ -1,5 +1,47 @@
|
|||||||
<a routerLink="/home">
|
|
||||||
<h1 class="w-full bg-zinc-700 p-5 text-white text-6xl font-bold text-center">
|
|
||||||
Navigation
|
<nav class="bg-skin-secondary">
|
||||||
</h1>
|
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||||
</a>
|
<a href="#" class="flex items-center space-x-3">
|
||||||
|
<img src="assets/icon.png" class="h-8" alt="Beekeeper Logo" />
|
||||||
|
<span class="text-skin-primary self-center text-2xl font-semibold whitespace-nowrap">Beekeeper</span>
|
||||||
|
</a>
|
||||||
|
<div class="flex items-center md:order-2 space-x-3 md:space-x-0">
|
||||||
|
<button type="button" class="block w-8 h-8 text-sm bg-skin-primary rounded-full md:me-0 focus:ring-4 focus:ring-gray-300" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
|
||||||
|
<span class="text-skin-secondary rounded-full">AA</span>
|
||||||
|
<!-- <img class="w-8 h-8 rounded-full" src="/docs/images/people/profile-picture-3.jpg" alt="user photo"> -->
|
||||||
|
</button>
|
||||||
|
<!-- Dropdown menu -->
|
||||||
|
<div class="z-50 hidden my-4 text-base list-none divide-y divide-gray-100 rounded-lg shadow bg-skin-primary" id="user-dropdown">
|
||||||
|
<div class="px-4 py-3">
|
||||||
|
<span class="block text-sm text-skin-accent font-bold">{{state?.username}}</span>
|
||||||
|
<span class="block text-sm text-skin-accent-muted truncate">{{state?.roleIdentifier}}</span>
|
||||||
|
</div>
|
||||||
|
<ul class="p-4" aria-labelledby="user-menu-button">
|
||||||
|
<li>
|
||||||
|
<a href="#" class="block py-2 px-3 rounded text-skin-primary-muted hover:text-skin-primary md:text-skin-secondary-muted md:hover:text-skin-secondary hover:bg-skin-secondary md:p-0">Einstellungen</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="w-full block py-2 px-3 rounded text-skin-primary-muted hover:text-skin-primary md:text-skin-secondary-muted md:hover:text-skin-secondary hover:bg-skin-secondary md:p-0" (click)="logout()">Ausloggen</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button data-collapse-toggle="navbar-user" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-skin-secondary bg-skin-primary rounded-lg md:hidden hover:bg-skin-primary-muted focus:outline-none focus:ring-2 focus:ring-gray-200" aria-controls="navbar-user" aria-expanded="false">
|
||||||
|
<span class="sr-only">Open main menu</span>
|
||||||
|
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="items-center justify-between hidden w-full md:flex md:w-auto md:order-1" id="navbar-user">
|
||||||
|
<ul class="flex flex-col font-medium p-4 md:p-0 mt-4 rounded-lg bg-skin-primary md:bg-skin-secondary md:space-x-8 md:flex-row md:mt-0 md:border-0 md:bg-skin-fill">
|
||||||
|
<li>
|
||||||
|
<a routerLink="/home" class="block py-2 px-3 rounded text-skin-primary md:text-skin-secondary md:p-0" aria-current="page">Home</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" class="block py-2 px-3 rounded text-skin-primary-muted hover:text-skin-primary md:text-skin-secondary-muted md:hover:text-skin-secondary hover:bg-skin-secondary md:p-0">About</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|||||||
@ -1,9 +1,36 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
import { UserStateResponse } from '../../models/user-state-request.model';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { filter, map } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navigation',
|
selector: 'app-navigation',
|
||||||
templateUrl: './navigation.component.html',
|
templateUrl: './navigation.component.html',
|
||||||
styleUrls: ['./navigation.component.scss'],
|
styleUrls: ['./navigation.component.scss'],
|
||||||
})
|
})
|
||||||
export class NavigationComponent {
|
export class NavigationComponent implements OnInit {
|
||||||
|
|
||||||
|
state: UserStateResponse | undefined | null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private router: Router,
|
||||||
|
) {
|
||||||
|
this.state = this.authService.currentState$.value;
|
||||||
|
this.authService.currentState$.pipe(
|
||||||
|
filter(state => state === undefined)
|
||||||
|
).subscribe( state =>
|
||||||
|
this.router.navigateByUrl('/auth/login')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
initFlowbite();
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
this.authService.logout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,9 @@ import { NgModule } from '@angular/core';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { HomeComponent } from './components/home/home.component';
|
import { HomeComponent } from './components/home/home.component';
|
||||||
import { NavigationComponent } from './components/navigation/navigation.component';
|
import { NavigationComponent } from './components/navigation/navigation.component';
|
||||||
|
import { AuthGuard } from './guards/auth.guard';
|
||||||
|
import { AuthService } from './services/auth.service';
|
||||||
|
import { RequestService } from './services/request.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -10,6 +13,7 @@ import { NavigationComponent } from './components/navigation/navigation.componen
|
|||||||
exports: [HomeComponent, NavigationComponent],
|
exports: [HomeComponent, NavigationComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule
|
CommonModule
|
||||||
]
|
],
|
||||||
|
providers: [AuthGuard, AuthService, RequestService]
|
||||||
})
|
})
|
||||||
export class CoreModule { }
|
export class CoreModule { }
|
||||||
|
|||||||
26
src/app/core/guards/auth.guard.ts
Normal file
26
src/app/core/guards/auth.guard.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
|
||||||
|
import { filter, map, Observable } from "rxjs";
|
||||||
|
import { AuthService } from "../services/auth.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivate(): Observable<boolean> | boolean {
|
||||||
|
return this.authService.currentState$.pipe(
|
||||||
|
map((currentState) => {
|
||||||
|
if (!currentState) {
|
||||||
|
this.router.navigateByUrl('/auth');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/app/core/models/login-request.model copy.ts
Normal file
8
src/app/core/models/login-request.model copy.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface LoginRequest {
|
||||||
|
identifier: string,
|
||||||
|
password: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginResponse {
|
||||||
|
sessionId: string
|
||||||
|
}
|
||||||
12
src/app/core/models/user-state-request.model.ts
Normal file
12
src/app/core/models/user-state-request.model.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export interface UserStateRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserStateResponse {
|
||||||
|
id: string,
|
||||||
|
sessionId: string,
|
||||||
|
username: string,
|
||||||
|
roleIdentifier: string,
|
||||||
|
createdAt: string,
|
||||||
|
updatedAt: string,
|
||||||
|
permissions: string[],
|
||||||
|
}
|
||||||
56
src/app/core/services/auth.service.ts
Normal file
56
src/app/core/services/auth.service.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { RequestService } from "./request.service";
|
||||||
|
import { UserStateResponse } from "../models/user-state-request.model";
|
||||||
|
import { BehaviorSubject, Observable } from "rxjs";
|
||||||
|
import { LoginRequest, LoginResponse } from "../models/login-request.model copy";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthService {
|
||||||
|
|
||||||
|
currentState$ = new BehaviorSubject<UserStateResponse | null | undefined>(undefined);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private requestService: RequestService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
readUserState(): void {
|
||||||
|
this.requestService.get(
|
||||||
|
'user/state',
|
||||||
|
{},
|
||||||
|
(response: UserStateResponse) => {
|
||||||
|
this.currentState$.next(response);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.currentState$.next(undefined);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
login(body: LoginRequest): LoginResponse|null {
|
||||||
|
let result = null;
|
||||||
|
|
||||||
|
this.requestService.post(
|
||||||
|
'auth/login-user',
|
||||||
|
body,
|
||||||
|
(response: LoginResponse) => {
|
||||||
|
result = response;
|
||||||
|
this.readUserState();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
this.requestService.post(
|
||||||
|
'auth/logout-user',
|
||||||
|
{},
|
||||||
|
(response: any) => {
|
||||||
|
this.readUserState();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -11,28 +10,46 @@ export class RequestService {
|
|||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private snackBar: MatSnackBar
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
post(apiPath: string, body: any, fct: Function)
|
public post(apiPath: string, body: any, successFunction: Function, errorFunction: Function|null = null)
|
||||||
{
|
{
|
||||||
let url = this.obtainUrl(apiPath);
|
let url = this.obtainUrl(apiPath);
|
||||||
let observable = this.http.post(url, body).subscribe(
|
let observable = this.http.post(url, body).subscribe(
|
||||||
(answer:any) => {
|
(answer:any) => {
|
||||||
fct(answer);
|
successFunction(answer);
|
||||||
},
|
},
|
||||||
(error:any) => {
|
(error:any) => {
|
||||||
this.handleError(error);
|
if (errorFunction === null)
|
||||||
|
this.handleError(error);
|
||||||
|
else
|
||||||
|
errorFunction(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(apiPath: string, body: any, successFunction: Function, errorFunction: Function|null = null)
|
||||||
|
{
|
||||||
|
let url = this.obtainUrl(apiPath);
|
||||||
|
let observable = this.http.get(url, body).subscribe(
|
||||||
|
(answer:any) => {
|
||||||
|
successFunction(answer);
|
||||||
|
},
|
||||||
|
(error:any) => {
|
||||||
|
if (errorFunction === null)
|
||||||
|
this.handleError(error);
|
||||||
|
else
|
||||||
|
errorFunction(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
postFiles(apiPath: string, files: File[], fct: Function) {
|
public postFiles(apiPath: string, files: File[], successFunction: Function, errorFunction: Function|null = null) {
|
||||||
if (!files || files.length === 0) {
|
if (!files || files.length === 0) {
|
||||||
throw 'Need to select at least one file';
|
throw 'Need to select at least one file';
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
||||||
@ -42,23 +59,13 @@ export class RequestService {
|
|||||||
let url = this.obtainUrl(apiPath);
|
let url = this.obtainUrl(apiPath);
|
||||||
let observable = this.http.post<any>(url, formData).subscribe(
|
let observable = this.http.post<any>(url, formData).subscribe(
|
||||||
(answer: any) => {
|
(answer: any) => {
|
||||||
fct(answer);
|
successFunction(answer);
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
this.handleError(error);
|
if (errorFunction === null)
|
||||||
}
|
this.handleError(error);
|
||||||
);
|
else
|
||||||
}
|
errorFunction(error);
|
||||||
|
|
||||||
get(apiPath: string, body: any, fct: Function)
|
|
||||||
{
|
|
||||||
let url = this.obtainUrl(apiPath);
|
|
||||||
let observable = this.http.get(url, body).subscribe(
|
|
||||||
(answer:any) => {
|
|
||||||
fct(answer);
|
|
||||||
},
|
|
||||||
(error:any) => {
|
|
||||||
this.handleError(error);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -98,8 +105,9 @@ export class RequestService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private showSnackBar(message: string, action?: string) {
|
private showSnackBar(message: string, action?: string) {
|
||||||
this.snackBar.open(message.toString(), action, {
|
/*this.snackBar.open(message.toString(), action, {
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
});
|
});*/
|
||||||
|
console.log(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,27 +7,6 @@ import { PaginatorComponent } from './components/paginator/paginator.component';
|
|||||||
import { TabControlComponent } from './components/tab-control/tab-control.component';
|
import { TabControlComponent } from './components/tab-control/tab-control.component';
|
||||||
import { TableComponent } from './components/table/table.component';
|
import { TableComponent } from './components/table/table.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
|
||||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
|
||||||
import { MatListModule } from '@angular/material/list';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatGridListModule } from '@angular/material/grid-list';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
|
||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
|
||||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
||||||
import { MatDividerModule } from '@angular/material/divider';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
|
||||||
import { MatTableModule } from '@angular/material/table';
|
|
||||||
import { MatChipsModule } from '@angular/material/chips';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -44,54 +23,12 @@ import { MatChipsModule } from '@angular/material/chips';
|
|||||||
FormComponent,
|
FormComponent,
|
||||||
TableComponent,
|
TableComponent,
|
||||||
|
|
||||||
MatSlideToggleModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatGridListModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MatExpansionModule,
|
|
||||||
MatMenuModule,
|
|
||||||
MatListModule,
|
|
||||||
MatToolbarModule,
|
|
||||||
MatSidenavModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatSelectModule,
|
|
||||||
MatDividerModule,
|
|
||||||
MatDialogModule,
|
|
||||||
MatSnackBarModule,
|
|
||||||
MatPaginatorModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
MatTabsModule,
|
|
||||||
MatTableModule,
|
|
||||||
MatChipsModule,
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule,
|
RouterModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
MatSlideToggleModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatButtonModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatGridListModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MatExpansionModule,
|
|
||||||
MatMenuModule,
|
|
||||||
MatListModule,
|
|
||||||
MatToolbarModule,
|
|
||||||
MatSidenavModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatSelectModule,
|
|
||||||
MatDividerModule,
|
|
||||||
MatDialogModule,
|
|
||||||
MatSnackBarModule,
|
|
||||||
MatPaginatorModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
MatTabsModule,
|
|
||||||
MatTableModule,
|
|
||||||
MatChipsModule,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SharedModule {}
|
export class SharedModule {}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 66 KiB |
BIN
src/assets/icon.png
Normal file
BIN
src/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 66 KiB |
@ -5,11 +5,10 @@
|
|||||||
<title>Bienen</title>
|
<title>Bienen</title>
|
||||||
<base href="/" />
|
<base href="/" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" type="image/x-icon" href="assets/icon.ico" />
|
<link rel="icon" type="image/x-icon" href="assets/icon.png" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-zinc-900">
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -1,3 +1,20 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--color-text-primary: 0,0,0;
|
||||||
|
--color-text-primary-muted: 100,100,100;
|
||||||
|
--color-text-secondary: 255,255,255;
|
||||||
|
--color-text-secondary-muted: 170,170,170;
|
||||||
|
--color-text-accent: 255, 199, 44;
|
||||||
|
--color-text-accent-muted: 255, 199, 44;
|
||||||
|
|
||||||
|
|
||||||
|
--color-primary: 255, 255, 255;
|
||||||
|
--color-secondary: 255, 199, 44;
|
||||||
|
--color-accent: 255, 199, 44;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,9 +1,41 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
function withOpacity(variableName) {
|
||||||
module.exports = {
|
return ({ opacityValue }) => {
|
||||||
content: ["./src/**/*.{html,ts}"],
|
if (opacityValue !== undefined) {
|
||||||
theme: {
|
return `rgba(var(${variableName}), ${opacityValue})`
|
||||||
extend: {},
|
}
|
||||||
},
|
return `rgb(var(${variableName}))`
|
||||||
plugins: [],
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./src/**/*.{html,ts}",
|
||||||
|
"./node_modules/flowbite/**/*.js"
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
textColor: {
|
||||||
|
skin: {
|
||||||
|
primary: withOpacity('--color-text-primary'),
|
||||||
|
'primary-muted': withOpacity('--color-text-primary-muted'),
|
||||||
|
secondary: withOpacity('--color-text-secondary'),
|
||||||
|
'secondary-muted': withOpacity('--color-text-secondary-muted'),
|
||||||
|
accent: withOpacity('--color-text-accent'),
|
||||||
|
'accent-muted': withOpacity('--color-text-accent-muted'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
skin: {
|
||||||
|
primary: withOpacity('--color-primary'),
|
||||||
|
secondary: withOpacity('--color-secondary'),
|
||||||
|
accent: withOpacity('--color-accent'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('flowbite/plugin')
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user