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: f1ad09a 2a37566
Author: 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: ff4011c 92272e4
Author: 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:
Nicolas Fuentes Maturana
2021-09-16 18:04:37 +02:00
parent fc2916fb0d
commit 1b281be531
57 changed files with 1818 additions and 77 deletions

View File

@@ -15,7 +15,8 @@ const routes: Routes = [
{
path: 'rapportera/:deltagareId',
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',
@@ -31,4 +32,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DeltagareRoutingModule {}
export class DeltagareRoutingModule { }

View File

@@ -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>

View File

@@ -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();
});
});

View File

@@ -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 {
}

View File

@@ -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 { }

View File

@@ -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>

View File

@@ -0,0 +1,7 @@
@import 'variables/gutters';
.fragor-form {
&__content {
margin-bottom: $digi--layout--gutter--xl;
}
}

View File

@@ -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();
});
});

View File

@@ -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;
}

View File

@@ -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 { }

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -0,0 +1,7 @@
@import 'variables/gutters';
.orsaks-form {
&__content {
margin-bottom: $digi--layout--gutter--xl;
}
}

View File

@@ -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();
});
});

View File

@@ -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;
}
}

View File

@@ -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 { }

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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();
});
});

View File

@@ -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;
}

View File

@@ -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 { }

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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();
});
});

View File

@@ -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']);
}
}

View File

@@ -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 { }

View File

@@ -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
}
]

View File

@@ -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;
}
}