feat(avrop): Implemented filter-tags for avrop-flow (TV-286)

Squashed commit of the following:

commit 820ed9b501f6fe14357dc0d1e9133b7a16a257c5
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 13:11:55 2021 +0200

    fixed conflicts

commit c42a985cb8b7cea5f0e891e70d706d8d3cbff619
Merge: e358b59 6b0ac72
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 13:05:22 2021 +0200

    Merge branch 'develop' into TV-286-avrop-filtertaggar

    # Conflicts:
    #	apps/dafa-web/src/app/app.module.ts
    #	apps/dafa-web/src/app/pages/avrop/avrop.component.html
    #	apps/dafa-web/src/app/pages/avrop/avrop.module.ts
    #	apps/dafa-web/src/app/shared/models/multiselect-filter-option.ts
    #	apps/dafa-web/src/app/shared/services/api/avrop-api.service.ts

commit e358b59360186a8dcb972fae331126b0ae572436
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:56:48 2021 +0200

    fix linting and scss __

commit 6a688c4740ff7e2575ae2f218174ce9012db8d6c
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:50:24 2021 +0200

    refactor

commit 90bf83119f8f1eec4b2e63f15840fa1a943d64a4
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:39:13 2021 +0200

    !==

commit 7b06dec881c6876bbae6f37fbe462e32ae43575f
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:32:14 2021 +0200

    move to component folder

commit d449edf11e88a492a2446ac8e7fda93a0836e5c7
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:26:17 2021 +0200

    Update avrop.component.html

commit 0ca49c7248186c6e56cadf1c5a92298612a4ad49
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 11:11:54 2021 +0200

    .

commit ec084d7b45d36bdeaec16671cb2bcbc94f7ebb70
Merge: 1b20328 c06452d
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 30 08:57:18 2021 +0200

    Merge branch 'develop' into TV-286-avrop-filtertaggar

    # Conflicts:
    #	apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.ts

commit 1b203287dc18d178753c72cd3025dfd70eb56d6f
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Tue Jun 29 12:10:38 2021 +0200

    fix unit tests

commit 320784bd3d3fbd6a7e0b8e6eb338eaec64151748
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Tue Jun 29 11:36:03 2021 +0200

    add unit tests and loading-spinners

commit 7ebb5ffaddcf6e3b68263eaad6a3d3de3e69811d
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Mon Jun 28 17:01:02 2021 +0200

    enhetstest

commit dc02e6cc17999adcaa07c6e385ed69860c0b4f97
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Mon Jun 28 15:15:13 2021 +0200

    Fix reset to step 1

commit e4759c0a59ebd090248f9765d23fdf3c5f8aea03
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Mon Jun 28 13:52:03 2021 +0200

    Clicking tags will remove selection

commit 0acdff3c137477b2422b2c8aba9f895990a37fc9
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Mon Jun 28 13:48:07 2021 +0200

    wip

commit 4e7a87134edb95c9d522514140dcf8ff8b5c9bfa
Merge: c586d67 6f97f51
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Mon Jun 28 09:12:35 2021 +0200

    Merge branch 'develop' into refactor/stricter-eslint

    # Conflicts:
    #	apps/dafa-web/src/app/pages/administration/pages/employee-form/employee-form.component.ts

commit c586d675ced7a0dd4bd88599f62dd7a72fe39723
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 23 16:24:37 2021 +0200

    Fix linting of avrop

commit 70aa93e06c7677ce6b2e5068c74709ef5f9feecc
Merge: ace9950 4afe9b5
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 23 16:12:30 2021 +0200

    Merge branch 'develop' into refactor/stricter-eslint

    # Conflicts:
    #	apps/dafa-web/src/app/pages/avrop/avrop.component.spec.ts
    #	apps/dafa-web/src/app/pages/ciam-landing/ciam-landing.component.spec.ts
    #	apps/dafa-web/src/app/pages/logout/logout.component.spec.ts

commit ace9950d3dc9517d8fe4e4b53af6813b6b175720
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 23 10:53:00 2021 +0200

    Fix remaining linting warnings/errors

commit c15b0a4b8a62604928871d45095d9ad257add0a8
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Wed Jun 23 10:44:32 2021 +0200

    fix more linting errors and warnings

... and 3 more commits
This commit is contained in:
Erik Tiekstra
2021-07-02 12:58:50 +02:00
parent 6b0ac723a2
commit a11d1665da
30 changed files with 249 additions and 116 deletions

View File

@@ -4,6 +4,7 @@
"overrides": [ "overrides": [
{ {
"files": ["*.ts"], "files": ["*.ts"],
"excludedFiles": ["*.spec.ts"],
"extends": [ "extends": [
"plugin:@nrwl/nx/angular", "plugin:@nrwl/nx/angular",
"eslint:recommended", "eslint:recommended",

View File

@@ -1,11 +0,0 @@
<div style=" display: flex">
<dafa-temporary-filter [filterLabel]="'Tjänster'" [filterOptions]="selectableTjanster$ | async" (selectedOptionsChange)="updateSelectedTjanster($event)"></dafa-temporary-filter>
<dafa-temporary-filter [filterLabel]="'Utförande verksamheter'" [filterOptions]="selectableUtforandeVerksamheter$ | async" (selectedOptionsChange)="updateSelectedUtforandeVerksamheter($event)"></dafa-temporary-filter>
<dafa-temporary-filter [filterLabel]="'Kommuner'" [filterOptions]="selectableKommuner$ | async" (selectedOptionsChange)="updateSelectedKommuner($event)"></dafa-temporary-filter>
</div>
<br><br>

View File

@@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AvropFiltersComponent } from './avrop-filters.component';
describe('AvropFiltersComponent', () => {
let component: AvropFiltersComponent;
let fixture: ComponentFixture<AvropFiltersComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AvropFiltersComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AvropFiltersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -4,13 +4,19 @@
<h2>Välj deltagare att tilldela</h2> <h2>Välj deltagare att tilldela</h2>
<p>Steg {{ currentStep }} av {{ steps }}:</p> <p>Steg {{ currentStep }} av {{ steps }}:</p>
</digi-typography> </digi-typography>
<digi-ng-progress-progressbar [afSteps]="steps" afAriaLabel="An aria label" [afActiveStep]="currentStep"> <digi-ng-progress-progressbar
[afSteps]="steps"
afAriaLabel="An aria label"
[afActiveStep]="currentStep">
</digi-ng-progress-progressbar> </digi-ng-progress-progressbar>
<div class="" style="height: 300px; padding: 30px 0"> <div>
<ng-container *ngIf="currentStep == 4"> <ng-container *ngIf="currentStep == 4">
<h2>Avropet är sparat</h2> <h2>Avropet är sparat</h2>
<digi-button af-size="m" class="employee-form__read-more" (afOnClick)="goToStep1()"> <digi-button
af-size="m"
class="employee-form__read-more"
(afOnClick)="goToStep1()">
Tillbaka till nya deltagare Tillbaka till nya deltagare
</digi-button> </digi-button>
</ng-container> </ng-container>
@@ -40,11 +46,9 @@
<ng-container *ngIf="currentStep == 2"> <ng-container *ngIf="currentStep == 2">
<h2>Välj handledare</h2> <h2>Välj handledare</h2>
<ng-container *ngIf="selectableHandledareList$ | async; let selectableHandledareList; else: loadingRefSmall"> <ng-container *ngIf="selectableHandledareList$ | async; let selectableHandledareList; else loadingRefSmall">
<select <select [value]="(selectedHandledare$ | async)?.id ? (selectedHandledare$ | async)?.id : ''"
[value]="(selectedHandledare$ | async)?.id ? (selectedHandledare$ | async)?.id : ''" (change)="changeHandledare($event)">
(change)="changeHandledare($event)"
>
<option disabled value="">Välj handledare</option> <option disabled value="">Välj handledare</option>
<option *ngFor="let selectableHandledare of selectableHandledareList" [value]="selectableHandledare?.id"> <option *ngFor="let selectableHandledare of selectableHandledareList" [value]="selectableHandledare?.id">

View File

@@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { AvropService } from './avrop.service'; import { AvropService } from './avrop.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { MultiselectFilterOption } from './models/AvropFilterOptions'; import { MultiselectFilterOption } from '@dafa-models/multiselect-filter-option';
import { Deltagare } from './models/Deltagare'; import { DeltagareAvrop } from './models/deltagare-avrop';
import { Handledare } from './models/Handledare'; import { HandledareAvrop } from './models/handledare-avrop';
@Component({ @Component({
selector: 'dafa-avrop', selector: 'dafa-avrop',
@@ -18,16 +18,16 @@ export class AvropComponent {
selectedUtforandeVerksamheter$: Observable<MultiselectFilterOption[]> = this.avropService selectedUtforandeVerksamheter$: Observable<MultiselectFilterOption[]> = this.avropService
.selectedUtforandeVerksamheter$; .selectedUtforandeVerksamheter$;
selectableDeltagareList$: Observable<Deltagare[]> = this.avropService.selectableDeltagareList$; selectableDeltagareList$: Observable<DeltagareAvrop[]> = this.avropService.selectableDeltagareList$;
selectedDeltagareList$: Observable<Deltagare[]> = this.avropService.selectedDeltagareList$; selectedDeltagareList$: Observable<DeltagareAvrop[]> = this.avropService.selectedDeltagareList$;
selectableHandledareList$: Observable<HandledareAvrop[]> = this.avropService.selectableHandledareList$;
selectedHandledare$: Observable<HandledareAvrop> = this.avropService.selectedHandledare$;
deltagareListIsLocked$: Observable<boolean> = this.avropService.deltagareListIsLocked$; deltagareListIsLocked$: Observable<boolean> = this.avropService.deltagareListIsLocked$;
selectableHandledareList$: Observable<Handledare[]> = this.avropService.selectableHandledareList$;
selectedHandledare$: Observable<Handledare> = this.avropService.selectedHandledare$;
handledareConfirmed$: Observable<boolean> = this.avropService.handledareIsConfirmed$; handledareConfirmed$: Observable<boolean> = this.avropService.handledareIsConfirmed$;
constructor(private avropService: AvropService) {} constructor(private avropService: AvropService) {}
updateSelectedDeltagareList(deltagareList: Deltagare[]): void { updateSelectedDeltagareList(deltagareList: DeltagareAvrop[]): void {
this.avropService.setSelectedDeltagare(deltagareList); this.avropService.setSelectedDeltagare(deltagareList);
} }

View File

@@ -4,11 +4,11 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { LayoutModule } from '@dafa-shared/components/layout/layout.module'; import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
import { AvropFiltersComponent } from './avrop-filters/avrop-filters.component'; import { AvropFiltersComponent } from './components/avrop-filters/avrop-filters.component';
import { TemporaryFilterComponent } from './avrop-filters/temporary-filter/temporary-filter.component'; import { TemporaryFilterComponent } from './components/avrop-filters/temporary-filter/temporary-filter.component';
import { AvropTableRowComponent } from './avrop-table/avrop-table-row/avrop-table-row.component'; import { AvropTableRowComponent } from './components/avrop-table/avrop-table-row/avrop-table-row.component';
import { AvropTableComponent } from './avrop-table/avrop-table.component';
import { AvropComponent } from './avrop.component'; import { AvropComponent } from './avrop.component';
import { AvropTableComponent } from './components/avrop-table/avrop-table.component';
@NgModule({ @NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],

View File

@@ -1,10 +1,10 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { MultiselectFilterOption } from './models/AvropFilterOptions'; import { DeltagareAvrop } from './models/deltagare-avrop';
import { Deltagare } from './models/Deltagare'; import { HandledareAvrop } from './models/handledare-avrop';
import { Handledare } from './models/Handledare';
import { first, map, switchMap } from 'rxjs/operators'; import { first, map, switchMap } from 'rxjs/operators';
import { AvropApiService } from '@dafa-services/api/avrop-api.service'; import { AvropApiService } from '@dafa-services/api/avrop-api.service';
import { MultiselectFilterOption } from '@dafa-models/multiselect-filter-option';
type Step = 1 | 2 | 3 | 4; type Step = 1 | 2 | 3 | 4;
@@ -15,9 +15,9 @@ export class AvropService {
private _selectedTjanster$ = new BehaviorSubject<MultiselectFilterOption[]>(null); private _selectedTjanster$ = new BehaviorSubject<MultiselectFilterOption[]>(null);
private _selectedUtforandeVerksamheter$ = new BehaviorSubject<MultiselectFilterOption[]>(null); private _selectedUtforandeVerksamheter$ = new BehaviorSubject<MultiselectFilterOption[]>(null);
private _selectedKommuner$ = new BehaviorSubject<MultiselectFilterOption[]>(null); private _selectedKommuner$ = new BehaviorSubject<MultiselectFilterOption[]>(null);
private _selectedDeltagareList$ = new BehaviorSubject<Deltagare[]>([]); private _selectedDeltagareList$ = new BehaviorSubject<DeltagareAvrop[]>([]);
private _deltagareListIsLocked$ = new BehaviorSubject<boolean>(null); private _deltagareListIsLocked$ = new BehaviorSubject<boolean>(null);
private _selectedHandledare$ = new BehaviorSubject<Handledare>(null); private _selectedHandledare$ = new BehaviorSubject<HandledareAvrop>(null);
private _handledareIsConfirmed$ = new BehaviorSubject<boolean>(false); private _handledareIsConfirmed$ = new BehaviorSubject<boolean>(false);
private _avropIsSaved$ = new BehaviorSubject<boolean>(false); private _avropIsSaved$ = new BehaviorSubject<boolean>(false);
@@ -27,7 +27,7 @@ export class AvropService {
> = this._selectedUtforandeVerksamheter$.asObservable(); > = this._selectedUtforandeVerksamheter$.asObservable();
selectedKommuner$: Observable<MultiselectFilterOption[]> = this._selectedKommuner$.asObservable(); selectedKommuner$: Observable<MultiselectFilterOption[]> = this._selectedKommuner$.asObservable();
selectableDeltagareList$: Observable<Deltagare[]> = combineLatest([ selectableDeltagareList$: Observable<DeltagareAvrop[]> = combineLatest([
this.selectedTjanster$, this.selectedTjanster$,
this.selectedUtforandeVerksamheter$, this.selectedUtforandeVerksamheter$,
this.selectedKommuner$, this.selectedKommuner$,
@@ -62,19 +62,19 @@ export class AvropService {
) )
); );
selectedDeltagareList$: Observable<Deltagare[]> = this._selectedDeltagareList$.asObservable(); selectedDeltagareList$: Observable<DeltagareAvrop[]> = this._selectedDeltagareList$.asObservable();
deltagareListIsLocked$: Observable<boolean> = this._deltagareListIsLocked$.asObservable(); deltagareListIsLocked$: Observable<boolean> = this._deltagareListIsLocked$.asObservable();
lockedDeltagareList$: Observable<Deltagare[]> = combineLatest([ lockedDeltagareList$: Observable<DeltagareAvrop[]> = combineLatest([
this.selectedDeltagareList$, this.selectedDeltagareList$,
this.deltagareListIsLocked$, this.deltagareListIsLocked$,
]).pipe(map(([selectedDeltagareList, isLocked]) => (isLocked ? selectedDeltagareList : null))); ]).pipe(map(([selectedDeltagareList, isLocked]) => (isLocked ? selectedDeltagareList : null)));
selectableHandledareList$: Observable<Handledare[]> = this.lockedDeltagareList$.pipe( selectableHandledareList$: Observable<HandledareAvrop[]> = this.lockedDeltagareList$.pipe(
switchMap(lockedDeltagare => this.avropApiService.getSelectableHandledare$(lockedDeltagare)) switchMap(lockedDeltagare => this.avropApiService.getSelectableHandledare$(lockedDeltagare))
); );
selectedHandledare$: Observable<Handledare> = this._selectedHandledare$.asObservable(); selectedHandledare$: Observable<HandledareAvrop> = this._selectedHandledare$.asObservable();
handledareIsConfirmed$: Observable<boolean> = this._handledareIsConfirmed$.asObservable(); handledareIsConfirmed$: Observable<boolean> = this._handledareIsConfirmed$.asObservable();
avropIsSaved$: Observable<boolean> = this._handledareIsConfirmed$.asObservable(); avropIsSaved$: Observable<boolean> = this._handledareIsConfirmed$.asObservable();
@@ -109,7 +109,7 @@ export class AvropService {
return 1; return 1;
} }
setSelectedDeltagare(deltagare: Deltagare[]): void { setSelectedDeltagare(deltagare: DeltagareAvrop[]): void {
this._selectedDeltagareList$.next(deltagare); this._selectedDeltagareList$.next(deltagare);
} }
@@ -171,8 +171,24 @@ export class AvropService {
goToStep1(): void { goToStep1(): void {
this._selectedHandledare$.next(null); this._selectedHandledare$.next(null);
this._selectedDeltagareList$.next(null); this._selectedDeltagareList$.next([]);
this._deltagareListIsLocked$.next(false); this._deltagareListIsLocked$.next(false);
this._handledareIsConfirmed$.next(false); this._handledareIsConfirmed$.next(false);
} }
removeKommun(kommunToRemove: MultiselectFilterOption) {
this.setSelectedKommuner(this._selectedKommuner$.value.filter(selectedKommun => selectedKommun !== kommunToRemove));
}
removeUtforandeVerksamhet(utforandeVerksamhetToRemove: MultiselectFilterOption) {
this.setSelectedUtforandeVerksamheter(
this._selectedUtforandeVerksamheter$.value.filter(
selectedUtforandeVerksamhet => selectedUtforandeVerksamhet !== utforandeVerksamhetToRemove
)
);
}
removeTjanst(tjanstToRemove: MultiselectFilterOption) {
this.setSelectedTjanster(this._selectedTjanster$.value.filter(selectedTjanst => selectedTjanst !== tjanstToRemove));
}
} }

View File

@@ -0,0 +1,54 @@
<div style="display: flex">
<ng-container *ngIf="selectableTjanster$ | async; let selectableTjanster; else loadingRef">
<dafa-temporary-filter [filterLabel]="'Tjänster'"
[filterOptions]="selectableTjanster"
[selectedOptions]="selectedTjanster$ | async"
(selectedOptionsChange)="updateSelectedTjanster($event)"></dafa-temporary-filter>
</ng-container>
<ng-container *ngIf="selectableUtforandeVerksamheter$ | async; let selectableUtforandeVerksamheter; else loadingRef">
<dafa-temporary-filter [filterLabel]="'Utförande verksamheter'"
[filterOptions]="selectableUtforandeVerksamheter"
[selectedOptions]="selectedUtforandeVerksamheter$ | async"
(selectedOptionsChange)="updateSelectedUtforandeVerksamheter($event)"></dafa-temporary-filter>
</ng-container>
<ng-container *ngIf="selectableKommuner$ | async; let selectableKommuner; else loadingRef">
<dafa-temporary-filter [filterLabel]="'Kommuner'" [filterOptions]="selectableKommuner"
[selectedOptions]="selectedKommuner$ | async"
(selectedOptionsChange)="updateSelectedKommuner($event)"></dafa-temporary-filter>
</ng-container>
</div>
<br><br>
<div class="avrop-filters__tags">
<div class="avrop-filters__tag" *ngFor="let kommun of selectedKommuner$ | async">
<digi-tag
[afText]="kommun.label"
(click)="removeKommun(kommun)"
af-no-icon="false"
af-size="s"
></digi-tag>
</div>
<div class="avrop-filters__tag" *ngFor="let kommun of selectedUtforandeVerksamheter$ | async">
<digi-tag
[afText]="kommun.label"
(click)="removeUtforandeVerksamhet(kommun)"
af-no-icon="false"
af-size="s"
></digi-tag>
</div>
<div class="avrop-filters__tag" *ngFor="let kommun of selectedTjanster$ | async">
<digi-tag
[afText]="kommun.label"
(click)="removeTjanst(kommun)"
af-no-icon="false"
af-size="s"
></digi-tag>
</div>
</div>
<ng-template #loadingRef>
<div class="avrop-filters__loading-spinner">
<digi-icon-spinner af-title="Laddar innehåll"></digi-icon-spinner>
</div>
</ng-template>

View File

@@ -0,0 +1,17 @@
@import "apps/dafa-web/src/styles/variables/gutters";
.avrop-filters {
&__tags {
display: flex;
flex-wrap: wrap;
width: 100%;
}
&__tag {
display: inline-block;
margin-right: $digi--layout--gutter--s;
}
&__loading-spinner {
margin-right: $digi--layout--gutter;
}
}

View File

@@ -0,0 +1,55 @@
import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { AvropFiltersComponent } from './avrop-filters.component';
import { TemporaryFilterComponent } from './temporary-filter/temporary-filter.component';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AvropService } from '../../avrop.service';
import { of } from 'rxjs';
import { By } from '@angular/platform-browser';
describe('AvropFiltersComponent', () => {
let component: AvropFiltersComponent;
let fixture: ComponentFixture<AvropFiltersComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [AvropFiltersComponent, TemporaryFilterComponent],
providers: [AvropService],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AvropFiltersComponent);
component = fixture.componentInstance;
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should show 1 tag if selectedKommuner$ is an observable with one value', () => {
component.selectedKommuner$ = of([{ id: '1', label: 'Stockholm', count: 1 }]);
fixture.detectChanges();
const tags = fixture.debugElement.queryAll(By.css('.avrop-filters--tag'));
expect(tags.length).toBe(1);
});
it('clicking a kommun-tag should trigger removeKommun()', fakeAsync(() => {
jest.spyOn(component, 'removeKommun').mockReturnThis();
component.selectedKommuner$ = of([{ id: '1', label: 'Stockholm', count: 1 }]);
fixture.detectChanges();
const tags = fixture.debugElement.query(By.css('digi-tag'));
tags.nativeElement.click();
tick();
fixture.detectChanges();
expect(component.removeKommun).toHaveBeenCalled();
discardPeriodicTasks();
}));
it('should show loading spinners when filters are loading', () => {
fixture.detectChanges();
const tags = fixture.debugElement.queryAll(By.css('digi-icon-spinner'));
expect(tags.length).toBe(3);
});
});

View File

@@ -1,7 +1,8 @@
import { Component, ChangeDetectionStrategy } from '@angular/core'; import { Component, ChangeDetectionStrategy } from '@angular/core';
import { AvropService } from '../avrop.service'; import { AvropService } from '../../avrop.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { MultiselectFilterOption } from '../models/AvropFilterOptions'; import { MultiselectFilterOption } from '@dafa-models/multiselect-filter-option';
import { first } from 'rxjs/operators';
@Component({ @Component({
selector: 'dafa-avrop-filters', selector: 'dafa-avrop-filters',
@@ -14,6 +15,10 @@ export class AvropFiltersComponent {
selectableUtforandeVerksamheter$: Observable<MultiselectFilterOption[]> = this.avropService selectableUtforandeVerksamheter$: Observable<MultiselectFilterOption[]> = this.avropService
.selectableUtforandeVerksamheter$; .selectableUtforandeVerksamheter$;
selectableKommuner$: Observable<MultiselectFilterOption[]> = this.avropService.selectableKommuner$; selectableKommuner$: Observable<MultiselectFilterOption[]> = this.avropService.selectableKommuner$;
selectedTjanster$: Observable<MultiselectFilterOption[]> = this.avropService.selectedTjanster$;
selectedUtforandeVerksamheter$: Observable<MultiselectFilterOption[]> = this.avropService
.selectedUtforandeVerksamheter$;
selectedKommuner$: Observable<MultiselectFilterOption[]> = this.avropService.selectedKommuner$;
constructor(private avropService: AvropService) {} constructor(private avropService: AvropService) {}
@@ -28,4 +33,16 @@ export class AvropFiltersComponent {
updateSelectedKommuner(filterOptions: MultiselectFilterOption[]): void { updateSelectedKommuner(filterOptions: MultiselectFilterOption[]): void {
this.avropService.setSelectedKommuner(filterOptions); this.avropService.setSelectedKommuner(filterOptions);
} }
removeKommun(kommunToRemove: MultiselectFilterOption) {
this.avropService.removeKommun(kommunToRemove);
}
removeUtforandeVerksamhet(utforandeVerksamhetToRemove: MultiselectFilterOption) {
this.avropService.removeUtforandeVerksamhet(utforandeVerksamhetToRemove);
}
removeTjanst(tjanstToRemove: MultiselectFilterOption) {
this.avropService.removeTjanst(tjanstToRemove);
}
} }

View File

@@ -3,7 +3,9 @@
<digi-form-checkbox <digi-form-checkbox
*ngFor="let filterOption of filterOptions" *ngFor="let filterOption of filterOptions"
[afLabel]="filterOption.label + ' (' + filterOption.count + ')'" [afLabel]="filterOption.label + ' (' + filterOption.count + ')'"
(change)="setOptionState(filterOption, $event.target.checked)"> (change)="setOptionState(filterOption, $event.target.checked)"
[afChecked]="isSelected(filterOption)"
>
</digi-form-checkbox> </digi-form-checkbox>
<digi-button (click)="emitSelectedOptions()" af-size="s">Spara</digi-button> <digi-button (click)="emitSelectedOptions()" af-size="s">Spara</digi-button>

View File

@@ -1,5 +1,5 @@
import { Component, OnInit, ChangeDetectionStrategy, Input, Output } from '@angular/core'; import { Component, OnInit, ChangeDetectionStrategy, Input, Output, SimpleChanges, OnChanges } from '@angular/core';
import { MultiselectFilterOption } from '../../models/AvropFilterOptions'; import { MultiselectFilterOption } from '@dafa-models/multiselect-filter-option';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { EventEmitter } from '@angular/core'; import { EventEmitter } from '@angular/core';
@@ -9,8 +9,8 @@ import { EventEmitter } from '@angular/core';
styleUrls: ['./temporary-filter.component.scss'], styleUrls: ['./temporary-filter.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class TemporaryFilterComponent implements OnInit { export class TemporaryFilterComponent implements OnInit, OnChanges {
private _selectedAvropFilterOption$: BehaviorSubject<MultiselectFilterOption[]>; private _selectedAvropFilterOption$ = new BehaviorSubject<MultiselectFilterOption[]>(null);
selectedAvropFilterOptionState$: Observable<MultiselectFilterOption[]>; selectedAvropFilterOptionState$: Observable<MultiselectFilterOption[]>;
@Input() filterLabel: string; @Input() filterLabel: string;
@@ -19,12 +19,17 @@ export class TemporaryFilterComponent implements OnInit {
@Output() selectedOptionsChange = new EventEmitter<MultiselectFilterOption[]>(); @Output() selectedOptionsChange = new EventEmitter<MultiselectFilterOption[]>();
// THIS SHOULD BE REPLACED BY DIGI COMPONENT // THIS SHOULD BE REPLACED BY DIGI COMPONENT
ngOnInit(): void { ngOnInit(): void {
this._selectedAvropFilterOption$ = new BehaviorSubject<MultiselectFilterOption[]>(this.selectedOptions); this._selectedAvropFilterOption$ = new BehaviorSubject<MultiselectFilterOption[]>(this.selectedOptions);
this.selectedAvropFilterOptionState$ = this._selectedAvropFilterOption$.asObservable(); this.selectedAvropFilterOptionState$ = this._selectedAvropFilterOption$.asObservable();
} }
ngOnChanges(changes: SimpleChanges): void {
if (changes.selectedOptions?.currentValue) {
this._selectedAvropFilterOption$.next(changes.selectedOptions.currentValue);
}
}
isSelected(filterOption: MultiselectFilterOption): boolean { isSelected(filterOption: MultiselectFilterOption): boolean {
return this.selectedOptions?.includes(filterOption) ?? false; return this.selectedOptions?.includes(filterOption) ?? false;
} }

View File

@@ -1,7 +1,7 @@
import { EventEmitter } from '@angular/core'; import { EventEmitter } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, Output } from '@angular/core'; import { Component, ChangeDetectionStrategy, Input, Output } from '@angular/core';
import { Deltagare } from '../../models/Deltagare'; import { DeltagareAvrop } from '../../../models/deltagare-avrop';
import { Handledare } from '../../models/Handledare'; import { HandledareAvrop } from '../../../models/handledare-avrop';
@Component({ @Component({
selector: 'dafa-avrop-table-row', selector: 'dafa-avrop-table-row',
@@ -10,11 +10,11 @@ import { Handledare } from '../../models/Handledare';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AvropTableRowComponent { export class AvropTableRowComponent {
@Input() deltagare: Deltagare; @Input() deltagare: DeltagareAvrop;
@Input() isSelected: boolean; @Input() isSelected: boolean;
@Input() isLocked: boolean; @Input() isLocked: boolean;
@Output() isSelectedChange = new EventEmitter<boolean>(); @Output() isSelectedChange = new EventEmitter<boolean>();
@Input() handledare: Handledare; @Input() handledare: HandledareAvrop;
@Input() handledareConfirmed: boolean; @Input() handledareConfirmed: boolean;
emitSelectionChange(isSelected: boolean): void { emitSelectionChange(isSelected: boolean): void {

View File

@@ -1,8 +1,8 @@
import { Component, OnInit, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core';
import { Deltagare } from '../models/Deltagare'; import { DeltagareAvrop } from '../../models/deltagare-avrop';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { Handledare } from '../models/Handledare'; import { HandledareAvrop } from '../../models/handledare-avrop';
@Component({ @Component({
selector: 'dafa-avrop-table', selector: 'dafa-avrop-table',
@@ -11,17 +11,17 @@ import { Handledare } from '../models/Handledare';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AvropTableComponent implements OnInit { export class AvropTableComponent implements OnInit {
private _selectedDeltagare$ = new BehaviorSubject<Deltagare[]>(null); private _selectedDeltagare$ = new BehaviorSubject<DeltagareAvrop[]>(null);
selectedDeltagareState$: Observable<Deltagare[]> = this._selectedDeltagare$.asObservable(); selectedDeltagareState$: Observable<DeltagareAvrop[]> = this._selectedDeltagare$.asObservable();
@Input() selectableDeltagareList: Deltagare[]; @Input() selectableDeltagareList: DeltagareAvrop[];
@Input() selectedDeltagareListInput: Deltagare[]; @Input() selectedDeltagareListInput: DeltagareAvrop[];
@Input() handledare: Handledare; @Input() handledare: HandledareAvrop;
@Input() isLocked: boolean; @Input() isLocked: boolean;
@Input() handledareConfirmed: boolean; @Input() handledareConfirmed: boolean;
@Output() changedSelectedDeltagareList = new EventEmitter<Deltagare[]>(); @Output() changedSelectedDeltagareList = new EventEmitter<DeltagareAvrop[]>();
get deltagareRows(): Deltagare[] { get deltagareRows(): DeltagareAvrop[] {
return this.isLocked ? this.selectedDeltagareListInput : this.selectableDeltagareList; return this.isLocked ? this.selectedDeltagareListInput : this.selectableDeltagareList;
} }
@@ -32,11 +32,11 @@ export class AvropTableComponent implements OnInit {
// TODO lägg till unusubscribeOnDestroy // TODO lägg till unusubscribeOnDestroy
} }
isSelected(deltagare: Deltagare): boolean { isSelected(deltagare: DeltagareAvrop): boolean {
return this.selectedDeltagareListInput?.includes(deltagare) ?? false; return this.selectedDeltagareListInput?.includes(deltagare) ?? false;
} }
isSelectedChange(deltagare: Deltagare, isSelected: boolean): void { isSelectedChange(deltagare: DeltagareAvrop, isSelected: boolean): void {
if (isSelected) { if (isSelected) {
return this._selectedDeltagare$.next([ return this._selectedDeltagare$.next([
...(this._selectedDeltagare$.value?.filter(deltagareInList => deltagareInList != deltagare) ?? []), ...(this._selectedDeltagare$.value?.filter(deltagareInList => deltagareInList != deltagare) ?? []),

View File

@@ -1,3 +0,0 @@
export interface Deltagare {
fullName: string;
}

View File

@@ -0,0 +1,3 @@
export interface DeltagareAvrop {
fullName: string;
}

View File

@@ -1,4 +1,4 @@
export interface Handledare { export interface HandledareAvrop {
fullName: string; fullName: string;
id: string; id: string;
} }

View File

@@ -1,16 +1,16 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators'; import { delay } from 'rxjs/operators';
import { MultiselectFilterOption } from '../../../pages/avrop/models/AvropFilterOptions'; import { MultiselectFilterOption } from '@dafa-models/multiselect-filter-option';
import { Deltagare } from '../../../pages/avrop/models/Deltagare'; import { HandledareAvrop } from '../../../pages/avrop/models/handledare-avrop';
import { Handledare } from '../../../pages/avrop/models/Handledare'; import { DeltagareAvrop } from '../../../pages/avrop/models/deltagare-avrop';
const tempHandledareMock: Handledare[] = [ const tempHandledareMock: HandledareAvrop[] = [
{ id: '1', fullName: 'Göran Persson' }, { id: '1', fullName: 'Göran Persson' },
{ id: '2', fullName: 'Stefan Löfven' }, { id: '2', fullName: 'Stefan Löfven' },
]; ];
const tempDeltagareMock: Deltagare[] = [{ fullName: 'Daniel' }, { fullName: 'Chingiz' }]; const tempDeltagareMock: DeltagareAvrop[] = [{ fullName: 'Daniel' }, { fullName: 'Chingiz' }];
const tempKommunerMock: MultiselectFilterOption[] = [ const tempKommunerMock: MultiselectFilterOption[] = [
{ id: '124', count: 12, label: 'Stockholm' }, { id: '124', count: 12, label: 'Stockholm' },
@@ -26,6 +26,8 @@ const tempTjansterMock: MultiselectFilterOption[] = [
{ id: '321', count: 142, label: 'Karriärval rusta och matcha' }, { id: '321', count: 142, label: 'Karriärval rusta och matcha' },
]; ];
const tempMockDelay = 300;
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
@@ -33,8 +35,10 @@ export class AvropApiService {
getNyaDeltagare$( getNyaDeltagare$(
tjanstIds: MultiselectFilterOption[], tjanstIds: MultiselectFilterOption[],
kommunIds: MultiselectFilterOption[], kommunIds: MultiselectFilterOption[],
utforandeVerksamhetIds: MultiselectFilterOption[] utforandeVerksamhetIds: MultiselectFilterOption[],
): Observable<Deltagare[]> { offset = 0,
limit = 20
): Observable<DeltagareAvrop[]> {
// TODO replace with API-call using tjanstIds, kommunIds, utforandeVerksamhetIds // TODO replace with API-call using tjanstIds, kommunIds, utforandeVerksamhetIds
console.log( console.log(
'[API call] getNyaDeltagare$. Inputs: tjanstIds, kommunIds, utforandeVerksamhetIds', '[API call] getNyaDeltagare$. Inputs: tjanstIds, kommunIds, utforandeVerksamhetIds',
@@ -42,19 +46,13 @@ export class AvropApiService {
kommunIds, kommunIds,
utforandeVerksamhetIds utforandeVerksamhetIds
); );
console.log( return of(tempDeltagareMock).pipe(delay(tempMockDelay));
'[API call] getNyaDeltagare$. Inputs: tjanstIds, kommunIds, utforandeVerksamhetIds',
tjanstIds,
kommunIds,
utforandeVerksamhetIds
);
return of(tempDeltagareMock).pipe(delay(300));
} }
getSelectableHandledare$(deltagare: Deltagare[]): Observable<Handledare[]> { getSelectableHandledare$(deltagare: DeltagareAvrop[]): Observable<HandledareAvrop[]> {
// TODO replace with API-call // TODO replace with API-call
console.log('[API call] getSelectableHandledare$. Inputs: deltagare', deltagare); console.log('[API call] getSelectableHandledare$. Inputs: deltagare', deltagare);
return of(tempHandledareMock).pipe(delay(350)); return of(tempHandledareMock).pipe(delay(tempMockDelay));
} }
getSelectableTjanster$( getSelectableTjanster$(
@@ -67,7 +65,7 @@ export class AvropApiService {
selectedKommuner, selectedKommuner,
selectedUtforandeVerksamheter selectedUtforandeVerksamheter
); );
return of(tempTjansterMock).pipe(delay(300)); return of(tempTjansterMock).pipe(delay(tempMockDelay));
} }
getSelectableUtforandeVerksamheter$( getSelectableUtforandeVerksamheter$(
@@ -80,7 +78,7 @@ export class AvropApiService {
selectedTjanster, selectedTjanster,
selectedKommuner selectedKommuner
); );
return of(tempUtforandeVerksamheterMock).pipe(delay(300)); return of(tempUtforandeVerksamheterMock).pipe(delay(tempMockDelay));
} }
getSelectableKommuner$( getSelectableKommuner$(
@@ -93,10 +91,10 @@ export class AvropApiService {
selectedTjanster, selectedTjanster,
selectedUtforandeVerksamheter selectedUtforandeVerksamheter
); );
return of(tempKommunerMock).pipe(delay(300)); return of(tempKommunerMock).pipe(delay(tempMockDelay));
} }
async tilldelaHandledare(deltagare: Deltagare[], handledare: Handledare): Promise<void> { async tilldelaHandledare(deltagare: DeltagareAvrop[], handledare: HandledareAvrop): Promise<void> {
console.log('[API call] SAVE avrop. Inputs: deltagare, handledare', deltagare, handledare); console.log('[API call] SAVE avrop. Inputs: deltagare, handledare', deltagare, handledare);
await of(null).pipe(delay(200)).toPromise(); await of(null).pipe(delay(200)).toPromise();
// TODO anropa API // TODO anropa API

View File

@@ -28,7 +28,7 @@
"affected:dep-graph": "nx affected:dep-graph", "affected:dep-graph": "nx affected:dep-graph",
"affected": "nx affected", "affected": "nx affected",
"format": "nx format:write", "format": "nx format:write",
"format:write": "nx format:write", "format:write": "nx formavrat:write",
"format:check": "nx format:check", "format:check": "nx format:check",
"update": "nx migrate latest", "update": "nx migrate latest",
"workspace-generator": "nx workspace-generator", "workspace-generator": "nx workspace-generator",