diff --git a/package.json b/package.json index 75b732e..f81289e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "trouve-ton-profile", - "version": "1.0.0", + "version": "1.1.0", "scripts": { "ng": "ng", "start": "bash replace-prod-env.sh src/environments/environment.development.ts $ENV_URL && ng serve", diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 3440c00..1052520 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -55,9 +55,9 @@ describe('AppComponent', () => { expect(app).toBeTruthy(); }); - it(`should have the 'TrouveTonProfile' title`, () => { + it(`should have the 'TrouveTonProfil' title`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; - expect(app.title).toEqual('TrouveTonProfile'); + expect(app.title).toEqual('TrouveTonProfil'); }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 641ec5e..dd759c8 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -13,6 +13,6 @@ import { ThemeService } from '@app/core/services/theme/theme.service'; styleUrl: './app.component.scss', }) export class AppComponent { - title = 'TrouveTonProfile'; + title = 'TrouveTonProfil'; themeService = inject(ThemeService); } diff --git a/src/app/core/guard/authentication/auth.guard.spec.ts b/src/app/core/guard/authentication/auth.guard.spec.ts index a40d13f..fbc7e4b 100644 --- a/src/app/core/guard/authentication/auth.guard.spec.ts +++ b/src/app/core/guard/authentication/auth.guard.spec.ts @@ -2,10 +2,6 @@ import { TestBed } from '@angular/core/testing'; import { authGuard } from './auth.guard'; import { CanActivateFn, Router, UrlTree } from '@angular/router'; -import { AuthRepository } from '@app/domain/authentification/auth.repository'; -import { ProfileRepository } from '@app/domain/profiles/profile.repository'; -import { AUTH_REPOSITORY_TOKEN } from '@app/infrastructure/authentification/auth-repository.token'; -import { PROFILE_REPOSITORY_TOKEN } from '@app/infrastructure/profiles/profile-repository.token'; import { AuthFacade } from '@app/ui/authentification/auth.facade'; describe('authGuard', () => { diff --git a/src/app/domain/profiles/profile.model.ts b/src/app/domain/profiles/profile.model.ts index b8b4796..e02e718 100644 --- a/src/app/domain/profiles/profile.model.ts +++ b/src/app/domain/profiles/profile.model.ts @@ -12,3 +12,11 @@ export interface Profile { projets: string[]; apropos: string; } + +export interface ProfilePaginated { + page: number; + perPage: number; + totalPages: number; + totalItems: number; + items: any[]; +} diff --git a/src/app/domain/profiles/profile.repository.ts b/src/app/domain/profiles/profile.repository.ts index 713a00a..440bad0 100644 --- a/src/app/domain/profiles/profile.repository.ts +++ b/src/app/domain/profiles/profile.repository.ts @@ -1,9 +1,9 @@ -import { Profile } from '@app/domain/profiles/profile.model'; +import { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; import { Observable } from 'rxjs'; import { SearchFilters } from '@app/domain/search/search-filters'; export interface ProfileRepository { - list(params?: SearchFilters): Observable; + list(params?: SearchFilters): Observable; getByUserId(userId: string): Observable; create(profile: Profile): Observable; update(profileId: string, profile: Partial): Observable; diff --git a/src/app/domain/search/search-filters.ts b/src/app/domain/search/search-filters.ts index bb394e3..aad9154 100644 --- a/src/app/domain/search/search-filters.ts +++ b/src/app/domain/search/search-filters.ts @@ -5,5 +5,7 @@ export interface SearchFilters { profession: string | null; sort: string; page?: number; - pageSize?: number; + perPage?: number; + totalPages?: number; + totalItems?: number; } diff --git a/src/app/infrastructure/profiles/pb-profile.repository.ts b/src/app/infrastructure/profiles/pb-profile.repository.ts index 5daa54f..925f89c 100644 --- a/src/app/infrastructure/profiles/pb-profile.repository.ts +++ b/src/app/infrastructure/profiles/pb-profile.repository.ts @@ -1,6 +1,6 @@ import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { from, Observable } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; +import { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; import { Injectable } from '@angular/core'; import PocketBase from 'pocketbase'; import { environment } from '@env/environment'; @@ -12,17 +12,21 @@ export class PbProfileRepository implements ProfileRepository { private pb = new PocketBase(environment.baseUrl); private defaultOptions = { - expand: 'utilisateur', + expand: 'utilisateur,secteur', }; - list(params?: SearchFilters): Observable { + list(params?: SearchFilters): Observable { const requestOptions = { ...this.defaultOptions, sort: this.onSortSetting(params), filter: this.onFilterSetting(params).join(' && '), }; - return from(this.pb.collection('profiles').getFullList(requestOptions)); + return from( + this.pb + .collection('profiles') + .getList(params?.page, params?.perPage, requestOptions) + ); } getByUserId(userId: string): Observable { @@ -49,7 +53,7 @@ export class PbProfileRepository implements ProfileRepository { if (params) { if (params.secteur) { - filters.push(`secteur ~ '${params.secteur}'`); + filters.push(`secteur.nom ~ '${params.secteur}'`); } if (params.profession) { diff --git a/src/app/infrastructure/search/search.service.ts b/src/app/infrastructure/search/search.service.ts index d56eef7..c38c392 100644 --- a/src/app/infrastructure/search/search.service.ts +++ b/src/app/infrastructure/search/search.service.ts @@ -12,6 +12,8 @@ export class SearchService implements SearchRepository { secteur: null, profession: null, sort: 'recent', + page: 1, + perPage: 25, }); setFilters(filters: SearchFilters) { diff --git a/src/app/routes/my-profile/my-profile.component.html b/src/app/routes/my-profile/my-profile.component.html index 9f8d667..a87e18b 100644 --- a/src/app/routes/my-profile/my-profile.component.html +++ b/src/app/routes/my-profile/my-profile.component.html @@ -78,8 +78,12 @@ {{ user()!.username }} } diff --git a/src/app/routes/profile/profile-detail/profile-detail.component.html b/src/app/routes/profile/profile-detail/profile-detail.component.html index 96496f6..6336a68 100644 --- a/src/app/routes/profile/profile-detail/profile-detail.component.html +++ b/src/app/routes/profile/profile-detail/profile-detail.component.html @@ -65,7 +65,7 @@
@if (user().avatar) { {{ user().username }} {{ user().name }} - } @else if (user().username) { -

- {{ user().username }} -

} @else {

{{ user().email }} diff --git a/src/app/routes/profile/profile-list/profile-list.component.html b/src/app/routes/profile/profile-list/profile-list.component.html index 5a80dab..f41b10f 100644 --- a/src/app/routes/profile/profile-list/profile-list.component.html +++ b/src/app/routes/profile/profile-list/profile-list.component.html @@ -70,13 +70,17 @@ d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z" /> - {{ profiles().length }} profil(s) + {{ profilePaginated().items.length }} profil(s)

- + +
+ +
+
} diff --git a/src/app/routes/profile/profile-list/profile-list.component.ts b/src/app/routes/profile/profile-list/profile-list.component.ts index 250813a..9e9ba17 100644 --- a/src/app/routes/profile/profile-list/profile-list.component.ts +++ b/src/app/routes/profile/profile-list/profile-list.component.ts @@ -6,34 +6,42 @@ import { ProfileFacade } from '@app/ui/profiles/profile.facade'; import { LoadingComponent } from '@app/shared/components/loading/loading.component'; import { Router } from '@angular/router'; import { SearchFilters } from '@app/domain/search/search-filters'; -import { SearchService } from '@app/infrastructure/search/search.service'; import { FilterComponent } from '@app/shared/features/filter/filter.component'; +import { PaginationComponent } from '@app/shared/features/pagination/pagination.component'; @Component({ selector: 'app-profile-list', standalone: true, - imports: [SearchComponent, VerticalProfileListComponent, LoadingComponent, FilterComponent], + imports: [ + SearchComponent, + VerticalProfileListComponent, + LoadingComponent, + FilterComponent, + PaginationComponent, + ], templateUrl: './profile-list.component.html', styleUrl: './profile-list.component.scss', }) @UntilDestroy() export class ProfileListComponent { - private readonly searchService = inject(SearchService); private readonly facade = inject(ProfileFacade); private readonly router = inject(Router); - protected readonly profiles = this.facade.profiles; + protected readonly searchFilters = this.facade.searchFilters; + protected readonly profilePaginated = this.facade.profilePaginated; protected readonly loading = this.facade.loading; protected readonly error = this.facade.error; - protected readonly searchFilters = this.searchService.getFilters(); - showNewQuery(filters: SearchFilters) { - this.facade.load(this.searchFilters()); + this.facade.load(filters); this.router.navigate(['/profiles'], { queryParams: { search: filters.search } }); } onFilterChange(filters: SearchFilters) { this.facade.load(filters); } + + onPageChange(filters: SearchFilters) { + this.facade.load(filters); + } } diff --git a/src/app/shared/components/footer/footer.component.html b/src/app/shared/components/footer/footer.component.html index 91d2e40..32069a1 100644 --- a/src/app/shared/components/footer/footer.component.html +++ b/src/app/shared/components/footer/footer.component.html @@ -17,7 +17,7 @@ - TrouveTonProfile + TrouveTonProfil @@ -120,7 +120,7 @@

- © {{ currentYear }} TrouveTonProfile. Tous droits réservés. + © {{ currentYear }} TrouveTonProfil. Tous droits réservés.

diff --git a/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.html b/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.html index bdc04f7..2cbfd4e 100644 --- a/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.html +++ b/src/app/shared/components/my-profile-update-form/my-profile-update-form.component.html @@ -134,7 +134,7 @@ for="profession" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" > - Profession + Profession *
@@ -170,7 +170,7 @@ for="secteur" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" > - Secteur d'activité + Secteur d'activité *
diff --git a/src/app/shared/components/nav-bar/nav-bar.component.html b/src/app/shared/components/nav-bar/nav-bar.component.html index edfe991..9671885 100644 --- a/src/app/shared/components/nav-bar/nav-bar.component.html +++ b/src/app/shared/components/nav-bar/nav-bar.component.html @@ -17,33 +17,7 @@ -
- - @if (isAuthenticated() && isEmailVerified() && user(); as user) { - - @if (user.avatar) { - - } @else { - - } - - } - +
diff --git a/src/app/shared/components/pagination/pagination.component.html b/src/app/shared/components/pagination/pagination.component.html deleted file mode 100644 index 37d1375..0000000 --- a/src/app/shared/components/pagination/pagination.component.html +++ /dev/null @@ -1,36 +0,0 @@ - - diff --git a/src/app/shared/components/pagination/pagination.component.ts b/src/app/shared/components/pagination/pagination.component.ts deleted file mode 100644 index f75e00d..0000000 --- a/src/app/shared/components/pagination/pagination.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-pagination', - standalone: true, - imports: [], - templateUrl: './pagination.component.html', - styleUrl: './pagination.component.scss', -}) -export class PaginationComponent {} diff --git a/src/app/shared/components/project-list/project-list.component.html b/src/app/shared/components/project-list/project-list.component.html index 000848a..0996bd1 100644 --- a/src/app/shared/components/project-list/project-list.component.html +++ b/src/app/shared/components/project-list/project-list.component.html @@ -1,6 +1,6 @@
-
+
@for (project of projects(); track project.id) { } @empty { diff --git a/src/app/shared/components/user-avatar-form/user-avatar-form.component.html b/src/app/shared/components/user-avatar-form/user-avatar-form.component.html index d5f731e..3efc84b 100644 --- a/src/app/shared/components/user-avatar-form/user-avatar-form.component.html +++ b/src/app/shared/components/user-avatar-form/user-avatar-form.component.html @@ -27,7 +27,9 @@ {{ user!.username }} } diff --git a/src/app/shared/components/user-form/user-form.component.html b/src/app/shared/components/user-form/user-form.component.html index c235072..b8b1c5a 100644 --- a/src/app/shared/components/user-form/user-form.component.html +++ b/src/app/shared/components/user-form/user-form.component.html @@ -34,7 +34,7 @@
@@ -64,7 +64,7 @@
@@ -108,7 +108,11 @@ 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" /> - Modifier mon identité + @if (userForm.valid) { + Sauvegarder les modifications + } @else { + Modifier mon identité + } diff --git a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html index ea08b57..d1cfdcb 100644 --- a/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html +++ b/src/app/shared/components/vertical-profile-item/vertical-profile-item.component.html @@ -1,9 +1,5 @@ @if (user() !== undefined) { - +
- {{ user().name }} + {{ user().firstName }} {{ user().lastName }} } @else if (user().username) {

+
+
    +
  • + +
  • + +
  • + + {{ currentPage }} / {{ filters.totalPages! }} + +
  • + +
  • + +
  • +
+
diff --git a/src/app/shared/components/pagination/pagination.component.scss b/src/app/shared/features/pagination/pagination.component.scss similarity index 100% rename from src/app/shared/components/pagination/pagination.component.scss rename to src/app/shared/features/pagination/pagination.component.scss diff --git a/src/app/shared/components/pagination/pagination.component.spec.ts b/src/app/shared/features/pagination/pagination.component.spec.ts similarity index 100% rename from src/app/shared/components/pagination/pagination.component.spec.ts rename to src/app/shared/features/pagination/pagination.component.spec.ts diff --git a/src/app/shared/features/pagination/pagination.component.ts b/src/app/shared/features/pagination/pagination.component.ts new file mode 100644 index 0000000..165633d --- /dev/null +++ b/src/app/shared/features/pagination/pagination.component.ts @@ -0,0 +1,34 @@ +import { Component, Input, OnInit, output } from '@angular/core'; +import { SearchFilters } from '@app/domain/search/search-filters'; + +@Component({ + selector: 'app-pagination', + standalone: true, + imports: [], + templateUrl: './pagination.component.html', + styleUrl: './pagination.component.scss', +}) +export class PaginationComponent implements OnInit { + @Input({ required: true }) filters: SearchFilters = {} as SearchFilters; + onPageChange = output(); + currentPage = 1; + + ngOnInit() { + this.currentPage = this.filters.page!; + } + + goToPreviousPage() { + this.currentPage = this.currentPage - 1; + this.emitPageChange(); + } + + goToNextPage() { + this.currentPage = this.currentPage + 1; + this.emitPageChange(); + } + + private emitPageChange() { + const filters = { ...this.filters, page: this.currentPage }; + this.onPageChange.emit(filters); + } +} diff --git a/src/app/shared/features/search/search.component.html b/src/app/shared/features/search/search.component.html index 4a435e5..85f649b 100644 --- a/src/app/shared/features/search/search.component.html +++ b/src/app/shared/features/search/search.component.html @@ -44,10 +44,10 @@ class="w-full sm:w-auto px-6 sm:px-8 py-3 sm:py-2.5 rounded-full sm:rounded-l-none sm:rounded-r-full bg-purple-600 hover:bg-purple-700 active:bg-purple-800 text-white font-medium text-sm sm:text-base transition-colors disabled:opacity-50 disabled:cursor-not-allowed" > {{ - searchForm.value!.search! === '' ? 'Tout' : 'Rechercher' + searchForm.value!.search! === '' ? 'Explorer' : 'Rechercher' }}

diff --git a/src/app/testing/domain/profiles/fake-profile.repository.ts b/src/app/testing/domain/profiles/fake-profile.repository.ts index 920a1f1..c54291c 100644 --- a/src/app/testing/domain/profiles/fake-profile.repository.ts +++ b/src/app/testing/domain/profiles/fake-profile.repository.ts @@ -1,11 +1,11 @@ -import { Profile } from '@app/domain/profiles/profile.model'; -import { mockProfiles } from '@app/testing/profile.mock'; +import { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; +import { mockProfilePaginated, mockProfiles } from '@app/testing/profile.mock'; import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { Observable, of } from 'rxjs'; export class FakeProfileRepository implements ProfileRepository { - list(): Observable { - return of(mockProfiles); + list(): Observable { + return of(mockProfilePaginated); } getByUserId(userId: string): Observable { diff --git a/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts b/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts index 40db7ba..87d4e8d 100644 --- a/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts +++ b/src/app/testing/infrastructure/profiles/pb-profile.repository.spec.ts @@ -2,7 +2,7 @@ import { PbProfileRepository } from '@app/infrastructure/profiles/pb-profile.rep import { Profile } from '@app/domain/profiles/profile.model'; import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto'; import PocketBase from 'pocketbase'; -import { mockProfiles } from '@app/testing/profile.mock'; +import { mockProfilePaginated, mockProfiles } from '@app/testing/profile.mock'; jest.mock('pocketbase'); // on mock le module PocketBase @@ -14,7 +14,7 @@ describe('PbProfileRepository', () => { beforeEach(() => { // Création d’un faux client PocketBase avec les méthodes dont on a besoin mockCollection = { - getFullList: jest.fn(), + getList: jest.fn(), getFirstListItem: jest.fn(), create: jest.fn(), update: jest.fn(), @@ -35,18 +35,18 @@ describe('PbProfileRepository', () => { // ------------------------------------------ // 🔹 TEST : list() // ------------------------------------------ - it('devrait appeler pb.collection("profiles").getFullList() avec un tri par profession', (done) => { - mockCollection.getFullList.mockResolvedValue(mockProfiles); + it('devrait appeler pb.collection("profiles").getList() avec un tri par profession', (done) => { + mockCollection.getList.mockResolvedValue(mockProfilePaginated); const options = { - expand: 'utilisateur', + expand: 'utilisateur,secteur', filter: "utilisateur.verified = true && utilisateur.name != '' && profession != 'Profession non renseignée' && secteur != ''", sort: '-created', }; repo.list().subscribe((result) => { expect(mockPocketBase.collection).toHaveBeenCalledWith('profiles'); - expect(mockCollection.getFullList).toHaveBeenCalledWith(options); - expect(result).toEqual(mockProfiles); + expect(mockCollection.getList).toHaveBeenCalledWith(undefined, undefined, options); + expect(result).toEqual(mockProfilePaginated); done(); }); }); diff --git a/src/app/testing/profile.mock.ts b/src/app/testing/profile.mock.ts index 79d3c79..7d316da 100644 --- a/src/app/testing/profile.mock.ts +++ b/src/app/testing/profile.mock.ts @@ -1,4 +1,4 @@ -import { Profile } from '@app/domain/profiles/profile.model'; +import { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; export const mockProfiles: Profile[] = [ { @@ -30,3 +30,11 @@ export const mockProfiles: Profile[] = [ apropos: 'Designer Freelance', }, ]; + +export const mockProfilePaginated: ProfilePaginated = { + page: 1, + perPage: 10, + totalPages: 1, + totalItems: 1, + items: mockProfiles, +}; diff --git a/src/app/testing/usecase/profiles/list-profiles.usecase.spec.ts b/src/app/testing/usecase/profiles/list-profiles.usecase.spec.ts index 13f9819..9943e8d 100644 --- a/src/app/testing/usecase/profiles/list-profiles.usecase.spec.ts +++ b/src/app/testing/usecase/profiles/list-profiles.usecase.spec.ts @@ -1,6 +1,6 @@ import { ListProfilesUseCase } from '@app/usecase/profiles/list-profiles.usecase'; import { FakeProfileRepository } from '@app/testing/domain/profiles/fake-profile.repository'; -import { mockProfiles } from '@app/testing/profile.mock'; +import { mockProfilePaginated, mockProfiles } from '@app/testing/profile.mock'; describe('ListProfilesUseCase', () => { it('doit retourner la liste des profils', () => { @@ -9,8 +9,8 @@ describe('ListProfilesUseCase', () => { useCase.execute().subscribe({ next: (profiles) => { - expect(profiles.length).toBe(2); - expect(profiles).toEqual(mockProfiles); + expect(profiles.items.length).toBe(2); + expect(profiles).toEqual(mockProfilePaginated); }, }); }); diff --git a/src/app/ui/authentification/auth.facade.ts b/src/app/ui/authentification/auth.facade.ts index acb10c7..1a06795 100644 --- a/src/app/ui/authentification/auth.facade.ts +++ b/src/app/ui/authentification/auth.facade.ts @@ -85,6 +85,7 @@ export class AuthFacade { logout() { this.logoutUseCase.execute(); + this.isAuthenticated.set(false); this.getCurrentUser(); } diff --git a/src/app/ui/profiles/profile.facade.ts b/src/app/ui/profiles/profile.facade.ts index aa3fba3..9521a75 100644 --- a/src/app/ui/profiles/profile.facade.ts +++ b/src/app/ui/profiles/profile.facade.ts @@ -1,7 +1,7 @@ import { ListProfilesUseCase } from '@app/usecase/profiles/list-profiles.usecase'; 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 { Profile, ProfilePaginated } from '@app/domain/profiles/profile.model'; 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'; @@ -12,19 +12,23 @@ import { UpdateProfileUseCase } from '@app/usecase/profiles/update-profile.useca import { GetProfileUseCase } from '@app/usecase/profiles/get-profile.usecase'; import { ProfileDTO } from '@app/domain/profiles/dto/create-profile.dto'; import { SearchFilters } from '@app/domain/search/search-filters'; +import { SearchService } from '@app/infrastructure/search/search.service'; @Injectable({ providedIn: 'root', }) export class ProfileFacade { private profileRepository = inject(PROFILE_REPOSITORY_TOKEN); + private readonly searchService = inject(SearchService); 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 searchFilters = this.searchService.getFilters(); readonly profiles = signal([]); + readonly profilePaginated = signal({} as ProfilePaginated); readonly profile = signal({} as ProfileViewModel); readonly loading = signal({ isLoading: false, action: ActionType.NONE }); readonly error = signal({ @@ -36,9 +40,25 @@ export class ProfileFacade { load(search?: SearchFilters) { this.handleError(ActionType.READ, false, null, true); + if (search === undefined || search === null) { + search = this.searchFilters(); + } + this.listUseCase.execute(search).subscribe({ - next: (profiles) => { - this.profiles.set(ProfilePresenter.toViewModels(profiles)); + next: (profilePaginated: ProfilePaginated) => { + const filters = { + ...this.searchFilters(), + page: profilePaginated.page, + perPage: profilePaginated.perPage, + totalItems: profilePaginated.totalItems, + totalPages: profilePaginated.totalPages, + }; + + this.searchService.setFilters(filters); + this.searchFilters.set(filters); + + this.profilePaginated.set(profilePaginated); + this.profiles.set(ProfilePresenter.toViewModels(profilePaginated.items as Profile[])); this.handleError(ActionType.READ, false, null, false); }, error: (err) => { diff --git a/src/app/ui/users/user.presenter.model.ts b/src/app/ui/users/user.presenter.model.ts index 5a6cc05..15c5be6 100644 --- a/src/app/ui/users/user.presenter.model.ts +++ b/src/app/ui/users/user.presenter.model.ts @@ -6,4 +6,7 @@ export interface UserViewModel { email: string; name: string; avatar: string; + firstName?: string; + lastName?: string; + slug?: string; } diff --git a/src/app/ui/users/user.presenter.ts b/src/app/ui/users/user.presenter.ts index 794ff80..1cb559c 100644 --- a/src/app/ui/users/user.presenter.ts +++ b/src/app/ui/users/user.presenter.ts @@ -3,7 +3,11 @@ import { User } from '@app/domain/users/user.model'; export class UserPresenter { toViewModel(user: User): UserViewModel { - return { + const slug = user.name + ? user.name.toLowerCase().replace(/\s/g, '-') + : user.email.split('@')[0].toLowerCase().trim(); + + let userViewModel: UserViewModel = { id: user.id, username: user.username, verified: user.verified, @@ -11,7 +15,16 @@ export class UserPresenter { email: user.email, name: user.name, avatar: user.avatar, + slug, }; + + if (user.name) { + const firstName = user.name.split(' ').slice(0, -1).join(' ').toLowerCase().trim() ?? ''; + const lastName = user.name.split(' ').slice(-1)[0].toUpperCase().trim() ?? ''; + userViewModel = { ...userViewModel, firstName, lastName }; + } + + return userViewModel; } toViewModels(users: User[]): UserViewModel[] { diff --git a/src/app/usecase/profiles/list-profiles.usecase.ts b/src/app/usecase/profiles/list-profiles.usecase.ts index 155d87a..efdfcfe 100644 --- a/src/app/usecase/profiles/list-profiles.usecase.ts +++ b/src/app/usecase/profiles/list-profiles.usecase.ts @@ -1,12 +1,12 @@ import { ProfileRepository } from '@app/domain/profiles/profile.repository'; import { Observable } from 'rxjs'; -import { Profile } from '@app/domain/profiles/profile.model'; +import { ProfilePaginated } from '@app/domain/profiles/profile.model'; import { SearchFilters } from '@app/domain/search/search-filters'; export class ListProfilesUseCase { constructor(private readonly repo: ProfileRepository) {} - execute(params?: SearchFilters): Observable { + execute(params?: SearchFilters): Observable { return this.repo.list(params); } }