Merge pull request #90 in TEA/mina-sidor-fa-web from feature/TV-407 to develop
Squashed commit of the following: commit f4fe49b7e5602b7041573c70b85b22bd978d237b Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Thu Sep 16 18:01:24 2021 +0200 TV-407 cleanup commit 141cd9afa8d73e5ad4860456da926ad1468de874 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Thu Sep 16 16:32:07 2021 +0200 TV-407 updated heading text commit 2d778bd4dd7982e0736bc8c720a69499662a2164 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Thu Sep 16 14:33:04 2021 +0200 TV-407 fixed run test issues, some refactoring commit 9f4cc2c3ad2572eef80923ae465e4d2218acb0cc Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 18:51:58 2021 +0200 TV-407 removed afInvalid on timepicker commit f10923c92ebab2c51593682de4748fc443699c28 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 17:54:49 2021 +0200 TV 407 service name commit cdf02cd956e9f75d8415d525645a5d2ecbeb7e41 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 17:51:39 2021 +0200 TV-407 changed api service name to AvvikelseApiService commit 0ebaddc235ba506aec7cf23ebf96c03cb7a0a79f Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 16:51:02 2021 +0200 TV-407 renaming service name to DeltagareAvvikelseService commit 60e59881099c99a550b70e310930b1f708fa7f70 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 16:40:57 2021 +0200 TV-407 digi-ng timepicker, fixed some pr reviews comments commit b80e79e915d3baa11d7850ddf9ef506b4dd1d1cd Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 15 01:42:42 2021 +0200 TV-407 restructoring files, some cleaning commit 1c92ccefa2f3441c55fd4beacbf38b2ce465aee0 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Tue Sep 14 14:54:53 2021 +0200 TV-407 refactoring, cleaning commit 02904debb8f8dc70c817d2b18b79c0da1b9fd102 Merge: f1ad09a2a37566Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Tue Sep 14 11:51:31 2021 +0200 Merge branch 'develop' into feature/TV-407 commit f1ad09ac823a909b2d6503677314850235670838 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Tue Sep 14 11:50:50 2021 +0200 TV-407 updating report-api service commit 1f766fba089ac0e1f9bd3e00d2a7f81bb5b979e9 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Tue Sep 14 11:40:10 2021 +0200 TV-407 sorting franvaro, validating, cleaning commit f153e574007dfcfe7a65cbd5034370ed31202a34 Merge: ff4011c92272e4Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Mon Sep 13 14:42:38 2021 +0200 Merge branch 'develop' into feature/TV-407 commit ff4011c86f1222c677b2d027ef479b2f82aff5e3 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Mon Sep 13 13:58:05 2021 +0200 TV-407 structoring code to reactive style, validation implemnted commit 25f9debe6216a7bf0a3c6d9a59e6b4499699e380 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 8 22:46:33 2021 +0200 TV-407 changed file structure and renaming commit 9f6f6d4a9f63698d7912668db542eefe285a3b83 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 8 20:11:20 2021 +0200 TV-407 conditions fixes commit 29c1a9536f799795712ded15a3ac746b807f8f94 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 8 15:02:26 2021 +0200 TV-407 reactive error messages, sokandeId to model, cleaning commit ba7a031b3e253cb05ecd1a96920bc8439884dec1 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 8 09:17:16 2021 +0200 TV-407 setTimeout, timepicker condition commit 2eb2c48bc89bc310d2b2e9de4e909fbb5f3bdcb4 Author: fueno <nicolas.fuentes-maturana@arbetsformedlingen.se> Date: Wed Sep 8 09:03:41 2021 +0200 TV-407 corrections ... and 34 more commits
This commit is contained in:
@@ -15,7 +15,8 @@ const routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'rapportera/:deltagareId',
|
path: 'rapportera/:deltagareId',
|
||||||
data: { title: 'Skapa rapport' },
|
data: { title: 'Skapa rapport' },
|
||||||
loadChildren: () => import('./pages/deltagare-report/deltagare-report.module').then(m => m.DeltagareReportModule),
|
// eslint-disable-next-line max-len
|
||||||
|
loadChildren: () => import('./pages/deltagare-report/pages/deltagare-avvikelse/deltagare-avvikelse.module').then(m => m.DeltagareAvvikelseModule),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'planering/:deltagareId',
|
path: 'planering/:deltagareId',
|
||||||
@@ -31,4 +32,4 @@ const routes: Routes = [
|
|||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class DeltagareRoutingModule {}
|
export class DeltagareRoutingModule { }
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<msfa-layout>
|
|
||||||
<section class="deltagare-report">
|
|
||||||
<digi-typography>
|
|
||||||
<h1>Avvikelserapport</h1>
|
|
||||||
<p>Här ska det komma en förklarande text om avvikelserapporter.</p>
|
|
||||||
<h2>Skapa rapport</h2>
|
|
||||||
<div class="deltagare-report__deltagare">
|
|
||||||
<p><strong>Deltagare:</strong> Göran Ekman</p>
|
|
||||||
<p><strong>Personnummer:</strong> 999999</p>
|
|
||||||
</div>
|
|
||||||
</digi-typography>
|
|
||||||
</section>
|
|
||||||
</msfa-layout>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { LayoutComponent } from '@msfa-shared/components/layout/layout.component';
|
|
||||||
|
|
||||||
import { DeltagareReportComponent } from './deltagare-report.component';
|
|
||||||
|
|
||||||
describe('DeltagareReportComponent', () => {
|
|
||||||
let component: DeltagareReportComponent;
|
|
||||||
let fixture: ComponentFixture<DeltagareReportComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
||||||
declarations: [DeltagareReportComponent, LayoutComponent],
|
|
||||||
imports: [RouterTestingModule, HttpClientTestingModule]
|
|
||||||
}).compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(DeltagareReportComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'msfa-deltagare-report',
|
|
||||||
templateUrl: './deltagare-report.component.html',
|
|
||||||
styleUrls: ['./deltagare-report.component.scss'],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
|
||||||
export class DeltagareReportComponent {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
|
||||||
import { DeltagareReportComponent } from './deltagare-report.component';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
||||||
declarations: [DeltagareReportComponent],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
RouterModule.forChild([{ path: '', component: DeltagareReportComponent }]),
|
|
||||||
LayoutModule
|
|
||||||
],
|
|
||||||
exports: [DeltagareReportComponent]
|
|
||||||
})
|
|
||||||
export class DeltagareReportModule { }
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<form class="fragor-form" [formGroup]="fragorFormGroup" *ngIf="fragorFormGroup">
|
||||||
|
<ng-container *ngFor="let fraga of fragor1 | filterFragor: selectedOrsaksKod">
|
||||||
|
<div class="fragor-form__content">
|
||||||
|
<digi-ng-form-textarea
|
||||||
|
[formControlName]="'fraga1'"
|
||||||
|
[afLabel]="fraga.name"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afRequired]="true"
|
||||||
|
[afInvalid]="avvikelseFormGroup?.errors?.motiveringIsRequired && fragorFormGroup.get('fraga1').touched"
|
||||||
|
[afMaxLength]="2000"
|
||||||
|
></digi-ng-form-textarea>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup?.errors?.motiveringIsRequired && fragorFormGroup.get('fraga1').touched"
|
||||||
|
>
|
||||||
|
Beskrivning är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngFor="let fraga of fragor2 | filterFragor: selectedOrsaksKod">
|
||||||
|
<div *ngIf="fragor1.length > 0" class="fragor-form__content">
|
||||||
|
<digi-ng-form-textarea
|
||||||
|
[formControlName]="'fraga2'"
|
||||||
|
[afLabel]="fraga.name"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afRequired]="fraga.descriptionIsRequired"
|
||||||
|
[afInvalid]="fraga.descriptionIsRequired && fragorFormGroup.get('fraga2').touched && !fragorFormGroup.get('fraga2').value"
|
||||||
|
[afMaxLength]="2000"
|
||||||
|
></digi-ng-form-textarea>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="fraga.descriptionIsRequired && fragorFormGroup.get('fraga2').touched && !fragorFormGroup.get('fraga2').value"
|
||||||
|
>
|
||||||
|
Beskrivning är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
|
.fragor-form {
|
||||||
|
&__content {
|
||||||
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { DigiNgFormTextareaModule } from '@af/digi-ng/_form/form-textarea';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import { DeltagareFragorFormComponent } from './deltagare-fragor-form.component';
|
||||||
|
|
||||||
|
describe('DeltagareAvvikelseFormComponent', () => {
|
||||||
|
let component: DeltagareFragorFormComponent;
|
||||||
|
let fixture: ComponentFixture<DeltagareFragorFormComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
imports: [DigiNgFormRadiobuttonGroupModule, ReactiveFormsModule, DigiNgFormTextareaModule],
|
||||||
|
declarations: [DeltagareFragorFormComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DeltagareFragorFormComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { FragorForAvvikelser } from '@msfa-models/fragor-for-avvikelser.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'msfa-deltagare-fragor-form',
|
||||||
|
templateUrl: './deltagare-fragor-form.component.html',
|
||||||
|
styleUrls: ['./deltagare-fragor-form.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
export class DeltagareFragorFormComponent {
|
||||||
|
@Input() fragor1: FragorForAvvikelser[] | null = null;
|
||||||
|
@Input() fragor2: FragorForAvvikelser[] | null = null;
|
||||||
|
@Input() fragorFormGroup: FormGroup | null = null;
|
||||||
|
@Input() avvikelseFormGroup: FormGroup | null = null;
|
||||||
|
@Input() selectedOrsaksKod: string | null = null;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { DeltagareFragorFormComponent } from './deltagare-fragor-form.component';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { DigiNgFormTextareaModule } from '@af/digi-ng/_form/form-textarea';
|
||||||
|
import { FilterFragorPipe } from './filter-fragor.pipe';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareFragorFormComponent, FilterFragorPipe],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DigiNgFormTextareaModule
|
||||||
|
],
|
||||||
|
exports: [DeltagareFragorFormComponent]
|
||||||
|
})
|
||||||
|
export class DeltagareFragorFormModule { }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { FragorForAvvikelser } from '@msfa-models/fragor-for-avvikelser.model';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'filterFragor',
|
||||||
|
|
||||||
|
})
|
||||||
|
export class FilterFragorPipe implements PipeTransform {
|
||||||
|
transform(fragor: FragorForAvvikelser[], id: string): FragorForAvvikelser[] {
|
||||||
|
if (fragor?.length === 0) {
|
||||||
|
return fragor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragor?.filter(fraga => fraga?.id.substring(0, 2) === id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<form class="orsaks-form" [formGroup]="orsakerFormGroup" *ngIf="orsakerFormGroup">
|
||||||
|
<ng-container *ngIf="selectedAlternative">
|
||||||
|
<div class="orsaks-form__content">
|
||||||
|
<digi-ng-form-select
|
||||||
|
[formControlName]="'orsaker'"
|
||||||
|
[afLabel]="selectedAlternative === 'franvaro' ? 'Frånvaroorsak' : 'Avvikelseorsak'"
|
||||||
|
[afPlaceholder]="'Välj orsak till ' + (selectedAlternative === 'franvaro' ? 'frånvaro' : 'avvikelse')"
|
||||||
|
[afSelectItems]="selectedAlternative === 'franvaro' ? franvaroOrsaker : avvikelseOrsaker"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afInvalid]="avvikelseFormGroup.errors?.orsakerIsRequired && orsakerFormGroup.touched"
|
||||||
|
></digi-ng-form-select>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup.errors?.orsakerIsRequired && orsakerFormGroup.touched"
|
||||||
|
>
|
||||||
|
Orsak är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="showAndraKandaOrsaker">
|
||||||
|
<div class="orsaks-form__content">
|
||||||
|
<digi-ng-form-select
|
||||||
|
[formControlName]="'andraKandaOrsaker'"
|
||||||
|
[afLabel]="'Välj känd orsak'"
|
||||||
|
[afPlaceholder]="'Känd orsak'"
|
||||||
|
[afSelectItems]="andraKandaOrsaker"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afInvalid]="avvikelseFormGroup.errors?.annanKandorsakIsRequired && orsakerFormGroup.touched"
|
||||||
|
></digi-ng-form-select>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup.errors?.annanKandorsakIsRequired && orsakerFormGroup.touched"
|
||||||
|
>
|
||||||
|
Orsak är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
|
.orsaks-form {
|
||||||
|
&__content {
|
||||||
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { DeltagareOrsaksFormComponent } from './deltagare-orsaks-form.component';
|
||||||
|
|
||||||
|
|
||||||
|
describe('DeltagareAvvikelseFormComponent', () => {
|
||||||
|
let component: DeltagareOrsaksFormComponent;
|
||||||
|
let fixture: ComponentFixture<DeltagareOrsaksFormComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
imports: [DigiNgFormRadiobuttonGroupModule, ReactiveFormsModule, DigiNgFormSelectModule],
|
||||||
|
declarations: [DeltagareOrsaksFormComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DeltagareOrsaksFormComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { Alternative } from '@msfa-enums/alternative.enum';
|
||||||
|
import { FranvaroOrsaksKodEnum } from '@msfa-enums/franvaro-orsak-kod.enum';
|
||||||
|
import { OrsaksKoderAvvikelse } from '@msfa-models/orsaks-koder-avvikelse.model';
|
||||||
|
import { OrsaksKoderFranvaro } from '@msfa-models/orsaks-koder-franvaro.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'msfa-deltagare-orsaks-form',
|
||||||
|
templateUrl: './deltagare-orsaks-form.component.html',
|
||||||
|
styleUrls: ['./deltagare-orsaks-form.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DeltagareOrsaksFormComponent implements OnChanges {
|
||||||
|
@Input() franvaroOrsaker: OrsaksKoderFranvaro[] | null = null;
|
||||||
|
@Input() avvikelseOrsaker: OrsaksKoderAvvikelse[] | null = null;
|
||||||
|
@Input() andraKandaOrsaker: OrsaksKoderFranvaro[] | null = null;
|
||||||
|
@Input() orsakerFormGroup: FormGroup | null = null;
|
||||||
|
@Input() avvikelseFormGroup: FormGroup | null = null;
|
||||||
|
@Input() selectedAlternative: string | null = null;
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if (changes) {
|
||||||
|
this.orsakerFormGroup.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get showAndraKandaOrsaker(): boolean {
|
||||||
|
return this.selectedAlternative === Alternative.FRANVARO &&
|
||||||
|
+this.orsakerFormGroup.get('orsaker')?.value === FranvaroOrsaksKodEnum.AnnanKandOrsak;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
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 { DeltagareOrsaksFormComponent } from './deltagare-orsaks-form.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareOrsaksFormComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DigiNgFormSelectModule
|
||||||
|
],
|
||||||
|
exports: [DeltagareOrsaksFormComponent]
|
||||||
|
})
|
||||||
|
export class DeltagareOrsaksFormModule { }
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<div class="deltagare-timepicker">
|
||||||
|
<form [formGroup]="timepickerFormGroup" *ngIf="timepickerFormGroup">
|
||||||
|
<digi-typography>
|
||||||
|
<label class="deltagare-timepicker__heading">Välj tid för frånvaro</label>
|
||||||
|
</digi-typography>
|
||||||
|
|
||||||
|
<div class="deltagare-timepicker__input deltagare-timepicker__start-time">
|
||||||
|
<digi-ng-form-input
|
||||||
|
afLabel
|
||||||
|
[afDescription]="'Ange starttid'"
|
||||||
|
[formControl]="timepickerFormGroup.get('startTime')"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
afType="time"
|
||||||
|
></digi-ng-form-input>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup.errors?.startTimeIsRequired && timepickerFormGroup.get('startTime').touched"
|
||||||
|
>
|
||||||
|
Starttid är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
<div class="deltagare-timepicker__input">
|
||||||
|
<digi-ng-form-input
|
||||||
|
afLabel
|
||||||
|
[afDescription]="'Ange sluttid'"
|
||||||
|
[formControl]="timepickerFormGroup.get('endTime')"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
afType="time"
|
||||||
|
></digi-ng-form-input>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup.errors?.endTimeIsRequired && timepickerFormGroup.get('endTime').touched"
|
||||||
|
>
|
||||||
|
Sluttid är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
|
.deltagare-timepicker {
|
||||||
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
|
&__heading {
|
||||||
|
font-weight: var(--digi--typography--font-weight--semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__start-time {
|
||||||
|
margin-bottom: $digi--layout--gutter--m;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
width: 127px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { DigiNgFormInputModule } from '@af/digi-ng/_form/form-input';
|
||||||
|
import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { DeltagareTimePickerComponent } from './deltagare-time-picker.component';
|
||||||
|
|
||||||
|
|
||||||
|
describe('DeltagareTimePickerComponent', () => {
|
||||||
|
let component: DeltagareTimePickerComponent;
|
||||||
|
let fixture: ComponentFixture<DeltagareTimePickerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareTimePickerComponent],
|
||||||
|
imports: [ReactiveFormsModule, DigiNgFormSelectModule, DigiNgFormInputModule]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DeltagareTimePickerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'msfa-deltagare-time-picker',
|
||||||
|
templateUrl: './deltagare-time-picker.component.html',
|
||||||
|
styleUrls: ['./deltagare-time-picker.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DeltagareTimePickerComponent {
|
||||||
|
@Input() timepickerFormGroup: FormGroup | null = null;
|
||||||
|
@Input() avvikelseFormGroup: FormGroup | null = null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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 { DeltagareTimePickerComponent } from './deltagare-time-picker.component';
|
||||||
|
import {DigiNgFormInputModule} from '@af/digi-ng/_form/form-input'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareTimePickerComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DigiNgFormSelectModule,
|
||||||
|
DigiNgFormInputModule
|
||||||
|
],
|
||||||
|
exports: [DeltagareTimePickerComponent]
|
||||||
|
})
|
||||||
|
export class DeltagareTimePickerModule { }
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<msfa-layout>
|
||||||
|
<section class="deltagare-avvikelse">
|
||||||
|
<digi-typography>
|
||||||
|
<h1>Rapport</h1>
|
||||||
|
<p>
|
||||||
|
Här rapporterar du deltagarens frånvaro och eventuella misskötsel i tjänsten. Rapportering via avvikelserapport
|
||||||
|
ska också ske om tjänsten inte fungerar för deltagaren.
|
||||||
|
</p>
|
||||||
|
<h2>Skapa rapport</h2>
|
||||||
|
<div *ngIf="contactInformation$ | async as contactInformation" class="deltagare-avvikelse__deltagare">
|
||||||
|
<p><span>Deltagare:</span> {{contactInformation.fornamn + ' ' + contactInformation.efternamn}}</p>
|
||||||
|
<p><span>Personnummer:</span> {{contactInformation.personnummer}}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="deltagare-avvikelse__alternative-heading">Vad är det du vill rapportera?</h3>
|
||||||
|
<form [formGroup]="avvikelseFormGroup" (ngSubmit)="onFormSubmitted()">
|
||||||
|
<div class="deltagare-avvikelse__alternative">
|
||||||
|
<digi-ng-form-radiobutton-group
|
||||||
|
[afRadiobuttons]="avvikelseAlternatives"
|
||||||
|
[formControlName]="alternativeFormControlName"
|
||||||
|
(change)="setAlternative()"
|
||||||
|
></digi-ng-form-radiobutton-group>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="alternativeFormControl.invalid && avvikelseFormGroup.touched"
|
||||||
|
>
|
||||||
|
Alternativ är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
<msfa-deltagare-orsaks-form
|
||||||
|
[franvaroOrsaker]="franvaroOrsaker$ | async"
|
||||||
|
[avvikelseOrsaker]="avvikelseOrsaker$ | async "
|
||||||
|
[andraKandaOrsaker]="andraKandaOrsaker$ | async"
|
||||||
|
[orsakerFormGroup]="avvikelseFormGroup.get('orsakerFormGroup')"
|
||||||
|
[avvikelseFormGroup]="avvikelseFormGroup"
|
||||||
|
[selectedAlternative]="alternativeFormControl.value"
|
||||||
|
(change)="setOrsakerChanged()"
|
||||||
|
></msfa-deltagare-orsaks-form>
|
||||||
|
|
||||||
|
<ng-container *ngIf="showDescription">
|
||||||
|
<div class="deltagare-avvikelse__description">
|
||||||
|
<digi-ng-form-textarea
|
||||||
|
[formControlName]="descriptionFormControlName"
|
||||||
|
afLabel="Beskriv frånvaro"
|
||||||
|
[afSize]="sizeTextArea"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afMaxLength]="2000"
|
||||||
|
[afRequired]="true"
|
||||||
|
[afInvalid]="avvikelseFormGroup?.errors?.descriptionIsRequired && descriptionFormControl.touched"
|
||||||
|
></digi-ng-form-textarea>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup?.errors?.descriptionIsRequired && descriptionFormControl.touched"
|
||||||
|
>
|
||||||
|
Beskrivning är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="showFragor">
|
||||||
|
<msfa-deltagare-fragor-form
|
||||||
|
[fragor1]="fragor1$ | async"
|
||||||
|
[fragor2]="fragor2$ | async"
|
||||||
|
[fragorFormGroup]="avvikelseFormGroup.get('fragorFormGroup')"
|
||||||
|
[avvikelseFormGroup]="avvikelseFormGroup"
|
||||||
|
[selectedOrsaksKod]="selectedOrsaksKod"
|
||||||
|
></msfa-deltagare-fragor-form>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<div *ngIf="showDatePicker" class="deltagare-avvikelse__datepicker">
|
||||||
|
<digi-ng-form-datepicker
|
||||||
|
[formControlName]="dateFormControlName"
|
||||||
|
[afLabel]="'Välj dag för ' + (alternativeFormControl.value === 'franvaro' ? 'frånvaro' : 'avvikelse')"
|
||||||
|
[afDisableValidStyle]="true"
|
||||||
|
[afInvalid]="avvikelseFormGroup.errors?.dateIsRequired"
|
||||||
|
></digi-ng-form-datepicker>
|
||||||
|
<digi-form-validation-message af-variation="error" *ngIf="avvikelseFormGroup.errors?.dateIsRequired">
|
||||||
|
{{avvikelseFormGroup.errors?.dateIsRequired}}
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="showDayOrPartOfDayPicker" class="deltagare-avvikelse__dayOrPartOfDay">
|
||||||
|
<digi-ng-form-radiobutton-group
|
||||||
|
[afRadiobuttons]="dayOrPartOfDay"
|
||||||
|
[formControlName]="dayOrPartOfDayFormControlName"
|
||||||
|
></digi-ng-form-radiobutton-group>
|
||||||
|
<digi-form-validation-message
|
||||||
|
af-variation="error"
|
||||||
|
*ngIf="avvikelseFormGroup.errors?.dayOrPartOfDayIsRequired && avvikelseFormGroup?.get('orsakerFormGroup')?.get('orsaker')?.value && avvikelseFormGroup.touched"
|
||||||
|
>
|
||||||
|
Hel- eller halvdag är obligatoriskt
|
||||||
|
</digi-form-validation-message>
|
||||||
|
</div>
|
||||||
|
<ng-container *ngIf="showTimePicker">
|
||||||
|
<msfa-deltagare-time-picker
|
||||||
|
[timepickerFormGroup]="avvikelseFormGroup.get('timepickerFormGroup')"
|
||||||
|
[avvikelseFormGroup]="avvikelseFormGroup"
|
||||||
|
></msfa-deltagare-time-picker>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<digi-button
|
||||||
|
[attr.af-aria-label]="'Tillbaka till deltagarkortet'"
|
||||||
|
class="deltagare-avvikelse__go-back"
|
||||||
|
af-size="m"
|
||||||
|
af-variation="secondary"
|
||||||
|
(afOnClick)="goBack()"
|
||||||
|
>
|
||||||
|
Tillbaka</digi-button
|
||||||
|
>
|
||||||
|
|
||||||
|
<digi-button [attr.af-aria-label]="'Skapar en avvikelserapport'" [attr.af-type]="'submit'" af-size="m"
|
||||||
|
>Nästa</digi-button
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</digi-typography>
|
||||||
|
</section>
|
||||||
|
</msfa-layout>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
|
.deltagare-avvikelse {
|
||||||
|
&__deltagare,
|
||||||
|
&__alternative,
|
||||||
|
&__description,
|
||||||
|
&__datepicker,
|
||||||
|
&__dayOrPartOfDay {
|
||||||
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: var(--digi--typography--font-weight--semibold);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: var(--digi--layout--gutter--s) 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__alternative-heading {
|
||||||
|
font-size: var(--digi--typography--font-size--h3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__go-back {
|
||||||
|
margin-right: $digi--layout--gutter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
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 { LayoutComponent } from '@msfa-shared/components/layout/layout.component';
|
||||||
|
import { DeltagareAvvikelseComponent } from './deltagare-avvikelse.component';
|
||||||
|
|
||||||
|
|
||||||
|
describe('DeltagareAvvikelseComponent', () => {
|
||||||
|
let component: DeltagareAvvikelseComponent;
|
||||||
|
let fixture: ComponentFixture<DeltagareAvvikelseComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareAvvikelseComponent, LayoutComponent],
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule,
|
||||||
|
HttpClientTestingModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DigiNgFormRadiobuttonGroupModule
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DeltagareAvvikelseComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
import { RadiobuttonModel } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { FormTextareaSize } from '@af/digi-ng/_form/form-textarea';
|
||||||
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { Alternative } from '@msfa-enums/alternative.enum';
|
||||||
|
import { DayOrPartOfDay } from '@msfa-enums/day-or-part-of-day.enum';
|
||||||
|
import { FranvaroOrsaksKodEnum } from '@msfa-enums/franvaro-orsak-kod.enum';
|
||||||
|
import { KandaOrsakerEnum } from '@msfa-enums/kanda-orsaker-kod.enum';
|
||||||
|
import { ContactInformationCompact } from '@msfa-models/api/contact-information.response.model';
|
||||||
|
import { AvvikelseAlternativ } from '@msfa-models/avvikelse-alternativ.model';
|
||||||
|
import { Avvikelse } from '@msfa-models/avvikelse.model';
|
||||||
|
import { FragorForAvvikelser } from '@msfa-models/fragor-for-avvikelser.model';
|
||||||
|
import { FranvaroAlternativ } from '@msfa-models/franvaro-alternativ.model';
|
||||||
|
import { OrsaksKoderAvvikelse } from '@msfa-models/orsaks-koder-avvikelse.model';
|
||||||
|
import { KandaAvvikelseKoder, OrsaksKoderFranvaro } from '@msfa-models/orsaks-koder-franvaro.model';
|
||||||
|
import {
|
||||||
|
AnnanKandOrsakeIsRequiredCheck,
|
||||||
|
DateIsRequiredCheck,
|
||||||
|
DayOrPartOfDayIsRequiredCheck,
|
||||||
|
DescriptionIsRequiredCheck,
|
||||||
|
EndTimeIsRequiredCheck,
|
||||||
|
MotiveringIsRequiredCheck,
|
||||||
|
OrsakerIsRequiredCheck, StartTimeIsRequiredCheck
|
||||||
|
} from '@msfa-utils/validators/avvikelse-form-validator';
|
||||||
|
import { RequiredValidator } from '@msfa-utils/validators/required.validator';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { first, map, switchMap } from 'rxjs/operators';
|
||||||
|
import { DeltagareAvvikelseService } from '../../services/deltagare-avvikelse.service';
|
||||||
|
import { avvikelseAlternatives, dayOrPartOfDay } from './report-alternatives';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'msfa-deltagare-avvikelse',
|
||||||
|
templateUrl: './deltagare-avvikelse.component.html',
|
||||||
|
styleUrls: ['./deltagare-avvikelse.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DeltagareAvvikelseComponent implements OnInit {
|
||||||
|
readonly alternativeFormControlName = 'alternative';
|
||||||
|
readonly descriptionFormControlName = 'description'
|
||||||
|
readonly dateFormControlName = 'date';
|
||||||
|
readonly dayOrPartOfDayFormControlName = 'dayOrPartOfDay';
|
||||||
|
readonly orsakerFormControlName = 'orsaker'
|
||||||
|
readonly andraKandaOrsakerFormControlName = 'andraKandaOrsaker';
|
||||||
|
readonly fraga1FormControlName = 'fraga1';
|
||||||
|
readonly fraga2FormControlName = 'fraga2';
|
||||||
|
readonly startTimeFormControlName = 'startTime';
|
||||||
|
readonly endTimeFormControlName = 'endTime';
|
||||||
|
|
||||||
|
contactInformation$: Observable<ContactInformationCompact> = this.activatedRoute.params
|
||||||
|
.pipe(
|
||||||
|
switchMap(({ deltagareId }) => this.deltagareAvvikelseService.getContactInformationCompact$(deltagareId))
|
||||||
|
)
|
||||||
|
franvaroOrsaker$: Observable<OrsaksKoderFranvaro[]>;
|
||||||
|
avvikelseOrsaker$: Observable<OrsaksKoderAvvikelse[]>;
|
||||||
|
andraKandaOrsaker$: Observable<KandaAvvikelseKoder[]>;
|
||||||
|
fragor1$: Observable<FragorForAvvikelser[]>;
|
||||||
|
fragor2$: Observable<FragorForAvvikelser[]>;
|
||||||
|
contactInformation: ContactInformationCompact;
|
||||||
|
sizeTextArea: FormTextareaSize.S;
|
||||||
|
todayDate = new Date().toISOString().slice(0, 10);
|
||||||
|
avvikelseAlternatives: RadiobuttonModel[] = avvikelseAlternatives;
|
||||||
|
dayOrPartOfDay: RadiobuttonModel[] = dayOrPartOfDay;
|
||||||
|
selectedOrsaksKod: string;
|
||||||
|
avvikelseFormGroup: FormGroup | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private deltagareAvvikelseService: DeltagareAvvikelseService,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private router: Router) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.contactInformation$
|
||||||
|
.pipe(
|
||||||
|
first(),
|
||||||
|
)
|
||||||
|
.subscribe(contactInformation => {
|
||||||
|
this.contactInformation = contactInformation;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.avvikelseFormGroup = new FormGroup({
|
||||||
|
alternative: new FormControl(null, [RequiredValidator()]),
|
||||||
|
description: new FormControl(''),
|
||||||
|
date: new FormControl(this.todayDate),
|
||||||
|
dayOrPartOfDay: new FormControl(null),
|
||||||
|
orsakerFormGroup: new FormGroup({
|
||||||
|
orsaker: new FormControl([]),
|
||||||
|
andraKandaOrsaker: new FormControl([])
|
||||||
|
}),
|
||||||
|
fragorFormGroup: new FormGroup({
|
||||||
|
fraga1: new FormControl(''),
|
||||||
|
fraga2: new FormControl('')
|
||||||
|
}),
|
||||||
|
timepickerFormGroup: new FormGroup({
|
||||||
|
startTime: new FormControl(''),
|
||||||
|
endTime: new FormControl('')
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
validators:
|
||||||
|
[
|
||||||
|
DescriptionIsRequiredCheck.CheckIfRequired('description', 'orsakerFormGroup', 'andraKandaOrsaker', KandaOrsakerEnum.AnnanOrsak),
|
||||||
|
DayOrPartOfDayIsRequiredCheck.CheckIfRequired('dayOrPartOfDay'),
|
||||||
|
OrsakerIsRequiredCheck.CheckIfRequired('orsakerFormGroup', 'orsaker'),
|
||||||
|
AnnanKandOrsakeIsRequiredCheck.CheckIfRequired('orsakerFormGroup', 'andraKandaOrsaker'),
|
||||||
|
DateIsRequiredCheck.CheckIfRequired('date'),
|
||||||
|
StartTimeIsRequiredCheck.CheckIfRequired('timepickerFormGroup', 'startTime'),
|
||||||
|
EndTimeIsRequiredCheck.CheckIfRequired('timepickerFormGroup', 'endTime'),
|
||||||
|
MotiveringIsRequiredCheck.CheckIfRequired('fraga1')
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
get alternativeFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get(this.alternativeFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get descriptionFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get(this.descriptionFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get dateFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get(this.dateFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get dayOrPartOfDayFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get(this.dayOrPartOfDayFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get orsakerFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get('orsakerFormGroup').get(this.orsakerFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get andraKandaOrsakerFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup?.get('orsakerFormGroup').get(this.andraKandaOrsakerFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get fraga1FormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup.get('fragorFormGroup').get(this.fraga1FormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get fraga2FormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup.get('fragorFormGroup').get(this.fraga2FormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get startTimeFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup.get('timepickerFormGroup').get(this.startTimeFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
get endTimeFormControl(): AbstractControl | undefined {
|
||||||
|
return this.avvikelseFormGroup.get('timepickerFormGroup').get(this.endTimeFormControlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
onFormSubmitted(): void {
|
||||||
|
if (this.avvikelseFormGroup.invalid) {
|
||||||
|
this.alternativeFormControl.markAsTouched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.avvikelseFormGroup.markAllAsTouched();
|
||||||
|
|
||||||
|
const postAvvikelse: Avvikelse = {
|
||||||
|
datum_for_rapportering: this.todayDate,
|
||||||
|
arbetssokande: {
|
||||||
|
personnummer: this.contactInformation.personnummer.toString(),
|
||||||
|
fornamn: this.contactInformation.fornamn.toString(),
|
||||||
|
efternamn: this.contactInformation.efternamn.toString()
|
||||||
|
},
|
||||||
|
sokandeId: +this.activatedRoute.snapshot.params['deltagareId']
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.alternativeFormControl.value as string === Alternative.AVVIKELSE) {
|
||||||
|
postAvvikelse['avvikelsealternativ'] = this.avvikelse;
|
||||||
|
} else if (this.alternativeFormControl.value as string == Alternative.FRANVARO) {
|
||||||
|
postAvvikelse['franvaro'] = this.franvaro;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deltagareAvvikelseService.createAvvikelse$(postAvvikelse, this.alternativeFormControl.value as string)
|
||||||
|
.subscribe({
|
||||||
|
next: () => this.avvikelseFormGroup.reset()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get franvaro(): FranvaroAlternativ {
|
||||||
|
return {
|
||||||
|
avvikelseorsakskod: this.orsakerFormControl.value as string,
|
||||||
|
datum: this.dateFormControl.value as string,
|
||||||
|
heldag: this.dayOrPartOfDayFormControl.value === DayOrPartOfDay.HELDAG ? true : false,
|
||||||
|
starttid: this.startTimeFormControl.value as string || '9:00',
|
||||||
|
sluttid: this.endTimeFormControl.value as string || '16:00',
|
||||||
|
forvantad_narvaro: {
|
||||||
|
starttid: '',
|
||||||
|
sluttid: ''
|
||||||
|
},
|
||||||
|
alternativ_for_kanda_orsaker: {
|
||||||
|
typ: this.andraKandaOrsakerFormControl.value as string || '',
|
||||||
|
motivering: this.descriptionFormControl.value as string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get avvikelse(): AvvikelseAlternativ {
|
||||||
|
return {
|
||||||
|
avvikelseorsakskod: this.orsakerFormControl.value as string,
|
||||||
|
frageformular: [
|
||||||
|
{
|
||||||
|
fraga: this.avvikelseFormGroup.get('orsakerFormGroup').get('orsaker').value as string + '_1',
|
||||||
|
svar: this.fraga1FormControl.value as string
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fraga: this.fraga2FormControl.value as string !== '' ?
|
||||||
|
this.avvikelseFormGroup.get('orsakerFormGroup').get('orsaker').value as string + '_2' : '',
|
||||||
|
svar: this.fraga2FormControl.value as string
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rapporteringsdatum: this.dateFormControl.value as string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setAlternative(): void {
|
||||||
|
if (this.alternativeFormControl.value as string == Alternative.FRANVARO) {
|
||||||
|
this.franvaroOrsaker$ = this.deltagareAvvikelseService.getOrsaksKoderFranvaro$();
|
||||||
|
this.andraKandaOrsaker$ = this.deltagareAvvikelseService.getAndraKandaOrsaker$();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.alternativeFormControl.value as string == Alternative.AVVIKELSE) {
|
||||||
|
this.avvikelseOrsaker$ = this.deltagareAvvikelseService.getOrsaksKoderAvvikelse$();
|
||||||
|
this.fragor1$ = this.deltagareAvvikelseService.getFragorForAvvikelser$()
|
||||||
|
.pipe(
|
||||||
|
map(fragor => fragor.filter(fraga => fraga.id.includes('_1'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.fragor2$ = this.deltagareAvvikelseService.getFragorForAvvikelser$()
|
||||||
|
.pipe(
|
||||||
|
map(fragor => fragor.filter(fraga => {
|
||||||
|
this.setIfRequiredDescription(fraga);
|
||||||
|
return fraga.id.includes('_2')
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clearControlOnAlternativeChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setIfRequiredDescription(fraga: FragorForAvvikelser) {
|
||||||
|
fraga.id === '19_2' || fraga.id === '20_2' ?
|
||||||
|
fraga.descriptionIsRequired = false :
|
||||||
|
fraga.descriptionIsRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOrsakerChanged(): void {
|
||||||
|
this.avvikelseFormGroup.markAsUntouched();
|
||||||
|
if (this.alternativeFormControl.value as string === Alternative.AVVIKELSE) {
|
||||||
|
this.selectedOrsaksKod = this.avvikelseFormGroup.get('orsakerFormGroup').get('orsaker').value as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.avvikelseFormGroup.get('orsakerFormGroup').get('orsaker').valueChanges
|
||||||
|
.subscribe(value => {
|
||||||
|
if (value !== null) {
|
||||||
|
this.avvikelseFormGroup.get('orsakerFormGroup').get('andraKandaOrsaker').reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get showDescription(): boolean {
|
||||||
|
return this.alternativeFormControl.value as string == Alternative.FRANVARO &&
|
||||||
|
+this.orsakerFormControl.value === FranvaroOrsaksKodEnum.AnnanKandOrsak &&
|
||||||
|
+this.andraKandaOrsakerFormControl.value === KandaOrsakerEnum.AnnanOrsak
|
||||||
|
}
|
||||||
|
|
||||||
|
get showFragor(): boolean {
|
||||||
|
return this.alternativeFormControl.value as string === Alternative.AVVIKELSE &&
|
||||||
|
this.orsakerFormControl.value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showDatePicker(): boolean {
|
||||||
|
return this.orsakerFormControl.value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showDayOrPartOfDayPicker(): boolean {
|
||||||
|
return this.alternativeFormControl.value as string === Alternative.FRANVARO && this.orsakerFormControl.value > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showTimePicker(): boolean {
|
||||||
|
return this.alternativeFormControl.value as string === Alternative.FRANVARO &&
|
||||||
|
this.dayOrPartOfDayFormControl.value as string === DayOrPartOfDay.DEL_AV_DAG
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearControlOnAlternativeChange(): void {
|
||||||
|
this.descriptionFormControl.setValue('');
|
||||||
|
this.fraga1FormControl.setValue('');
|
||||||
|
this.fraga2FormControl.setValue('');
|
||||||
|
this.dayOrPartOfDayFormControl.reset();
|
||||||
|
this.avvikelseFormGroup?.get('timepickerFormGroup').reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack(): void {
|
||||||
|
void this.router.navigate(['./deltagare']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { DigiNgFormTextareaModule } from '@af/digi-ng/_form/form-textarea';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||||
|
import { DeltagareFragorFormModule } from './components/deltagare-fragor-form/deltagare-fragor-form.module';
|
||||||
|
import { DeltagareOrsaksFormModule } from './components/deltagare-orsaks-form/deltagare-orsaks-form.module';
|
||||||
|
import { DeltagareTimePickerModule } from './components/deltagare-time-picker/deltagare-time-picker.module';
|
||||||
|
import { DeltagareAvvikelseComponent } from './deltagare-avvikelse.component';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
declarations: [DeltagareAvvikelseComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule.forChild([{ path: '', component: DeltagareAvvikelseComponent }]),
|
||||||
|
LayoutModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
DigiNgFormRadiobuttonGroupModule,
|
||||||
|
DigiNgFormDatepickerModule,
|
||||||
|
DigiNgFormTextareaModule,
|
||||||
|
DeltagareOrsaksFormModule,
|
||||||
|
DeltagareFragorFormModule,
|
||||||
|
DeltagareTimePickerModule
|
||||||
|
],
|
||||||
|
exports: [DeltagareAvvikelseComponent]
|
||||||
|
})
|
||||||
|
export class DeltagareAvvikelseModule { }
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Alternative } from '@msfa-enums/alternative.enum'
|
||||||
|
import { DayOrPartOfDay } from '@msfa-enums/day-or-part-of-day.enum'
|
||||||
|
import { RadiobuttonModel } from '@af/digi-ng/_form/form-radiobutton-group'
|
||||||
|
|
||||||
|
export const avvikelseAlternatives: RadiobuttonModel[] = [
|
||||||
|
{
|
||||||
|
label: 'Frånvaro',
|
||||||
|
value: Alternative.FRANVARO
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Avvikelse',
|
||||||
|
value: Alternative.AVVIKELSE
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export const dayOrPartOfDay: RadiobuttonModel[] = [{
|
||||||
|
label: 'Heldag',
|
||||||
|
value: DayOrPartOfDay.HELDAG
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Del av dag',
|
||||||
|
value: DayOrPartOfDay.DEL_AV_DAG
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { FranvaroOrsaksKodEnum } from '@msfa-enums/franvaro-orsak-kod.enum';
|
||||||
|
import { ContactInformationCompact } from '@msfa-models/api/contact-information.response.model';
|
||||||
|
import { Avvikelse } from '@msfa-models/avvikelse.model';
|
||||||
|
import { FragorForAvvikelser } from '@msfa-models/fragor-for-avvikelser.model';
|
||||||
|
import { OrsaksKoderAvvikelse } from '@msfa-models/orsaks-koder-avvikelse.model';
|
||||||
|
import { KandaAvvikelseKoder, OrsaksKoderFranvaro } from '@msfa-models/orsaks-koder-franvaro.model';
|
||||||
|
import { AvvikelseApiService } from '@msfa-services/api/avvikelse-api.service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class DeltagareAvvikelseService {
|
||||||
|
|
||||||
|
constructor(private avvikelseApiService: AvvikelseApiService) { }
|
||||||
|
|
||||||
|
public getOrsaksKoderFranvaro$(): Observable<OrsaksKoderFranvaro[]> {
|
||||||
|
return this.avvikelseApiService.getOrsaksKoderFranvaro$()
|
||||||
|
.pipe(
|
||||||
|
map((orsaksKoder: OrsaksKoderFranvaro[]) => this.sortOrsaksKoder(orsaksKoder))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOrsaksKoderAvvikelse$(): Observable<OrsaksKoderAvvikelse[]> {
|
||||||
|
return this.avvikelseApiService.getOrsaksKoderAvvikelse$();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAndraKandaOrsaker$(): Observable<KandaAvvikelseKoder[]> {
|
||||||
|
return this.avvikelseApiService.getAndraKandaOrsaker$();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFragorForAvvikelser$(): Observable<FragorForAvvikelser[]> {
|
||||||
|
return this.avvikelseApiService.getFragorForAvvikelser$();
|
||||||
|
}
|
||||||
|
|
||||||
|
public createAvvikelse$(avvikelse: Avvikelse, alternative: string): Observable<Avvikelse> {
|
||||||
|
return this.avvikelseApiService.createAvvikelse$(avvikelse, alternative);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getContactInformationCompact$(id: number): Observable<ContactInformationCompact> {
|
||||||
|
return this.avvikelseApiService.getContactInformation$(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sortOrsaksKoder(orsaksKoder: OrsaksKoderFranvaro[]): OrsaksKoderFranvaro[] {
|
||||||
|
orsaksKoder.map(orsak => {
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.Sjuk) {
|
||||||
|
orsak.index = 1;
|
||||||
|
}
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.Arbete) {
|
||||||
|
orsak.index = 3;
|
||||||
|
}
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.OkandOrsak) {
|
||||||
|
orsak.index = 6;
|
||||||
|
}
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.AnnanKandOrsak) {
|
||||||
|
orsak.index = 5;
|
||||||
|
}
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.VAB) {
|
||||||
|
orsak.index = 2;
|
||||||
|
}
|
||||||
|
if (+orsak.value == FranvaroOrsaksKodEnum.Utbildning) {
|
||||||
|
orsak.index = 4;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const sortedOrsaksKoder = orsaksKoder.sort((kodA, kodB) => kodA.index < kodB.index ? -1 : 1);
|
||||||
|
return sortedOrsaksKoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export enum Alternative {
|
||||||
|
FRANVARO = 'franvaro',
|
||||||
|
AVVIKELSE = 'avvikelse'
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export enum AvvikelseOrsaksKodEnum {
|
||||||
|
TackatNejTillInsatsEllerAktivitet = 19,
|
||||||
|
TackatNejTillErbjudetArbete = 20,
|
||||||
|
KanInteTillGodoGoraSigProgrammet = 21,
|
||||||
|
MisskottSigEllerStortVerksamheten = 22,
|
||||||
|
SerTillAttErbjudetArbeteInteKommerTillStand = 28
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export enum DayOrPartOfDay {
|
||||||
|
HELDAG = 'HELDAG',
|
||||||
|
DEL_AV_DAG = 'DEL_AV_DAG'
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export enum FranvaroOrsaksKodEnum {
|
||||||
|
Sjuk = 15,
|
||||||
|
Arbete = 16,
|
||||||
|
OkandOrsak = 17,
|
||||||
|
AnnanKandOrsak = 18,
|
||||||
|
VAB = 26,
|
||||||
|
Utbildning = 27,
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export enum KandaOrsakerEnum {
|
||||||
|
LakarbesokTandlakarbesok = 1,
|
||||||
|
Familjeangelagenhet = 2,
|
||||||
|
MoteMedMyndighet = 3,
|
||||||
|
Anstallningsintervju = 4,
|
||||||
|
AnnanOrsak = 5
|
||||||
|
}
|
||||||
@@ -9,3 +9,19 @@ export interface ContactInformationResponse {
|
|||||||
telekomadresser: PhoneNumberResponse[];
|
telekomadresser: PhoneNumberResponse[];
|
||||||
adresser: AddressResponse[];
|
adresser: AddressResponse[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ContactInformationCompact {
|
||||||
|
fornamn: string;
|
||||||
|
efternamn: string;
|
||||||
|
personnummer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapResponseToContactInformationCompact(data: ContactInformationResponse): ContactInformationCompact {
|
||||||
|
const { fornamn, efternamn, personnummer } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
fornamn,
|
||||||
|
efternamn,
|
||||||
|
personnummer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface FragorForAvvikelserResponse {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface KandaAvvikelseKoderResponse {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
export interface OrsakResponse {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface OrsaksKoderAvvikelseResponse {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
state: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface OrsaksKoderFranvaroResponse {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
state: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface Arbetssokande {
|
||||||
|
personnummer: string,
|
||||||
|
fornamn: string,
|
||||||
|
efternamn: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Fraga } from './fraga.model';
|
||||||
|
|
||||||
|
export interface AvvikelseAlternativ {
|
||||||
|
avvikelseorsakskod: string,
|
||||||
|
frageformular: Array<Fraga>,
|
||||||
|
rapporteringsdatum: string
|
||||||
|
}
|
||||||
36
apps/mina-sidor-fa/src/app/shared/models/avvikelse.model.ts
Normal file
36
apps/mina-sidor-fa/src/app/shared/models/avvikelse.model.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Arbetssokande } from './arbetssokande.model';
|
||||||
|
import { AvvikelseAlternativ } from './avvikelse-alternativ.model';
|
||||||
|
import { FranvaroAlternativ } from './franvaro-alternativ.model';
|
||||||
|
|
||||||
|
export interface Avvikelse {
|
||||||
|
datum_for_rapportering: string,
|
||||||
|
arbetssokande: Arbetssokande,
|
||||||
|
sokandeId: number;
|
||||||
|
avvikelsealternativ?: AvvikelseAlternativ,
|
||||||
|
franvaro?: FranvaroAlternativ
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvvikelseRequestData {
|
||||||
|
datum_for_rapportering: string,
|
||||||
|
arbetssokande: Arbetssokande,
|
||||||
|
sokandeId: number;
|
||||||
|
avvikelsealternativ: AvvikelseAlternativ,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FranvaroRequestData {
|
||||||
|
datum_for_rapportering: string,
|
||||||
|
arbetssokande: Arbetssokande,
|
||||||
|
sokandeId: number;
|
||||||
|
franvaro: FranvaroAlternativ
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapAvvikelseRequestDataToAvvikelse(data: AvvikelseRequestData): Avvikelse {
|
||||||
|
const { datum_for_rapportering, arbetssokande, sokandeId, avvikelsealternativ } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
datum_for_rapportering,
|
||||||
|
arbetssokande,
|
||||||
|
sokandeId,
|
||||||
|
avvikelsealternativ
|
||||||
|
}
|
||||||
|
}
|
||||||
4
apps/mina-sidor-fa/src/app/shared/models/fraga.model.ts
Normal file
4
apps/mina-sidor-fa/src/app/shared/models/fraga.model.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface Fraga {
|
||||||
|
fraga: string,
|
||||||
|
svar: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { FragorForAvvikelserResponse } from './api/fragor-for-avvikelser.response';
|
||||||
|
|
||||||
|
export interface FragorForAvvikelser {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
descriptionIsRequired?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapResponseToFragorForAvvikelser(data: FragorForAvvikelserResponse): FragorForAvvikelser {
|
||||||
|
const { name, id } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export interface FranvaroAlternativ {
|
||||||
|
avvikelseorsakskod: string;
|
||||||
|
datum: string;
|
||||||
|
heldag: boolean;
|
||||||
|
starttid: string;
|
||||||
|
sluttid: string;
|
||||||
|
forvantad_narvaro: {
|
||||||
|
starttid: string;
|
||||||
|
sluttid: string;
|
||||||
|
},
|
||||||
|
alternativ_for_kanda_orsaker: {
|
||||||
|
typ: string,
|
||||||
|
motivering: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { AvvikelseOrsaksKodEnum } from '@msfa-enums/avvikelse-orsak-kod.enum';
|
||||||
|
import { OrsaksKoderAvvikelseResponse } from './api/orsaks-koder-avvikelse.response.model';
|
||||||
|
|
||||||
|
export interface OrsaksKoderAvvikelse {
|
||||||
|
name: string;
|
||||||
|
value: AvvikelseOrsaksKodEnum;
|
||||||
|
state: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapResponseToOrsaksKoderAvvikelse(data: OrsaksKoderAvvikelseResponse): OrsaksKoderAvvikelse {
|
||||||
|
const { name, id, state } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
value: id,
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { AvvikelseOrsaksKodEnum } from '@msfa-enums/avvikelse-orsak-kod.enum';
|
||||||
|
import { KandaOrsakerEnum } from '@msfa-enums/kanda-orsaker-kod.enum';
|
||||||
|
import { KandaAvvikelseKoderResponse } from './api/kanda-avvikelse-koder.response.model';
|
||||||
|
import { OrsaksKoderFranvaroResponse } from './api/orsaks-koder-franvaro.response.model';
|
||||||
|
|
||||||
|
export interface OrsaksKoderFranvaro {
|
||||||
|
name: string;
|
||||||
|
value: AvvikelseOrsaksKodEnum | KandaOrsakerEnum;
|
||||||
|
state: number;
|
||||||
|
index?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KandaAvvikelseKoder {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapResponseToOrsaksKoderFranvaro(data: OrsaksKoderFranvaroResponse): OrsaksKoderFranvaro {
|
||||||
|
const { name, id, state } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
value: id,
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapResponseToAndraKandaOrsaker(data: KandaAvvikelseKoderResponse): KandaAvvikelseKoder {
|
||||||
|
const { name, id } = data;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
value: id
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Alternative } from '@msfa-enums/alternative.enum';
|
||||||
|
import { ErrorType } from '@msfa-enums/error-type.enum';
|
||||||
|
import { environment } from '@msfa-environment';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ContactInformationCompact,
|
||||||
|
ContactInformationResponse,
|
||||||
|
mapResponseToContactInformationCompact
|
||||||
|
} from '@msfa-models/api/contact-information.response.model';
|
||||||
|
import { FragorForAvvikelserResponse } from '@msfa-models/api/fragor-for-avvikelser.response';
|
||||||
|
import { KandaAvvikelseKoderResponse } from '@msfa-models/api/kanda-avvikelse-koder.response.model';
|
||||||
|
import { OrsaksKoderAvvikelseResponse } from '@msfa-models/api/orsaks-koder-avvikelse.response.model';
|
||||||
|
import { Avvikelse, AvvikelseRequestData, mapAvvikelseRequestDataToAvvikelse } from '@msfa-models/avvikelse.model';
|
||||||
|
import { errorToCustomError } from '@msfa-models/error/custom-error';
|
||||||
|
import { FragorForAvvikelser, mapResponseToFragorForAvvikelser } from '@msfa-models/fragor-for-avvikelser.model';
|
||||||
|
import { mapResponseToOrsaksKoderAvvikelse, OrsaksKoderAvvikelse } from '@msfa-models/orsaks-koder-avvikelse.model';
|
||||||
|
import {
|
||||||
|
KandaAvvikelseKoder,
|
||||||
|
mapResponseToAndraKandaOrsaker,
|
||||||
|
mapResponseToOrsaksKoderFranvaro,
|
||||||
|
OrsaksKoderFranvaro
|
||||||
|
} from '@msfa-models/orsaks-koder-franvaro.model';
|
||||||
|
import { ErrorService } from '@msfa-services/error.service';
|
||||||
|
import { Observable, of, throwError } from 'rxjs';
|
||||||
|
import { catchError, filter, map, take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class AvvikelseApiService {
|
||||||
|
|
||||||
|
private _apiBaseUrl = `${environment.api.url}`;
|
||||||
|
|
||||||
|
public getOrsaksKoderFranvaro$(): Observable<OrsaksKoderFranvaro[]> {
|
||||||
|
return this.httpClient.get<{ data: OrsaksKoderAvvikelseResponse[] }>(`${this._apiBaseUrl}/orsakskoderfranvaro`).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
map(({ data }) => data.map(orsak => mapResponseToOrsaksKoderFranvaro(orsak)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOrsaksKoderAvvikelse$(): Observable<OrsaksKoderAvvikelse[]> {
|
||||||
|
return this.httpClient.get<{ data: OrsaksKoderAvvikelseResponse[] }>(`${this._apiBaseUrl}/orsakskoderavvikelse`).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
map(({ data }) => data.map(avvikelse => mapResponseToOrsaksKoderAvvikelse(avvikelse)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAndraKandaOrsaker$(): Observable<KandaAvvikelseKoder[]> {
|
||||||
|
return this.httpClient.get<{ data: KandaAvvikelseKoderResponse[] }>(`${this._apiBaseUrl}/kandaavvikelsekoder`).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
map(({ data }) => data.map(annanKandOrsak => mapResponseToAndraKandaOrsaker(annanKandOrsak)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFragorForAvvikelser$(): Observable<FragorForAvvikelser[]> {
|
||||||
|
return this.httpClient.get<{ data: FragorForAvvikelserResponse[] }>(`${this._apiBaseUrl}/fragorforavvikelser`).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
map(({ data }) => data.map(fraga => mapResponseToFragorForAvvikelser(fraga)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getContactInformation$(id: number): Observable<ContactInformationCompact> {
|
||||||
|
return this.httpClient.get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/deltagare/${id}/contact`).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
map(({ data }) => mapResponseToContactInformationCompact(data),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public createAvvikelse$(avvikelse: Avvikelse, alternative: string): Observable<Avvikelse> {
|
||||||
|
|
||||||
|
return this.httpClient
|
||||||
|
.post<{ data: AvvikelseRequestData }>(`${this._apiBaseUrl}/${this.setEndPoint(alternative)}`, avvikelse).pipe(
|
||||||
|
filter(response => !!response?.data),
|
||||||
|
take(1),
|
||||||
|
map(({ data }) => mapAvvikelseRequestDataToAvvikelse(data)),
|
||||||
|
catchError(error => throwError({ message: error as string, type: ErrorType.API }))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private setEndPoint(alternative: string): string {
|
||||||
|
let endpoint = '';
|
||||||
|
|
||||||
|
switch (alternative) {
|
||||||
|
case Alternative.AVVIKELSE:
|
||||||
|
endpoint = 'avvikelse';
|
||||||
|
break;
|
||||||
|
case Alternative.FRANVARO:
|
||||||
|
endpoint = 'franvaro';
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient, private errorService: ErrorService) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
|
||||||
|
import { SortOrder } from '@msfa-enums/sort-order.enum';
|
||||||
|
import { environment } from '@msfa-environment';
|
||||||
|
import { AvropResponse } from '@msfa-models/api/avrop.response.model';
|
||||||
|
import { ContactInformationResponse } from '@msfa-models/api/contact-information.response.model';
|
||||||
|
import { DeltagareCompactApiResponse } from '@msfa-models/api/deltagare.response.model';
|
||||||
|
import { DisabilityResponse } from '@msfa-models/api/disability.response.model';
|
||||||
|
import { DriversLicenseResponse } from '@msfa-models/api/drivers-license.response.model';
|
||||||
|
import { EducationsResponse } from '@msfa-models/api/educations.response.model';
|
||||||
|
import { HighestEducationResponse } from '@msfa-models/api/highest-education.response.model';
|
||||||
|
import { Params } from '@msfa-models/api/params.model';
|
||||||
|
import { TranslatorResponse } from '@msfa-models/api/translator.response.model';
|
||||||
|
import { WorkExperiencesResponse } from '@msfa-models/api/work-experiences.response.model';
|
||||||
|
import { WorkLanguagesResponse } from '@msfa-models/api/work-languages.response.model';
|
||||||
|
import { Avrop, mapAvropResponseToAvrop } from '@msfa-models/avrop.model';
|
||||||
|
import { ContactInformation, mapResponseToContactInformation } from '@msfa-models/contact-information.model';
|
||||||
|
import {
|
||||||
|
Deltagare,
|
||||||
|
DeltagareCompact,
|
||||||
|
DeltagareCompactData,
|
||||||
|
mapResponseToDeltagareCompact
|
||||||
|
} from '@msfa-models/deltagare.model';
|
||||||
|
import { Disability, mapResponseToDisability } from '@msfa-models/disability.model';
|
||||||
|
import { DriversLicense, mapResponseToDriversLicense } from '@msfa-models/drivers-license.model';
|
||||||
|
import { Education, mapResponseToEducation } from '@msfa-models/education.model';
|
||||||
|
import { errorToCustomError } from '@msfa-models/error/custom-error';
|
||||||
|
import { HighestEducation, mapResponseToHighestEducation } from '@msfa-models/highest-education.model';
|
||||||
|
import { Sort } from '@msfa-models/sort.model';
|
||||||
|
import { mapResponseToWorkExperience, WorkExperience } from '@msfa-models/work-experience.model';
|
||||||
|
import { ErrorService } from '@msfa-services/error.service';
|
||||||
|
import { sortFromToDates } from '@msfa-utils/sort.util';
|
||||||
|
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
|
||||||
|
import { catchError, filter, map, switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class DeltagareApiService extends UnsubscribeDirective {
|
||||||
|
private _apiBaseUrl = `${environment.api.url}/deltagare`;
|
||||||
|
private _currentDeltagareId$ = new BehaviorSubject<string>(null);
|
||||||
|
private _limit$ = new BehaviorSubject<number>(20);
|
||||||
|
private _page$ = new BehaviorSubject<number>(1);
|
||||||
|
private _sort$ = new BehaviorSubject<Sort<keyof DeltagareCompact>>({ key: 'fullName', order: SortOrder.ASC });
|
||||||
|
public sort$: Observable<Sort<keyof DeltagareCompact>> = this._sort$.asObservable();
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient, private errorService: ErrorService) {
|
||||||
|
super();
|
||||||
|
super.unsubscribeOnDestroy(
|
||||||
|
this._currentDeltagareId$
|
||||||
|
.pipe(
|
||||||
|
filter(currentDeltagareId => !!currentDeltagareId),
|
||||||
|
switchMap(currentDeltagareId => this._fetchDeltagare$(currentDeltagareId))
|
||||||
|
)
|
||||||
|
.subscribe(deltagare => {
|
||||||
|
this._deltagare$.next(deltagare);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _deltagare$ = new BehaviorSubject<Deltagare>(null);
|
||||||
|
public deltagare$: Observable<Deltagare> = this._deltagare$.asObservable();
|
||||||
|
|
||||||
|
public allDeltagareData$: Observable<DeltagareCompactData> = combineLatest([
|
||||||
|
this._limit$,
|
||||||
|
this._page$,
|
||||||
|
this._sort$,
|
||||||
|
]).pipe(switchMap(([limit, page, sort]) => this._fetchAllDeltagare$(limit, page, sort)));
|
||||||
|
|
||||||
|
public setSort(newSortKey: keyof DeltagareCompact): void {
|
||||||
|
const currentSort = this._sort$.getValue();
|
||||||
|
const order =
|
||||||
|
currentSort.key === newSortKey && currentSort.order === SortOrder.ASC ? SortOrder.DESC : SortOrder.ASC;
|
||||||
|
|
||||||
|
this._sort$.next({ key: newSortKey, order });
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPage(page: number): void {
|
||||||
|
this._page$.next(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchAllDeltagare$(
|
||||||
|
limit: number,
|
||||||
|
page: number,
|
||||||
|
sort: Sort<keyof DeltagareCompact>
|
||||||
|
): Observable<DeltagareCompactData> {
|
||||||
|
const params: Params = {
|
||||||
|
sort: sort.key as string,
|
||||||
|
order: sort.order as string,
|
||||||
|
limit: limit.toString(),
|
||||||
|
page: page.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.httpClient
|
||||||
|
.get<DeltagareCompactApiResponse>(this._apiBaseUrl, {
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
map(({ data, meta }) => {
|
||||||
|
return { data: data.map(deltagare => mapResponseToDeltagareCompact(deltagare)), meta };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setCurrentDeltagareId(currentDeltagareId: string): void {
|
||||||
|
this._deltagare$.next(null);
|
||||||
|
this._currentDeltagareId$.next(currentDeltagareId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchContactInformation$(id: string): Observable<ContactInformation | Partial<ContactInformation>> {
|
||||||
|
return this.httpClient.get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/${id}/contact`).pipe(
|
||||||
|
map(({ data }) => mapResponseToContactInformation(data)),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchDriversLicense$(id: string): Observable<DriversLicense | Partial<DriversLicense>> {
|
||||||
|
return this.httpClient.get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/${id}/driverlicense`).pipe(
|
||||||
|
map(({ data }) => mapResponseToDriversLicense(data)),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchHighestEducation$(id: string): Observable<HighestEducation | Partial<HighestEducation>> {
|
||||||
|
return this.httpClient
|
||||||
|
.get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/${id}/educationlevels/highest`)
|
||||||
|
.pipe(
|
||||||
|
map(({ data }) => mapResponseToHighestEducation(data)),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchEducations$(id: string): Observable<Education[]> {
|
||||||
|
return this.httpClient.get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/${id}/educations`).pipe(
|
||||||
|
map(({ data }) =>
|
||||||
|
data.utbildningar
|
||||||
|
? data.utbildningar.sort((a, b) =>
|
||||||
|
sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom })
|
||||||
|
)
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
map(educations => educations.map(utbildning => mapResponseToEducation(utbildning))),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchTranslator$(id: string): Observable<string> {
|
||||||
|
return this.httpClient.get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/${id}/translator`).pipe(
|
||||||
|
map(({ data }) => data.sprak?.beskrivning || null),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of('');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchWorkLanguages$(id: string): Observable<string[]> {
|
||||||
|
return this.httpClient.get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/${id}/work/languages`).pipe(
|
||||||
|
map(({ data }) => data?.sprak?.map(sprak => sprak.beskrivning) || []),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchDisabilities$(id: string): Observable<Disability[]> {
|
||||||
|
return this.httpClient.get<{ data: DisabilityResponse[] }>(`${this._apiBaseUrl}/${id}/work/disabilities`).pipe(
|
||||||
|
map(({ data }) => data?.map(funktionsnedsattning => mapResponseToDisability(funktionsnedsattning)) || []),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchWorkExperiences$(id: string): Observable<WorkExperience[]> {
|
||||||
|
return this.httpClient.get<{ data: WorkExperiencesResponse }>(`${this._apiBaseUrl}/${id}/work/experiences`).pipe(
|
||||||
|
map(
|
||||||
|
({ data }) =>
|
||||||
|
data?.arbetslivserfarenheter?.sort((a, b) =>
|
||||||
|
sortFromToDates({ from: a.period_from, to: a.period_tom }, { from: b.period_from, to: b.period_tom })
|
||||||
|
) || []
|
||||||
|
),
|
||||||
|
map(workExperiences => workExperiences.map(erfarenhet => mapResponseToWorkExperience(erfarenhet))),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _fetchAvropInformation$(id: string): Observable<Avrop | Partial<Avrop>> {
|
||||||
|
return this.httpClient.get<{ data: AvropResponse }>(`${this._apiBaseUrl}/${id}/avrop`).pipe(
|
||||||
|
map(({ data }) => (data ? mapAvropResponseToAvrop(data) : {})),
|
||||||
|
catchError(error => {
|
||||||
|
this.errorService.add(errorToCustomError(error));
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// As TypeScript has some limitations regarding combining Observables this way,
|
||||||
|
// we need to type it manually when exceeding 6 Observables inside a combineLatest.
|
||||||
|
// Read: https://github.com/ReactiveX/rxjs/issues/3601#issuecomment-384711601
|
||||||
|
private _fetchDeltagare$(id: string): Observable<Deltagare> {
|
||||||
|
return combineLatest([
|
||||||
|
this._fetchContactInformation$(id),
|
||||||
|
this._fetchDriversLicense$(id),
|
||||||
|
this._fetchHighestEducation$(id),
|
||||||
|
this._fetchEducations$(id),
|
||||||
|
this._fetchTranslator$(id),
|
||||||
|
this._fetchWorkLanguages$(id),
|
||||||
|
this._fetchDisabilities$(id),
|
||||||
|
this._fetchWorkExperiences$(id),
|
||||||
|
this._fetchAvropInformation$(id),
|
||||||
|
]).pipe(
|
||||||
|
map(
|
||||||
|
([
|
||||||
|
contactInformation,
|
||||||
|
driversLicense,
|
||||||
|
highestEducation,
|
||||||
|
educations,
|
||||||
|
translator,
|
||||||
|
workLanguages,
|
||||||
|
disabilities,
|
||||||
|
workExperiences,
|
||||||
|
avropInformation,
|
||||||
|
]: [
|
||||||
|
ContactInformation,
|
||||||
|
DriversLicense,
|
||||||
|
HighestEducation,
|
||||||
|
Education[],
|
||||||
|
string,
|
||||||
|
string[],
|
||||||
|
Disability[],
|
||||||
|
WorkExperience[],
|
||||||
|
Avrop
|
||||||
|
]) => ({
|
||||||
|
id,
|
||||||
|
...contactInformation,
|
||||||
|
driversLicense,
|
||||||
|
highestEducation,
|
||||||
|
educations,
|
||||||
|
translator,
|
||||||
|
workLanguages,
|
||||||
|
disabilities,
|
||||||
|
workExperiences,
|
||||||
|
avropInformation,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||||
|
import { Alternative } from '@msfa-enums/alternative.enum';
|
||||||
|
import { DayOrPartOfDay } from '@msfa-enums/day-or-part-of-day.enum';
|
||||||
|
import { FranvaroOrsaksKodEnum } from '@msfa-enums/franvaro-orsak-kod.enum';
|
||||||
|
import { KandaOrsakerEnum } from '@msfa-enums/kanda-orsaker-kod.enum';
|
||||||
|
|
||||||
|
export class DescriptionIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
controlToValidateName: string,
|
||||||
|
nestedFormGroupName: string,
|
||||||
|
nestedFormGroupControlName: string,
|
||||||
|
valueForWhichTheControlShouldBeRequired: KandaOrsakerEnum
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfControlToValidate = fg?.get(controlToValidateName)?.value as string;
|
||||||
|
const valueOfNestedFormControl = fg?.get(nestedFormGroupName)?.get(nestedFormGroupControlName)?.value as string;
|
||||||
|
const isRequired = +valueOfNestedFormControl === valueForWhichTheControlShouldBeRequired && valueOfControlToValidate === '';
|
||||||
|
|
||||||
|
return isRequired ? { descriptionIsRequired: true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DayOrPartOfDayIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
controlToValidateName: string,
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfControlToValidate = fg?.get(controlToValidateName)?.value as string;
|
||||||
|
const isRequired = valueOfControlToValidate === null && fg?.get('alternative').value === Alternative.FRANVARO;
|
||||||
|
|
||||||
|
return isRequired ? { dayOrPartOfDayIsRequired: true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OrsakerIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
nestedFormGroupName: string,
|
||||||
|
controlToValidateName: string,
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfNestedFormControl = fg?.get(nestedFormGroupName)?.get(controlToValidateName)?.value as string;
|
||||||
|
const isRequired = valueOfNestedFormControl === null && fg?.get(nestedFormGroupName)?.get('andraKandaOrsaker')?.value === null;
|
||||||
|
|
||||||
|
return isRequired ? { orsakerIsRequired: true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AnnanKandOrsakeIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
nestedFormGroupName: string,
|
||||||
|
controlToValidateName: string,
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfNestedFormControl = fg?.get(nestedFormGroupName)?.get(controlToValidateName)?.value as string;
|
||||||
|
const isRequired = +fg?.get(nestedFormGroupName).get('orsaker').value === FranvaroOrsaksKodEnum.AnnanKandOrsak &&
|
||||||
|
valueOfNestedFormControl === null;
|
||||||
|
|
||||||
|
return isRequired ? { annanKandorsakIsRequired: true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StartTimeIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
nestedFormGroupName: string,
|
||||||
|
startTimeControlToValidateName: string,
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfStartTimeFormControl = fg?.get(nestedFormGroupName)?.get(startTimeControlToValidateName)?.value as string;
|
||||||
|
const isRequired = fg?.get('alternative')?.value as string === Alternative.FRANVARO &&
|
||||||
|
fg?.get('dayOrPartOfDay').value === DayOrPartOfDay.DEL_AV_DAG && !valueOfStartTimeFormControl;
|
||||||
|
|
||||||
|
return isRequired ? { startTimeIsRequired: true } : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EndTimeIsRequiredCheck {
|
||||||
|
static CheckIfRequired(
|
||||||
|
nestedFormGroupName: string,
|
||||||
|
endTimeControlToValidateName: string
|
||||||
|
): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfEndTimeFormControl = fg?.get(nestedFormGroupName)?.get(endTimeControlToValidateName)?.value as string;
|
||||||
|
const isRequired = fg?.get('alternative').value as string === Alternative.FRANVARO &&
|
||||||
|
fg?.get('dayOrPartOfDay').value === DayOrPartOfDay.DEL_AV_DAG && !valueOfEndTimeFormControl;
|
||||||
|
|
||||||
|
return isRequired ? { endTimeIsRequired: true } : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MotiveringIsRequiredCheck {
|
||||||
|
static CheckIfRequired(controlToValidateName: string): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: boolean } => {
|
||||||
|
const valueOfControlToValidate = fg?.get('fragorFormGroup').get(controlToValidateName)?.value as string;
|
||||||
|
const isRequired = fg?.get('alternative').value as string === Alternative.AVVIKELSE && valueOfControlToValidate === '';
|
||||||
|
|
||||||
|
return isRequired ? { motiveringIsRequired: true } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class DateIsRequiredCheck {
|
||||||
|
static CheckIfRequired(controlToValidateName: string): ValidatorFn {
|
||||||
|
return (fg: AbstractControl): { [key: string]: string } => {
|
||||||
|
const valueOfControlToValidate = fg?.get(controlToValidateName).value as string;
|
||||||
|
const isRequired = valueOfControlToValidate === '';
|
||||||
|
|
||||||
|
return isRequired ? { dateIsRequired: 'Datum är obligatoriskt' } : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function generateAndraKandaOrsaker() {
|
||||||
|
const andraKandaOrsaker = [
|
||||||
|
{ name: 'Läkarbesök/Tandläkarbesök', id: 1 },
|
||||||
|
{ name: 'Familjeangelägenhet', id: 2 },
|
||||||
|
{ name: 'Möte med myndighet', id: 3 },
|
||||||
|
{ name: 'Anställningsintervju', id: 4 },
|
||||||
|
{ name: 'Annan orsak', id: 5 },
|
||||||
|
];
|
||||||
|
|
||||||
|
console.info('AndraKandaOrsaker generated...');
|
||||||
|
|
||||||
|
return andraKandaOrsaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
generate: generateAndraKandaOrsaker,
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function generateAvvikelseOrsaker() {
|
||||||
|
const avvikelseOrsaker = [
|
||||||
|
{ name: 'Tackat nej till insats eller aktivitet', id: 19 },
|
||||||
|
{ name: 'Tackat nej till erbjudet arbete', id: 20 },
|
||||||
|
{ name: 'Misskött sig eller stört verksamheten', id: 22 },
|
||||||
|
{ name: 'Kan inte tillgodogöra sig programmet', id: 21 },
|
||||||
|
{ name: 'Ser till att erbjudet arbete inte kommer till stånd', id: 28 },
|
||||||
|
];
|
||||||
|
|
||||||
|
console.info('AvvikelseOrsaker generated...');
|
||||||
|
|
||||||
|
return avvikelseOrsaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
generate: generateAvvikelseOrsaker,
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
function generateFragorForAvvikelser() {
|
||||||
|
const fragaForAvvikelseOrsak = [
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.TackatNejTillInsatsEllerAktivitet
|
||||||
|
name: 'Vilken insats eller aktivitet har deltagaren tackat nej till? Obligatoriskt',
|
||||||
|
id: '19.1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.TackatNejTillInsatsEllerAktivitet
|
||||||
|
name: 'Motivering som deltagaren angett',
|
||||||
|
id: '19.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.TackatNejTillErbjudetArbete
|
||||||
|
name: 'Vilket arbete har deltagaren tackat nej till? Obligatoriskt',
|
||||||
|
id: '20.1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.TackatNejTillErbjudetArbete
|
||||||
|
name: 'Motivering som deltagaren angett',
|
||||||
|
id: '20.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.KanInteTillGodoGoraSigProgrammet
|
||||||
|
name: 'På vilket sätt kan deltagaren inte tillgodogöra sig programmet? Obigatoriskt',
|
||||||
|
id: '21.1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.KanInteTillGodoGoraSigProgrammet
|
||||||
|
name: 'Vad har ni gjort för att stötta deltagaren/anpassa programmet?',
|
||||||
|
id: '21.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.MisskottSigEllerStortVerksamheten
|
||||||
|
name: 'På vilket sätt har deltagaren misskött sig eller stört verksamheten? Obligatoriskt',
|
||||||
|
id: '22.1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnum.MisskottSigEllerStortVerksamheten
|
||||||
|
name: 'Hur har ni försökt lösa problemet? Obligatoriskt',
|
||||||
|
id: '22.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AvvikelseOrsaksKodEnumSerTillAttErbjudetArbeteInteKommerTillStand
|
||||||
|
name: 'På vilket sätt har deltagaren agerat för att inte få ett arbete?',
|
||||||
|
id: '28.1',
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
console.info('FragaForAvvikelseOrsak generated...');
|
||||||
|
|
||||||
|
return fragaForAvvikelseOrsak;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
generate: generateFragorForAvvikelser,
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
function generateFranvaroOrsaker() {
|
||||||
|
const franvaroOrsaker = [
|
||||||
|
{ name: 'Sjuk', id: 15 },
|
||||||
|
{ name: 'VAB', id: 23 },
|
||||||
|
{ name: 'Arbete', id: 16 },
|
||||||
|
{ name: 'Utbildning', id: 24 },
|
||||||
|
{ name: 'Annan känd orsak', id: 18 },
|
||||||
|
{ name: 'Okänd orsak', id: 17 },
|
||||||
|
];
|
||||||
|
|
||||||
|
console.info('FranvaroOrsaker generated...');
|
||||||
|
|
||||||
|
return franvaroOrsaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
generate: generateFranvaroOrsaker,
|
||||||
|
};
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { authTokens } from './auth-tokens.js';
|
import { authTokens } from './auth-tokens.js';
|
||||||
import avrop from './avrop.js';
|
import avrop from './avrop.js';
|
||||||
|
import franvaroOrsaker from './avvikelse-alternative.js/franvaro-orsaker.js';
|
||||||
|
import avvikelseOrsaker from './avvikelse-alternative.js/avvikelse-orsaker.js';
|
||||||
|
import andraKandaOrsaker from './avvikelse-alternative.js/andra-kanda-orsaker.js';
|
||||||
|
import fragaForAvvikelseOrsak from './avvikelse-alternative.js/fraga-for-avvikelse-orsak.js';
|
||||||
import currentUser from './current-user.js';
|
import currentUser from './current-user.js';
|
||||||
import userinfo from './userinfo.js';
|
import userinfo from './userinfo.js';
|
||||||
import deltagare from './deltagare.js';
|
import deltagare from './deltagare.js';
|
||||||
@@ -30,6 +34,10 @@ const generatedUserinfo = {
|
|||||||
const avropTjanster = [];
|
const avropTjanster = [];
|
||||||
const utforandeVerksamheter = [];
|
const utforandeVerksamheter = [];
|
||||||
const avropKommuner = [];
|
const avropKommuner = [];
|
||||||
|
const generatedFranvaroOrsaker = franvaroOrsaker.generate();
|
||||||
|
const generateAvvikelseOrsaker = avvikelseOrsaker.generate();
|
||||||
|
const generateAndraKandaOrsaker = andraKandaOrsaker.generate();
|
||||||
|
const generatefragaForAvvikelseOrsak = fragaForAvvikelseOrsak.generate();
|
||||||
|
|
||||||
generatedAvrop.forEach(({ tjanstekod, tjansteNamn, utforandeVerksamhetId, utforandeverksamhet, kommunKod, kommun }) => {
|
generatedAvrop.forEach(({ tjanstekod, tjansteNamn, utforandeVerksamhetId, utforandeverksamhet, kommunKod, kommun }) => {
|
||||||
const tjanstExists = avropTjanster.find(tjanst => tjanst.id === tjanstekod);
|
const tjanstExists = avropTjanster.find(tjanst => tjanst.id === tjanstekod);
|
||||||
@@ -113,6 +121,10 @@ const apiData = {
|
|||||||
userinfo: generatedUserinfo,
|
userinfo: generatedUserinfo,
|
||||||
getTokenFullAccess: authTokens.auth_code_from_CIAM_with_all_permissions,
|
getTokenFullAccess: authTokens.auth_code_from_CIAM_with_all_permissions,
|
||||||
invites: [],
|
invites: [],
|
||||||
|
franvaroOrsaker: generatedFranvaroOrsaker,
|
||||||
|
avvikelseOrsaker: generateAvvikelseOrsaker,
|
||||||
|
andraKandaOrsaker: generateAndraKandaOrsaker,
|
||||||
|
fragaForAvvikelseOrsaker: generatefragaForAvvikelseOrsak,
|
||||||
minaDeltagare: chooseRandom(generatedAvrop, 3),
|
minaDeltagare: chooseRandom(generatedAvrop, 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ server.use(
|
|||||||
'/deltagare?*': '/avrop?$1',
|
'/deltagare?*': '/avrop?$1',
|
||||||
'/deltagare/:sokandeId/avrop': '/avrop?sokandeId=:sokandeId',
|
'/deltagare/:sokandeId/avrop': '/avrop?sokandeId=:sokandeId',
|
||||||
'/deltagare/:sokandeId/*': '/deltagare/:sokandeId',
|
'/deltagare/:sokandeId/*': '/deltagare/:sokandeId',
|
||||||
|
'/franvaro/franvaroOrsaker': '/franvaroOrsaker',
|
||||||
|
'/avvikelse/avvikelseOrsaker': '/avvikelseOrsaker',
|
||||||
|
'/andraKandaOrsaker': '/andraKandaOrsaker',
|
||||||
|
'/fragaForAvvikelseOrsaker': '/fragaForAvvikelseOrsaker',
|
||||||
'*page=*': '$1_page=$2',
|
'*page=*': '$1_page=$2',
|
||||||
'*limit=*': '$1_limit=$2',
|
'*limit=*': '$1_limit=$2',
|
||||||
'*sort=*': '$1_sort=$2',
|
'*sort=*': '$1_sort=$2',
|
||||||
|
|||||||
Reference in New Issue
Block a user