Add login component.
This commit is contained in:
@@ -3,7 +3,7 @@ root = true
|
|||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = tab
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve --proxy-config proxy.conf.json",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
|
|||||||
6
src/main/ts/proxy.conf.json
Normal file
6
src/main/ts/proxy.conf.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"/api": {
|
||||||
|
"target": "http://localhost:8080",
|
||||||
|
"secure": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
const routes: Routes = [];
|
const routes: Routes = [
|
||||||
|
{ path: 'serviceUnavailable', component: ServiceUnavailableComponent },
|
||||||
|
{ path: '', component: AppComponent }
|
||||||
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import { ServiceUnavailableInterceptor } from './core/interceptors/service-unavailable.interceptor';
|
||||||
|
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
import { UserService } from './core/services/user.service';
|
||||||
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
@@ -9,21 +13,34 @@ import { HeaderComponent } from './header/header.component';
|
|||||||
import { FooterComponent } from './footer/footer.component';
|
import { FooterComponent } from './footer/footer.component';
|
||||||
import { NotificationElement } from './core/notifications/notification-element/notification-element.component';
|
import { NotificationElement } from './core/notifications/notification-element/notification-element.component';
|
||||||
import { NotificationsComponent } from './core/notifications/notifications.component';
|
import { NotificationsComponent } from './core/notifications/notifications.component';
|
||||||
|
import { LoginComponent } from './login/login.component';
|
||||||
|
import { ServiceUnavailableComponent } from './service-unavailable/service-unavailable.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
|
LoginComponent,
|
||||||
NotificationElement,
|
NotificationElement,
|
||||||
NotificationsComponent
|
NotificationsComponent,
|
||||||
|
ServiceUnavailableComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
BrowserModule,
|
||||||
|
FormsModule,
|
||||||
|
HttpClientModule,
|
||||||
MDBBootstrapModule.forRoot()
|
MDBBootstrapModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [
|
||||||
|
UserService,
|
||||||
|
{
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: ServiceUnavailableInterceptor,
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
],
|
||||||
bootstrap: [
|
bootstrap: [
|
||||||
AppComponent
|
AppComponent
|
||||||
]
|
]
|
||||||
|
|||||||
46
src/main/ts/src/app/core/entities.ts
Normal file
46
src/main/ts/src/app/core/entities.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
export class User {
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public name: string,
|
||||||
|
public email: string
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static new(): User {
|
||||||
|
return new User('', '', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignUpDTO {
|
||||||
|
constructor(
|
||||||
|
public name: string,
|
||||||
|
public email: string,
|
||||||
|
public password: string,
|
||||||
|
public confirmPassword: string
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static new(): SignUpDTO {
|
||||||
|
return new SignUpDTO('', '', '', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ConfigurationFile {
|
||||||
|
constructor(
|
||||||
|
public id: string
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static new(): ConfigurationFile {
|
||||||
|
return new ConfigurationFile('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Application {
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public name: string,
|
||||||
|
public configurationFileList: Array<ConfigurationFile>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static new(): Application {
|
||||||
|
return new Application('', '', []);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpInterceptor, HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
import { NotificationsComponent } from '../notifications/notifications.component';
|
||||||
|
|
||||||
|
@Injectable({providedIn: 'root'})
|
||||||
|
export class ServiceUnavailableInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
return next.handle(req).pipe(catchError(ex => {
|
||||||
|
if (!!ex && ex.status === 504) {
|
||||||
|
NotificationsComponent.error('Le serveur est actuellement indisponible. Veuillez contacter l\'administrateur.');
|
||||||
|
this.router.navigate(['/serviceUnavailable']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return throwError(ex);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/main/ts/src/app/core/services/user.service.spec.ts
Normal file
16
src/main/ts/src/app/core/services/user.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/* tslint:disable:no-unused-variable */
|
||||||
|
|
||||||
|
import { TestBed, async, inject } from '@angular/core/testing';
|
||||||
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
|
describe('Service: User', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [UserService]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ...', inject([UserService], (service: UserService) => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
||||||
21
src/main/ts/src/app/core/services/user.service.ts
Normal file
21
src/main/ts/src/app/core/services/user.service.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { User } from '../entities';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UserService {
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
login(user: User): Observable<void> {
|
||||||
|
return this.httpClient.post<void>(`/api/users/login`, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnection(): Observable<void> {
|
||||||
|
return this.httpClient.get<void>(`/api/users/disconnection`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,9 +11,10 @@
|
|||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span id="right-area">
|
<span id="right-area">
|
||||||
<button mdbBtn class="flat rounded-pill" mdbWavesEffect>
|
<button mdbBtn class="flat rounded-pill" (click)="loginForm.show()" mdbWavesEffect>
|
||||||
<i class="fa fa-sign-in-alt"></i>
|
<i class="fa fa-sign-in-alt"></i>
|
||||||
Connexion
|
Connexion
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</header>
|
</header>
|
||||||
|
<app-login #loginForm></app-login>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { NotificationsComponent } from './../core/notifications/notifications.component';
|
import { NotificationsComponent } from './../core/notifications/notifications.component';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { LoginComponent } from '../login/login.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
@@ -7,6 +8,7 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
styleUrls: ['./header.component.scss']
|
styleUrls: ['./header.component.scss']
|
||||||
})
|
})
|
||||||
export class HeaderComponent implements OnInit {
|
export class HeaderComponent implements OnInit {
|
||||||
|
@ViewChild('loginForm', {static: true}) loginForm: LoginComponent;
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
|
|||||||
59
src/main/ts/src/app/login/login.component.html
Normal file
59
src/main/ts/src/app/login/login.component.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<div mdbModal
|
||||||
|
#loginModal="mdbModal"
|
||||||
|
class="modal fade"
|
||||||
|
tabindex="-1"
|
||||||
|
role="dialog"
|
||||||
|
aria-labelledby="loginModal"
|
||||||
|
aria-hidden="true">
|
||||||
|
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form (ngSubmit)="onSubmit()" ngNativeValidate>
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close pull-right" aria-label="Close" (click)="loginModal.hide()">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<img src="assets/images/icon-64.png"/>
|
||||||
|
<h4 class="modal-title w-100">
|
||||||
|
Connexion
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<!-- Email address -->
|
||||||
|
<div class="md-form">
|
||||||
|
<input mdbInputDirective
|
||||||
|
type="email"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
class="form-control"
|
||||||
|
#email="ngModel"
|
||||||
|
[(ngModel)]="model.email"
|
||||||
|
data-error="Veuillez saisir une adresse email valide"
|
||||||
|
[validateSuccess]="false"
|
||||||
|
required >
|
||||||
|
<label for="email">Adresse email</label>
|
||||||
|
</div>
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="md-form">
|
||||||
|
<input mdbInputDirective
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
class="form-control"
|
||||||
|
#password="ngModel"
|
||||||
|
[(ngModel)]="model.password"
|
||||||
|
data-error="Veuillez saisir votre mot de passe"
|
||||||
|
[validateSuccess]="false"
|
||||||
|
required >
|
||||||
|
<label for="password">Mot de passe</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button mdbBtn type="submit" color="indigo" size="sm" class="rounded-pill" mdbWavesEffect>
|
||||||
|
Valider
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
59
src/main/ts/src/app/login/login.component.scss
Normal file
59
src/main/ts/src/app/login/login.component.scss
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// #form {
|
||||||
|
// width: 300px;
|
||||||
|
// margin: auto;
|
||||||
|
// margin-top: 50px;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #logo {
|
||||||
|
// text-align: center;
|
||||||
|
// margin-bottom: 15px;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #title {
|
||||||
|
// text-align: center;
|
||||||
|
// font-size: 1.5em;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #buttons-area {
|
||||||
|
// button {
|
||||||
|
// width: 90%;
|
||||||
|
// margin: auto;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// a {
|
||||||
|
// margin: auto;
|
||||||
|
// margin-bottom: 20px;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// #signup {
|
||||||
|
// text-align: center;
|
||||||
|
// margin-top: 35px;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
margin-top: 50px;
|
||||||
|
width: 300px;
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
.modal-header {
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
top: -25px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 64px;
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/main/ts/src/app/login/login.component.spec.ts
Normal file
28
src/main/ts/src/app/login/login.component.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* tslint:disable:no-unused-variable */
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
|
||||||
|
describe('LoginComponent', () => {
|
||||||
|
let component: LoginComponent;
|
||||||
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ LoginComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
41
src/main/ts/src/app/login/login.component.ts
Normal file
41
src/main/ts/src/app/login/login.component.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { User } from './../core/entities';
|
||||||
|
import { ModalDirective } from 'angular-bootstrap-md';
|
||||||
|
import { UserService } from '../core/services/user.service';
|
||||||
|
import { NotificationsComponent } from '../core/notifications/notifications.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrls: ['./login.component.scss']
|
||||||
|
})
|
||||||
|
export class LoginComponent implements OnInit {
|
||||||
|
model: User = User.new();
|
||||||
|
@ViewChild('loginModal', {static: true}) loginModal: ModalDirective;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private userService: UserService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
this.userService.login(this.model).subscribe(() => {
|
||||||
|
NotificationsComponent.success('Connexion réussie.');
|
||||||
|
this.loginModal.hide();
|
||||||
|
}, ex => {
|
||||||
|
console.error('Error during login attempt: ', ex);
|
||||||
|
if (ex.error.status === 400) {
|
||||||
|
NotificationsComponent.error(`Login ou mot de passe incorrect.`);
|
||||||
|
} else {
|
||||||
|
NotificationsComponent.error(`Une erreur technique est survenue :\n${ex.error.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
show(): void {
|
||||||
|
this.loginModal.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<div id="content">
|
||||||
|
<mdb-card>
|
||||||
|
<!--Card image-->
|
||||||
|
<mdb-card-img src="assets/images/service-unavailable.jpg" alt="Service unavailable"></mdb-card-img>
|
||||||
|
<!--Card content-->
|
||||||
|
<mdb-card-body>
|
||||||
|
<!--Title-->
|
||||||
|
<mdb-card-title>
|
||||||
|
<h4>Service indisponible</h4>
|
||||||
|
</mdb-card-title>
|
||||||
|
<!--Text-->
|
||||||
|
<mdb-card-text>
|
||||||
|
Le serveur est actuellement indisponible.<br/>
|
||||||
|
Veuillez contacter l'administrateur.
|
||||||
|
</mdb-card-text>
|
||||||
|
</mdb-card-body>
|
||||||
|
</mdb-card>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#content {
|
||||||
|
width: 450px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/* tslint:disable:no-unused-variable */
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { ServiceUnavailableComponent } from './service-unavailable.component';
|
||||||
|
|
||||||
|
describe('ServiceUnavailableComponent', () => {
|
||||||
|
let component: ServiceUnavailableComponent;
|
||||||
|
let fixture: ComponentFixture<ServiceUnavailableComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ ServiceUnavailableComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ServiceUnavailableComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-service-unavailable',
|
||||||
|
templateUrl: './service-unavailable.component.html',
|
||||||
|
styleUrls: ['./service-unavailable.component.scss']
|
||||||
|
})
|
||||||
|
export class ServiceUnavailableComponent {
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
BIN
src/main/ts/src/assets/images/icon-128.png
Normal file
BIN
src/main/ts/src/assets/images/icon-128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
src/main/ts/src/assets/images/icon-64.png
Normal file
BIN
src/main/ts/src/assets/images/icon-64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
BIN
src/main/ts/src/assets/images/service-unavailable.jpg
Normal file
BIN
src/main/ts/src/assets/images/service-unavailable.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Reference in New Issue
Block a user