refacto et TU user
This commit is contained in:
@@ -1,69 +1,75 @@
|
||||
@if (user) {
|
||||
<h3 class="font-ubuntu font-bold text-xl uppercase dark:text-white mb-4">Ma photo de profil</h3>
|
||||
|
||||
<div
|
||||
class="w-40 h-40 rounded-full inline-flex items-center justify-center bg-gray-200 text-gray-400"
|
||||
>
|
||||
@if (imagePreviewUrl != null) {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
[src]="imagePreviewUrl"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else if (user.avatar) {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
src="{{ environment.baseUrl }}/api/files/users/{{ user.id }}/{{ user.avatar }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
src="https://api.dicebear.com/9.x/adventurer/svg?seed={{ user.username }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
@if (loading().action === ActionType.UPDATE && loading().isLoading && onSubmitted()) {
|
||||
<app-loading message="Mise à jour de la photo de profile..." />
|
||||
} @else {
|
||||
<ng-container *ngTemplateOutlet="content" />
|
||||
}
|
||||
|
||||
<label
|
||||
for="uploadFile1"
|
||||
class="flex bg-gray-800 hover:bg-gray-700 text-white text-base px-5 py-3 outline-none rounded w-max cursor-pointer mx-auto font-[sans-serif]"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-4 h-4 mr-2 fill-white inline"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
d="M23.75 11.044a7.99 7.99 0 0 0-15.5-.009A8 8 0 0 0 9 27h3a1 1 0 0 0 0-2H9a6 6 0 0 1-.035-12 1.038 1.038 0 0 0 1.1-.854 5.991 5.991 0 0 1 11.862 0A1.08 1.08 0 0 0 23 13a6 6 0 0 1 0 12h-3a1 1 0 0 0 0 2h3a8 8 0 0 0 .75-15.956z"
|
||||
data-original="#000000"
|
||||
/>
|
||||
<path
|
||||
d="M20.293 19.707a1 1 0 0 0 1.414-1.414l-5-5a1 1 0 0 0-1.414 0l-5 5a1 1 0 0 0 1.414 1.414L15 16.414V29a1 1 0 0 0 2 0V16.414z"
|
||||
data-original="#000000"
|
||||
/>
|
||||
</svg>
|
||||
<small class="text-xs">Selectionner une image</small>
|
||||
<input
|
||||
type="file"
|
||||
id="uploadFile1"
|
||||
class="hidden"
|
||||
accept="image/*"
|
||||
(change)="onPictureChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<ng-template #content>
|
||||
@if (user) {
|
||||
<div
|
||||
class="w-40 h-40 rounded-full inline-flex items-center justify-center bg-gray-200 text-gray-400"
|
||||
>
|
||||
@if (imagePreviewUrl != null) {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
[src]="imagePreviewUrl"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else if (user.avatar) {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
src="{{ environment.baseUrl }}/api/files/users/{{ user.id }}/{{ user.avatar }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else {
|
||||
<img
|
||||
alt="{{ user!.username }}"
|
||||
class="object-cover object-center h-full w-full rounded-full"
|
||||
src="https://api.dicebear.com/9.x/adventurer/svg?seed={{ user.username }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (file != null || imagePreviewUrl != null) {
|
||||
<button
|
||||
type="button"
|
||||
[ngClass]="{ 'bg-purple-600': file != null || imagePreviewUrl != null }"
|
||||
class="!mt-2 px-6 py-2 w-full bg-[#333] hover:bg-[#444] text-sm text-white mx-auto block"
|
||||
(click)="onUserAvatarFormSubmit()"
|
||||
<label
|
||||
for="uploadFile1"
|
||||
class="flex bg-gray-800 hover:bg-gray-700 text-white text-base px-5 py-3 outline-none rounded w-max cursor-pointer mx-auto font-[sans-serif]"
|
||||
>
|
||||
Mettre à jour ma photo de profile
|
||||
</button>
|
||||
}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-4 h-4 mr-2 fill-white inline"
|
||||
viewBox="0 0 32 32"
|
||||
>
|
||||
<path
|
||||
d="M23.75 11.044a7.99 7.99 0 0 0-15.5-.009A8 8 0 0 0 9 27h3a1 1 0 0 0 0-2H9a6 6 0 0 1-.035-12 1.038 1.038 0 0 0 1.1-.854 5.991 5.991 0 0 1 11.862 0A1.08 1.08 0 0 0 23 13a6 6 0 0 1 0 12h-3a1 1 0 0 0 0 2h3a8 8 0 0 0 .75-15.956z"
|
||||
data-original="#000000"
|
||||
/>
|
||||
<path
|
||||
d="M20.293 19.707a1 1 0 0 0 1.414-1.414l-5-5a1 1 0 0 0-1.414 0l-5 5a1 1 0 0 0 1.414 1.414L15 16.414V29a1 1 0 0 0 2 0V16.414z"
|
||||
data-original="#000000"
|
||||
/>
|
||||
</svg>
|
||||
<small class="text-xs">Selectionner une image</small>
|
||||
<input
|
||||
type="file"
|
||||
id="uploadFile1"
|
||||
class="hidden"
|
||||
accept="image/*"
|
||||
(change)="onPictureChange($event)"
|
||||
/>
|
||||
</label>
|
||||
|
||||
@if (file != null || imagePreviewUrl != null) {
|
||||
<button
|
||||
type="button"
|
||||
[ngClass]="{ 'bg-purple-600': file != null || imagePreviewUrl != null }"
|
||||
class="!mt-2 px-6 py-2 w-full bg-[#333] hover:bg-[#444] text-sm text-white mx-auto block"
|
||||
(click)="onUserAvatarFormSubmit()"
|
||||
>
|
||||
Mettre à jour ma photo de profile
|
||||
</button>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Component, effect, inject, Input, output } from '@angular/core';
|
||||
import { Component, effect, inject, Input, output, signal } from '@angular/core';
|
||||
import { User } from '@app/domain/users/user.model';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { environment } from '@env/environment';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { NgClass, NgTemplateOutlet } from '@angular/common';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { UserFacade } from '@app/ui/users/user.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { LoadingComponent } from '@app/shared/components/loading/loading.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-avatar-form',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, NgClass],
|
||||
imports: [ReactiveFormsModule, NgClass, NgTemplateOutlet, LoadingComponent],
|
||||
templateUrl: './user-avatar-form.component.html',
|
||||
styleUrl: './user-avatar-form.component.scss',
|
||||
})
|
||||
@@ -23,10 +23,9 @@ export class UserAvatarFormComponent {
|
||||
|
||||
onFormSubmitted = output<any>();
|
||||
|
||||
private authService = inject(AuthService);
|
||||
|
||||
file: File | null = null; // Variable to store file
|
||||
imagePreviewUrl: string | null = null; // URL for image preview
|
||||
protected onSubmitted = signal<boolean>(false);
|
||||
|
||||
protected readonly loading = this.facade.loading;
|
||||
protected readonly error = this.facade.error;
|
||||
@@ -35,12 +34,12 @@ export class UserAvatarFormComponent {
|
||||
let message = '';
|
||||
|
||||
effect(() => {
|
||||
if (!this.loading().isLoading) {
|
||||
if (!this.loading().isLoading && this.onSubmitted()) {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
this.authService.updateUser();
|
||||
message = `Votre photo de profile a bien été modifier !`;
|
||||
this.customToast(ActionType.UPDATE, message);
|
||||
this.onSubmitted.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -55,6 +54,7 @@ export class UserAvatarFormComponent {
|
||||
this.facade.update(this.user?.id!, formData as Partial<User>);
|
||||
|
||||
this.onFormSubmitted.emit('');
|
||||
this.onSubmitted.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,4 +98,6 @@ export class UserAvatarFormComponent {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected readonly ActionType = ActionType;
|
||||
}
|
||||
|
||||
@@ -1,107 +1,115 @@
|
||||
<form
|
||||
[formGroup]="userForm"
|
||||
(ngSubmit)="onUserFormSubmit()"
|
||||
class="w-full space-y-6 animate-fade-in"
|
||||
>
|
||||
<!-- Titre -->
|
||||
<div class="flex items-center gap-3 pb-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div
|
||||
class="w-10 h-10 bg-indigo-100 dark:bg-indigo-900 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6 text-indigo-600 dark:text-indigo-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Mon identité</h3>
|
||||
</div>
|
||||
@if (loading().action === ActionType.UPDATE && loading().isLoading && onSubmitted()) {
|
||||
<app-loading message="Mise à jour encours..." />
|
||||
} @else {
|
||||
<ng-container *ngTemplateOutlet="forms" />
|
||||
}
|
||||
|
||||
<!-- Champ Nom -->
|
||||
<div class="space-y-2">
|
||||
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Nom
|
||||
</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="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Votre nom"
|
||||
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>
|
||||
</div>
|
||||
|
||||
<!-- Champ Prénom -->
|
||||
<div class="space-y-2">
|
||||
<label for="firstname" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Prénom
|
||||
</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="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="firstname"
|
||||
type="text"
|
||||
formControlName="firstname"
|
||||
placeholder="Votre prénom"
|
||||
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>
|
||||
</div>
|
||||
|
||||
<!-- Bouton de soumission -->
|
||||
<button
|
||||
type="submit"
|
||||
[disabled]="userForm.invalid"
|
||||
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"
|
||||
<ng-template #forms>
|
||||
<form
|
||||
[formGroup]="userForm"
|
||||
(ngSubmit)="onUserFormSubmit()"
|
||||
class="w-full space-y-6 animate-fade-in"
|
||||
>
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
<!-- Titre -->
|
||||
<div class="flex items-center gap-3 pb-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div
|
||||
class="w-10 h-10 bg-indigo-100 dark:bg-indigo-900 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<path
|
||||
d="M7.707 10.293a1 1 0 10-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 11.586V6h5a2 2 0 012 2v7a2 2 0 01-2 2H4a2 2 0 01-2-2V8a2 2 0 012-2h5v5.586l-1.293-1.293zM9 4a1 1 0 012 0v2H9V4z"
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6 text-indigo-600 dark:text-indigo-400"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Mon identité</h3>
|
||||
</div>
|
||||
|
||||
<!-- Champ Nom -->
|
||||
<div class="space-y-2">
|
||||
<label for="name" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Nom
|
||||
</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="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
formControlName="name"
|
||||
placeholder="Votre nom"
|
||||
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"
|
||||
/>
|
||||
</svg>
|
||||
Modifier mon identité
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Champ Prénom -->
|
||||
<div class="space-y-2">
|
||||
<label for="firstname" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Prénom
|
||||
</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="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="firstname"
|
||||
type="text"
|
||||
formControlName="firstname"
|
||||
placeholder="Votre prénom"
|
||||
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>
|
||||
</div>
|
||||
|
||||
<!-- Bouton de soumission -->
|
||||
<button
|
||||
type="submit"
|
||||
[disabled]="userForm.invalid"
|
||||
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"
|
||||
>
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M7.707 10.293a1 1 0 10-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 11.586V6h5a2 2 0 012 2v7a2 2 0 01-2 2H4a2 2 0 01-2-2V8a2 2 0 012-2h5v5.586l-1.293-1.293zM9 4a1 1 0 012 0v2H9V4z"
|
||||
/>
|
||||
</svg>
|
||||
Modifier mon identité
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, effect, inject, Input, OnInit, output } from '@angular/core';
|
||||
import { Component, effect, inject, Input, OnInit, output, signal } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
@@ -7,16 +7,17 @@ import {
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import { User } from '@app/domain/users/user.model';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { UserFacade } from '@app/ui/users/user.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { LoadingComponent } from '@app/shared/components/loading/loading.component';
|
||||
import { NgTemplateOutlet } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-form',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule],
|
||||
imports: [ReactiveFormsModule, LoadingComponent, NgTemplateOutlet],
|
||||
templateUrl: './user-form.component.html',
|
||||
styleUrl: './user-form.component.scss',
|
||||
})
|
||||
@@ -24,28 +25,28 @@ import { ActionType } from '@app/domain/action-type.util';
|
||||
export class UserFormComponent implements OnInit {
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
private readonly facade = inject(UserFacade);
|
||||
protected readonly ActionType = ActionType;
|
||||
|
||||
@Input({ required: true }) user: User | undefined = undefined;
|
||||
onFormSubmitted = output<any>();
|
||||
|
||||
private authService = inject(AuthService);
|
||||
|
||||
private fb = inject(FormBuilder);
|
||||
protected userForm!: FormGroup;
|
||||
|
||||
protected readonly loading = this.facade.loading;
|
||||
protected readonly error = this.facade.error;
|
||||
protected onSubmitted = signal<boolean>(false);
|
||||
|
||||
constructor() {
|
||||
let message = '';
|
||||
|
||||
effect(() => {
|
||||
if (!this.loading().isLoading) {
|
||||
if (!this.loading().isLoading && this.onSubmitted()) {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
this.authService.updateUser();
|
||||
message = `Vos informations personnelles ont bien été modifier !`;
|
||||
this.customToast(ActionType.UPDATE, message);
|
||||
this.onSubmitted.set(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -74,6 +75,7 @@ export class UserFormComponent implements OnInit {
|
||||
this.facade.update(this.user?.id!, data);
|
||||
|
||||
this.onFormSubmitted.emit(data);
|
||||
this.onSubmitted.set(true);
|
||||
}
|
||||
|
||||
private customToast(action: ActionType, message: string): void {
|
||||
|
||||
Reference in New Issue
Block a user