feat(employee): Now possible to submit edit employee form. (TV-513)

Squashed commit of the following:

commit fc79d20601988735b407a54009426e10e233df39
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 13:24:30 2021 +0200

    Small fixes

commit bc8741bab9b3161d356d1375b7ab869b202a8195
Merge: 1ad9db8 cac0515
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 13:16:21 2021 +0200

    Merged develop

commit 1ad9db87e7f1f19fdb2cd3e2cfcc17e08c9ccfef
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 12:49:37 2021 +0200

    Stylechanges

commit 5a3b863f87f956ed90564fecbef9abe9460558bd
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 11:26:35 2021 +0200

    Now possible to edit employee-accounts

commit 0677f2ebeee12adeba6cb65a673781dea7a6c06d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 10:05:35 2021 +0200

    Updated models to include new structure

commit 76bde9e0afbbf44a09348ee8e4849b4816b0c39d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Sep 7 08:43:25 2021 +0200

    edit employee

commit c8cf93b6bbeef0a3b4b6f141f36aea7ea86f399e
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 16:22:46 2021 +0200

    WIP

commit fe5cff4aa209c4da0025ebfb70b79d6a95c8d1f1
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 15:46:26 2021 +0200

    Fixed issue not fetching new utforande verksamheter on page load

commit c997dbe80c8f9f5ec84aad2ac18805918b7ab6f5
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 15:35:34 2021 +0200

    Added scrollPositionRestoration

commit 58ee0147ff553f2a97fdf143ddcbdf1b0241d26f
Merge: 27b595c 9a73ffe
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 15:30:08 2021 +0200

    Merge branch 'develop' into feature/TV-513

commit 27b595cbf94dc1d95ad32a0da1943e2e6fce61c4
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 14:28:10 2021 +0200

    WIP

commit 81cb9df1869784a80f6747ac68bfdc81ae5d777a
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Sep 6 13:21:41 2021 +0200

    Fixed roles
This commit is contained in:
Erik Tiekstra
2021-09-07 13:26:46 +02:00
parent cac0515c9c
commit bb4d88a8e0
37 changed files with 386 additions and 359 deletions

View File

@@ -9,12 +9,12 @@ const routes: Routes = [
},
{
path: 'personal',
data: { title: 'Personalinformation' },
data: { title: 'Hantera personal' },
loadChildren: () => import('./pages/employees/employees.module').then(m => m.EmployeesModule),
},
{
path: 'personal/:employeeId',
data: { title: 'Personalinformation' },
data: { title: 'Personalkonto' },
loadChildren: () => import('./pages/employee-card/employee-card.module').then(m => m.EmployeeCardModule),
},
{

View File

@@ -1,6 +1,18 @@
<msfa-layout>
<section class="employee-card">
<digi-typography *ngIf="employee$ | async as employee; else loadingRef">
<ng-container *ngIf="lastUpdatedEmployeeId$ | async as lastUpdatedEmployeeId">
<digi-notification-alert
*ngIf="employee.id === lastUpdatedEmployeeId"
af-variation="success"
af-heading="Allt gick bra"
af-heading-level="h2"
[afCloseable]="true"
(afOnClose)="closeUpdatedNotificationAlert()"
>
<p>Personalkontot för {{employee.fullName}} har uppdaterats.</p>
</digi-notification-alert>
</ng-container>
<header class="employee-card__header">
<a class="employee-card__edit-button" [routerLink]="['/administration/redigera-personalkonto', employee.id]"
>Redigera</a

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Employee } from '@msfa-models/employee.model';
import { Role } from '@msfa-models/role.model';
@@ -11,16 +11,30 @@ import { BehaviorSubject, Observable } from 'rxjs';
styleUrls: ['./employee-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EmployeeCardComponent {
export class EmployeeCardComponent implements OnDestroy {
private _employeeId$ = new BehaviorSubject<string>(this.activatedRoute.snapshot.params['employeeId']);
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
employee$: Observable<Employee> = this.employeeService.employee$;
lastUpdatedEmployeeId$: Observable<string> = this.employeeService.lastUpdatedEmployeeId$;
allRoles: Role[] = this.employeeService.allRoles;
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
this.employeeService.setCurrentEmployeeId(this.activatedRoute.snapshot.params.employeeId);
this.employeeService.setCurrentEmployeeId(this.employeeId);
}
ngOnDestroy(): void {
this.employeeService.resetLastUpdatedEmployeeId();
}
get employeeId(): string {
return this._employeeId$.getValue();
}
get pendingSelectedParticipants(): string[] {
return this._pendingSelectedParticipants$.getValue();
}
closeUpdatedNotificationAlert(): void {
this.employeeService.resetLastUpdatedEmployeeId();
}
}

View File

@@ -45,13 +45,14 @@
</p>
<div class="edit-employee-form__choose_all-utforande-verksamh">
<digi-ng-form-checkbox
[formControlName]="toggleAllUtforandeVerksamhetFormControlName"
[formControl]="toggleAllUtforandeVerksamhetFormControl"
[afLabel]="'Välj alla utförande verksamheter och alla utförande adresser'"
(afOnChange)="toggleAllUtforandeVerksamheter($event)"
>
</digi-ng-form-checkbox>
</div>
<msfa-tree-nodes-selector
*ngIf="!toggleAllUtforandeVerksamhetFormControl.value"
[headingText]="'Välj utförande verksamheter och adresser'"
[formControlName]="utforandeVerksamhetFormControlName"
[isInvalid]="utforandeVerksamhetFormControl?.invalid"
@@ -99,7 +100,10 @@
</fieldset>
<div class="edit-employee-form__footer">
<a class="edit-employee-form__link-btn edit-employee-form__link-btn--secondary" routerLink="/administration/">
<a
class="edit-employee-form__link-btn edit-employee-form__link-btn--secondary"
[routerLink]="['/administration/personal', employee.id]"
>
Avbryt
</a>
<digi-button af-type="submit">Spara ändringar</digi-button>

View File

@@ -1,19 +1,20 @@
import { ButtonSize, ButtonType, ButtonVariation } from '@af/digi-ng/_button/button';
import { FormSelectItem } from '@af/digi-ng/_form/form-select';
import {
Component,
OnInit,
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges,
SimpleChanges,
EventEmitter,
OnInit,
Output,
SimpleChanges,
} from '@angular/core';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { EmployeeEditRequest } from '@msfa-models/api/employee-edit.request.model';
import { Employee } from '@msfa-models/employee.model';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { FormSelectItem } from '@af/digi-ng/_form/form-select';
import { TreeNodeValidator } from '@msfa-utils/validators/tree-node.validator';
import {
UtforandeVerksamhet,
UtforandeVerksamheterService,
@@ -22,6 +23,9 @@ import {
TreeNode,
TreeNodesSelectorService,
} from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
import { EmailValidator } from '@msfa-utils/validators/email.validator';
import { RequiredValidator } from '@msfa-utils/validators/required.validator';
import { TreeNodeValidator } from '@msfa-utils/validators/tree-node.validator';
import { EmployeeFormService } from '../services/employee-form.service';
export interface EditEmployeeFormData {
@@ -38,15 +42,13 @@ export interface EditEmployeeFormData {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EditEmployeeFormComponent implements OnInit, OnChanges {
@Input() currentEmail: string;
@Input() employee: Employee;
@Input() availableRoles: Role[];
@Input() currentEmployeeRoles: string[];
@Input() availableTjanster: Tjanst[];
@Input() currentEmployeeTjanster: Tjanst[];
@Input() availableUtforandeVerksamheter: UtforandeVerksamhet[];
@Output() tjansterSelected = new EventEmitter<Tjanst[]>();
@Output() formSubmitted = new EventEmitter<EditEmployeeFormData>();
@Output() formSubmitted = new EventEmitter<EmployeeEditRequest>();
readonly ButtonVariation = ButtonVariation;
readonly ButtonType = ButtonType;
@@ -55,10 +57,9 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
readonly emailFormControlName = 'email';
readonly tjansterFormControlName = 'tjanster';
readonly utforandeVerksamhetFormControlName = 'utforandeVerksamheter';
readonly toggleAllUtforandeVerksamhetFormControlName = 'toggleAllUtforandeVerksamhet';
readonly toggleAllUtforandeVerksamhetFormControlName = 'allaUtforandeVerksamheter';
editEmployeeFormGroup: FormGroup | null = null;
rolesFormGroup: FormGroup | null = null;
displayRolesDialog = false;
@@ -68,11 +69,13 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
private employeeFormService: EmployeeFormService,
private utforandeVerksamheterService: UtforandeVerksamheterService,
private treeNodesSelectorService: TreeNodesSelectorService
) {}
) {
this.updateSelectableTjansterFormItems();
}
ngOnInit(): void {
this.initializeEditEmployeeFormGroup();
this.updateSelectableTjansterFormItems();
this.toggleTjanst();
}
ngOnChanges(changes: SimpleChanges): void {
@@ -96,24 +99,8 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
])
);
this.editEmployeeFormGroup.patchValue(
Object.fromEntries([[this.toggleAllUtforandeVerksamhetFormControlName, false]])
);
this.updateUtforandeVerksamhetStatus();
}
if (changes.currentEmployeeRoles) {
this.updateRolesFormGroup();
}
if (changes.currentEmail) {
this.editEmployeeFormGroup.patchValue(Object.fromEntries([[this.emailFormControlName, this.currentEmail]]));
}
if (changes.currentEmployeeTjanster) {
this.editEmployeeFormGroup.patchValue(Object.fromEntries([[this.tjansterFormControlName, '']]));
}
}
get emailFormControl(): AbstractControl | undefined {
@@ -124,6 +111,10 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
return this.editEmployeeFormGroup?.get(this.tjansterFormControlName);
}
get rolesFormGroup(): AbstractControl {
return this.editEmployeeFormGroup.get('roles');
}
get utforandeVerksamhetFormControl(): AbstractControl | undefined {
return this.editEmployeeFormGroup?.get(this.utforandeVerksamhetFormControlName);
}
@@ -150,45 +141,25 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
}
private initializeEditEmployeeFormGroup(): void {
this.rolesFormGroup = this.employeeFormService.getRolesFormGroup(this.availableRoles, this.currentEmployeeRoles);
this.editEmployeeFormGroup = new FormGroup({
// eslint-disable-next-line
email: new FormControl(this.currentEmail, [Validators.required, Validators.email]),
// eslint-disable-next-line
tjanster: new FormControl('', [Validators.required]),
roles: this.rolesFormGroup,
email: new FormControl(this.employee.email, [RequiredValidator('E-postadress'), EmailValidator()]),
tjanster: new FormControl(this.employee.tjanster[0]?.tjanstId, [RequiredValidator('Tjänst')]),
roles: this.employeeFormService.getRolesFormGroup(this.availableRoles, this.employee.roles),
utforandeVerksamheter: new FormControl(
this.utforandeVerksamheterService.getTreeNodeDataFromUtforandeVerksamheter(this.availableUtforandeVerksamheter),
[
// eslint-disable-next-line
TreeNodeValidator.IsValidTreeNode(
this.utforandeVerksamheterService.hasSelectedUtforandeVerksamhet,
'required'
),
]
),
toggleAllUtforandeVerksamhet: new FormControl(false, []),
allaUtforandeVerksamheter: new FormControl(this.employee.allaUtforandeVerksamheter),
});
this.updateUtforandeVerksamhetStatus();
}
private updateRolesFormGroup(): void {
if (!this.rolesFormGroup || !this.availableRoles) {
return;
}
this.rolesFormGroup.patchValue(
Object.fromEntries(
this.availableRoles.map(role => [
this.employeeFormService.getFormControlName(role),
this.employeeFormService.isSelectedRole(role, this.currentEmployeeRoles),
])
)
);
}
getFormControlName(role: Role): string {
return this.employeeFormService.getFormControlName(role);
}
@@ -206,21 +177,26 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
this.formSubmitted.emit({
email: this.emailFormControl?.value as string,
tjanster: this.employeeFormService.getSelectedTjanster(
this.availableTjanster,
parseInt(this.tjansterFormControl?.value, 10)
),
tjanstIds: this.employeeFormService
.getSelectedTjanster(this.availableTjanster, +this.tjansterFormControl?.value)
.map(tjanst => tjanst.tjanstId),
roles: this.employeeFormService.getRolesFromFormGroup(this.rolesFormGroup, this.availableRoles),
utforandeVerksamheter: this.utforandeVerksamheterService.getSelectedUtforandeVerksamheterFromTreeNode(
this.utforandeVerksamhetFormControl?.value
),
adressIds: this.toggleAllUtforandeVerksamhetFormControl.value
? []
: this.utforandeVerksamheterService.getSelectedAdressIdsFromTreeNode(
this.utforandeVerksamhetFormControl?.value
),
allaUtforandeVerksamheter: !!this.toggleAllUtforandeVerksamhetFormControl.value,
utforandeVerksamhetIds: [],
});
}
toggleTjanst(): void {
this.tjansterSelected.emit(
this.employeeFormService.getSelectedTjanster(this.availableTjanster, parseInt(this.tjansterFormControl.value, 10))
);
if (this.tjansterFormControl.value) {
this.tjansterSelected.emit(
this.employeeFormService.getSelectedTjanster(this.availableTjanster, +this.tjansterFormControl.value)
);
}
}
openRolesDialog(): void {

View File

@@ -2,7 +2,7 @@
<section class="employee-form" *ngIf="employee$ | async as employee">
<digi-typography>
<header class="employee-form__header">
<h1>{{ employee.fullName }}</h1>
<h1>Redigera personalkonto</h1>
<msfa-employee-delete [returnToEmployeeList]="true"></msfa-employee-delete>
<!-- <digi-button
class="employee-card__delete-account-button"
@@ -15,7 +15,6 @@
</header>
</digi-typography>
<!--### Personuppgifter ###-->
<div class="employee-form__block">
<digi-typography>
<h2>Personuppgifter</h2>
@@ -40,18 +39,13 @@
</digi-typography>
</ng-container>
</div>
<!-- Component för att hantera formuläret -->
<ng-container>
<msfa-edit-employee-form
[currentEmail]="employee?.email"
[availableRoles]="selectableRoles"
[currentEmployeeRoles]="currentEmployeeRoles$ | async"
[availableTjanster]="tjanster$ | async"
[currentEmployeeTjanster]="employee.tjanster"
[availableUtforandeVerksamheter]="availableUtforandeVerksamheter$ | async"
(tjansterSelected)="setupAvailableUtforandeVerksamheter($event)"
(formSubmitted)="updateEmployee($event)"
></msfa-edit-employee-form>
</ng-container>
<msfa-edit-employee-form
[employee]="employee"
[availableRoles]="availableRoles"
[availableTjanster]="tjanster$ | async"
[availableUtforandeVerksamheter]="availableUtforandeVerksamheter$ | async"
(tjansterSelected)="setupAvailableUtforandeVerksamheter($event)"
(formSubmitted)="updateEmployee($event)"
></msfa-edit-employee-form>
</section>
</msfa-layout>

View File

@@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { EmployeeEditRequest } from '@msfa-models/api/employee-edit.request.model';
import { Employee } from '@msfa-models/employee.model';
import { mapRoleResponseToRoleObject, Role } from '@msfa-models/role.model';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { EmployeeService } from '@msfa-services/api/employee.service';
import { TjanstService } from '@msfa-services/api/tjanst.service';
@@ -9,9 +10,8 @@ import {
UtforandeVerksamhet,
UtforandeVerksamheterService,
} from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { EditEmployeeFormData } from './edit-employee-form/edit-employee-form.component';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
@Component({
selector: 'msfa-employee-form',
@@ -20,40 +20,48 @@ import { EditEmployeeFormData } from './edit-employee-form/edit-employee-form.co
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EmployeeFormComponent implements OnInit {
private _employeeId$ = new BehaviorSubject<string>(this.activatedRoute.snapshot.params['employeeId']);
private _selectedTjanstIds$ = new BehaviorSubject<number[]>(null);
employee$ = this.employeeService.employee$;
tjanster$: Observable<Tjanst[]> = this.tjanstService.tjanster$;
currentEmployeeRoles$: Observable<string[] | undefined | null> = null;
availableUtforandeVerksamheter$: Observable<Array<UtforandeVerksamhet>> | null = null;
availableUtforandeVerksamheter$: Observable<UtforandeVerksamhet[]> = this._selectedTjanstIds$.pipe(
filter(selectedTjanstIds => !!selectedTjanstIds?.length),
switchMap(selectedTjanstIds => this.utforandeVerksamheterService.getUtforandeVerksamheter(selectedTjanstIds))
);
selectableRoles: Role[] = this.employeeService.allRoles;
availableRoles: Role[] = this.employeeService.allRoles;
constructor(
private employeeService: EmployeeService,
private tjanstService: TjanstService,
private utforandeVerksamheterService: UtforandeVerksamheterService,
private activatedRoute: ActivatedRoute
private activatedRoute: ActivatedRoute,
private router: Router
) {}
get employeeId(): string {
return this._employeeId$.getValue();
}
ngOnInit(): void {
this.employeeService.setCurrentEmployeeId(this.activatedRoute.snapshot.params['employeeId']);
this.currentEmployeeRoles$ = this.employee$.pipe(
map(employee => employee?.roles?.map(role => mapRoleResponseToRoleObject(role)?.type))
);
this.employeeService.setCurrentEmployeeId(this.employeeId);
}
updateEmployee(editEmployeeFormData: EditEmployeeFormData): void {
console.log(editEmployeeFormData);
updateEmployee(employeeFormData: EmployeeEditRequest): void {
const updateEmployeeSubscription = this.employeeService
.updateEmployee$(this.employeeId, employeeFormData)
.subscribe({
next: () => {
void this.router.navigateByUrl(`/administration/personal/${this.employeeId}`);
},
complete: () => {
updateEmployeeSubscription.unsubscribe();
},
});
}
setupAvailableUtforandeVerksamheter(selectedTjanster: Array<Tjanst>): void {
if (!selectedTjanster) {
return;
}
this.availableUtforandeVerksamheter$ = this.utforandeVerksamheterService.getUtforandeVerksamheter(
selectedTjanster.map(tjanst => tjanst.tjanstId)
);
setupAvailableUtforandeVerksamheter(selectedTjanster: Tjanst[]): void {
this._selectedTjanstIds$.next(selectedTjanster.map(tjanst => tjanst.tjanstId));
}
setEmployeeToDelete(employee: Employee): void {
this.employeeService.setEmployeeToDelete(employee);

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { RoleEnum } from '@msfa-enums/role.enum';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
@@ -9,7 +9,7 @@ import { EmployeeValidator } from '@msfa-utils/validators/employee.validator';
providedIn: 'root',
})
export class EmployeeFormService {
isSelectedRole(role: Role, selectedRoles: Array<string> | null): boolean {
isSelectedRole(role: Role, selectedRoles: RoleEnum[]): boolean {
if (!selectedRoles || !role) {
return false;
}
@@ -29,15 +29,15 @@ export class EmployeeFormService {
return selectedTjanst ? [selectedTjanst] : [];
}
getRolesFromFormGroup(formGroup: FormGroup | null, roles: Array<Role> | null): Array<Role> {
getRolesFromFormGroup(formGroup: AbstractControl | null, roles: Array<Role> | null): Array<RoleEnum> {
if (!formGroup || !roles) {
return;
}
return roles.filter(role => formGroup.get(this.getFormControlName(role))?.value === true);
return roles.filter(role => formGroup.get(this.getFormControlName(role))?.value).map(role => role.type);
}
getRolesFormGroup(roles: Array<Role> | null, selectedRoles: Array<string> | null): FormGroup {
getRolesFormGroup(roles: Array<Role> | null, selectedRoles: RoleEnum[]): FormGroup {
if (!roles) {
return new FormGroup({});
}