commit
79d5fd5aef
@ -1,4 +1,4 @@
|
||||
<app-navbar *ngIf="isAuth"></app-navbar>
|
||||
<app-home-navbar *ngIf="!isAuth"></app-home-navbar>
|
||||
<app-navbar *ngIf="localStorageService.getToken()"></app-navbar>
|
||||
<app-home-navbar *ngIf="!localStorageService.getToken()"></app-home-navbar>
|
||||
|
||||
<router-outlet />
|
||||
|
@ -0,0 +1,129 @@
|
||||
<!-- Modal toggle -->
|
||||
<button
|
||||
(click)="openRegisterModal()"
|
||||
class="block py-2 text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300"
|
||||
type="button"
|
||||
>
|
||||
Inscription
|
||||
</button>
|
||||
|
||||
<!-- Main modal -->
|
||||
<div
|
||||
class="fixed inset-0 z-40 bg-gray-900 bg-opacity-50 w-full h-full transition-opacity duration-300 ease-in-out"
|
||||
[ngClass]="{
|
||||
'opacity-0 pointer-events-none': !isRegisterModalOpen,
|
||||
'opacity-100': isRegisterModalOpen
|
||||
}"
|
||||
(click)="closeRegisterModal()"
|
||||
></div>
|
||||
|
||||
<div
|
||||
id="register-modal"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
[ngClass]="{
|
||||
'opacity-0 scale-0 pointer-events-none': !isRegisterModalOpen,
|
||||
'opacity-100 scale-100': isRegisterModalOpen
|
||||
}"
|
||||
class="fixed top-0 right-0 left-0 z-50 flex justify-center items-center w-full h-full transition-opacity transition-transform 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 transition-transform duration-300 ease-in-out"
|
||||
>
|
||||
<!-- 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">
|
||||
Formulaire d'inscription
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
(click)="closeRegisterModal()"
|
||||
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"
|
||||
>
|
||||
<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"
|
||||
>Identifiant</label
|
||||
>
|
||||
<input
|
||||
formControlName="login"
|
||||
type="text"
|
||||
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="ex: captain24"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="password"
|
||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>Mot de passe (6 caractères minimum)</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>
|
||||
<label
|
||||
for="verifyPassword"
|
||||
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||
>Entrez le mot de passe à nouveau</label
|
||||
>
|
||||
<input
|
||||
formControlName="verifyPassword"
|
||||
type="password"
|
||||
name="verifyPassword"
|
||||
id="verifyPassword"
|
||||
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 *ngIf="errorMessage" class="text-red-500 text-sm">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
<button
|
||||
(click)="register()"
|
||||
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"
|
||||
>
|
||||
Démarrer l'aventure !
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegisterPageComponent } from './register-page.component';
|
||||
|
||||
describe('RegisterPageComponent', () => {
|
||||
let component: RegisterPageComponent;
|
||||
let fixture: ComponentFixture<RegisterPageComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RegisterPageComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegisterPageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,91 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { User } from '../../model/User';
|
||||
import { LocalStorageService } from '../../services/localstorage.service';
|
||||
import { RegisterService } from '../../services/register.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register-page',
|
||||
imports: [FormsModule, ReactiveFormsModule, CommonModule],
|
||||
templateUrl: './register-page.component.html',
|
||||
styleUrl: './register-page.component.css',
|
||||
})
|
||||
export class RegisterPageComponent {
|
||||
userForm: FormGroup;
|
||||
user: User = { login: '', password: '' };
|
||||
errorMessage: string = '';
|
||||
isRegisterModalOpen: boolean = false;
|
||||
|
||||
constructor(
|
||||
private registerService: RegisterService,
|
||||
private fb: FormBuilder,
|
||||
private localStorageService: LocalStorageService,
|
||||
private router: Router
|
||||
) {
|
||||
this.userForm = this.fb.group(
|
||||
{
|
||||
login: [
|
||||
this.user.login,
|
||||
[Validators.required, Validators.minLength(3)],
|
||||
],
|
||||
password: [
|
||||
this.user.password,
|
||||
[Validators.required, Validators.minLength(6)],
|
||||
],
|
||||
verifyPassword: ['', [Validators.required]],
|
||||
},
|
||||
{ validator: this.passwordMatchValidator }
|
||||
);
|
||||
}
|
||||
|
||||
passwordMatchValidator(formGroup: FormGroup) {
|
||||
const password = formGroup.get('password')?.value;
|
||||
const verifyPassword = formGroup.get('verifyPassword')?.value;
|
||||
|
||||
return password === verifyPassword ? null : { mismatch: true };
|
||||
}
|
||||
|
||||
public register() {
|
||||
if (this.userForm.invalid) {
|
||||
this.errorMessage =
|
||||
'Veuillez remplir tous les champs (identifiant de 3 caractères et mot de passe de 6 caractères minimum)';
|
||||
return;
|
||||
}
|
||||
|
||||
this.user.login = this.userForm.value.login;
|
||||
this.user.password = this.userForm.value.password;
|
||||
|
||||
this.registerService
|
||||
.register(this.user.login, this.user.password)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
console.log('Register OK: ', response);
|
||||
this.localStorageService.setToken(response.access_token);
|
||||
this.closeRegisterModal();
|
||||
setTimeout(() => {
|
||||
this.router.navigate(['/map']);
|
||||
}, 1);
|
||||
},
|
||||
error: (response) => {
|
||||
console.log('Register KO: ', response.error.detail);
|
||||
this.errorMessage = response.error.detail;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
openRegisterModal() {
|
||||
this.isRegisterModalOpen = true;
|
||||
}
|
||||
|
||||
closeRegisterModal() {
|
||||
this.isRegisterModalOpen = false;
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
export interface Monument {
|
||||
coords: number[];
|
||||
name: string;
|
||||
images: string[];
|
||||
location: number[];
|
||||
title: string;
|
||||
files: string[];
|
||||
description: string;
|
||||
visited: boolean;
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AddPinService {
|
||||
private apiURL = environment.apiURL;
|
||||
private token = localStorage.getItem('auth_token');
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
addPin(pin: {
|
||||
title: string;
|
||||
description: string;
|
||||
location: string;
|
||||
files: any[];
|
||||
}) {
|
||||
const url = `${this.apiURL}/pin/add`;
|
||||
const headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
});
|
||||
return this.http
|
||||
.post<any>(
|
||||
url,
|
||||
{
|
||||
title: pin.title,
|
||||
description: pin.description,
|
||||
location: pin.location,
|
||||
files: pin.files,
|
||||
},
|
||||
{ headers }
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
@ -1,23 +1,22 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LocalStorageService {
|
||||
private readonly AUTH_TOKEN_KEY = 'auth_token';
|
||||
|
||||
private readonly AUTH_TOKEN_KEY = 'auth_token';
|
||||
constructor() {}
|
||||
|
||||
constructor() { }
|
||||
setToken(token: string): void {
|
||||
localStorage.setItem(this.AUTH_TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
setToken(token: string): void {
|
||||
localStorage.setItem(this.AUTH_TOKEN_KEY, token);
|
||||
}
|
||||
getToken(): string | null {
|
||||
return localStorage.getItem(this.AUTH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
getToken(): string | null {
|
||||
return localStorage.getItem(this.AUTH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
removeToken(): void {
|
||||
localStorage.removeItem(this.AUTH_TOKEN_KEY);
|
||||
}
|
||||
}
|
||||
removeToken(): void {
|
||||
localStorage.removeItem(this.AUTH_TOKEN_KEY);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AddPinService } from './add-pin.service';
|
||||
import { PinService } from './pin.service';
|
||||
|
||||
describe('AddPinService', () => {
|
||||
let service: AddPinService;
|
||||
describe('PinService', () => {
|
||||
let service: PinService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(AddPinService);
|
||||
service = TestBed.inject(PinService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
@ -0,0 +1,55 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { switchMap } from 'rxjs';
|
||||
import { environment } from '../../environments/environment';
|
||||
import { AutocompleteService } from './auto-complete.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PinService {
|
||||
private apiURL = environment.apiURL;
|
||||
private token = localStorage.getItem('auth_token');
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private autoCompleteService: AutocompleteService
|
||||
) {}
|
||||
|
||||
getPins(): any {
|
||||
const url = `${this.apiURL}/pins`;
|
||||
const headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
});
|
||||
return this.http.get<any>(url, { headers });
|
||||
}
|
||||
|
||||
addPin(pin: {
|
||||
title: string;
|
||||
description: string;
|
||||
location: string;
|
||||
files: any[];
|
||||
}) {
|
||||
const url = `${this.apiURL}/pin/add`;
|
||||
const headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer ' + this.token,
|
||||
});
|
||||
return this.autoCompleteService.getAdressCoordinates(pin.location).pipe(
|
||||
switchMap((response: any) => {
|
||||
const coords: [string, string] = [response[0].lat, response[0].lon];
|
||||
return this.http.post<any>(
|
||||
url,
|
||||
{
|
||||
title: pin.title,
|
||||
description: pin.description,
|
||||
location: coords,
|
||||
files: pin.files,
|
||||
user_id: '',
|
||||
},
|
||||
{ headers }
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegisterService } from './register.service';
|
||||
|
||||
describe('RegisterService', () => {
|
||||
let service: RegisterService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(RegisterService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegisterService {
|
||||
private apiUrl = environment.apiURL;
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
register(username: string, password: string): Observable<any> {
|
||||
return this.http.post(this.apiUrl + '/register', { username, password });
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiURL: 'http://127.0.0.1:8000/api/v1',
|
||||
apiURL: 'https://api.memorymap.fr/api/v1',
|
||||
};
|
||||
|
Loading…
Reference in new issue