From d139f7504bf32a6b94450c6ea8594c314e5b2e95 Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Mon, 4 Oct 2021 12:19:35 +0200 Subject: [PATCH] feat(handledare): Added functionality to change handledare inside deltagare-card. Also implemented same component inside avrop. (TV-603) Squashed commit of the following: commit 7a7db1d1eb43ac059fe012cd53e59a74410b86be Author: Erik Tiekstra Date: Mon Oct 4 12:14:36 2021 +0200 Fixed imports commit 7f312731fc3fb1dd7b0ae6e0e4e88598ab45db70 Author: Erik Tiekstra Date: Mon Oct 4 12:07:42 2021 +0200 Updated service commit 30164f5d5bc452727408c57ea16aeb87e5e5c91e Author: Erik Tiekstra Date: Mon Oct 4 10:06:50 2021 +0200 Fixed test commit 5e5c7f54d9338ba8c5d8c97381e33cfd8ecaaa52 Merge: bb0e92e0 c2a02dba Author: Erik Tiekstra Date: Mon Oct 4 09:57:28 2021 +0200 Merge branch 'develop' into feature/TV-603-erik commit bb0e92e0d515cc4cca059e09d7dd887ceb074c95 Merge: 500b37b9 93556d48 Author: Erik Tiekstra Date: Mon Oct 4 08:58:08 2021 +0200 Merged develop, fixed conflicts and fixed some minor issues commit 500b37b9d640f5a181fe5080c5f2d213fa1e0182 Author: Erik Tiekstra Date: Wed Sep 29 16:03:31 2021 +0200 Fixed error handling commit 60e753d3eebf94d3a0823a752dd220e2ed171d14 Author: Erik Tiekstra Date: Wed Sep 29 15:47:38 2021 +0200 Cleanup commit 0ef8c0df78e6c8a6301df73d9275b4b153fcc747 Author: Erik Tiekstra Date: Wed Sep 29 15:38:40 2021 +0200 Implemented handledare-service and handledare picker inside avrop and deltagare card commit 89f03f6be1872cc1db83b81f881793ce9806ce4a Merge: 5d2a6876 776889ae Author: Erik Tiekstra Date: Wed Sep 29 11:02:41 2021 +0200 Merge branch 'develop' into feature/TV-603-erik commit 5d2a687694c52e6591f1dea8b553f03b3c2c821f Merge: 548dd2be 82bcab40 Author: Erik Tiekstra Date: Wed Sep 29 10:55:21 2021 +0200 Merged develop and fixed conflicts commit 548dd2bea713af4b17f5e97f4fc315bd8b0d92c3 Author: WP\holno Date: Mon Sep 27 13:46:27 2021 +0200 Cleanup commit 1bafcc6045506e87319ddf8cf51447ff87816494 Author: WP\holno Date: Mon Sep 27 11:27:31 2021 +0200 Implementation of Handledare select on avrop. commit d20285e3ccff7761c88d3a78592262de6ad4dee8 Author: WP\holno Date: Fri Sep 24 14:35:34 2021 +0200 Added validation-messages commit 4a5771e05104ba3c7e771e9c028faa349e4de14d Author: Erik Tiekstra Date: Fri Sep 24 12:52:28 2021 +0200 Assign handledare from deltagare-card --- .../src/app/pages/avrop/avrop.component.html | 23 +++--- .../src/app/pages/avrop/avrop.module.ts | 2 + ...re-tab-personal-information.component.html | 21 ++--- ...gare-tab-personal-information.component.ts | 5 ++ .../deltagare-tab-reports.component.spec.ts | 6 +- .../deltagare-tab-reports.component.ts | 2 +- .../deltagare-card.component.html | 2 + .../deltagare-card.component.spec.ts | 2 + .../deltagare-card.component.ts | 20 ++++- .../deltagare-card/deltagare-card.module.ts | 4 + .../services/deltagare-card.service.ts | 16 ++-- .../handledare-picker-form.component.html | 35 +++++++++ .../handledare-picker-form.component.scss | 35 +++++++++ .../handledare-picker-form.component.spec.ts | 29 +++++++ .../handledare-picker-form.component.ts | 77 +++++++++++++++++++ .../handledare-picker-form.module.ts | 14 ++++ .../components/loader/loader.component.html | 4 +- .../components/loader/loader.component.scss | 4 + .../components/loader/loader.component.ts | 7 +- .../src/app/shared/models/avrop.model.ts | 1 - .../shared/services/api/avrop-api.service.ts | 29 +------ .../services/api/handledare.api.service.ts | 43 +++++++++++ .../src/app/shared/services/avrop.service.ts | 7 +- .../app/shared/services/handledare.service.ts | 43 +++++++++++ 24 files changed, 362 insertions(+), 69 deletions(-) rename apps/mina-sidor-fa/src/app/{shared => pages/deltagare/pages/deltagare-card}/services/deltagare-card.service.ts (78%) create mode 100644 apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.html create mode 100644 apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.scss create mode 100644 apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.spec.ts create mode 100644 apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.ts create mode 100644 apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.module.ts create mode 100644 apps/mina-sidor-fa/src/app/shared/services/api/handledare.api.service.ts create mode 100644 apps/mina-sidor-fa/src/app/shared/services/handledare.service.ts diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.html b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.html index 2020e4e..3acae70 100644 --- a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.html +++ b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.html @@ -57,20 +57,15 @@
- - - - +

Inga handledare har behörighet till markerade deltagare

diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.module.ts b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.module.ts index 15e0fe2..83d04c4 100644 --- a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.module.ts +++ b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.module.ts @@ -3,6 +3,7 @@ import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base'; import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; +import { HandledarePickerFormModule } from '@msfa-shared/components/handledare-picker-form/handledare-picker-form.module'; import { LayoutModule } from '@msfa-shared/components/layout/layout.module'; import { LoaderModule } from '@msfa-shared/components/loader/loader.module'; import { UnauthorizedAlertModule } from '@msfa-shared/components/unauthorized-alert/unauthorized-alert.module'; @@ -22,6 +23,7 @@ import { AvropListModule } from './components/avrop-list/avrop-list.module'; DigiNgProgressProgressbarModule, DigiNgSkeletonBaseModule, LoaderModule, + HandledarePickerFormModule, UnauthorizedAlertModule, ], }) diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html index 8da1008..446187f 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.html @@ -26,15 +26,6 @@ {{ address.postalCode }} {{ address.city }} -
Telefon:
@@ -81,6 +72,15 @@
Tilldelad handledare:
{{ avropInformation.handledare }}
+ + +
@@ -88,3 +88,6 @@
Info saknas
+ + + diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts index ba5b9b9..0abc60a 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-personal-information/deltagare-tab-personal-information.component.ts @@ -1,6 +1,8 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Avrop } from '@msfa-models/avrop.model'; import { ContactInformation } from '@msfa-models/contact-information.model'; +import { Handledare } from '@msfa-models/handledare.model'; +import { Role } from '@msfa-models/role.model'; @Component({ selector: 'msfa-deltagare-tab-personal-information', @@ -11,4 +13,7 @@ import { ContactInformation } from '@msfa-models/contact-information.model'; export class DeltagareTabPersonalInformationComponent { @Input() contactInformation: ContactInformation; @Input() avropInformation: Avrop; + @Input() availableHandledare: Handledare[]; + @Input() userRoles: Role[]; + @Input() handledarePickerVisible: boolean; } diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.spec.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.spec.ts index 27456af..e0f1ea3 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.spec.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.spec.ts @@ -1,11 +1,12 @@ +import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select'; import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { LoaderModule } from '@msfa-shared/components/loader/loader.module'; +import { DeltagareCardService } from '../../services/deltagare-card.service'; import { DeltagareTabReportsComponent } from './deltagare-tab-reports.component'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select'; describe('DeltagareTabReportsComponent', () => { let component: DeltagareTabReportsComponent; @@ -21,6 +22,7 @@ describe('DeltagareTabReportsComponent', () => { LoaderModule, DigiNgFormSelectModule, ], + providers: [DeltagareCardService], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); }); diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.ts index f05a081..4893b1c 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/components/deltagare-tab-reports/deltagare-tab-reports.component.ts @@ -3,9 +3,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { ReportsData } from '@msfa-models/reports.model'; -import { DeltagareCardService } from '@msfa-services/deltagare-card.service'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { distinctUntilChanged, map, shareReplay, switchMap } from 'rxjs/operators'; +import { DeltagareCardService } from '../../services/deltagare-card.service'; @Component({ selector: 'msfa-deltagare-tab-reports', diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.html b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.html index ad9d54c..246e81f 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.html +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.html @@ -18,6 +18,8 @@ class="deltagare-card__tab-contents" [contactInformation]="contactInformation$ | async" [avropInformation]="avropInformation$ | async" + [availableHandledare]="availableHandledare$ | async" + [handledarePickerVisible]="handledarePickerVisible" > diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.spec.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.spec.ts index e12814f..6935444 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.spec.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.spec.ts @@ -4,6 +4,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { LayoutComponent } from '@msfa-shared/components/layout/layout.component'; import { DeltagareCardComponent } from './deltagare-card.component'; +import { DeltagareCardService } from './services/deltagare-card.service'; describe('DeltagareCardComponent', () => { let component: DeltagareCardComponent; @@ -14,6 +15,7 @@ describe('DeltagareCardComponent', () => { void TestBed.configureTestingModule({ declarations: [DeltagareCardComponent, LayoutComponent], imports: [RouterTestingModule, HttpClientTestingModule], + providers: [DeltagareCardService], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); }) diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.ts index e240bde..c157ede 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.component.ts @@ -8,13 +8,15 @@ import { ContactInformation } from '@msfa-models/contact-information.model'; import { Disability } from '@msfa-models/disability.model'; import { DriversLicense } from '@msfa-models/drivers-license.model'; import { Education } from '@msfa-models/education.model'; +import { Handledare } from '@msfa-models/handledare.model'; import { HighestEducation } from '@msfa-models/highest-education.model'; import { Role } from '@msfa-models/role.model'; import { WorkExperience } from '@msfa-models/work-experience.model'; import { UserService } from '@msfa-services/api/user.service'; -import { DeltagareCardService } from '@msfa-services/deltagare-card.service'; +import { HandledareService } from '@msfa-services/handledare.service'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; -import { distinctUntilChanged, map, shareReplay, startWith, switchMap } from 'rxjs/operators'; +import { distinctUntilChanged, filter, map, shareReplay, startWith, switchMap } from 'rxjs/operators'; +import { DeltagareCardService } from './services/deltagare-card.service'; @Component({ selector: 'msfa-deltagare-card', @@ -27,8 +29,9 @@ export class DeltagareCardComponent { private _activeTab$ = new BehaviorSubject('0'); private _userRoles: Role[] = this.userService.userRolesSnapshot; - public activeTab$: Observable = this._activeTab$.asObservable(); - public currentGenomforandeReferens$: Observable = this.activatedRoute.params.pipe( + activeTab$: Observable = this._activeTab$.asObservable(); + + currentGenomforandeReferens$: Observable = this.activatedRoute.params.pipe( map(params => params.genomforandeReferens as string), distinctUntilChanged( ([prevGenomforandeReferens], [currGenomforandeReferens]) => prevGenomforandeReferens === currGenomforandeReferens @@ -67,6 +70,11 @@ export class DeltagareCardComponent { switchMap(genomforandeReferens => this.deltagareCardService.fetchDisabilities$(genomforandeReferens)), shareReplay(1) ); + availableHandledare$: Observable = this.avropInformation$.pipe( + filter(() => !!this.handledarePickerVisible), + distinctUntilChanged((prevAvrop, currAvrop) => prevAvrop.id === currAvrop.id), + switchMap(avropInformation => this.handledareService.fetchAvailableHandledare$([avropInformation.id])) + ); tab0Loading$: Observable = combineLatest([this.contactInformation$, this.avropInformation$]).pipe( map(([contactInformation, avropInformation]) => !(contactInformation && avropInformation)), @@ -99,6 +107,9 @@ export class DeltagareCardComponent { role => role.type === RoleEnum.MSFA_ReportAndPlanning || role.type === RoleEnum.MSFA_ReceiveDeltagare ); } + get handledarePickerVisible(): boolean { + return this._userRoles?.some(role => role.type === RoleEnum.MSFA_ReceiveDeltagare); + } get reportingTabVisible(): boolean { return ( this._activeFeatures.includes(Feature.REPORTING) && @@ -118,6 +129,7 @@ export class DeltagareCardComponent { constructor( private activatedRoute: ActivatedRoute, private deltagareCardService: DeltagareCardService, + private handledareService: HandledareService, private userService: UserService ) {} diff --git a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.module.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.module.ts index 7b8056d..0a3cfb2 100644 --- a/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.module.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/deltagare-card.module.ts @@ -7,6 +7,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { BackLinkModule } from '@msfa-shared/components/back-link/back-link.module'; +import { HandledarePickerFormModule } from '@msfa-shared/components/handledare-picker-form/handledare-picker-form.module'; import { HideTextModule } from '@msfa-shared/components/hide-text/hide-text.module'; import { LayoutModule } from '@msfa-shared/components/layout/layout.module'; import { LoaderModule } from '@msfa-shared/components/loader/loader.module'; @@ -16,6 +17,7 @@ import { DeltagareTabReportsComponent } from './components/deltagare-tab-reports import { DeltagareTabSensitiveInformationComponent } from './components/deltagare-tab-sensitive-information/deltagare-tab-sensitive-information.component'; import { ReportsModule } from './components/reports/reports.module'; import { DeltagareCardComponent } from './deltagare-card.component'; +import { DeltagareCardService } from './services/deltagare-card.service'; @NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -35,11 +37,13 @@ import { DeltagareCardComponent } from './deltagare-card.component'; BackLinkModule, HideTextModule, LoaderModule, + HandledarePickerFormModule, DigiNgLayoutExpansionPanelModule, DigiNgPopoverModule, DigiNgLinkButtonModule, DigiNgFormSelectModule, ], + providers: [DeltagareCardService], exports: [DeltagareCardComponent], }) export class DeltagareCardModule {} diff --git a/apps/mina-sidor-fa/src/app/shared/services/deltagare-card.service.ts b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/services/deltagare-card.service.ts similarity index 78% rename from apps/mina-sidor-fa/src/app/shared/services/deltagare-card.service.ts rename to apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/services/deltagare-card.service.ts index 9e7f649..56414f4 100644 --- a/apps/mina-sidor-fa/src/app/shared/services/deltagare-card.service.ts +++ b/apps/mina-sidor-fa/src/app/pages/deltagare/pages/deltagare-card/services/deltagare-card.service.ts @@ -7,20 +7,24 @@ import { Education } from '@msfa-models/education.model'; import { HighestEducation } from '@msfa-models/highest-education.model'; import { ReportsData } from '@msfa-models/reports.model'; import { WorkExperience } from '@msfa-models/work-experience.model'; +import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service'; +import { HandledareService } from '@msfa-services/handledare.service'; import { Observable } from 'rxjs'; -import { DeltagareApiService } from './api/deltagare.api.service'; +import { mapTo, switchMap } from 'rxjs/operators'; -@Injectable({ - providedIn: 'root', -}) +@Injectable() export class DeltagareCardService { - constructor(private deltagareApiService: DeltagareApiService) {} + avropNeedsUpdate$: Observable = this.handledareService.lastSavedHandledare$.pipe(mapTo(undefined as void)); + + constructor(private deltagareApiService: DeltagareApiService, private handledareService: HandledareService) {} public fetchContactInformation$(genomforandeReferens: number): Observable { return this.deltagareApiService.fetchContactInformation$(genomforandeReferens); } public fetchAvropInformation$(genomforandeReferens: number): Observable { - return this.deltagareApiService.fetchAvropInformation$(genomforandeReferens); + return this.avropNeedsUpdate$.pipe( + switchMap(() => this.deltagareApiService.fetchAvropInformation$(genomforandeReferens)) + ); } public fetchWorkExperiences$(genomforandeReferens: number): Observable { return this.deltagareApiService.fetchWorkExperiences$(genomforandeReferens); diff --git a/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.html b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.html new file mode 100644 index 0000000..98a4129 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.html @@ -0,0 +1,35 @@ +
+ + + + {{submitText}} + + + +
diff --git a/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.scss b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.scss new file mode 100644 index 0000000..5383fe7 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.scss @@ -0,0 +1,35 @@ +@import 'variables/gutters'; + +.handledare-picker-form { + position: relative; + display: grid; + grid-template-columns: 1fr auto; + column-gap: $digi--layout--gutter; + row-gap: $digi--layout--gutter--s; + grid-template-areas: + 'select select' + 'validation validation' + 'submit .'; + + &__select { + grid-area: select; + } + + &__submit { + grid-area: submit; + align-self: end; + } + + &__validation-wrapper { + grid-area: validation; + } + + &__validation-message { + display: block; + margin-bottom: $digi--layout--gutter--s; + } + + ::ng-deep .digi-ng-form-select__footer { + display: none !important; + } +} diff --git a/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.spec.ts b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.spec.ts new file mode 100644 index 0000000..34b4386 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.spec.ts @@ -0,0 +1,29 @@ +import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { HandledarePickerFormComponent } from './handledare-picker-form.component'; + +describe('HandledarePickerFormComponent', () => { + let component: HandledarePickerFormComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ReactiveFormsModule, HttpClientTestingModule, FormsModule, DigiNgFormSelectModule], + declarations: [HandledarePickerFormComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HandledarePickerFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.ts b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.ts new file mode 100644 index 0000000..7ff599f --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.component.ts @@ -0,0 +1,77 @@ +import { FormSelectItem } from '@af/digi-ng/_form/form-select'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges, +} from '@angular/core'; +import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; +import { Handledare } from '@msfa-models/handledare.model'; +import { HandledareService } from '@msfa-services/handledare.service'; +import { RequiredValidator } from '@msfa-utils/validators/required.validator'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'msfa-handledare-picker-form', + templateUrl: './handledare-picker-form.component.html', + styleUrls: ['./handledare-picker-form.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class HandledarePickerFormComponent implements OnChanges { + @Input() selectedHandledareId: string; + @Input() handledare: Handledare[]; + @Input() avropIds: string[]; + @Input() label = 'Välj handledare'; + @Input() submitText = 'Spara handledare'; + @Input() skipSubmit = false; + @Input() invalid = false; + @Output() selectedHandledareChanged = new EventEmitter(); + formGroup: FormGroup = new FormGroup({ + handledare: new FormControl(null, [RequiredValidator('Handledare')]), + }); + selectableHandledare: FormSelectItem[] = []; + submitted = false; + lastSavedHandledare$: Observable = this.handledareService.lastSavedHandledare$; + submitHandledareLoading$: Observable = this.handledareService.submitHandledareLoading$; + + constructor(private handledareService: HandledareService) {} + + ngOnChanges(changes: SimpleChanges): void { + if (changes.selectedHandledareId) { + this.handledareFormControl.patchValue(this.selectedHandledareId); + } + if (changes.handledare && this.handledare?.length) { + this.selectableHandledare = this.handledare.map(({ ciamUserId, fullName }) => ({ + name: fullName, + value: ciamUserId, + })); + } + } + + get handledareFormControl(): AbstractControl { + return this.formGroup.get('handledare'); + } + + handledareChanged(): void { + this.submitted = false; + this.selectedHandledareChanged.emit(this.handledareFormControl.value); + } + + onFormSubmitted(): void { + this.submitted = true; + this.formGroup.markAllAsTouched(); + + if (this.formGroup.invalid || this.handledareFormControl.value === this.selectedHandledareId) { + return; + } + + const newHandledare = this.handledare.find( + handledare => handledare.ciamUserId === this.handledareFormControl.value + ); + + this.handledareService.assignHandledare(this.avropIds, newHandledare); + } +} diff --git a/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.module.ts b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.module.ts new file mode 100644 index 0000000..742ea47 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/components/handledare-picker-form/handledare-picker-form.module.ts @@ -0,0 +1,14 @@ +import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select'; +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { LoaderModule } from '../loader/loader.module'; +import { HandledarePickerFormComponent } from './handledare-picker-form.component'; + +@NgModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [HandledarePickerFormComponent], + imports: [CommonModule, ReactiveFormsModule, LoaderModule, DigiNgFormSelectModule], + exports: [HandledarePickerFormComponent], +}) +export class HandledarePickerFormModule {} diff --git a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.html b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.html index 7ff866f..889ea9a 100644 --- a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.html +++ b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.html @@ -1,3 +1,3 @@ -
- +
+
diff --git a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.scss b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.scss index 70aa16a..850c27d 100644 --- a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.scss +++ b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.scss @@ -28,5 +28,9 @@ &__spinner { display: inline-flex; animation: spinning 1s linear infinite; + + &--s { + width: 2.5rem; + } } } diff --git a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.ts b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.ts index 0a4b831..279ddef 100644 --- a/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.ts +++ b/apps/mina-sidor-fa/src/app/shared/components/loader/loader.component.ts @@ -10,11 +10,16 @@ import { LoaderType } from '@msfa-enums/loader-type.enum'; export class LoaderComponent { private readonly _defaultClass = 'loader'; @Input() type: LoaderType; + @Input() size: 's' | 'm' = 'm'; - get classes(): string { + get loaderClass(): string { if (this.type) { return `${this._defaultClass} ${this._defaultClass}--${this.type as string}`; } return this._defaultClass; } + + get spinnerClass(): string { + return `${this._defaultClass}__spinner ${this._defaultClass}__spinner--${this.size}`; + } } diff --git a/apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts b/apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts index cb04f72..6e55df1 100644 --- a/apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts +++ b/apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts @@ -41,7 +41,6 @@ export function mapAvropResponseToAvrop(data: AvropResponse): Avrop { sprakstod, adress, sparkod, - sparNamn, genomforandeReferens, deltagandeGrad, utforandeverksamhet, diff --git a/apps/mina-sidor-fa/src/app/shared/services/api/avrop-api.service.ts b/apps/mina-sidor-fa/src/app/shared/services/api/avrop-api.service.ts index aed50ae..17d08d3 100644 --- a/apps/mina-sidor-fa/src/app/shared/services/api/avrop-api.service.ts +++ b/apps/mina-sidor-fa/src/app/shared/services/api/avrop-api.service.ts @@ -3,14 +3,13 @@ import { Injectable } from '@angular/core'; import { environment } from '@msfa-environment'; import { AvropFilterResponse } from '@msfa-models/api/avrop-filter.response.model'; import { AvropApiResponse } from '@msfa-models/api/avrop.response.model'; -import { HandledareResponse } from '@msfa-models/api/handledare.response.model'; import { Params } from '@msfa-models/api/params.model'; import { AvropFilter, mapResponseToAvropFilter } from '@msfa-models/avrop-filter.model'; import { AvropCompact, AvropCompactData, mapAvropResponseToAvrop } from '@msfa-models/avrop.model'; import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error'; -import { Handledare, mapHandledareResponseToHandledare } from '@msfa-models/handledare.model'; +import { Handledare } from '@msfa-models/handledare.model'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { catchError, filter, map, tap } from 'rxjs/operators'; +import { catchError, filter, map } from 'rxjs/operators'; @Injectable({ providedIn: 'root', @@ -46,30 +45,6 @@ export class AvropApiService { ); } - fetchAvailableHandledare$(avrop: AvropCompact[]): Observable { - const lockedAvropIsEqual = this.lockedAvropValue?.every( - (lockedAvrop, index) => lockedAvrop.id === avrop[index]?.id - ); - - // Checking to see if we really need to make a new api-request - if (lockedAvropIsEqual) { - return of(this._availableHandledareSnapshot$.getValue()); - } - - this._lockedAvropSnapshot$.next(avrop); - - return this.httpClient - .get<{ data: HandledareResponse[] }>(`${this._apiBaseUrl}/handledare`, { - params: { avropIds: avrop.map(a => a.id) }, - }) - .pipe( - map(({ data }) => data.map(handledare => mapHandledareResponseToHandledare(handledare))), - tap(handledare => { - this._availableHandledareSnapshot$.next(handledare); - }) - ); - } - fetchAvailableTjanster$(params: Params): Observable { return this.httpClient .get<{ data: AvropFilterResponse[] }>(`${this._apiBaseUrl}/tjanster`, { params }) diff --git a/apps/mina-sidor-fa/src/app/shared/services/api/handledare.api.service.ts b/apps/mina-sidor-fa/src/app/shared/services/api/handledare.api.service.ts new file mode 100644 index 0000000..a11fa97 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/services/api/handledare.api.service.ts @@ -0,0 +1,43 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { environment } from '@msfa-environment'; +import { HandledareResponse } from '@msfa-models/api/handledare.response.model'; +import { Params } from '@msfa-models/api/params.model'; +import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error'; +import { Handledare, mapHandledareResponseToHandledare } from '@msfa-models/handledare.model'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +@Injectable({ + providedIn: 'root', +}) +export class HandledareApiService { + private _apiBaseUrl = `${environment.api.url}/avrop/handledare`; + + constructor(private httpClient: HttpClient) {} + + public fetchAvailableHandledare$(avropIds: string[]): Observable { + return this.httpClient + .get<{ data: HandledareResponse[] }>(`${this._apiBaseUrl}`, { + params: { avropIds }, + }) + .pipe( + map(({ data }) => data.map(handledare => mapHandledareResponseToHandledare(handledare))), + catchError((error: Error) => { + throw new CustomError( + errorToCustomError({ ...error, message: `Kunde inte hämta handledare.\n\n${error.message}` }) + ); + }) + ); + } + + async assignHandledare(avropIds: string[], handledare: Handledare): Promise { + const params: Params = { + avropIds, + ciamUserId: handledare.ciamUserId, + }; + return this.httpClient + .patch(`${this._apiBaseUrl}/assign`, null, { params }) + .toPromise(); + } +} diff --git a/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts b/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts index 05c4fd0..9b75ee9 100644 --- a/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts +++ b/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts @@ -6,6 +6,7 @@ import { AvropApiService } from '@msfa-services/api/avrop-api.service'; import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option'; import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs'; import { distinctUntilChanged, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators'; +import { HandledareApiService } from './api/handledare.api.service'; type Step = 1 | 2 | 3 | 4; @@ -103,7 +104,9 @@ export class AvropService { public availableHandledare$: Observable = this._lockedAvrop$.pipe( filter(lockedAvrop => !!lockedAvrop?.length), - switchMap(lockedAvrop => this.avropApiService.fetchAvailableHandledare$(lockedAvrop)) + map(lockedAvrop => lockedAvrop.map(avrop => avrop.id)), + switchMap(lockedAvrop => this.handledareApiService.fetchAvailableHandledare$(lockedAvrop)), + shareReplay(1) ); public currentStep$: Observable = combineLatest([ @@ -194,7 +197,7 @@ export class AvropService { this._selectedAvrop$.next(deltagare); } - constructor(private avropApiService: AvropApiService) {} + constructor(private avropApiService: AvropApiService, private handledareApiService: HandledareApiService) {} public resetError(): void { this._error$.next(null); diff --git a/apps/mina-sidor-fa/src/app/shared/services/handledare.service.ts b/apps/mina-sidor-fa/src/app/shared/services/handledare.service.ts new file mode 100644 index 0000000..0dfbf73 --- /dev/null +++ b/apps/mina-sidor-fa/src/app/shared/services/handledare.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@angular/core'; +import { errorToCustomError } from '@msfa-models/error/custom-error'; +import { Handledare } from '@msfa-models/handledare.model'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { HandledareApiService } from './api/handledare.api.service'; +import { ErrorService } from './error.service'; + +@Injectable({ + providedIn: 'root', +}) +export class HandledareService { + private _lastSavedHandledare$ = new BehaviorSubject(null); + public lastSavedHandledare$: Observable = this._lastSavedHandledare$.asObservable(); + private _submitHandledareLoading$ = new BehaviorSubject(false); + public submitHandledareLoading$: Observable = this._submitHandledareLoading$.asObservable(); + + constructor(private handledareApiService: HandledareApiService, private errorService: ErrorService) {} + + public resetLastSavedHandledare(): void { + this._lastSavedHandledare$.next(null); + } + + public fetchAvailableHandledare$(avropIds: string[]): Observable { + return this.handledareApiService.fetchAvailableHandledare$(avropIds); + } + + public assignHandledare(avropIds: string[], handledare: Handledare): void { + this._submitHandledareLoading$.next(true); + this.handledareApiService + .assignHandledare(avropIds, handledare) + .then(() => { + this._lastSavedHandledare$.next(handledare); + }) + .catch((error: Error) => { + this.errorService.add( + errorToCustomError({ ...error, message: `Kunde inte tilldela handledare.\n\n${error.message}` }) + ); + }) + .finally(() => { + this._submitHandledareLoading$.next(false); + }); + } +}