diff --git a/src/app/app.component.html b/src/app/app.component.html index 642c284..7490ec0 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,9 +1,9 @@
- - Flotte + fLotte @@ -16,6 +16,7 @@ Dark Mode
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7131c97..ab69dbd 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,6 @@ import { Component, Renderer2 } from '@angular/core'; import { ColorThemeService } from './services/colorTheme.service'; +import { AuthService } from './services/auth.service'; @Component({ selector: 'app-root', @@ -7,16 +8,19 @@ import { ColorThemeService } from './services/colorTheme.service'; styleUrls: ['./app.component.scss'], }) export class AppComponent { - title = 'flotte-frontend'; + title = 'fLotte-fRontend'; darkThemeIsActive: boolean = false; + loggedIn = false; constructor( private renderer: Renderer2, - private themeService: ColorThemeService + private themeService: ColorThemeService, + private authService: AuthService ) { this.renderer.addClass(document.body, 'mat-app-background'); //so the background color changes dependent on current theme this.themeService.load(); this.darkThemeIsActive = this.themeService.currentActive() === 'dark-theme'; + this.authService.loggedIn.subscribe((value) => (this.loggedIn = value)); } changeTheme(event) { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 546efd0..a2df947 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,5 +1,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; // Angular Material Components import {MatToolbarModule} from '@angular/material/toolbar'; @@ -11,6 +13,9 @@ import {MatSlideToggleModule} from '@angular/material/slide-toggle'; import {MatIconModule} from '@angular/material/icon'; import {MatSidenavModule} from '@angular/material/sidenav'; import {MatListModule} from '@angular/material/list'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {MatProgressBarModule} from '@angular/material/progress-bar'; import { AppRoutingModule } from './app-routing.module'; @@ -29,8 +34,11 @@ import { BikesComponent } from './pages/bikes/bikes.component'; ], imports: [ BrowserModule, + HttpClientModule, AppRoutingModule, BrowserAnimationsModule, + FormsModule, + ReactiveFormsModule, MatToolbarModule, MatButtonModule, MatTableModule, @@ -39,7 +47,10 @@ import { BikesComponent } from './pages/bikes/bikes.component'; MatSlideToggleModule, MatIconModule, MatSidenavModule, - MatListModule + MatListModule, + MatFormFieldModule, + MatProgressSpinnerModule, + MatProgressBarModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/app/models/user.ts b/src/app/models/user.ts new file mode 100644 index 0000000..16091b4 --- /dev/null +++ b/src/app/models/user.ts @@ -0,0 +1,5 @@ +export class User { + email: string; + requestToken: string; + refreshToken: string; +} \ No newline at end of file diff --git a/src/app/pages/login/login.component.html b/src/app/pages/login/login.component.html index 147cfc4..290b9a0 100644 --- a/src/app/pages/login/login.component.html +++ b/src/app/pages/login/login.component.html @@ -1 +1,38 @@ -

login works!

+
+

fLotte Login

+ + E-Mail-Adresse eingeben + + + Bitte geben Sie eine E-Mail-Adresse ein. + + + Bitte geben Sie eine valide E-Mail-Adresse ein. + + + + + Passwort eingeben + + + Bitte geben Sie Ihr Passwort ein. + + + + + +
diff --git a/src/app/pages/login/login.component.scss b/src/app/pages/login/login.component.scss index e69de29..542b480 100644 --- a/src/app/pages/login/login.component.scss +++ b/src/app/pages/login/login.component.scss @@ -0,0 +1,16 @@ +#login-form { + height: 100%; + display: flex; + flex-direction: column; + max-width: 32em; + min-width: 5em; + margin: auto; + margin-top: 3em; + padding: 1em; + .mat-form-field { + margin: 0.5em 0; + } + #loading-bar { + margin-bottom: 1em; + } +} \ No newline at end of file diff --git a/src/app/pages/login/login.component.ts b/src/app/pages/login/login.component.ts index c74528f..653e5bb 100644 --- a/src/app/pages/login/login.component.ts +++ b/src/app/pages/login/login.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import {FormControl, Validators} from '@angular/forms'; +import {AuthService} from '../../services/auth.service'; @Component({ selector: 'app-login', @@ -6,10 +8,20 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./login.component.scss'] }) export class LoginComponent implements OnInit { - - constructor() { } + email = new FormControl('', [Validators.required, Validators.email]); + password = new FormControl('', [Validators.required]); + hide = true; + loading = false; + constructor(private authService: AuthService) { } ngOnInit(): void { } + login() { + if (this.email.invalid || this.password.invalid) { + return; + } + this.authService.login(this.email.value, this.password.value).subscribe(); + } + } diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts new file mode 100644 index 0000000..85bf050 --- /dev/null +++ b/src/app/services/auth.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { map } from 'rxjs/operators'; +import { environment } from '../../environments/environment'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class AuthService { + public loggedIn: BehaviorSubject; + + constructor(private http: HttpClient) { + this.loggedIn = new BehaviorSubject(false); + this.checkIfUserIsLoggedIn(); + } + + private checkIfUserIsLoggedIn(): void { + this.loggedIn.next(!!this.requestToken); + } + + public get requestToken(): string { + return localStorage.getItem('requestToken'); + } + + public get refreshToken(): string { + return localStorage.getItem('refreshToken'); + } + + login(email: string, password: string) { + return this.http + .post(`${environment.authUrl}/login`, { email, password }) + .pipe( + map((response) => { + // store request and refresh token in local storage to keep user logged in between page refreshes + localStorage.setItem('requestToken', response.request_token); + localStorage.setItem('refreshToken', response.refresh_token); + this.checkIfUserIsLoggedIn(); + }) + ); + } + + logout() { + // remove token from local storage to log user out + localStorage.removeItem('requestToken'); + localStorage.removeItem('refreshToken'); + this.checkIfUserIsLoggedIn(); + } +} diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7b4f817..459188a 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,7 +3,9 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + apiUrl: "http://localhost:4000", + authUrl: "http://localhost:8080" }; /* diff --git a/src/styles.scss b/src/styles.scss index f31f353..42b42d7 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -3,3 +3,17 @@ html, body { height: 100%; } body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } + +h1 { + display: block; + padding-bottom: 5px; + position: relative; +} +h1:before { + content: ""; + position: absolute; + width: 5rem; + height: 1px; + bottom: 0; + border-bottom: 3px solid #7fc600; +} \ No newline at end of file