merge home into master #4
Merged
maxence.jouannet
merged 5 commits from home
into master
5 months ago
@ -1,8 +1,9 @@
|
|||||||
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
|
import { provideHttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
|
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),provideHttpClient()]
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { HomePageComponent } from './components/home-page/home-page.component';
|
import { HomePageComponent } from './components/home-page/home-page.component';
|
||||||
import { LeafletMapComponent } from './components/leaflet-map/leaflet-map.component';
|
import { LeafletMapComponent } from './components/leaflet-map/leaflet-map.component';
|
||||||
|
import { LoginPageComponent } from './components/login-page/login-page.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{path: '', component: HomePageComponent},
|
{path: '', component: HomePageComponent},
|
||||||
{path: 'map', component: LeafletMapComponent}
|
{path: 'map', component: LeafletMapComponent},
|
||||||
|
{path: 'sign', component:LoginPageComponent}
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
#authentication-modal.show {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#authentication-modal.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-in-out;
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<!-- Modal toggle -->
|
||||||
|
<button data-modal-target="authentication-modal" data-modal-toggle="authentication-modal" class="block py-2 text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300"
|
||||||
|
type="button">
|
||||||
|
Connexion
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Main modal -->
|
||||||
|
<div id="authentication-modal" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full transition-opacity duration-300 ease-in-out">
|
||||||
|
<div class="relative p-4 w-full max-w-md max-h-full">
|
||||||
|
<!-- Modal content -->
|
||||||
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||||
|
<!-- Modal header -->
|
||||||
|
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
||||||
|
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
Sign in to our platform
|
||||||
|
</h3>
|
||||||
|
<button type="button" id="close-login-modal" class="end-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide="authentication-modal">
|
||||||
|
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
||||||
|
</svg>
|
||||||
|
<span class="sr-only">Close modal</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Modal body -->
|
||||||
|
<div class="p-4 md:p-5">
|
||||||
|
<form [formGroup]="userForm" class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label for="login" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your login</label>
|
||||||
|
<input formControlName="login" type="login" name="login" id="login" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="user" required />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your password</label>
|
||||||
|
<input formControlName="password" type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<div class="flex items-start">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input id="remember" type="checkbox" value="" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300 dark:bg-gray-600 dark:border-gray-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800"/>
|
||||||
|
</div>
|
||||||
|
<label for="remember" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Remember me</label>
|
||||||
|
</div>
|
||||||
|
<a href="#" class="text-sm text-blue-700 hover:underline dark:text-blue-500">Lost Password?</a>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="errorMessage" class="text-red-500 text-sm">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</div>
|
||||||
|
<button (click)="login()" class="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Login to your account</button>
|
||||||
|
<div class="text-sm font-medium text-gray-500 dark:text-gray-300">
|
||||||
|
Not registered? <a href="#" class="text-blue-700 hover:underline dark:text-blue-500">Create account</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoginPageComponent } from './login-page.component';
|
||||||
|
|
||||||
|
describe('LoginPageComponent', () => {
|
||||||
|
let component: LoginPageComponent;
|
||||||
|
let fixture: ComponentFixture<LoginPageComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [LoginPageComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(LoginPageComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Component, Renderer2 } from '@angular/core';
|
||||||
|
import { LoginService } from '../../services/login.service';
|
||||||
|
import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { User } from '../../model/User';
|
||||||
|
import { LocalStorageService } from '../../services/localstorage.service';
|
||||||
|
import { NgIf } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login-page',
|
||||||
|
imports: [FormsModule, ReactiveFormsModule, NgIf],
|
||||||
|
templateUrl: './login-page.component.html',
|
||||||
|
styleUrl: './login-page.component.css'
|
||||||
|
})
|
||||||
|
export class LoginPageComponent {
|
||||||
|
|
||||||
|
userForm: FormGroup;
|
||||||
|
user: User = {login: '', password: ''};
|
||||||
|
errorMessage: string = '';
|
||||||
|
|
||||||
|
constructor(private loginService: LoginService, private fb: FormBuilder, private router: Router, private localStorageService: LocalStorageService, private renderer: Renderer2) {
|
||||||
|
this.userForm = this.fb.group({
|
||||||
|
login: [this.user.login, [Validators.required, Validators.minLength(3)]],
|
||||||
|
password: [this.user.password, [Validators.required, Validators.minLength(3)]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public login(){
|
||||||
|
if (this.userForm.invalid){
|
||||||
|
this.errorMessage = "Veuillez remplir tous les champs";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.user.login = this.userForm.value.login;
|
||||||
|
this.user.password = this.userForm.value.password;
|
||||||
|
|
||||||
|
this.loginService.login(this.user.login, this.user.password).subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
console.log("Connexion OK: ", response);
|
||||||
|
this.localStorageService.setToken(response.access_token);
|
||||||
|
this.closeModal();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.router.navigate(['/map']);
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
error: (response) => {
|
||||||
|
console.log("Connexion KO: ", response.error.detail);
|
||||||
|
this.errorMessage = response.error.detail;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private closeModal() {
|
||||||
|
const modal = document.getElementById('close-login-modal');
|
||||||
|
if (modal) {
|
||||||
|
modal.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
export interface User{
|
||||||
|
login:string;
|
||||||
|
password:string;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class LocalStorageService {
|
||||||
|
|
||||||
|
private readonly AUTH_TOKEN_KEY = 'auth_token';
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
setToken(token: string): void {
|
||||||
|
localStorage.setItem(this.AUTH_TOKEN_KEY, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
getToken(): string | null {
|
||||||
|
return localStorage.getItem(this.AUTH_TOKEN_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeToken(): void {
|
||||||
|
localStorage.removeItem(this.AUTH_TOKEN_KEY);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
apiURL: 'https://api.memorymap.fr/api/v1',
|
apiURL: 'http://127.0.0.1:8000/api/v1',
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in new issue