From da8a65934e5d8aff30633bca2e6354b1695d0f25 Mon Sep 17 00:00:00 2001 From: nekorpeche Date: Mon, 29 Nov 2021 19:46:57 +0100 Subject: [PATCH] RI-192: [admin/front] permet d'archiver plusieurs offres depuis le listing d'offres * code review * suppression composant jobs-table --- .../app/admin/jobs/admin-jobs.component.html | 92 ++++++++++- .../app/admin/jobs/admin-jobs.component.scss | 13 ++ .../app/admin/jobs/admin-jobs.component.ts | 145 +++++++++++++++++- .../src/app/admin/jobs/admin-jobs.module.ts | 2 - .../jobs-table/jobs-table.component.html | 81 ---------- .../jobs-table/jobs-table.component.scss | 13 -- .../jobs-table/jobs-table.component.spec.ts | 25 --- .../jobs-table/jobs-table.component.ts | 144 ----------------- 8 files changed, 240 insertions(+), 275 deletions(-) delete mode 100644 frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.html delete mode 100644 frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.scss delete mode 100644 frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.spec.ts delete mode 100644 frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.ts diff --git a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.html b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.html index 552bb9084..08f690bcf 100644 --- a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.html +++ b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.html @@ -12,20 +12,106 @@
Toutes les offres d'emplois
> - + + + + + + + Nom + Type + Localisation + Description + Actions + + + + + + + + + {{job.title}} + {{job.contractType?.label}} + {{job.location}} + {{job.description}} + +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ + +
+
+ diff --git a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.scss b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.scss index e69de29bb..f3dfcba30 100644 --- a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.scss +++ b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.scss @@ -0,0 +1,13 @@ +::ng-deep { + .p-datatable .p-datatable-tbody > tr > td { + border-width: 0 !important; + } + + .p-datatable-thead { + + th { + background-color: transparent !important; + border: 0 !important; + } + } +} diff --git a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.ts b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.ts index 5138faba5..ea15c0bad 100644 --- a/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.ts +++ b/frontend-implicaction/src/app/admin/jobs/admin-jobs.component.ts @@ -1,20 +1,147 @@ -import {Component, ViewChild} from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {SidebarService} from '../../shared/services/sidebar.service'; import {JobPostingFormComponent} from './components/job-posting-form/job-posting-form.component'; -import {JobsTableComponent} from './components/jobs-table/jobs-table.component'; +import {BaseWithPaginationComponent} from '../../shared/components/base-with-pagination/base-with-pagination.component'; +import {JobPosting} from '../../shared/models/job-posting'; +import {JobCriteriaFilter} from '../../job/models/job-criteria-filter'; +import {Constants} from '../../config/constants'; +import {Pageable} from '../../shared/models/pageable'; +import {JobSortEnum} from '../../job/enums/job-sort.enum'; +import {SortDirectionEnum} from '../../shared/enums/sort-direction.enum'; +import {JobService} from '../../job/services/job.service'; +import {ToasterService} from '../../core/services/toaster.service'; +import {JobFilterContextService} from '../../job/services/job-filter-context.service'; +import {ActivatedRoute} from '@angular/router'; +import {finalize, take} from 'rxjs/operators'; @Component({ selector: 'app-job', templateUrl: './admin-jobs.component.html', styleUrls: ['./admin-jobs.component.scss'] }) -export class AdminJobsComponent { - @ViewChild(JobsTableComponent) - jobsTableComponent: JobsTableComponent; +export class AdminJobsComponent extends BaseWithPaginationComponent implements OnInit { + readonly ROWS_PER_PAGE_OPTIONS = Constants.ROWS_PER_PAGE_OPTIONS; + loading = true; // indique si les données sont en chargement + isArchiveEnabled: boolean; + isArchive: boolean; + selectedJobs: JobPosting[] = []; + + // Pagination + pageable: Pageable = Constants.PAGEABLE_DEFAULT; + orderByEnums = JobSortEnum.all(); + selectedOrder = JobSortEnum.DATE_DESC; + criteria: JobCriteriaFilter; + selectedOrderCode: string; + sortDirection = SortDirectionEnum; constructor( + private jobService: JobService, + private toastService: ToasterService, private sidebarService: SidebarService, + private filterService: JobFilterContextService, + protected route: ActivatedRoute ) { + super(route); + } + + ngOnInit(): void { + this.pageable.sortOrder = JobSortEnum.DATE_DESC.sortDirection; + this.pageable.sortBy = JobSortEnum.DATE_DESC.sortBy; + this.selectedOrderCode = JobSortEnum.DATE_DESC.code; + + this.filterService + .observe() + .subscribe(criteria => { + this.criteria = criteria; + const objectParam = this.buildQueryParams(); + this.filterService.updateRouteQueryParams(objectParam); + this.paginate(); + }); + + this.getFilterFromQueryParams().then(() => this.filterService.criteria = this.criteria); + } + + onSortChange({value}): void { + const selectedOrderField = JobSortEnum.from(value); + this.pageable.sortBy = selectedOrderField.sortBy; + this.pageable.sortOrder = selectedOrderField.sortDirection; + this.filterService.criteria = this.criteria; // on relance la recherche en updatant le filtre + } + + onSearchChange(): void { + this.filterService.criteria = this.criteria; + } + + protected innerPaginate(): void { + this.jobService + .getAllByCriteria(this.pageable, this.criteria) + .pipe( + take(1), + finalize(() => this.loading = false) + ) + .subscribe( + data => { + this.pageable.totalPages = data.totalPages; + this.pageable.rows = data.size; + this.pageable.totalElements = data.totalElements; + this.pageable.content = data.content; + }, + () => this.toastService.error('Oops', 'Une erreur est survenue lors de la récupération des données'), + ); + } + + editJob(job: JobPosting): void { + this.sidebarService + .open({ + title: `Editer une nouvelle offre d'emploi`, + input: {job}, + component: JobPostingFormComponent, + width: 650 + }); + } + + archiveJob(job: JobPosting): void { + this.jobService + .archiveJob(job.id) + .subscribe( + () => this.paginate(), + () => this.toastService.error('Oops', 'Une erreur est survenue'), + () => this.toastService.success('Succès', job.archive ? 'Offre désarchivée' : `Offre archivée`) + ); + } + + protected async getFilterFromQueryParams(): Promise { + // TODO: voir si y'a un moyen plus élégant avec typeof + const filterKeys = ['search', 'contractType']; + const pageableKeys = ['rows', 'page', 'sortOrder', 'sortBy']; + return new Promise(resolve => { + this.route + .queryParams + .subscribe(params => { + Object.entries(params) + .forEach(([key, value]) => { + if (filterKeys.includes(key)) { + this.criteria[key] = value; + } else if (pageableKeys.includes(key)) { + this.pageable[key] = value; + } + }); + return resolve(); + }); + }); + } + + archiveJobList(): void { + const jobsId = this.selectedJobs.map(job => job.id); + this.jobService + .toggleArchiveJobs(jobsId) + .subscribe( + () => this.paginate(), + () => this.toastService.error('Oops', 'Une erreur est survenue'), + () => this.toastService.success('Succès', 'Opération effectuée'), + ); + this.selectedJobs = []; + this.isArchiveEnabled = false; } onAddJob(): void { @@ -26,8 +153,12 @@ export class AdminJobsComponent { }); } - archive(): void { - this.jobsTableComponent.archiveJobList(); + onRowSelect(): void { + // on vérifie que tous les éléments sélectionné sont tous archivés ou désarchivés + this.isArchiveEnabled = this.selectedJobs.every(job => job.archive === this.selectedJobs[0].archive); + // on recherche si le bouton toggleArchive doit archiver ou désarchiver + this.isArchive = this.selectedJobs.length > 0 ? this.selectedJobs[0].archive : false; + } } diff --git a/frontend-implicaction/src/app/admin/jobs/admin-jobs.module.ts b/frontend-implicaction/src/app/admin/jobs/admin-jobs.module.ts index f9be2146b..2f31963fc 100644 --- a/frontend-implicaction/src/app/admin/jobs/admin-jobs.module.ts +++ b/frontend-implicaction/src/app/admin/jobs/admin-jobs.module.ts @@ -1,6 +1,5 @@ import {NgModule} from '@angular/core'; import {CommonModule} from '@angular/common'; -import {JobsTableComponent} from './components/jobs-table/jobs-table.component'; import {AdminJobsComponent} from './admin-jobs.component'; import {AdminJobsRoutingModule} from './admin-jobs-routing.module'; import {TableModule} from 'primeng/table'; @@ -15,7 +14,6 @@ import {CheckboxModule} from 'primeng/checkbox'; @NgModule({ declarations: [ AdminJobsComponent, - JobsTableComponent, JobPostingFormComponent ], imports: [ diff --git a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.html b/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.html deleted file mode 100644 index 232578805..000000000 --- a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - Nom - Type - Localisation - Description - Actions - - - - - - - - {{job.title}} - {{job.contractType?.label}} - {{job.location}} - {{job.description}} - -
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
- - -
-
diff --git a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.scss b/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.scss deleted file mode 100644 index f3dfcba30..000000000 --- a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -::ng-deep { - .p-datatable .p-datatable-tbody > tr > td { - border-width: 0 !important; - } - - .p-datatable-thead { - - th { - background-color: transparent !important; - border: 0 !important; - } - } -} diff --git a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.spec.ts b/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.spec.ts deleted file mode 100644 index 41224298c..000000000 --- a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {ComponentFixture, TestBed} from '@angular/core/testing'; - -import {JobsTableComponent} from './jobs-table.component'; - -describe('JobTableComponent', () => { - let component: JobsTableComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [JobsTableComponent] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(JobsTableComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.ts b/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.ts deleted file mode 100644 index 7c6891b67..000000000 --- a/frontend-implicaction/src/app/admin/jobs/components/jobs-table/jobs-table.component.ts +++ /dev/null @@ -1,144 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {Pageable} from '../../../../shared/models/pageable'; -import {Constants} from '../../../../config/constants'; -import {ToasterService} from '../../../../core/services/toaster.service'; -import {JobService} from '../../../../job/services/job.service'; -import {finalize, take} from 'rxjs/operators'; -import {JobSortEnum} from '../../../../job/enums/job-sort.enum'; -import {JobCriteriaFilter} from '../../../../job/models/job-criteria-filter'; -import {JobPosting} from '../../../../shared/models/job-posting'; -import {JobPostingFormComponent} from '../job-posting-form/job-posting-form.component'; -import {SidebarService} from '../../../../shared/services/sidebar.service'; -import {SortDirectionEnum} from '../../../../shared/enums/sort-direction.enum'; -import {JobFilterContextService} from '../../../../job/services/job-filter-context.service'; -import {ActivatedRoute} from '@angular/router'; -import {BaseWithPaginationComponent} from '../../../../shared/components/base-with-pagination/base-with-pagination.component'; - -@Component({ - selector: 'app-jobs-table', - templateUrl: './jobs-table.component.html', - styleUrls: ['./jobs-table.component.scss'] -}) -export class JobsTableComponent extends BaseWithPaginationComponent implements OnInit { - - readonly ROWS_PER_PAGE_OPTIONS = Constants.ROWS_PER_PAGE_OPTIONS; - loading = true; // indique si les données sont en chargement - - selectedJobs: JobPosting[] = []; - - // Pagination - pageable: Pageable = Constants.PAGEABLE_DEFAULT; - orderByEnums = JobSortEnum.all(); - selectedOrder = JobSortEnum.DATE_DESC; - criteria: JobCriteriaFilter; - selectedOrderCode: string; - sortDirection = SortDirectionEnum; - - constructor( - private jobService: JobService, - private toastService: ToasterService, - private sidebarService: SidebarService, - private filterService: JobFilterContextService, - protected route: ActivatedRoute - ) { - super(route); - } - - ngOnInit(): void { - this.pageable.sortOrder = JobSortEnum.DATE_DESC.sortDirection; - this.pageable.sortBy = JobSortEnum.DATE_DESC.sortBy; - this.selectedOrderCode = JobSortEnum.DATE_DESC.code; - - this.filterService - .observe() - .subscribe(criteria => { - this.criteria = criteria; - const objectParam = this.buildQueryParams(); - this.filterService.updateRouteQueryParams(objectParam); - this.paginate(); - }); - - this.getFilterFromQueryParams().then(() => this.filterService.criteria = this.criteria); - } - - onSortChange({value}): void { - const selectedOrderField = JobSortEnum.from(value); - this.pageable.sortBy = selectedOrderField.sortBy; - this.pageable.sortOrder = selectedOrderField.sortDirection; - this.filterService.criteria = this.criteria; // on relance la recherche en updatant le filtre - } - - onSearchChange(): void { - this.filterService.criteria = this.criteria; - } - - protected innerPaginate(): void { - this.jobService - .getAllByCriteria(this.pageable, this.criteria) - .pipe( - take(1), - finalize(() => this.loading = false) - ) - .subscribe( - data => { - this.pageable.totalPages = data.totalPages; - this.pageable.rows = data.size; - this.pageable.totalElements = data.totalElements; - this.pageable.content = data.content; - }, - () => this.toastService.error('Oops', 'Une erreur est survenue lors de la récupération des données'), - ); - } - - editJob(job: JobPosting): void { - this.sidebarService - .open({ - title: `Editer une nouvelle offre d'emploi`, - input: {job}, - component: JobPostingFormComponent, - width: 650 - }); - } - - archiveJob(job: JobPosting): void { - this.jobService - .archiveJob(job.id) - .subscribe( - () => this.paginate(), - () => this.toastService.error('Oops', 'Une erreur est survenue'), - () => this.toastService.success('Succès', job.archive ? 'Offre désarchivée' : `Offre archivée`) - ); - } - - protected async getFilterFromQueryParams(): Promise { - // TODO: voir si y'a un moyen plus élégant avec typeof - const filterKeys = ['search', 'contractType']; - const pageableKeys = ['rows', 'page', 'sortOrder', 'sortBy']; - return new Promise(resolve => { - this.route - .queryParams - .subscribe(params => { - Object.entries(params) - .forEach(([key, value]) => { - if (filterKeys.includes(key)) { - this.criteria[key] = value; - } else if (pageableKeys.includes(key)) { - this.pageable[key] = value; - } - }); - return resolve(); - }); - }); - } - - archiveJobList(): void { - const jobsId = this.selectedJobs.map(job => job.id); - this.jobService - .toggleArchiveJobs(jobsId) - .subscribe( - () => this.paginate(), - () => this.toastService.error('Oops', 'Une erreur est survenue'), - () => this.toastService.success('Succès', 'Opération effectuée'), - ); - } -}