refacto des pages home, register, login, detail profile

This commit is contained in:
styve Lioumba
2025-11-15 10:31:11 +01:00
parent 0301a75e4d
commit 620b781219
16 changed files with 1106 additions and 453 deletions

View 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>

View 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();
});
});

View 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...';
}

View File

@@ -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>
}

View File

@@ -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>
}