refacto des pages home, register, login, detail profile
This commit is contained in:
10
src/app/shared/components/loading/loading.component.html
Normal file
10
src/app/shared/components/loading/loading.component.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!-- État de chargement amélioré -->
|
||||
<div class="flex flex-col items-center justify-center h-96 space-y-4">
|
||||
<div class="relative">
|
||||
<div class="w-16 h-16 border-4 border-indigo-200 dark:border-indigo-800 rounded-full animate-spin border-t-indigo-600 dark:border-t-indigo-400"></div>
|
||||
<div class="absolute inset-0 w-16 h-16 border-4 border-transparent border-t-purple-600 dark:border-t-purple-400 rounded-full animate-spin-slow"></div>
|
||||
</div>
|
||||
<p class="text-lg text-gray-600 dark:text-gray-300 font-medium animate-pulse">
|
||||
{{message}}
|
||||
</p>
|
||||
</div>
|
||||
23
src/app/shared/components/loading/loading.component.spec.ts
Normal file
23
src/app/shared/components/loading/loading.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoadingComponent } from './loading.component';
|
||||
|
||||
describe('LoadingComponent', () => {
|
||||
let component: LoadingComponent;
|
||||
let fixture: ComponentFixture<LoadingComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [LoadingComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoadingComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
12
src/app/shared/components/loading/loading.component.ts
Normal file
12
src/app/shared/components/loading/loading.component.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-loading',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './loading.component.html',
|
||||
styleUrl: './loading.component.scss'
|
||||
})
|
||||
export class LoadingComponent {
|
||||
@Input() message: string = 'Chargement...';
|
||||
}
|
||||
@@ -1,107 +1,116 @@
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" class="w-full space-y-4">
|
||||
<div class="">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
d="M256 64C150 64 64 150 64 256s86 192 192 192c17.7 0 32 14.3 32 32s-14.3 32-32 32C114.6 512 0 397.4 0 256S114.6 0 256 0S512 114.6 512 256v32c0 53-43 96-96 96c-29.3 0-55.6-13.2-73.2-33.9C320 371.1 289.5 384 256 384c-70.7 0-128-57.3-128-128s57.3-128 128-128c27.9 0 53.7 8.9 74.7 24.1c5.7-5 13.1-8.1 21.3-8.1c17.7 0 32 14.3 32 32v80 32c0 17.7 14.3 32 32 32s32-14.3 32-32V256c0-106-86-192-192-192zm64 192a64 64 0 1 0 -128 0 64 64 0 1 0 128 0z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" class="space-y-4">
|
||||
|
||||
<!-- Champ Email -->
|
||||
<div class="space-y-2">
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Adresse email
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"/>
|
||||
<path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
formControlName="email"
|
||||
placeholder="email"
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"
|
||||
placeholder="votre@email.com"
|
||||
class="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
|
||||
/>
|
||||
</div>
|
||||
@if (loginForm.get('email')?.invalid && loginForm.get('email')?.touched) {
|
||||
<p class="text-xs text-red-500 mt-1">Veuillez entrer une adresse email valide</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="text-right">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input
|
||||
#pwdInput
|
||||
formControlName="password"
|
||||
autocomplete="on"
|
||||
placeholder="mot de passe"
|
||||
type="password"
|
||||
id="password"
|
||||
name=""
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"
|
||||
/>
|
||||
<button
|
||||
class="absolute w-4 h-4 -translate-y-1/2 right-1 top-1/2 togglePasswordVisibility"
|
||||
type="button"
|
||||
(click)="pwdInput.type = pwdInput.type === 'password' ? 'text' : 'password'"
|
||||
>
|
||||
<span class="inline-block w-4 h-4">
|
||||
@if (pwdInput.type === 'password') {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 21 21"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2 10.5Q5.805 16 10.5 16t8.5-5.5M4.5 13.423l-2 2.077m14-2.077l2 2.077m-6 .5l1 2.5m-5-2.5l-1 2.5"
|
||||
/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path
|
||||
d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
<!-- Champ Mot de passe -->
|
||||
<div class="space-y-2">
|
||||
<label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Mot de passe
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</div>
|
||||
<a [routerLink]="['']" class="text-xs">Mot de passe oublié?</a>
|
||||
<input
|
||||
#pwdInput
|
||||
formControlName="password"
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="••••••••"
|
||||
autocomplete="current-password"
|
||||
class="w-full pl-10 pr-12 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
(click)="pwdInput.type = pwdInput.type === 'password' ? 'text' : 'password'"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
@if (pwdInput.type === 'password') {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/>
|
||||
<path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/>
|
||||
<path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/>
|
||||
</svg>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
@if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {
|
||||
<p class="text-xs text-red-500 mt-1">Le mot de passe est requis</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<button class="text-xs py-2 px-4 border bg-[#002B2F] w-1/2 text-center text-gray-50 rounded-md">
|
||||
Se connecter
|
||||
</button>
|
||||
<!-- Mot de passe oublié -->
|
||||
<div class="flex justify-end">
|
||||
<a [routerLink]="['/forgot-password']" class="text-sm text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 font-medium transition-colors">
|
||||
Mot de passe oublié ?
|
||||
</a>
|
||||
</div>
|
||||
<div class="">
|
||||
<p class="text-xs font-light text-center">
|
||||
Vous n'avez pas de compte?
|
||||
<a [routerLink]="['register']" class="font-bold">Créez-en ici</a>
|
||||
|
||||
<!-- Bouton de connexion -->
|
||||
<button
|
||||
type="submit"
|
||||
[disabled]="loginForm.invalid || isLoading()"
|
||||
class="w-full py-3 px-4 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
|
||||
>
|
||||
@if (isLoading()) {
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Connexion en cours...
|
||||
</span>
|
||||
} @else {
|
||||
Se connecter
|
||||
}
|
||||
</button>
|
||||
|
||||
<!-- Lien vers l'inscription -->
|
||||
<div class="text-center">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Vous n'avez pas de compte ?
|
||||
<a [routerLink]="['register']" class="text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 font-semibold transition-colors">
|
||||
Créez-en un ici
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Progress bar -->
|
||||
@if (isLoading()) {
|
||||
<ng-container>
|
||||
<p-progressBar mode="indeterminate" [style]="{ height: '6px' }" />
|
||||
</ng-container>
|
||||
<div class="mt-6">
|
||||
<p-progressBar mode="indeterminate" [style]="{ height: '4px' }" />
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,174 +1,180 @@
|
||||
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()" class="w-full space-y-4">
|
||||
<div class="">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path
|
||||
d="M256 64C150 64 64 150 64 256s86 192 192 192c17.7 0 32 14.3 32 32s-14.3 32-32 32C114.6 512 0 397.4 0 256S114.6 0 256 0S512 114.6 512 256v32c0 53-43 96-96 96c-29.3 0-55.6-13.2-73.2-33.9C320 371.1 289.5 384 256 384c-70.7 0-128-57.3-128-128s57.3-128 128-128c27.9 0 53.7 8.9 74.7 24.1c5.7-5 13.1-8.1 21.3-8.1c17.7 0 32 14.3 32 32v80 32c0 17.7 14.3 32 32 32s32-14.3 32-32V256c0-106-86-192-192-192zm64 192a64 64 0 1 0 -128 0 64 64 0 1 0 128 0z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()" class="space-y-4">
|
||||
|
||||
<!-- Champ Email -->
|
||||
<div class="space-y-2">
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Adresse email
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"/>
|
||||
<path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
formControlName="email"
|
||||
placeholder="email"
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"
|
||||
placeholder="votre@email.com"
|
||||
class="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
|
||||
/>
|
||||
</div>
|
||||
@if (registerForm.get('email')?.invalid && registerForm.get('email')?.touched) {
|
||||
<p class="text-xs text-red-500 mt-1">Veuillez entrer une adresse email valide</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="text-right">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input
|
||||
#pwdInput
|
||||
formControlName="password"
|
||||
placeholder="mot de passe"
|
||||
autocomplete="on"
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"
|
||||
/>
|
||||
<button
|
||||
class="absolute w-4 h-4 -translate-y-1/2 right-1 top-1/2 togglePasswordVisibility"
|
||||
type="button"
|
||||
(click)="pwdInput.type = pwdInput.type === 'password' ? 'text' : 'password'"
|
||||
>
|
||||
<span class="inline-block w-4 h-4">
|
||||
@if (pwdInput.type === 'password') {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 21 21"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2 10.5Q5.805 16 10.5 16t8.5-5.5M4.5 13.423l-2 2.077m14-2.077l2 2.077m-6 .5l1 2.5m-5-2.5l-1 2.5"
|
||||
/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path
|
||||
d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
<!-- Champ Mot de passe -->
|
||||
<div class="space-y-2">
|
||||
<label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Mot de passe
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="text-right">
|
||||
<div class="relative">
|
||||
<span class="absolute block w-3 h-3 -translate-y-1/2 top-1/2 left-1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 448 512"
|
||||
>
|
||||
<path
|
||||
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"
|
||||
/>
|
||||
<input
|
||||
#pwdInput
|
||||
formControlName="password"
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="••••••••"
|
||||
autocomplete="new-password"
|
||||
class="w-full pl-10 pr-12 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
(click)="pwdInput.type = pwdInput.type === 'password' ? 'text' : 'password'"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
@if (pwdInput.type === 'password') {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/>
|
||||
<path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<input
|
||||
#pwdInputConfirmation
|
||||
formControlName="passwordConfirm"
|
||||
placeholder="confirme le mot de passe"
|
||||
autocomplete="on"
|
||||
type="password"
|
||||
id="passwordConfirm"
|
||||
name="password"
|
||||
class="w-full h-10 px-5 py-2 text-xs bg-transparent border rounded-md"
|
||||
/>
|
||||
<button
|
||||
class="absolute w-4 h-4 -translate-y-1/2 right-1 top-1/2 togglePasswordVisibility"
|
||||
type="button"
|
||||
(click)="
|
||||
pwdInputConfirmation.type =
|
||||
pwdInputConfirmation.type === 'password' ? 'text' : 'password'
|
||||
"
|
||||
>
|
||||
<span class="inline-block w-4 h-4">
|
||||
@if (pwdInputConfirmation.type === 'password') {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 0 21 21"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2 10.5Q5.805 16 10.5 16t8.5-5.5M4.5 13.423l-2 2.077m14-2.077l2 2.077m-6 .5l1 2.5m-5-2.5l-1 2.5"
|
||||
/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-full h-full fill-current"
|
||||
viewBox="0 -960 960 960"
|
||||
>
|
||||
<path
|
||||
d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/>
|
||||
<path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/>
|
||||
</svg>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
@if (registerForm.get('password')?.invalid && registerForm.get('password')?.touched) {
|
||||
<p class="text-xs text-red-500 mt-1">Le mot de passe doit contenir au moins 8 caractères</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<button
|
||||
type="submit"
|
||||
class="text-xs py-2 px-4 border bg-[#002B2F] w-1/2 text-center text-gray-50 rounded-md"
|
||||
>
|
||||
<!-- Champ Confirmation mot de passe -->
|
||||
<div class="space-y-2">
|
||||
<label for="passwordConfirm" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Confirmer le mot de passe
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
#pwdInputConfirmation
|
||||
formControlName="passwordConfirm"
|
||||
type="password"
|
||||
id="passwordConfirm"
|
||||
name="passwordConfirm"
|
||||
placeholder="••••••••"
|
||||
autocomplete="new-password"
|
||||
class="w-full pl-10 pr-12 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-500 focus:border-transparent transition-all"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
(click)="pwdInputConfirmation.type = pwdInputConfirmation.type === 'password' ? 'text' : 'password'"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
@if (pwdInputConfirmation.type === 'password') {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z"/>
|
||||
<path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M3.707 2.293a1 1 0 00-1.414 1.414l14 14a1 1 0 001.414-1.414l-1.473-1.473A10.014 10.014 0 0019.542 10C18.268 5.943 14.478 3 10 3a9.958 9.958 0 00-4.512 1.074l-1.78-1.781zm4.261 4.26l1.514 1.515a2.003 2.003 0 012.45 2.45l1.514 1.514a4 4 0 00-5.478-5.478z" clip-rule="evenodd"/>
|
||||
<path d="M12.454 16.697L9.75 13.992a4 4 0 01-3.742-3.741L2.335 6.578A9.98 9.98 0 00.458 10c1.274 4.057 5.065 7 9.542 7 .847 0 1.669-.105 2.454-.303z"/>
|
||||
</svg>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
@if (registerForm.get('passwordConfirm')?.invalid && registerForm.get('passwordConfirm')?.touched) {
|
||||
<p class="text-xs text-red-500 mt-1">Les mots de passe ne correspondent pas</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Indicateur de force du mot de passe -->
|
||||
@if (registerForm.get('password')!.value; as pwd) {
|
||||
<div class="space-y-2">
|
||||
<div class="flex gap-1">
|
||||
<div class="h-1 flex-1 rounded-full bg-red-500"></div>
|
||||
<div class="h-1 flex-1 rounded-full" [class.bg-yellow-500]="pwd.length >= 8" [class.bg-gray-200]="pwd.length < 8"></div>
|
||||
<div class="h-1 flex-1 rounded-full" [class.bg-green-500]="pwd.length >= 10" [class.bg-gray-200]="pwd.length < 10"></div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
@if (pwd.length < 8) {
|
||||
Mot de passe faible
|
||||
} @else if (pwd.length < 10) {
|
||||
Mot de passe moyen
|
||||
} @else {
|
||||
Mot de passe fort
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Bouton d'inscription -->
|
||||
<button
|
||||
type="submit"
|
||||
[disabled]="registerForm.invalid || isLoading()"
|
||||
class="w-full py-3 px-4 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:-translate-y-0.5 transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
|
||||
>
|
||||
@if (isLoading()) {
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Inscription en cours...
|
||||
</span>
|
||||
} @else {
|
||||
S'inscrire
|
||||
</button>
|
||||
</div>
|
||||
<div class="">
|
||||
<p class="text-xs font-light text-center">
|
||||
Vous avez un compte?
|
||||
<a [routerLink]="['/auth']" class="font-bold">Connectez vous ici</a>
|
||||
}
|
||||
</button>
|
||||
|
||||
<!-- Lien vers la connexion -->
|
||||
<div class="text-center">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Vous avez déjà un compte ?
|
||||
<a [routerLink]="['/auth']" class="text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 font-semibold transition-colors">
|
||||
Connectez-vous ici
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Conditions d'utilisation -->
|
||||
<p class="text-xs text-center text-gray-500 dark:text-gray-400">
|
||||
En créant un compte, vous acceptez nos
|
||||
<a href="#" class="text-indigo-600 hover:underline">Conditions d'utilisation</a>
|
||||
et notre
|
||||
<a href="#" class="text-indigo-600 hover:underline">Politique de confidentialité</a>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<!-- Progress bar -->
|
||||
@if (isLoading()) {
|
||||
<ng-container class="my-6">
|
||||
<p-progressBar mode="indeterminate" [style]="{ height: '6px' }" />
|
||||
</ng-container>
|
||||
<div class="mt-6">
|
||||
<p-progressBar mode="indeterminate" [style]="{ height: '4px' }" />
|
||||
</div>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user