project et profile => clean archi et test vert
This commit is contained in:
@@ -3,7 +3,7 @@ import { Router } from '@angular/router';
|
||||
|
||||
import { detailResolver } from './detail.resolver';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
describe('detailResolver', () => {
|
||||
let mockRoute: Partial<Router>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ResolveFn, Router } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
export const detailResolver: ResolveFn<{ user: User; profile: Profile }> = (route, state) => {
|
||||
const paramValue = route.params['name'];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ResolveFn } from '@angular/router';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
export const listResolver: ResolveFn<Profile[]> = (route, state) => {
|
||||
const queryValue = route.queryParams['search'];
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProfileService } from './profile.service';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
describe('ProfileService', () => {
|
||||
let service: ProfileService;
|
||||
|
||||
const routerSpy = {
|
||||
navigate: jest.fn(),
|
||||
navigateByUrl: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: Router, useValue: routerSpy }, // <<— spy: neutralise la navigation
|
||||
],
|
||||
imports: [],
|
||||
});
|
||||
service = TestBed.inject(ProfileService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import PocketBase from 'pocketbase';
|
||||
import { environment } from '@env/environment';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { from } from 'rxjs';
|
||||
import { ProfileDto } from '@app/shared/models/profile-dto';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProfileService {
|
||||
createProfile(profileDto: ProfileDto) {
|
||||
const pb = new PocketBase(environment.baseUrl);
|
||||
return from(pb.collection('profiles').create(profileDto));
|
||||
}
|
||||
|
||||
get profiles() {
|
||||
const pb = new PocketBase(environment.baseUrl);
|
||||
return from(
|
||||
pb.collection('profiles').getFullList<Profile>({
|
||||
sort: 'profession',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getProfileByUserId(userId: string) {
|
||||
const pb = new PocketBase(environment.baseUrl);
|
||||
return from(pb.collection<Profile>('profiles').getFirstListItem(`utilisateur="${userId}"`));
|
||||
}
|
||||
|
||||
updateProfile(id: string, data: Profile | any) {
|
||||
const pb = new PocketBase(environment.baseUrl);
|
||||
return from(pb.collection('profiles').update<Profile>(id, data));
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
|
||||
|
||||
export interface ProfileRepository {
|
||||
list(params?: { search?: string; page?: number; pageSize?: number }): Observable<Profile[]>;
|
||||
getByUserId(userId: string): Observable<Profile | null>;
|
||||
getByUserId(userId: string): Observable<Profile>;
|
||||
create(profile: Profile): Observable<Profile>;
|
||||
update(id: string, profile: Partial<Profile>): Observable<Profile>;
|
||||
update(profileId: string, profile: Partial<Profile>): Observable<Profile>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { Project } from '@app/shared/models/project';
|
||||
import { CreateProjectDto } from '@app/domain/projects/dto/create-project.dto';
|
||||
import { Project } from '@app/domain/projects/project.model';
|
||||
|
||||
export interface ProjectRepository {
|
||||
create(projectDto: CreateProjectDto): Observable<Project>;
|
||||
|
||||
@@ -14,7 +14,7 @@ export class PbProfileRepository implements ProfileRepository {
|
||||
return from(this.pb.collection('profiles').getFullList<Profile>({ sort: 'profession' }));
|
||||
}
|
||||
|
||||
getByUserId(userId: string): Observable<Profile | null> {
|
||||
getByUserId(userId: string): Observable<Profile> {
|
||||
return from(
|
||||
this.pb.collection('profiles').getFirstListItem<Profile>(`utilisateur="${userId}"`)
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '@env/environment';
|
||||
import { ProjectRepository } from '@app/domain/projects/project.repository';
|
||||
import { Project } from '@app/shared/models/project';
|
||||
import { from, Observable } from 'rxjs';
|
||||
import PocketBase from 'pocketbase';
|
||||
import { CreateProjectDto } from '@app/domain/projects/dto/create-project.dto';
|
||||
import { Project } from '@app/domain/projects/project.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
@@ -9,6 +10,7 @@ describe('HomeComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HomeComponent],
|
||||
providers: [provideRouter([])],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
@if (profile.estVerifier) {
|
||||
@if (profile().estVerifier) {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -100,8 +100,8 @@
|
||||
</h2>
|
||||
}
|
||||
<div class="w-12 h-1 bg-indigo-500 rounded mt-2 mb-4"></div>
|
||||
@if (profile.bio) {
|
||||
<p class="text-base dark:text-white w-full">{{ profile.bio }}</p>
|
||||
@if (profile().bio) {
|
||||
<p class="text-base dark:text-white w-full">{{ profile().bio }}</p>
|
||||
} @else {
|
||||
<p class="text-base dark:text-white w-full">
|
||||
Je suis sur la plateforme Trouve Ton Profile pour partager mon expertise et mes
|
||||
@@ -110,17 +110,17 @@
|
||||
</p>
|
||||
}
|
||||
|
||||
@if (profile.secteur) {
|
||||
@if (profile().secteur) {
|
||||
<div class="space-y-2 flex flex-col my-4">
|
||||
<p class="text-base dark:text-white">Secteur</p>
|
||||
<app-chips [sectorId]="profile.secteur" />
|
||||
<app-chips [sectorId]="profile().secteur" />
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (profile.reseaux) {
|
||||
@if (profile().reseaux) {
|
||||
<div class="space-y-2 flex flex-col my-4">
|
||||
<p class="text-base dark:text-white">Réseaux</p>
|
||||
<app-reseaux [reseaux]="profile.reseaux" />
|
||||
<app-reseaux [reseaux]="profile().reseaux" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -240,23 +240,23 @@
|
||||
<div id="homeContent" class="tab-content max-w-2xl block mt-8">
|
||||
@switch (menu().toLowerCase()) {
|
||||
@case ('home'.toLowerCase()) {
|
||||
<app-my-home-profile [profile]="profile" />
|
||||
<app-my-home-profile [profile]="profile()" />
|
||||
}
|
||||
@case ('projects'.toLowerCase()) {
|
||||
<app-my-profile-project-list
|
||||
[projectIds]="profile.projets"
|
||||
[projectIds]="profile().projets"
|
||||
[userId]="user().id"
|
||||
/>
|
||||
<router-outlet />
|
||||
}
|
||||
@case ('update'.toLowerCase()) {
|
||||
<app-my-profile-update-form [profile]="profile" />
|
||||
<app-my-profile-update-form [profile]="profile()" />
|
||||
}
|
||||
@case ('cv'.toLowerCase()) {
|
||||
<app-pdf-viewer [profile]="profile" />
|
||||
<app-pdf-viewer [profile]="profile()" />
|
||||
}
|
||||
@default {
|
||||
<app-my-home-profile [profile]="profile" />
|
||||
<app-my-home-profile [profile]="profile()" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -2,15 +2,30 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MyProfileComponent } from './my-profile.component';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
import { of } from 'rxjs';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
describe('MyProfileComponent', () => {
|
||||
let component: MyProfileComponent;
|
||||
let fixture: ComponentFixture<MyProfileComponent>;
|
||||
|
||||
let mockProfileRepo: ProfileRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockProfileRepo = {
|
||||
create: jest.fn(),
|
||||
list: jest.fn(),
|
||||
update: jest.fn(),
|
||||
getByUserId: jest.fn().mockReturnValue(of({} as Profile)),
|
||||
};
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MyProfileComponent],
|
||||
providers: [provideRouter([])],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MyProfileComponent);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, computed, inject, OnInit, signal } from '@angular/core';
|
||||
import { ActivatedRoute, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { AsyncPipe, JsonPipe, Location, NgClass, UpperCasePipe } from '@angular/common';
|
||||
import { Location, NgClass } from '@angular/common';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { SafeUrl } from '@angular/platform-browser';
|
||||
import { QRCodeModule } from 'angularx-qrcode';
|
||||
@@ -12,22 +12,18 @@ import { UpdateUserComponent } from '@app/shared/features/update-user/update-use
|
||||
import { MyProfileProjectListComponent } from '@app/shared/components/my-profile-project-list/my-profile-project-list.component';
|
||||
import { MyHomeProfileComponent } from '@app/shared/components/my-home-profile/my-home-profile.component';
|
||||
import { MyProfileUpdateFormComponent } from '@app/shared/components/my-profile-update-form/my-profile-update-form.component';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { PdfViewerComponent } from '@app/shared/features/pdf-viewer/pdf-viewer.component';
|
||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-profile',
|
||||
standalone: true,
|
||||
imports: [
|
||||
JsonPipe,
|
||||
RouterLink,
|
||||
AsyncPipe,
|
||||
QRCodeModule,
|
||||
ChipsComponent,
|
||||
ReseauxComponent,
|
||||
UpdateUserComponent,
|
||||
UpperCasePipe,
|
||||
MyProfileProjectListComponent,
|
||||
RouterOutlet,
|
||||
MyHomeProfileComponent,
|
||||
@@ -40,8 +36,6 @@ import { PdfViewerComponent } from '@app/shared/features/pdf-viewer/pdf-viewer.c
|
||||
})
|
||||
@UntilDestroy()
|
||||
export class MyProfileComponent implements OnInit {
|
||||
private profileService = inject(ProfileService);
|
||||
|
||||
protected readonly environment = environment;
|
||||
protected menu = signal<string>('home');
|
||||
|
||||
@@ -58,8 +52,6 @@ export class MyProfileComponent implements OnInit {
|
||||
return {} as User;
|
||||
});
|
||||
|
||||
protected profile: Profile = {} as Profile;
|
||||
|
||||
protected isEditMode = signal<boolean>(false);
|
||||
|
||||
onChangeURL(url: SafeUrl) {
|
||||
@@ -70,13 +62,13 @@ export class MyProfileComponent implements OnInit {
|
||||
this.isEditMode.set(!$event);
|
||||
}
|
||||
|
||||
private readonly profileFacade = new ProfileFacade();
|
||||
protected profile = this.profileFacade.profile;
|
||||
protected readonly loading = this.profileFacade.loading;
|
||||
protected readonly error = this.profileFacade.error;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.myProfileQrCode = `${this.myProfileQrCode}/profiles/${this.user().id}`;
|
||||
|
||||
this.profileService.getProfileByUserId(this.user().id).subscribe({
|
||||
next: (value: Profile) => {
|
||||
this.profile = value;
|
||||
},
|
||||
});
|
||||
this.profileFacade.loadOne(this.user().id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { QRCodeModule } from 'angularx-qrcode';
|
||||
import { UpperCasePipe } from '@angular/common';
|
||||
import { User } from '@app/shared/models/user';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { ChipsComponent } from '@app/shared/components/chips/chips.component';
|
||||
import { ReseauxComponent } from '@app/shared/components/reseaux/reseaux.component';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { ProjectListComponent } from '@app/shared/components/project-list/project-list.component';
|
||||
import { environment } from '@env/environment';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-profile-detail',
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { AsyncPipe, JsonPipe, UpperCasePipe } from '@angular/common';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { UpperCasePipe } from '@angular/common';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-home-profile',
|
||||
standalone: true,
|
||||
imports: [UpperCasePipe, AsyncPipe, JsonPipe],
|
||||
imports: [UpperCasePipe],
|
||||
templateUrl: './my-home-profile.component.html',
|
||||
styleUrl: './my-home-profile.component.scss',
|
||||
})
|
||||
@UntilDestroy()
|
||||
export class MyHomeProfileComponent {
|
||||
@Input({ required: true }) profile: Profile | undefined = undefined;
|
||||
@Input({ required: true }) profile: ProfileViewModel | undefined = undefined;
|
||||
}
|
||||
|
||||
@@ -2,19 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MyProfileUpdateCvFormComponent } from './my-profile-update-cv-form.component';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { signal } from '@angular/core';
|
||||
import { Auth } from '@app/shared/models/auth';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { of } from 'rxjs';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
|
||||
describe('MyProfileUpdateCvFormComponent', () => {
|
||||
let component: MyProfileUpdateCvFormComponent;
|
||||
let fixture: ComponentFixture<MyProfileUpdateCvFormComponent>;
|
||||
|
||||
let mockToastrService: Partial<ToastrService>;
|
||||
let mockProfileService: Partial<ProfileService>;
|
||||
let mockAuthService: Partial<AuthService>;
|
||||
let mockProfileRepo: ProfileRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockToastrService = {
|
||||
@@ -23,10 +26,11 @@ describe('MyProfileUpdateCvFormComponent', () => {
|
||||
warning: jest.fn(),
|
||||
};
|
||||
|
||||
mockProfileService = {
|
||||
updateProfile: jest.fn().mockReturnValue({
|
||||
subscribe: jest.fn(),
|
||||
}),
|
||||
mockProfileRepo = {
|
||||
create: jest.fn(),
|
||||
list: jest.fn(),
|
||||
update: jest.fn().mockReturnValue(of({} as Profile)),
|
||||
getByUserId: jest.fn().mockReturnValue(of({} as Profile)),
|
||||
};
|
||||
|
||||
mockAuthService = {
|
||||
@@ -38,8 +42,8 @@ describe('MyProfileUpdateCvFormComponent', () => {
|
||||
imports: [MyProfileUpdateCvFormComponent],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{ provide: ProfileService, useValue: mockProfileService },
|
||||
{ provide: AuthService, useValue: mockAuthService },
|
||||
],
|
||||
}).compileComponents();
|
||||
@@ -47,6 +51,8 @@ describe('MyProfileUpdateCvFormComponent', () => {
|
||||
fixture = TestBed.createComponent(MyProfileUpdateCvFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Component, inject, Input, output } from '@angular/core';
|
||||
import { Component, effect, inject, Input } from '@angular/core';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-profile-update-cv-form',
|
||||
@@ -13,29 +15,40 @@ import { ToastrService } from 'ngx-toastr';
|
||||
styleUrl: './my-profile-update-cv-form.component.scss',
|
||||
})
|
||||
export class MyProfileUpdateCvFormComponent {
|
||||
@Input({ required: true }) profile: Profile | undefined = undefined;
|
||||
@Input({ required: true }) profile: ProfileViewModel | undefined = undefined;
|
||||
|
||||
private readonly profileService = inject(ProfileService);
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
|
||||
private readonly authService = inject(AuthService);
|
||||
|
||||
file: File | null = null; // Variable to store file
|
||||
|
||||
private readonly profileFacade = new ProfileFacade();
|
||||
protected readonly loading = this.profileFacade.loading;
|
||||
protected readonly error = this.profileFacade.error;
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
if (!this.loading() && !this.error().hasError) {
|
||||
this.authService.updateUser();
|
||||
|
||||
this.toastrService.success(` Votre CV a bien été modifier !`, `Mise à jour`, {
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.file != null) {
|
||||
const formData = new FormData();
|
||||
formData.append('cv', this.file); // "avatar" est le nom du champ dans PocketBase
|
||||
|
||||
this.profileService.updateProfile(this.profile?.id!, formData).subscribe((value) => {
|
||||
this.authService.updateUser();
|
||||
|
||||
this.toastrService.success(` Votre CV a bien été modifier !`, `Mise à jour`, {
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
});
|
||||
});
|
||||
this.profileFacade.update(this.profile?.id!, formData as Partial<Profile>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@ import { MyProfileUpdateFormComponent } from './my-profile-update-form.component
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { of } from 'rxjs';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
describe('MyProfileUpdateFormComponent', () => {
|
||||
let component: MyProfileUpdateFormComponent;
|
||||
let fixture: ComponentFixture<MyProfileUpdateFormComponent>;
|
||||
|
||||
let mockToastrService: Partial<ToastrService>;
|
||||
let mockProfileRepo: ProfileRepository;
|
||||
|
||||
const mockProfileData = {
|
||||
profession: '',
|
||||
@@ -26,18 +31,28 @@ describe('MyProfileUpdateFormComponent', () => {
|
||||
error: jest.fn(),
|
||||
};
|
||||
|
||||
mockProfileRepo = {
|
||||
create: jest.fn(),
|
||||
list: jest.fn(),
|
||||
update: jest.fn().mockReturnValue(of({} as Profile)),
|
||||
getByUserId: jest.fn().mockReturnValue(of({} as Profile)),
|
||||
};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MyProfileUpdateFormComponent],
|
||||
providers: [
|
||||
FormBuilder,
|
||||
provideRouter([]),
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MyProfileUpdateFormComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, inject, Input, OnInit, signal } from '@angular/core';
|
||||
import { Component, effect, inject, Input, OnInit, signal } from '@angular/core';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
@@ -7,14 +7,16 @@ import {
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { SectorService } from '@app/core/services/sector/sector.service';
|
||||
import { Sector } from '@app/shared/models/sector';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { MyProfileUpdateCvFormComponent } from '@app/shared/components/my-profile-update-cv-form/my-profile-update-cv-form.component';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-my-profile-update-form',
|
||||
@@ -27,14 +29,38 @@ import { ToastrService } from 'ngx-toastr';
|
||||
export class MyProfileUpdateFormComponent implements OnInit {
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
|
||||
@Input({ required: true }) profile: Profile = {} as Profile;
|
||||
@Input({ required: true }) profile: ProfileViewModel = {} as ProfileViewModel;
|
||||
private readonly formBuilder = inject(FormBuilder);
|
||||
protected readonly sectorService = inject(SectorService);
|
||||
protected readonly profileService = inject(ProfileService);
|
||||
protected readonly authService = inject(AuthService);
|
||||
profileForm!: FormGroup;
|
||||
protected sectors = signal<Sector[]>([]);
|
||||
|
||||
private readonly profileFacade = new ProfileFacade();
|
||||
protected readonly loading = this.profileFacade.loading;
|
||||
protected readonly error = this.profileFacade.error;
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.UPDATE:
|
||||
if (!this.loading() && !this.error().hasError) {
|
||||
this.authService.updateUser();
|
||||
|
||||
this.toastrService.success(
|
||||
` Vos informations personnelles ont bien été modifier !`,
|
||||
`Mise à jour`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.profileForm = this.formBuilder.group({
|
||||
profession: new FormControl(
|
||||
@@ -90,26 +116,6 @@ export class MyProfileUpdateFormComponent implements OnInit {
|
||||
reseaux: this.profileForm.getRawValue().reseaux,
|
||||
} as Profile;
|
||||
|
||||
this.profileService.updateProfile(this.profile.id, data).subscribe({
|
||||
next: (value) => {
|
||||
this.authService.updateUser();
|
||||
|
||||
this.toastrService.success(
|
||||
` Vos informations personnelles ont 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 profil',
|
||||
'Erreur'
|
||||
);
|
||||
},
|
||||
});
|
||||
this.profileFacade.update(this.profile.id, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ export class MyProfileUpdateProjectFormComponent implements OnInit, OnChanges {
|
||||
|
||||
if (this.project() !== undefined) {
|
||||
this.projectForm.setValue({
|
||||
nom: this.project()!.nom,
|
||||
description: this.project()!.description,
|
||||
lien: this.project()!.lien,
|
||||
nom: this.project().nom ?? '',
|
||||
description: this.project().description ?? '',
|
||||
lien: this.project().lien ?? '',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PdfViewerComponent } from './pdf-viewer.component';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
|
||||
describe('PdfViewerComponent', () => {
|
||||
let component: PdfViewerComponent;
|
||||
let fixture: ComponentFixture<PdfViewerComponent>;
|
||||
|
||||
const mockProfile: Profile = {
|
||||
const mockProfile: ProfileViewModel = {
|
||||
id: '123',
|
||||
cv: 'cvfilename.pdf',
|
||||
} as Profile;
|
||||
} as ProfileViewModel;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, computed, Input } from '@angular/core';
|
||||
import { PdfViewerModule } from 'ng2-pdf-viewer';
|
||||
import { Profile } from '@app/shared/models/profile';
|
||||
import { environment } from '@env/environment';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pdf-viewer',
|
||||
@@ -11,7 +11,7 @@ import { environment } from '@env/environment';
|
||||
styleUrl: './pdf-viewer.component.scss',
|
||||
})
|
||||
export class PdfViewerComponent {
|
||||
@Input({ required: true }) profile: Profile | undefined = undefined;
|
||||
@Input({ required: true }) profile: ProfileViewModel | undefined = undefined;
|
||||
protected readonly environment = environment;
|
||||
protected readonly cv_link = computed(() => {
|
||||
return `${environment.baseUrl}/api/files/profiles/${this.profile!.id}/${this.profile!.cv}`;
|
||||
|
||||
@@ -3,8 +3,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RegisterComponent } from './register.component';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
|
||||
describe('RegisterComponent', () => {
|
||||
let component: RegisterComponent;
|
||||
@@ -12,19 +13,22 @@ describe('RegisterComponent', () => {
|
||||
|
||||
let mockToastrService: Partial<ToastrService>;
|
||||
let mockAuthService: Partial<AuthService>;
|
||||
let mockProfileService: Partial<ProfileService>;
|
||||
let mockProfileRepo: ProfileRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockProfileRepo = {
|
||||
create: jest.fn(),
|
||||
list: jest.fn(),
|
||||
update: jest.fn(),
|
||||
getByUserId: jest.fn(),
|
||||
};
|
||||
|
||||
mockToastrService = {
|
||||
success: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warning: jest.fn(),
|
||||
};
|
||||
|
||||
mockProfileService = {
|
||||
createProfile: jest.fn().mockResolvedValue(true),
|
||||
};
|
||||
|
||||
mockAuthService = {};
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
@@ -33,7 +37,7 @@ describe('RegisterComponent', () => {
|
||||
provideRouter([]),
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{ provide: AuthService, useValue: mockAuthService },
|
||||
{ provide: ProfileService, useValue: mockProfileService },
|
||||
{ provide: PROFILE_REPOSITORY_TOKEN, useValue: mockProfileRepo },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, inject, output, signal } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, effect, inject, output, signal } from '@angular/core';
|
||||
import { Router, RouterLink } from '@angular/router';
|
||||
import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { AuthService } from '@app/core/services/authentication/auth.service';
|
||||
import { RegisterDto } from '@app/shared/models/register-dto';
|
||||
import { UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { ProfileService } from '@app/core/services/profile/profile.service';
|
||||
import { ProfileDto } from '@app/shared/models/profile-dto';
|
||||
import { ProgressBarModule } from 'primeng/progressbar';
|
||||
import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto';
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
@@ -20,7 +21,6 @@ import { ProgressBarModule } from 'primeng/progressbar';
|
||||
@UntilDestroy()
|
||||
export class RegisterComponent {
|
||||
private readonly authService = inject(AuthService);
|
||||
private readonly profileService = inject(ProfileService);
|
||||
private readonly toastrService = inject(ToastrService);
|
||||
|
||||
private readonly formBuilder = inject(FormBuilder);
|
||||
@@ -34,6 +34,26 @@ export class RegisterComponent {
|
||||
formSubmitted = output<any>();
|
||||
protected isLoading = signal<boolean>(false);
|
||||
|
||||
private readonly profileFacade = new ProfileFacade();
|
||||
protected readonly loading = this.profileFacade.loading;
|
||||
protected readonly error = this.profileFacade.error;
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
switch (this.loading().action) {
|
||||
case ActionType.CREATE:
|
||||
if (!this.loading().isLoading) {
|
||||
if (!this.error().hasError) {
|
||||
this.router.navigate(['/auth']).then(() => {
|
||||
this.sendVerificationEmail();
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.registerForm.invalid) {
|
||||
this.isLoading.set(false);
|
||||
@@ -63,13 +83,13 @@ export class RegisterComponent {
|
||||
register(registerDto: RegisterDto) {
|
||||
this.authService.register(registerDto).then((res) => {
|
||||
if (res) {
|
||||
this.createProfile(res.id, registerDto.email);
|
||||
this.createProfile(res.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createProfile(userId: string, email: string) {
|
||||
const profileDto: ProfileDto = {
|
||||
createProfile(userId: string) {
|
||||
const profileDto: ProfileDTO = {
|
||||
profession: 'Profession non renseignée',
|
||||
utilisateur: userId,
|
||||
reseaux: {
|
||||
@@ -83,28 +103,11 @@ export class RegisterComponent {
|
||||
},
|
||||
};
|
||||
|
||||
this.profileService.createProfile(profileDto).subscribe({
|
||||
next: (profile) => {
|
||||
if (profile)
|
||||
this.router.navigate(['/auth']).then(() => {
|
||||
this.sendVerificationEmail(email);
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
this.toastrService.error(
|
||||
`Une erreur est survenue lors de la création de votre profil.`,
|
||||
`Erreur`,
|
||||
{
|
||||
closeButton: true,
|
||||
progressAnimation: 'decreasing',
|
||||
progressBar: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
this.profileFacade.create(profileDto);
|
||||
}
|
||||
|
||||
sendVerificationEmail(email: string) {
|
||||
sendVerificationEmail() {
|
||||
const email = this.registerForm.getRawValue().email!;
|
||||
this.authService.verifyEmail(email).then((isVerified: boolean) => {
|
||||
this.isLoading.set(false);
|
||||
this.registerForm.enable();
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export interface ProfileDto {
|
||||
profession: string;
|
||||
utilisateur: string;
|
||||
reseaux: any;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
export interface Profile {
|
||||
id: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
profession: string;
|
||||
utilisateur: string;
|
||||
estVerifier: boolean;
|
||||
secteur: string;
|
||||
reseaux: JSON;
|
||||
bio: string;
|
||||
cv: string;
|
||||
projets: string[];
|
||||
apropos: string;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export interface ProjectDto {
|
||||
nom: string;
|
||||
description: string;
|
||||
lien: string;
|
||||
utilisateur: string;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export interface Project {
|
||||
id: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
nom: string;
|
||||
lien: string;
|
||||
description: string;
|
||||
fichier: string[];
|
||||
utilisateur: string;
|
||||
}
|
||||
@@ -8,8 +8,8 @@ export class FakeProfileRepository implements ProfileRepository {
|
||||
return of(mockProfiles);
|
||||
}
|
||||
|
||||
getByUserId(userId: string): Observable<Profile | null> {
|
||||
const profile = mockProfiles.find((p) => p.utilisateur === userId) ?? null;
|
||||
getByUserId(userId: string): Observable<Profile> {
|
||||
const profile = mockProfiles.find((p) => p.utilisateur === userId) ?? ({} as Profile);
|
||||
return of(profile);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ProjectRepository } from '@app/domain/projects/project.repository';
|
||||
import { Project } from '@app/shared/models/project';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { CreateProjectDto } from '@app/domain/projects/dto/create-project.dto';
|
||||
import { fakeProjects } from '@app/testing/project.mock';
|
||||
import { Project } from '@app/domain/projects/project.model';
|
||||
|
||||
export class FakeProjectRepository implements ProjectRepository {
|
||||
private projects: Project[] = [...fakeProjects];
|
||||
|
||||
@@ -2,6 +2,9 @@ import { ProfileFacade } from '@app/ui/profiles/profile.facade';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
import { FakeProfileRepository } from '@app/testing/domain/profiles/fake-profile.repository';
|
||||
import { mockProfiles } from '@app/testing/profile.mock';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto';
|
||||
|
||||
describe('ProfileFacade', () => {
|
||||
let facade: ProfileFacade;
|
||||
@@ -27,4 +30,52 @@ describe('ProfileFacade', () => {
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it("doit charger le profile d'un utilisateur ", () => {
|
||||
facade.loadOne('1');
|
||||
const expectedProfile = mockProfiles[0];
|
||||
|
||||
// attendre un peu le .subscribe
|
||||
setTimeout(() => {
|
||||
expect(facade.profile()).toBe(expectedProfile);
|
||||
expect(facade.loading().isLoading).toBe(false);
|
||||
expect(facade.error().hasError).toBe(false);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('doit mettre à jour un profile ', () => {
|
||||
expect(mockProfiles[0].profession).toBe('Développeur Web');
|
||||
|
||||
const profileUpdated: Profile = {
|
||||
...mockProfiles[0],
|
||||
profession: 'Devops',
|
||||
};
|
||||
|
||||
facade.update('1', profileUpdated);
|
||||
|
||||
// attendre un peu le .subscribe
|
||||
setTimeout(() => {
|
||||
expect(facade.profile().profession).toBe('Devops');
|
||||
expect(facade.loading().isLoading).toBe(false);
|
||||
expect(facade.error().hasError).toBe(false);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('doit creer un nouveau profile ', () => {
|
||||
const profile: ProfileDTO = {
|
||||
utilisateur: 'john doe',
|
||||
reseaux: {},
|
||||
profession: 'Journaliste',
|
||||
};
|
||||
|
||||
facade.create(profile);
|
||||
|
||||
// attendre un peu le .subscribe
|
||||
setTimeout(() => {
|
||||
expect(mockProfiles.find((profile) => profile.id === facade.profile().id)).toBeDefined();
|
||||
expect(facade.profile().profession).toBe('Journaliste');
|
||||
expect(facade.loading().isLoading).toBe(false);
|
||||
expect(facade.error().hasError).toBe(false);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,6 +19,10 @@ describe('ProfilePresenter', () => {
|
||||
utilisateur: 'user_abc',
|
||||
createdAtFormatted: new Date(profile.created).toLocaleDateString(),
|
||||
avatarUrl: '',
|
||||
apropos: 'Développeur Angular & Node.js',
|
||||
bio: 'Passionné de code.',
|
||||
cv: 'cv.pdf',
|
||||
projets: ['p1', 'p2'],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { FakeProfileRepository } from '@app/testing/domain/profiles/fake-profile.repository';
|
||||
import { mockProfiles } from '@app/testing/profile.mock';
|
||||
import { CreateProfileUseCase } from '@app/usecase/profiles/create-profile.usecase';
|
||||
import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto';
|
||||
|
||||
describe('CreateProfileUseCase', () => {
|
||||
it('doit creer nouveau un profile', () => {
|
||||
const repo = new FakeProfileRepository();
|
||||
const useCase = new CreateProfileUseCase(repo);
|
||||
|
||||
const profile: ProfileDTO = {
|
||||
utilisateur: 'john doe',
|
||||
profession: 'Designer',
|
||||
reseaux: {},
|
||||
};
|
||||
|
||||
useCase.execute(profile).subscribe({
|
||||
next: (profile) => {
|
||||
expect(mockProfiles).toContain(profile);
|
||||
expect(mockProfiles.find((current_profile) => profile.id === current_profile.id)).toBe(
|
||||
profile.id
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
16
src/app/testing/usecase/profiles/get-profile.usecase.spec.ts
Normal file
16
src/app/testing/usecase/profiles/get-profile.usecase.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { FakeProfileRepository } from '@app/testing/domain/profiles/fake-profile.repository';
|
||||
import { mockProfiles } from '@app/testing/profile.mock';
|
||||
import { GetProfileUseCase } from '@app/usecase/profiles/get-profile.usecase';
|
||||
|
||||
describe('GetProfileUseCase', () => {
|
||||
it('doit retourner un profile', () => {
|
||||
const repo = new FakeProfileRepository();
|
||||
const useCase = new GetProfileUseCase(repo);
|
||||
|
||||
useCase.execute('1').subscribe({
|
||||
next: (profile) => {
|
||||
expect(profile).toEqual(mockProfiles[0]);
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { FakeProfileRepository } from '@app/testing/domain/profiles/fake-profile.repository';
|
||||
import { mockProfiles } from '@app/testing/profile.mock';
|
||||
import { UpdateProfileUseCase } from '@app/usecase/profiles/update-profile.usecase';
|
||||
|
||||
describe('UpdateProfileUseCase', () => {
|
||||
it('doit retourner un profile modifier', () => {
|
||||
const repo = new FakeProfileRepository();
|
||||
const useCase = new UpdateProfileUseCase(repo);
|
||||
const profile = mockProfiles[0];
|
||||
|
||||
expect(profile.profession).toBe('Développeur Web');
|
||||
|
||||
const profileUpdate = {
|
||||
...profile,
|
||||
profession: 'Développeur fullstack',
|
||||
};
|
||||
useCase.execute('1', profileUpdate).subscribe({
|
||||
next: (profile) => {
|
||||
expect(profile.profession).toEqual('Développeur fullstack');
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,21 +1,30 @@
|
||||
import { ListProfilesUseCase } from '@app/usecase/profiles/list-profiles.usecase';
|
||||
import { inject, signal } from '@angular/core';
|
||||
import { inject, Injectable, signal } from '@angular/core';
|
||||
import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ProfilePresenter } from '@app/ui/profiles/profile.presenter';
|
||||
import { ProfileViewModel } from '@app/ui/profiles/profile.presenter.model';
|
||||
import { LoaderAction } from '@app/domain/loader-action.util';
|
||||
import { ActionType } from '@app/domain/action-type.util';
|
||||
import { ErrorResponse } from '@app/domain/error-response.util';
|
||||
import { CreateProfileUseCase } from '@app/usecase/profiles/create-profile.usecase';
|
||||
import { UpdateProfileUseCase } from '@app/usecase/profiles/update-profile.usecase';
|
||||
import { GetProfileUseCase } from '@app/usecase/profiles/get-profile.usecase';
|
||||
import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProfileFacade {
|
||||
private profileRepository = inject(PROFILE_REPOSITORY_TOKEN);
|
||||
|
||||
private listUseCase = new ListProfilesUseCase(this.profileRepository);
|
||||
private createUseCase = new CreateProfileUseCase(this.profileRepository);
|
||||
private updateUseCase = new UpdateProfileUseCase(this.profileRepository);
|
||||
private getUseCase = new GetProfileUseCase(this.profileRepository);
|
||||
|
||||
readonly profiles = signal<ProfileViewModel[]>([]);
|
||||
readonly profile = signal<ProfileViewModel>({} as ProfileViewModel);
|
||||
readonly loading = signal<LoaderAction>({ isLoading: false, action: ActionType.NONE });
|
||||
readonly error = signal<ErrorResponse>({
|
||||
action: ActionType.NONE,
|
||||
@@ -37,6 +46,48 @@ export class ProfileFacade {
|
||||
});
|
||||
}
|
||||
|
||||
loadOne(userId: string) {
|
||||
this.handleError(ActionType.READ, false, null, true);
|
||||
|
||||
this.getUseCase.execute(userId).subscribe({
|
||||
next: (profile: Profile) => {
|
||||
this.profile.set(ProfilePresenter.toViewModel(profile));
|
||||
this.handleError(ActionType.READ, false, null, false);
|
||||
},
|
||||
error: (err) => {
|
||||
this.handleError(ActionType.READ, false, err, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
create(profileDto: ProfileDTO) {
|
||||
this.handleError(ActionType.CREATE, false, null, true);
|
||||
|
||||
this.createUseCase.execute(profileDto).subscribe({
|
||||
next: (profile: Profile) => {
|
||||
this.profile.set(ProfilePresenter.toViewModel(profile));
|
||||
this.handleError(ActionType.CREATE, false, null, false);
|
||||
},
|
||||
error: (err) => {
|
||||
this.handleError(ActionType.CREATE, false, err, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
update(profileId: string, profile: Partial<Profile>) {
|
||||
this.handleError(ActionType.UPDATE, false, null, true);
|
||||
|
||||
this.updateUseCase.execute(profileId, profile).subscribe({
|
||||
next: (profile: Profile) => {
|
||||
this.profile.set(ProfilePresenter.toViewModel(profile));
|
||||
this.handleError(ActionType.UPDATE, false, null, false);
|
||||
},
|
||||
error: (err) => {
|
||||
this.handleError(ActionType.UPDATE, false, err, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private handleError(
|
||||
action: ActionType = ActionType.NONE,
|
||||
hasError: boolean,
|
||||
|
||||
@@ -9,4 +9,8 @@ export interface ProfileViewModel {
|
||||
profession: string;
|
||||
secteur: string;
|
||||
reseaux: any;
|
||||
apropos: string;
|
||||
bio: string;
|
||||
cv: string;
|
||||
projets: string[];
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ export class ProfilePresenter {
|
||||
profession: profile.profession,
|
||||
secteur: profile.secteur,
|
||||
reseaux: profile.reseaux,
|
||||
apropos: profile.apropos,
|
||||
projets: profile.projets,
|
||||
cv: profile.cv,
|
||||
bio: profile.bio,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
12
src/app/usecase/profiles/create-profile.usecase.ts
Normal file
12
src/app/usecase/profiles/create-profile.usecase.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto';
|
||||
|
||||
export class CreateProfileUseCase {
|
||||
constructor(private readonly repo: ProfileRepository) {}
|
||||
|
||||
execute(profileDto: ProfileDTO): Observable<Profile> {
|
||||
return this.repo.create(profileDto as Profile);
|
||||
}
|
||||
}
|
||||
11
src/app/usecase/profiles/get-profile.usecase.ts
Normal file
11
src/app/usecase/profiles/get-profile.usecase.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
|
||||
export class GetProfileUseCase {
|
||||
constructor(private readonly repo: ProfileRepository) {}
|
||||
|
||||
execute(userId: string): Observable<Profile> {
|
||||
return this.repo.getByUserId(userId);
|
||||
}
|
||||
}
|
||||
11
src/app/usecase/profiles/update-profile.usecase.ts
Normal file
11
src/app/usecase/profiles/update-profile.usecase.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ProfileRepository } from '@app/domain/profiles/profile.repository';
|
||||
import { Profile } from '@app/domain/profiles/profile.model';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export class UpdateProfileUseCase {
|
||||
constructor(private readonly repo: ProfileRepository) {}
|
||||
|
||||
execute(profileId: string, profile: Partial<Profile>): Observable<Profile> {
|
||||
return this.repo.update(profileId, profile as Profile);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user