user => clean archi
This commit is contained in:
@@ -8,5 +8,5 @@ import { Component, Input } from '@angular/core';
|
||||
styleUrl: './loading.component.scss',
|
||||
})
|
||||
export class LoadingComponent {
|
||||
@Input() message: string = 'Chargement...';
|
||||
@Input() message = 'Chargement...';
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { PaginatorModule } from 'primeng/paginator';
|
||||
import { ProjectPictureFormComponent } from '@app/shared/components/project-picture-form/project-picture-form.component';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
@@ -22,13 +21,7 @@ import { LoadingComponent } from '@app/shared/components/loading/loading.compone
|
||||
@Component({
|
||||
selector: 'app-my-profile-update-project-form',
|
||||
standalone: true,
|
||||
imports: [
|
||||
PaginatorModule,
|
||||
ReactiveFormsModule,
|
||||
NgClass,
|
||||
ProjectPictureFormComponent,
|
||||
LoadingComponent,
|
||||
],
|
||||
imports: [PaginatorModule, ReactiveFormsModule, ProjectPictureFormComponent, LoadingComponent],
|
||||
templateUrl: './my-profile-update-project-form.component.html',
|
||||
styleUrl: './my-profile-update-project-form.component.scss',
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { signal } from '@angular/core';
|
||||
import { Auth } from '@app/shared/models/auth';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { User } from '@app/domain/users/user.model';
|
||||
|
||||
describe('NavBarComponent', () => {
|
||||
let component: NavBarComponent;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { UserAvatarFormComponent } from './user-avatar-form.component';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { UserService } from '@app/core/services/user/user.service';
|
||||
import { UserRepository } from '@app/domain/users/user.repository';
|
||||
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
|
||||
|
||||
describe('UserAvatarFormComponent', () => {
|
||||
let component: UserAvatarFormComponent;
|
||||
@@ -12,7 +13,7 @@ describe('UserAvatarFormComponent', () => {
|
||||
|
||||
let mockToastrService: Partial<ToastrService>;
|
||||
let mockAuthService: Partial<AuthService>;
|
||||
let mockUserService: Partial<UserService>;
|
||||
let mockUserRepo: UserRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockToastrService = {
|
||||
@@ -25,19 +26,18 @@ describe('UserAvatarFormComponent', () => {
|
||||
updateUser: jest.fn(),
|
||||
};
|
||||
|
||||
mockUserService = {
|
||||
updateUser: jest.fn().mockReturnValue({
|
||||
subscribe: jest.fn(),
|
||||
}),
|
||||
mockUserRepo = {
|
||||
update: jest.fn(),
|
||||
getUserById: jest.fn(),
|
||||
};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UserAvatarFormComponent],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{ provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{ provide: AuthService, useValue: mockAuthService },
|
||||
{ provide: UserService, useValue: mockUserService },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Component, inject, Input, output } from '@angular/core';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { Component, effect, inject, Input, output } 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 { UserService } from '@app/core/services/user/user.service';
|
||||
import { environment } from '@env/environment';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { UserFacade } from '@app/ui/users/user.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-avatar-form',
|
||||
@@ -17,47 +18,42 @@ import { ToastrService } from 'ngx-toastr';
|
||||
export class UserAvatarFormComponent {
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
protected readonly environment = environment;
|
||||
private readonly facade = inject(UserFacade);
|
||||
@Input({ required: true }) user: User | undefined = undefined;
|
||||
|
||||
onFormSubmitted = output<any>();
|
||||
private userService = inject(UserService);
|
||||
|
||||
private authService = inject(AuthService);
|
||||
|
||||
file: File | null = null; // Variable to store file
|
||||
imagePreviewUrl: string | null = null; // URL for image preview
|
||||
|
||||
protected readonly loading = this.facade.loading;
|
||||
protected readonly error = this.facade.error;
|
||||
|
||||
constructor() {
|
||||
let message = '';
|
||||
|
||||
effect(() => {
|
||||
if (!this.loading().isLoading) {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
this.authService.updateUser();
|
||||
message = `Votre photo de profile a bien été modifier !`;
|
||||
this.customToast(ActionType.UPDATE, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onUserAvatarFormSubmit() {
|
||||
if (this.file != null) {
|
||||
const formData = new FormData();
|
||||
formData.append('avatar', this.file); // "avatar" est le nom du champ dans PocketBase
|
||||
|
||||
this.userService.updateUser(this.user?.id!, formData).subscribe({
|
||||
next: (value) => {
|
||||
this.authService.updateUser();
|
||||
this.facade.update(this.user?.id!, formData as Partial<User>);
|
||||
|
||||
this.toastrService.success(
|
||||
`Votre photo de profile a bien été modifier !`,
|
||||
`Mise à jour`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastrService.error(
|
||||
`Une erreur est survenue lors de la mise à jour de votre photo de profile !`,
|
||||
`Erreur`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
this.onFormSubmitted.emit('');
|
||||
}
|
||||
}
|
||||
@@ -77,4 +73,29 @@ export class UserAvatarFormComponent {
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
private customToast(action: ActionType, message: string): void {
|
||||
if (this.error().hasError) {
|
||||
this.toastrService.error(
|
||||
`Une erreur s'est produite, veuillez réessayer ulterieurement`,
|
||||
`Erreur`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.toastrService.success(
|
||||
`${message}`,
|
||||
`${action === ActionType.UPDATE ? 'Mise à jour' : ''}`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { UserFormComponent } from './user-form.component';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { UserService } from '@app/core/services/user/user.service';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
|
||||
import { UserRepository } from '@app/domain/users/user.repository';
|
||||
|
||||
describe('UserFormComponent', () => {
|
||||
let component: UserFormComponent;
|
||||
@@ -13,7 +14,7 @@ describe('UserFormComponent', () => {
|
||||
|
||||
let mockToastrService: Partial<ToastrService>;
|
||||
let mockAuthService: Partial<AuthService>;
|
||||
let mockUserService: Partial<UserService>;
|
||||
let mockUserRepo: UserRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockToastrService = {
|
||||
@@ -26,10 +27,9 @@ describe('UserFormComponent', () => {
|
||||
updateUser: jest.fn(),
|
||||
};
|
||||
|
||||
mockUserService = {
|
||||
updateUser: jest.fn().mockReturnValue({
|
||||
subscribe: jest.fn(),
|
||||
}),
|
||||
mockUserRepo = {
|
||||
update: jest.fn(),
|
||||
getUserById: jest.fn(),
|
||||
};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
@@ -37,9 +37,9 @@ describe('UserFormComponent', () => {
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
FormBuilder,
|
||||
{ provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{ provide: AuthService, useValue: mockAuthService },
|
||||
{ provide: UserService, useValue: mockUserService },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, inject, Input, OnInit, output } from '@angular/core';
|
||||
import { Component, effect, inject, Input, OnInit, output } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
@@ -6,33 +6,51 @@ import {
|
||||
ReactiveFormsModule,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { UserService } from '@app/core/services/user/user.service';
|
||||
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';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-form',
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, NgClass],
|
||||
imports: [ReactiveFormsModule],
|
||||
templateUrl: './user-form.component.html',
|
||||
styleUrl: './user-form.component.scss',
|
||||
})
|
||||
@UntilDestroy()
|
||||
export class UserFormComponent implements OnInit {
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
private readonly facade = inject(UserFacade);
|
||||
|
||||
@Input({ required: true }) user: User | undefined = undefined;
|
||||
onFormSubmitted = output<any>();
|
||||
|
||||
private userService = inject(UserService);
|
||||
private authService = inject(AuthService);
|
||||
|
||||
private fb = inject(FormBuilder);
|
||||
protected userForm!: FormGroup;
|
||||
|
||||
protected readonly loading = this.facade.loading;
|
||||
protected readonly error = this.facade.error;
|
||||
|
||||
constructor() {
|
||||
let message = '';
|
||||
|
||||
effect(() => {
|
||||
if (!this.loading().isLoading) {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
this.authService.updateUser();
|
||||
message = `Vos informations personnelles ont bien été modifier !`;
|
||||
this.customToast(ActionType.UPDATE, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.userForm = this.fb.group({
|
||||
firstname: new FormControl(this.user?.name?.split(' ').slice(0, -1).join(' ') ?? '', [
|
||||
@@ -53,20 +71,33 @@ export class UserFormComponent implements OnInit {
|
||||
name: this.userForm.getRawValue()!.firstname! + ' ' + this.userForm.getRawValue()!.name!,
|
||||
} as User;
|
||||
|
||||
this.userService.updateUser(this.user?.id!, data).subscribe((value) => {
|
||||
this.authService.updateUser();
|
||||
this.facade.update(this.user?.id!, data);
|
||||
|
||||
this.toastrService.success(
|
||||
`Vos informations personnelles ont bien été modifier !`,
|
||||
`Mise à jour`,
|
||||
this.onFormSubmitted.emit(data);
|
||||
}
|
||||
|
||||
private customToast(action: ActionType, message: string): void {
|
||||
if (this.error().hasError) {
|
||||
this.toastrService.error(
|
||||
`Une erreur s'est produite, veuillez réessayer ulterieurement`,
|
||||
`Erreur`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.onFormSubmitted.emit(data);
|
||||
this.toastrService.success(
|
||||
`${message}`,
|
||||
`${action === ActionType.UPDATE ? 'Mise à jour' : ''}`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, inject, Input, output } from '@angular/core';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { User } from '@app/domain/users/user.model';
|
||||
import { FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||
import { UserService } from '@app/core/services/user/user.service';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
|
||||
@Component({
|
||||
@@ -15,7 +14,6 @@ export class UserPasswordFormComponent {
|
||||
@Input({ required: true }) user: User | undefined = undefined;
|
||||
onFormSubmitted = output<any>();
|
||||
|
||||
private userService = inject(UserService);
|
||||
private authService = inject(AuthService);
|
||||
|
||||
private fb = inject(FormBuilder);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@if (user != undefined) {
|
||||
@if (user() != undefined) {
|
||||
<a
|
||||
[routerLink]="[user.username ? user.username : user.id]"
|
||||
[state]="{ user, profile }"
|
||||
[routerLink]="[user().username ? user().username : user().id]"
|
||||
[state]="{ user: user(), profile }"
|
||||
class="block group"
|
||||
>
|
||||
<!-- Card du profil -->
|
||||
@@ -33,18 +33,18 @@
|
||||
<!-- Avatar avec bordure gradient -->
|
||||
<div class="relative inline-block mb-4">
|
||||
<div class="w-32 h-32 rounded-full bg-gradient-to-br from-indigo-500 to-purple-600 p-1">
|
||||
@if (user.avatar) {
|
||||
@if (user().avatar) {
|
||||
<img
|
||||
class="w-full h-full rounded-full object-cover grayscale group-hover:grayscale-0 transition-all duration-500 group-hover:scale-105"
|
||||
src="{{ environment.baseUrl }}/api/files/users/{{ user.id }}/{{ user.avatar }}"
|
||||
alt="{{ user.username }}"
|
||||
src="{{ environment.baseUrl }}/api/files/users/{{ user().id }}/{{ user().avatar }}"
|
||||
alt="{{ user().username }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
} @else {
|
||||
<img
|
||||
class="w-full h-full rounded-full object-cover grayscale group-hover:grayscale-0 transition-all duration-500 group-hover:scale-105"
|
||||
src="https://api.dicebear.com/9.x/adventurer/svg?seed={{ user.username }}"
|
||||
alt="{{ user.username }}"
|
||||
src="https://api.dicebear.com/9.x/adventurer/svg?seed={{ user().username }}"
|
||||
alt="{{ user().username }}"
|
||||
loading="lazy"
|
||||
/>
|
||||
}
|
||||
@@ -52,17 +52,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Nom -->
|
||||
@if (user.name) {
|
||||
@if (user().name) {
|
||||
<h3
|
||||
class="text-lg font-bold text-gray-900 dark:text-white mb-2 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors"
|
||||
>
|
||||
{{ user.name }}
|
||||
{{ user().name }}
|
||||
</h3>
|
||||
} @else if (user.username) {
|
||||
} @else if (user().username) {
|
||||
<h3
|
||||
class="text-lg font-bold text-gray-900 dark:text-white mb-2 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors"
|
||||
>
|
||||
{{ user.username }}
|
||||
{{ user().username }}
|
||||
</h3>
|
||||
} @else {
|
||||
<h3 class="text-lg font-bold text-gray-500 dark:text-gray-400 mb-2">Non mentionné</h3>
|
||||
|
||||
@@ -1,14 +1,40 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { VerticalProfileItemComponent } from './vertical-profile-item.component';
|
||||
import { UserRepository } from '@app/domain/users/user.repository';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { USER_REPOSITORY_TOKEN } from '@app/infrastructure/users/user-repository.token';
|
||||
import { User } from '@app/domain/users/user.model';
|
||||
import { of } from 'rxjs';
|
||||
import { SECTOR_REPOSITORY_TOKEN } from '@app/infrastructure/sectors/sector-repository.token';
|
||||
import { SectorRepository } from '@app/domain/sectors/sector.repository';
|
||||
import { Sector } from '@app/domain/sectors/sector.model';
|
||||
|
||||
describe('VerticalProfileItemComponent', () => {
|
||||
let component: VerticalProfileItemComponent;
|
||||
let fixture: ComponentFixture<VerticalProfileItemComponent>;
|
||||
|
||||
let mockUserRepo: UserRepository;
|
||||
let mockSectorRepo: SectorRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockUserRepo = {
|
||||
update: jest.fn().mockReturnValue(of({} as User)),
|
||||
getUserById: jest.fn().mockReturnValue(of({} as User)),
|
||||
};
|
||||
|
||||
mockSectorRepo = {
|
||||
list: jest.fn().mockReturnValue(of({} as Sector)),
|
||||
getOne: jest.fn().mockReturnValue(of({} as Sector)),
|
||||
};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [VerticalProfileItemComponent],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{ provide: USER_REPOSITORY_TOKEN, useValue: mockUserRepo },
|
||||
{ provide: SECTOR_REPOSITORY_TOKEN, useValue: mockSectorRepo },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(VerticalProfileItemComponent);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Component, inject, Input, OnInit } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { UserService } from '@app/core/services/user/user.service';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { ChipsComponent } from '@app/shared/components/chips/chips.component';
|
||||
import { ReseauxComponent } from '@app/shared/components/reseaux/reseaux.component';
|
||||
import { environment } from '@env/environment';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
import { UserFacade } from '@app/ui/users/user.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vertical-profile-item',
|
||||
@@ -19,14 +18,14 @@ import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
export class VerticalProfileItemComponent implements OnInit {
|
||||
@Input({ required: true }) profile: ProfileViewModel = {} as ProfileViewModel;
|
||||
protected router = inject(Router);
|
||||
protected userService = inject(UserService);
|
||||
private readonly facade = inject(UserFacade);
|
||||
|
||||
protected user: User | undefined = undefined;
|
||||
protected user = this.facade.user;
|
||||
protected readonly loading = this.facade.loading;
|
||||
protected readonly error = this.facade.error;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.userService
|
||||
.getUserById(this.profile.utilisateur)
|
||||
.subscribe((value) => (this.user = value));
|
||||
this.facade.loadOne(this.profile.utilisateur);
|
||||
}
|
||||
|
||||
protected readonly environment = environment;
|
||||
|
||||
Reference in New Issue
Block a user