feat(employee): Now showing utförande verksamheter/adresser and tjänster correctly. (TV-554)

Squashed commit of the following:

commit 3d1d4a33905f41028f97e7f86131e6e284aebba9
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Sep 8 11:51:06 2021 +0200

    Fixed some tests and linting

commit 651300f244f8ef3ca71f290de421033c05f4a1ca
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Sep 8 11:43:34 2021 +0200

    Some style changes

commit bc0762ba3fa36dc3b85ac3316d87a8a942fe30ee
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Sep 8 09:13:57 2021 +0200

    Fixed issue with edit employee after api changes

commit 757f69ddcdf3913fcbc967df3fdcf8cbb6ed3eb5
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Sep 8 08:48:44 2021 +0200

    Added tjänst and utforandeverksamheter/adresser to employee card
This commit is contained in:
Erik Tiekstra
2021-09-08 13:32:56 +02:00
parent e589eec505
commit 26a56fdf1f
28 changed files with 405 additions and 376 deletions

View File

@@ -17,11 +17,11 @@
<a class="employee-card__edit-button" [routerLink]="['/administration/redigera-personalkonto', employee.id]"
>Redigera</a
>
<h1>{{ employee.fullName }}</h1>
<h1>Personalkonto</h1>
</header>
<p>Här kan du se och ändra personalkontots behörigheter. Ändra behörighet genom att klicka på redigera.</p>
<p>Här ser ni personalkontot. Ändra behörighet genom att klicka på redigera.</p>
<div class="employee-card__contents">
<div class="employee-card__column">
<div class="employee-card__block">
<h2>Personuppgifter</h2>
<dl class="employee-card__description-list">
<dt>Förnamn</dt>
@@ -42,58 +42,67 @@
</dd>
</dl>
</div>
<div class="employee-card__column">
<h2>Tjänst</h2>
<div class="employee-card__block">
<h2>Behörigheter</h2>
<p>Här kan du se personalkontots behörigheter.</p>
</div>
<div class="employee-card__block">
<h3>Tjänst</h3>
<ul class="employee-card__list" *ngIf="employee.tjanster.length">
<li *ngFor="let tjanst of employee.tjanster">{{ tjanst.name }}</li>
<li *ngFor="let tjanst of employee.tjanster">
<digi-icon-check-circle
class="employee-card__authorization-icon employee-card__authorization-icon--authorized"
></digi-icon-check-circle>
{{ tjanst.name }}
</li>
</ul>
<p *ngIf="!employee.tjanster.length">Kontot har inga registrerade tjänster ännu.</p>
</div>
<div class="employee-card__utforandeverksamheter">
<h2>Utförande verksamheter och utförande adresser</h2>
<div class="employee-card__block">
<h3>Utförande verksamheter och utförande adresser</h3>
<p *ngIf="employee.allaUtforandeVerksamheter; else specificUtforandeVerksamheter">
Kontot har behörighet till alla utförande verksamheter och utförande adresser inom organisationen.
</p>
<ng-template #specificUtforandeVerksamheter>
<p style="color: red">
OBS: BEHÖVER FIXAS, ÄVEN OM MAN HAR UTFÖRANDE VERKSAMHETER SÅ SYNS DOM INTE DÅ VI BARA FÅR UT ID
</p>
<div
<ul
*ngIf="employee.utforandeVerksamheter?.length; else missingUtforandeVerksamheter"
class="employee-card__utforandeverksamheter-cards"
class="employee-card__utforandeverksamheter"
>
<digi-info-card
*ngFor="let utforandeverksamhet of employee.utforandeVerksamhet"
[afHeading]="utforandeverksamhet.namn"
af-heading-level="h2"
af-type="info"
class="employee-card__utforandeverksamheter-card"
>
<digi-ng-layout-expansion-panel *ngIf="utforandeverksamhet.adresser.length > 0">
<span data-slot-trigger>
<!-- vad refererar accordionExpanded till här?? Templaten bygger inte om det inte finns en definition av variabeln.. {{ accordionExpanded ? 'Dölj' : 'Visa' }} {{utforandeverksamhet.adresser.length}} -->
{{utforandeverksamhet.adresser.length === 1 ? 'adress' : 'adresser'}}
</span>
<ul class="employee-card__utforandeverksamheter-address-list">
<li
class="employee-card__utforandeverksamheter-address-list-item"
*ngFor="let address of utforandeverksamhet.adresser"
>
<span>{{address.adressrad}}</span>
<span>{{address.postnummer}}</span>
<span>{{address.postort}}</span>
</li>
</ul>
</digi-ng-layout-expansion-panel>
</digi-info-card>
</div>
<li *ngFor="let utforandeVerksamhet of employee.utforandeVerksamheter">
<digi-info-card
[afHeading]="utforandeVerksamhet.name"
af-heading-level="h4"
af-type="info"
class="employee-card__utforandeverksamhet-card"
>
<p *ngIf="utforandeVerksamhet.allaAdresser">Alla adresser inom utförande verksamheten valda.</p>
<digi-ng-layout-expansion-panel
*ngIf="!utforandeVerksamhet.allaAdresser && utforandeVerksamhet.adresser.length > 0"
[afExpanded]="isAccordionExpanded(utforandeVerksamhet.id)"
(click)="toggleAccordionExpanded(utforandeVerksamhet.id)"
>
<span data-slot-trigger>
{{ isAccordionExpanded(utforandeVerksamhet.id) ? 'Dölj' : 'Visa' }}
{{utforandeVerksamhet.adresser.length}} {{utforandeVerksamhet.adresser.length === 1 ? 'adress' :
'adresser'}}
</span>
<ul class="employee-card__adresser">
<li *ngFor="let address of utforandeVerksamhet.adresser; let last = last">
{{address.name}}{{last ? '' : ','}}
</li>
</ul>
</digi-ng-layout-expansion-panel>
</digi-info-card>
</li>
</ul>
<ng-template #missingUtforandeVerksamheter>
<p>Kontot har inga registrerade utförande verksamheter eller utförande adresser ännu.</p>
</ng-template>
</ng-template>
</div>
<div class="employee-card__column">
<h2>Behörigheter</h2>
<div class="employee-card__block">
<h3>Roller</h3>
<ul class="employee-card__list">
<li *ngFor="let role of allRoles">
<digi-icon-check-circle

View File

@@ -1,3 +1,4 @@
@import 'functions/rem';
@import 'variables/gutters';
@import 'variables/colors';
@import 'mixins/buttons';
@@ -10,39 +11,31 @@
gap: $digi--layout--gutter--l $digi--layout--gutter--l;
}
&__column {
&__block {
width: 100%;
max-width: var(--digi--typography--text--max-width);
}
&__utforandeverksamheter-cards {
&__utforandeverksamheter {
@include msfa__reset-list;
display: flex;
flex-direction: column;
gap: 1rem;
gap: $digi--layout--gutter;
}
&__utforandeverksamheter-card {
--digi-info-card--padding:
var(--digi--layout--padding--20)
var(--digi--layout--padding--40)
var(--digi--layout--padding--40)
var(--digi--layout--padding--40);
&__utforandeverksamhet-card {
--digi-info-card--padding: 1.5rem 1rem;
::ng-deep .digi-info-card__heading {
margin-top: 0;
}
}
&__utforandeverksamheter-address-list {
&__adresser {
@include msfa__reset-list;
padding-top: var(--digi--layout--padding--10);
}
&__utforandeverksamheter-address-list-item span:not(:empty):not(:last-child):after {
content: ', ';
}
&__utforandeverksamheter {
display: flex;
flex-direction: column;
}
&__header,
&__footer {
display: flex;
@@ -78,12 +71,7 @@
}
&__edit-button {
@include msfa-button-template(
$msfa-button--background--secondary,
$msfa-button--text--secondary,
$msfa-button--hover--secondary
);
width: var(--digi-button--width);
@include msfa-button('secondary');
}
&__authorization-icon {

View File

@@ -17,6 +17,7 @@ export class EmployeeCardComponent implements OnDestroy {
employee$: Observable<Employee> = this.employeeService.employee$;
lastUpdatedEmployeeId$: Observable<string> = this.employeeService.lastUpdatedEmployeeId$;
allRoles: Role[] = this.employeeService.allRoles;
accordionsExpanded = [];
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
this.employeeService.setCurrentEmployeeId(this.employeeId);
@@ -34,7 +35,19 @@ export class EmployeeCardComponent implements OnDestroy {
return this._pendingSelectedParticipants$.getValue();
}
isAccordionExpanded(id: number): boolean {
return this.accordionsExpanded.includes(id);
}
closeUpdatedNotificationAlert(): void {
this.employeeService.resetLastUpdatedEmployeeId();
}
toggleAccordionExpanded(currentId: number): void {
if (this.accordionsExpanded.includes(currentId)) {
this.accordionsExpanded = this.accordionsExpanded.filter(id => id !== currentId);
} else {
this.accordionsExpanded.push(currentId);
}
}
}

View File

@@ -6,7 +6,6 @@
(ngSubmit)="onFormSubmitted()"
>
<digi-ng-form-input
class="edit-employee-form__input"
afId="edit-employee-form-email"
afLabel="E-post adress"
afType="email"
@@ -16,94 +15,102 @@
[afInvalid]="emailFormControl.invalid && emailFormControl.touched"
></digi-ng-form-input>
<fieldset>
<legend>Tjänster</legend>
<p>Välj de tjänster du vill ge personalen tillgång till.</p>
<digi-ng-form-select
[formControl]="tjansterFormControl"
afLabel="Välj tjänster"
[afPlaceholder]="'Välj tjänst'"
[afSelectItems]="selectableTjansterFormItems"
[afDisableValidStyle]="true"
[afInvalid]="tjansterFormControl.invalid && tjansterFormControl.touched"
(afOnChange)="toggleTjanst()"
></digi-ng-form-select>
<digi-form-validation-message
*ngIf="tjansterFormControl.invalid && tjansterFormControl.touched"
af-variation="error"
>
Du måste välja minst en tjänst
</digi-form-validation-message>
<!-- Vi får se till att bygga en kontrol för att kunna välja flera tjänster här istället, en digi-ng-select får vara en temporär lösning.. -->
</fieldset>
<div class="edit-employee-form__contents">
<div class="edit-employee-form__block">
<h2>Behörigheter</h2>
<p>Här kan du ändra personalkontots behörigheter.</p>
</div>
<fieldset>
<legend>Utförande verksamheter och adresser</legend>
<p>Välj de utförandeverksamheter och utförande adresser du vill ge personalen behörighet till.</p>
<p *ngIf="!availableUtforandeVerksamheter || availableUtforandeVerksamheter.length === 0">
<strong>Du måste välja en eller flera tjänster för att kunna välja utförande verksamheter.</strong>
</p>
<div class="edit-employee-form__choose_all-utforande-verksamh">
<div class="edit-employee-form__block">
<h3>Tjänster</h3>
<p>Välj de tjänster du vill ge personalen tillgång till.</p>
<!-- Vi får se till att bygga en kontrol för att kunna välja flera tjänster här istället, en digi-ng-select får vara en temporär lösning.. -->
<digi-ng-form-select
[formControl]="tjansterFormControl"
afLabel="Välj tjänster"
[afPlaceholder]="'Välj tjänst'"
[afSelectItems]="selectableTjansterFormItems"
[afDisableValidStyle]="true"
[afInvalid]="tjansterFormControl.invalid && tjansterFormControl.touched"
(afOnChange)="toggleTjanst()"
></digi-ng-form-select>
<digi-form-validation-message
*ngIf="tjansterFormControl.invalid && tjansterFormControl.touched"
af-variation="error"
>
Du måste välja minst en tjänst
</digi-form-validation-message>
</div>
<div class="edit-employee-form__block">
<h3>Utförande verksamheter och adresser</h3>
<p>Välj de utförandeverksamheter och utförande adresser du vill ge personalen behörighet till.</p>
<p *ngIf="!availableUtforandeVerksamheter || availableUtforandeVerksamheter.length === 0">
<strong>Du måste välja en eller flera tjänster för att kunna välja utförande verksamheter.</strong>
</p>
<digi-ng-form-checkbox
class="edit-employee-form__choose-all-utforande-verksamheter"
[formControl]="toggleAllUtforandeVerksamhetFormControl"
[afLabel]="'Välj alla utförande verksamheter och alla utförande adresser'"
(afOnChange)="toggleAllUtforandeVerksamheter($event)"
>
</digi-ng-form-checkbox>
></digi-ng-form-checkbox>
<msfa-tree-nodes-selector
*ngIf="!toggleAllUtforandeVerksamhetFormControl.value"
[headingText]="'Välj utförande verksamheter och adresser'"
[formControlName]="utforandeVerksamhetFormControlName"
[isInvalid]="utforandeVerksamhetFormControl?.invalid"
[showValidation]="utforandeVerksamhetFormControl?.touched"
[validationMessages]="utforandeVerksamhetFormControl.errors?.required ? ['Välj minst en utförande verksamhet'] : []"
(selectedTreeNodesChanged)="updateToggleAllUtforandeVerksamheter()"
></msfa-tree-nodes-selector>
</div>
<msfa-tree-nodes-selector
*ngIf="!toggleAllUtforandeVerksamhetFormControl.value"
[headingText]="'Välj utförande verksamheter och adresser'"
[formControlName]="utforandeVerksamhetFormControlName"
[isInvalid]="utforandeVerksamhetFormControl?.invalid"
[showValidation]="utforandeVerksamhetFormControl?.touched"
[validationMessages]="utforandeVerksamhetFormControl.errors?.required ? ['Välj minst en utförande verksamhet'] : []"
(selectedTreeNodesChanged)="updateToggleAllUtforandeVerksamheter()"
<div class="edit-employee-form__block" *ngIf="rolesFormGroup && availableRoles" [formGroup]="rolesFormGroup">
<h3>Roller</h3>
<p>
Här tilldelar du specifika roller i systemet. Välj nedan vilka arbetsuppgifter som användaren ska kunna
utföra. Tänk på att rollen i systemet är begränsad till de utförande verksamheter och adresser som användaren
hör till. Användaren kan därför endast utföra uppgifter och se information inom den/ de utförande adresser som
tilldelats användaren.
<digi-ng-button
class="edit-employee-form__roles-dialog-button"
[afVariation]="ButtonVariation.TERTIARY"
[afType]="ButtonType.BUTTON"
[afSize]="ButtonSize.S"
afAriaControls="roles-dialog"
[afAriaLabel]="'Öppnar en dialog med information om behörigheter'"
(afOnClick)="openRolesDialog()"
>
Läs mer om roller här
</digi-ng-button>
</p>
<fieldset class="edit-employee-form__fieldset">
<legend class="msfa__a11y-sr-only">Välj roller</legend>
<ul class="edit-employee-form__roles">
<li class="edit-employee-form__role" *ngFor="let role of availableRoles">
<digi-ng-form-checkbox
[afLabel]="role.name"
[formControlName]="getFormControlName(role)"
></digi-ng-form-checkbox>
</li>
</ul>
</fieldset>
</div>
<digi-notification-alert
*ngIf="errorWhileUpdating"
af-variation="danger"
af-heading="Kunde inte spara"
af-heading-level="h4"
[afCloseable]="true"
(afOnClose)="emitCloseError()"
>
</msfa-tree-nodes-selector>
</fieldset>
<fieldset *ngIf="rolesFormGroup && availableRoles" [formGroup]="rolesFormGroup">
<legend>Behörigheter</legend>
<p>
Här tilldelar du specifika behörigheter i systemet. Välj nedan vilka arbetsuppgifter som användaren ska kunna
utföra. Tänk på att behörigheten i systemet är begränsad till de utförande verksamheter och adresser som
användaren hör till. Användaren kan därför endast utföra uppgifter och se information inom den/ de utförande
adresser som tilldelats användaren.
<digi-ng-button
class="edit-employee-form__open-roles-dialog-btn"
[afVariation]="ButtonVariation.TERTIARY"
[afType]="ButtonType.BUTTON"
[afSize]="ButtonSize.S"
afAriaControls="roles-dialog"
[afAriaLabel]="'Öppnar en dialog med information om behörigheter'"
(afOnClick)="openRolesDialog()"
>
Läs mer om behörigheter här
</digi-ng-button>
</p>
<ul class="edit-employee-form__roles">
<li class="edit-employee-form__roles-item" *ngFor="let role of availableRoles">
<digi-ng-form-checkbox
[afLabel]="role.name"
[formControlName]="getFormControlName(role)"
></digi-ng-form-checkbox>
</li>
</ul>
</fieldset>
<digi-notification-alert
*ngIf="errorWhileUpdating"
af-variation="danger"
af-heading="Kunde inte spara"
af-heading-level="h2"
[afCloseable]="true"
(afOnClose)="emitCloseError()"
>
<p>Personalkontot för {{employee.fullName}} kunde inte redigeras. Vänligen försök igen.</p>
<p class="msfa__small-text" *ngIf="errorWhileUpdating.message">{{errorWhileUpdating.message}}</p>
</digi-notification-alert>
<p>Personalkontot för {{employee.fullName}} kunde inte redigeras. Vänligen försök igen.</p>
<p class="msfa__small-text" *ngIf="errorWhileUpdating.message">{{errorWhileUpdating.message}}</p>
</digi-notification-alert>
</div>
<footer class="edit-employee-form__footer">
<a
@@ -138,29 +145,29 @@
[afActive]="displayRolesDialog"
(afOnInactive)="closeRolesDialog()"
(afOnPrimaryClick)="closeRolesDialog()"
afHeading="Om behörigheterna i systemet"
afHeading="Om rollerna i systemet"
afHeadingLevel="h2"
afPrimaryButtonText="Stäng"
afSecondaryButtonText=""
>
<p>
Läs beskrivningarna nedan för att lära dig mer om de olika behörigheterna. Personalen kan tilldelas en behörighet,
eller flera behörigheter, beroende på vad de arbetar med. Tänk på att behörigheten endast gäller inom de utförande
verksamheter och adresser som personalen fått behörighet till.
Läs beskrivningarna nedan för att lära dig mer om de olika rollerna. Personalen kan tilldelas en roll, eller flera
roller, beroende på vad de arbetar med. Tänk på att rollen endast gäller inom de utförande verksamheter och adresser
som personalen fått behörighet till.
</p>
<p>
All personal kommer att kunna se sitt eget personalkonto, där de kan se vilka behörigheter och utförande
verksamheter och adresser som tilldelats dem i systemet. De kommer även att se startsidan.
All personal kommer att kunna se sitt eget personalkonto, där de kan se vilka roller och utförande verksamheter och
adresser som tilldelats dem i systemet. De kommer även att se startsidan.
</p>
<h3>Administrera behörigheter</h3>
<p>
Behörigheten passar personal som ska administrera behörigheter i systemet. Behörigheten bör begränsas till ett fåtal
personer och kan användas av exempelvis firmatecknare, behörighetsadministratör, eller annan person som ska kunna
administrera personalens behörigheter. Behörigheten gäller endast inom de utförande verksamheter och adresser som
getts behörighet till.
Rollen passar personal som ska administrera behörigheter i systemet. Rollen bör begränsas till ett fåtal personer
och kan användas av exempelvis firmatecknare, behörighetsadministratör, eller annan person som ska kunna
administrera personalens behörigheter. Rollen gäller endast inom de utförande verksamheter och adresser som getts
behörighet till.
</p>
<p>Behörigheten ger tillgång till följande funktioner:</p>
<p>Rollen ger tillgång till följande funktioner:</p>
<ul>
<li>Skapa nya personalkonton</li>
<li>Se personallista</li>
@@ -170,12 +177,12 @@
<h3>Ta emot nya deltagare</h3>
<p>
Behörigheten passar personal som ska se nya deltagare som inkommit i systemet och som ska tilldela handledare till
nya deltagare. Behörigheten kan exempelvis användas av samordnande roller, handledare, administratörer, eller annan
personal som ska kunna utföra dessa arbetsuppgifter. Behörigheten gäller endast inom de utförande verksamheter och
adresser som getts behörighet till.
Rollen passar personal som ska se nya deltagare som inkommit i systemet och som ska tilldela handledare till nya
deltagare. Rollen kan exempelvis användas av samordnande roller, handledare, administratörer, eller annan personal
som ska kunna utföra dessa arbetsuppgifter. Rollen gäller endast inom de utförande verksamheter och adresser som
getts behörighet till.
</p>
<p>Behörigheten ger tillgång till följande funktioner:</p>
<p>Rollen ger tillgång till följande funktioner:</p>
<ul>
<li>Se lista över nya deltagare som inkommit</li>
<li>Tilldela handledare till nya deltagare</li>
@@ -184,12 +191,12 @@
<h3>Rapportering, planering och information om deltagare</h3>
<p>
Behörigheten passar personal som arbetar nära deltagare. Behörigheten kan användas av exempelvis handledare,
coacher, studie- och yrkesvägledare, lärare eller andra roller som behöver se information om deltagare, planera
aktiviteter med deltagare eller hantera deltagares rapporter. Behörigheten gäller endast inom de utförande
verksamheter och adresser som getts behörighet till.
Rollen passar personal som arbetar nära deltagare. Rollen kan användas av exempelvis handledare, coacher, studie-
och yrkesvägledare, lärare eller andra roller som behöver se information om deltagare, planera aktiviteter med
deltagare eller hantera deltagares rapporter. Rollen gäller endast inom de utförande verksamheter och adresser som
getts behörighet till.
</p>
<p>Behörigheten ger tillgång till följande funktioner:</p>
<p>Rollen ger tillgång till följande funktioner:</p>
<ul>
<li>Se lista över deltagare</li>

View File

@@ -1,38 +1,24 @@
@import 'mixins/buttons';
@import 'mixins/list';
@import 'variables/gutters';
@import '~@digi/core/dist/collection/components/_button/button/button.css';
.edit-employee-form {
max-width: var(--digi--typography--text--max-width);
fieldset {
margin: 2.5rem 0;
padding: 0;
border: 0 none transparent;
}
legend {
width: 100%;
padding: 0;
&__contents {
display: flex;
align-items: center;
font-weight: var(--digi--typography--font-weight--semibold);
font-size: var(--digi--typography--font-size--h2--desktop);
margin-bottom: var(--digi-typography--margin--h2);
flex-direction: column;
gap: $digi--layout--gutter--l $digi--layout--gutter--l;
}
&__service-tag {
padding-top: .5rem;
}
&__service-tag--item {
margin-right: 1rem;
}
&__input {
display: block;
&__block {
width: 100%;
margin-bottom: var(--digi--layout--gutter);
max-width: var(--digi--typography--text--max-width);
}
&__fieldset {
margin: 0;
padding: 0;
border-width: 0;
}
&__roles {
@@ -40,7 +26,7 @@
margin-bottom: var(--digi--layout--gutter);
}
&__roles-item {
&__role {
margin-top: var(--digi--layout--gutter);
::ng-deep label {
@@ -48,7 +34,7 @@
}
}
&__open-roles-dialog-btn {
&__roles-dialog-button {
::ng-deep button {
padding: 0 !important;
}
@@ -61,40 +47,11 @@
}
&__link-btn {
font-family: var(--digi-button--font-family);
background: var(--digi-button--background);
color: var(--digi-button--color);
padding: var(--digi-button--padding);
border-radius: var(--digi-button--border-radius);
border: var(--digi-button--border);
border-color: var(--digi-button--border-color);
font-weight: var(--digi-button--font-weight);
font-size: var(--digi-button--font-size);
outline: var(--digi-button--outline);
text-align: var(--digi-button--text-align);
cursor: pointer;
width: var(--digi-button--width);
display: var(--digi-button--display);
text-align: var(--digi-button--text-align);
text-decoration: none;
@include msfa-button('secondary');
}
&__link-btn--secondary {
--digi-button--background: var(--digi-button--background--secondary);
--digi-button--background--hover: var(--digi-button--background--secondary--hover);
--digi-button--color: var(--digi-button--color--secondary);
--digi-button--color--hover: var(--digi-button--color--secondary);
--digi-button--border-color--disabled: var(--digi-button--border-color--secondary--disabled);
&:focus,
&:hover {
--digi-button--background: var(--digi-button--background--hover);
--digi-button--border-color: var(--digi-button--border-color--hover);
--digi-button--color: var(--digi-button--color--hover);
--digi-button--outline: var(--digi-button--outline--focus);
}
}
&__choose_all-utforande-verksamh {
&__choose-all-utforande-verksamheter {
display: block;
margin: 1.5rem 0;
}
}

View File

@@ -49,10 +49,6 @@ describe('EditEmployeeFormComponent', () => {
tjanster: [],
allaUtforandeVerksamheter: false,
utforandeVerksamheter: [],
tjanstCodes: [],
utforandeVerksamhetIds: [],
utforandeAdressIds: [],
};
fixture.detectChanges();
});

View File

@@ -17,10 +17,8 @@ import { Employee } from '@msfa-models/employee.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import {
UtforandeVerksamhet,
UtforandeVerksamheterService,
} from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import {
TreeNode,
TreeNodesSelectorService,
@@ -30,13 +28,6 @@ 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 {
email: string;
tjanster: Tjanst[];
roles: Role[];
utforandeVerksamheter: UtforandeVerksamhet[];
}
@Component({
selector: 'msfa-edit-employee-form',
templateUrl: './edit-employee-form.component.html',
@@ -146,9 +137,14 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
}
private initializeEditEmployeeFormGroup(): void {
const currentTjanst = this.employee.tjanster[0];
const tjanstId = currentTjanst
? this.availableTjanster.find(tjanst => tjanst.code === currentTjanst.tjansteKod).tjanstId
: null;
this.editEmployeeFormGroup = new FormGroup({
email: new FormControl(this.employee.email, [RequiredValidator('E-postadress'), EmailValidator()]),
tjanster: new FormControl(this.employee.tjanster[0]?.tjanstId, [RequiredValidator('Tjänst')]),
tjanster: new FormControl(tjanstId, [RequiredValidator('Tjänst')]),
roles: this.employeeFormService.getRolesFormGroup(this.availableRoles, this.employee.roles),
utforandeVerksamheter: new FormControl(
this.utforandeVerksamheterService.getTreeNodeDataFromUtforandeVerksamheter(this.availableUtforandeVerksamheter),

View File

@@ -37,6 +37,7 @@
</div>
<div class="employee-form__block">
<msfa-edit-employee-form
*ngIf="employee && (tjanster$ | async)"
[employee]="employee"
[availableRoles]="availableRoles"
[availableTjanster]="tjanster$ | async"

View File

@@ -10,7 +10,6 @@
&__block {
max-width: var(--digi--typography--text--max-width);
margin-bottom: $digi--layout--gutter--xl;
}
&__input {

View File

@@ -5,12 +5,10 @@ import { Employee } from '@msfa-models/employee.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import { EmployeeService } from '@msfa-services/api/employee.service';
import { TjanstService } from '@msfa-services/api/tjanst.service';
import {
UtforandeVerksamhet,
UtforandeVerksamheterService,
} from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
@@ -29,7 +27,7 @@ export class EmployeeFormComponent implements OnInit {
tjanster$: Observable<Tjanst[]> = this.tjanstService.tjanster$;
availableUtforandeVerksamheter$: Observable<UtforandeVerksamhet[]> = this._selectedTjanstIds$.pipe(
filter(selectedTjanstIds => !!selectedTjanstIds?.length),
switchMap(selectedTjanstIds => this.utforandeVerksamheterService.getUtforandeVerksamheter(selectedTjanstIds))
switchMap(selectedTjanstIds => this.utforandeVerksamheterService.fetchUtforandeVerksamheter$(selectedTjanstIds))
);
availableRoles: Role[] = this.employeeService.allRoles;

View File

@@ -2,7 +2,6 @@ import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { SortOrder } from '@msfa-enums/sort-order.enum';
import { EmployeeCompactResponse } from '@msfa-models/api/employee.response.model';
@@ -13,7 +12,6 @@ import { employeesMock } from './employees-list.mock';
describe('EmployeesListComponent', () => {
let component: EmployeesListComponent;
let fixture: ComponentFixture<EmployeesListComponent>;
const getEmployeeRows = () => fixture.debugElement.queryAll(By.css('.employees-list__row'));
beforeEach(async () => {
await TestBed.configureTestingModule({

View File

@@ -33,15 +33,15 @@ export class AvropFiltersComponent {
this.avropService.setSelectedKommuner(filterOptions);
}
removeKommun(kommunToRemove: MultiselectFilterOption) {
removeKommun(kommunToRemove: MultiselectFilterOption): void {
this.avropService.removeKommun(kommunToRemove);
}
removeUtforandeVerksamhet(utforandeVerksamhetToRemove: MultiselectFilterOption) {
removeUtforandeVerksamhet(utforandeVerksamhetToRemove: MultiselectFilterOption): void {
this.avropService.removeUtforandeVerksamhet(utforandeVerksamhetToRemove);
}
removeTjanst(tjanstToRemove: MultiselectFilterOption) {
removeTjanst(tjanstToRemove: MultiselectFilterOption): void {
this.avropService.removeTjanst(tjanstToRemove);
}
}

View File

@@ -0,0 +1,4 @@
export interface EmployeeAdressResponse {
id: number;
namn: string;
}

View File

@@ -0,0 +1,4 @@
export interface EmployeeTjanstResponse {
namn: string;
tjansteKod: string;
}

View File

@@ -0,0 +1,8 @@
import { EmployeeAdressResponse } from './employee-adress.response.model';
export interface EmployeeUtforandeVerksamhetResponse {
id: number;
namn: string;
allaAdresser: boolean;
adresser: EmployeeAdressResponse[];
}

View File

@@ -1,18 +1,7 @@
import { RoleEnum } from '@msfa-enums/role.enum';
import { PaginationMeta } from '@msfa-models/pagination-meta.model';
import { TjanstResponse } from './tjanst.response.model';
interface UtforandeVerksamhetResponse {
id: number;
name: string;
allaAdresser: boolean;
adresser?: AdressResponse[];
}
interface AdressResponse {
id: number;
name: string;
}
import { EmployeeTjanstResponse } from './employee-tjanst.response.model';
import { EmployeeUtforandeVerksamhetResponse } from './employee-utforande-verksamhet.response.model';
export interface EmployeeCompactResponse {
ciamUserId: string;
@@ -29,14 +18,9 @@ export interface EmployeeResponse {
email: string;
ssn: string;
roles: RoleEnum[];
tjanster: TjanstResponse[];
tjanster: EmployeeTjanstResponse[];
allaUtforandeVerksamheter: boolean;
utforandeVerksamheter: UtforandeVerksamhetResponse[];
// Will be removed
tjansteKoder: string[];
utforandeVerksamhetIds: number[];
adressIds: number[];
utforandeVerksamheter: EmployeeUtforandeVerksamhetResponse[];
}
export interface EmployeesDataResponse {

View File

@@ -0,0 +1,4 @@
export interface UtforandeAdressResponse {
id: number;
namn: string;
}

View File

@@ -0,0 +1,7 @@
import { UtforandeAdressResponse } from './utforande-adress.response.model';
export interface UtforandeVerksamhetResponse {
id: number;
name: string;
adresser: UtforandeAdressResponse[];
}

View File

@@ -0,0 +1,15 @@
import { EmployeeAdressResponse } from './api/employee-adress.response.model';
export interface EmployeeAdress {
id: number;
name: string;
}
export function mapResponseToEmployeeAdress(data: EmployeeAdressResponse): EmployeeAdress {
const { id, namn } = data;
return {
id,
name: namn,
};
}

View File

@@ -0,0 +1,15 @@
import { EmployeeTjanstResponse } from './api/employee-tjanst.response.model';
export interface EmployeeTjanst {
name: string;
tjansteKod: string;
}
export function mapResponseToEmployeeTjanst(data: EmployeeTjanstResponse): EmployeeTjanst {
const { namn, tjansteKod } = data;
return {
name: namn,
tjansteKod,
};
}

View File

@@ -0,0 +1,22 @@
import { EmployeeUtforandeVerksamhetResponse } from './api/employee-utforande-verksamhet.response.model';
import { EmployeeAdress, mapResponseToEmployeeAdress } from './employee-adress.model';
export interface EmployeeUtforandeVerksamhet {
id: number;
name: string;
allaAdresser: boolean;
adresser: EmployeeAdress[];
}
export function mapResponseToEmployeeUtforandeVerksamhet(
data: EmployeeUtforandeVerksamhetResponse
): EmployeeUtforandeVerksamhet {
const { id, namn, allaAdresser, adresser } = data;
return {
id,
name: namn,
allaAdresser,
adresser: adresser.map(adress => mapResponseToEmployeeAdress(adress)),
};
}

View File

@@ -1,22 +1,14 @@
import { RoleEnum } from '@msfa-enums/role.enum';
import { EmployeeCompactResponse, EmployeeResponse } from './api/employee.response.model';
import { EmployeeTjanst, mapResponseToEmployeeTjanst } from './employee-tjanst.model';
import {
EmployeeUtforandeVerksamhet,
mapResponseToEmployeeUtforandeVerksamhet,
} from './employee-utforande-verksamhet.model';
import { PaginationMeta } from './pagination-meta.model';
import { mapResponseToTjanst, Tjanst } from './tjanst.model';
const CURRENT_YEAR = new Date().getFullYear().toString().slice(2, 4);
interface UtforandeVerksamhet {
id: number;
name: string;
allaAdresser: boolean;
adresser?: Adress[];
}
interface Adress {
id: number;
name: string;
}
export interface EmployeeCompact {
id: string;
fullName: string;
@@ -33,13 +25,9 @@ export interface Employee {
email: string;
ssn: string;
roles: RoleEnum[];
tjanster: Tjanst[];
tjanster: EmployeeTjanst[];
allaUtforandeVerksamheter: boolean;
utforandeVerksamheter: UtforandeVerksamhet[];
tjanstCodes: string[];
utforandeVerksamhetIds: number[];
utforandeAdressIds: number[];
utforandeVerksamheter: EmployeeUtforandeVerksamhet[];
}
export interface EmployeesData {
@@ -81,9 +69,6 @@ export function mapResponseToEmployee(data: EmployeeResponse): Employee {
tjanster,
allaUtforandeVerksamheter,
utforandeVerksamheter,
tjansteKoder,
utforandeVerksamhetIds,
adressIds,
} = data;
return {
id: ciamUserId,
@@ -93,11 +78,10 @@ export function mapResponseToEmployee(data: EmployeeResponse): Employee {
email,
ssn: ssn ? mapResponseToSsn(ssn) : null,
roles: roles || [],
tjanster: tjanster?.map(tjanst => mapResponseToTjanst(tjanst)),
tjanster: tjanster?.map(tjanst => mapResponseToEmployeeTjanst(tjanst)),
allaUtforandeVerksamheter,
utforandeVerksamheter,
tjanstCodes: tjansteKoder || [],
utforandeVerksamhetIds: utforandeVerksamhetIds || [],
utforandeAdressIds: adressIds || [],
utforandeVerksamheter: utforandeVerksamheter.map(utforandeVerksamhet =>
mapResponseToEmployeeUtforandeVerksamhet(utforandeVerksamhet)
),
};
}

View File

@@ -1,12 +1,11 @@
import { Tjanst } from "./tjanst.model";
import { Tjanst } from './tjanst.model';
export interface FormTagData {
tjanstekod: string,
name: string;
tjanstekod: string;
name: string;
}
export function mapTjanstToFormTag(tjanstData: Tjanst): FormTagData {
const { name, code } = tjanstData;
return { tjanstekod: code, name}
}
const { name, code } = tjanstData;
return { tjanstekod: code, name };
}

View File

@@ -0,0 +1,15 @@
import { UtforandeAdressResponse } from './api/utforande-adress.response.model';
export interface UtforandeAdress {
id: number;
name: string;
}
export function mapResponseToUtforandeAdress(data: UtforandeAdressResponse): UtforandeAdress {
const { id, namn } = data;
return {
id,
name: namn,
};
}

View File

@@ -0,0 +1,18 @@
import { UtforandeVerksamhetResponse } from './api/utforande-verksamhet.response.model';
import { mapResponseToUtforandeAdress, UtforandeAdress } from './utforande-adress.model';
export interface UtforandeVerksamhet {
id: number;
name: string;
adresser: UtforandeAdress[];
}
export function mapResponseToUtforandeVerksamhet(data: UtforandeVerksamhetResponse): UtforandeVerksamhet {
const { id, name, adresser } = data;
return {
id,
name,
adresser: adresser.map(adress => mapResponseToUtforandeAdress(adress)),
};
}

View File

@@ -24,7 +24,6 @@ import { Sort } from '@msfa-models/sort.model';
import { ErrorService } from '@msfa-services/error.service';
import { BehaviorSubject, combineLatest, Observable, of, throwError } from 'rxjs';
import { catchError, distinctUntilChanged, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { TjanstService } from './tjanst.service';
@Injectable({
providedIn: 'root',
@@ -48,11 +47,7 @@ export class EmployeeService extends UnsubscribeDirective {
private _employeeToDelete$ = new BehaviorSubject<Employee>(null);
public employeeToDelete$: Observable<Employee> = this._employeeToDelete$.asObservable();
constructor(
private httpClient: HttpClient,
private errorService: ErrorService,
private tjanstService: TjanstService
) {
constructor(private httpClient: HttpClient, private errorService: ErrorService) {
super();
super.unsubscribeOnDestroy(
combineLatest([this._currentEmployeeId$, this._lastUpdatedEmployeeId$])
@@ -63,20 +58,7 @@ export class EmployeeService extends UnsubscribeDirective {
!currLastUpdatedEmployeeId && prevEmployeeId === currEmployeeId
),
switchMap(([currentEmployeeId]) =>
combineLatest([this._fetchEmployee$(currentEmployeeId), this.tjanstService.tjanster$]).pipe(
filter(([employee, allTjanster]) => !!(employee && allTjanster?.length)),
map(([employee, allTjanster]) => {
const tjanster = [];
employee.tjanstCodes?.forEach(code => {
const currentTjanst = allTjanster.find(tjanst => tjanst.code === code);
if (currentTjanst) {
tjanster.push(currentTjanst);
}
});
return { ...employee, tjanster };
})
)
this._fetchEmployee$(currentEmployeeId).pipe(filter(employee => !!employee))
)
)
.subscribe(employee => {

View File

@@ -2,39 +2,34 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { Params } from '@msfa-models/api/params.model';
import { UtforandeVerksamhetResponse } from '@msfa-models/api/utforande-verksamhet.response.model';
import { UtforandeAdress } from '@msfa-models/utforande-adress.model';
import { mapResponseToUtforandeVerksamhet, UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import {
TreeNode,
TreeNodesSelectorService,
} from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
import { Observable, of } from 'rxjs';
export interface UtforandeVerksamhetAdress {
id: number;
namn: string;
}
export interface UtforandeVerksamhet {
id: number;
name: string;
adresser: Array<UtforandeVerksamhetAdress>;
}
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class UtforandeVerksamheterService {
private readonly apiBaseUrl = `${environment.api.url}/utforandeverksamheter`;
private readonly _apiBaseUrl = `${environment.api.url}/utforandeverksamheter`;
constructor(private treeNodesSelectorService: TreeNodesSelectorService, private httpClient: HttpClient) {}
getUtforandeVerksamheter(tjanstIds: Array<number>): Observable<Array<UtforandeVerksamhet>> {
fetchUtforandeVerksamheter$(tjanstIds: number[]): Observable<UtforandeVerksamhet[]> {
if (!tjanstIds.length) {
return of<Array<UtforandeVerksamhet>>([]);
return of<UtforandeVerksamhet[]>([]);
}
const params: Params = { tjansteIds: tjanstIds.map(tjanstId => tjanstId.toString()) };
return this.httpClient.get<Array<UtforandeVerksamhet>>(`${this.apiBaseUrl}`, { params });
return this.httpClient
.get<{ data: UtforandeVerksamhetResponse[] }>(`${this._apiBaseUrl}`, { params })
.pipe(map(({ data }) => data.map(uv => mapResponseToUtforandeVerksamhet(uv))));
}
getSelectedAdressIdsFromTreeNode(treeNode: TreeNode): number[] {
@@ -43,7 +38,7 @@ export class UtforandeVerksamheterService {
return selectedUtforandeVerksamheter.map(uv => uv.adresser.map(adress => adress.id)).flat();
}
getTreeNodeDataFromUtforandeVerksamheter(utforandeVerksamhetList: Array<UtforandeVerksamhet>): TreeNode | null {
getTreeNodeDataFromUtforandeVerksamheter(utforandeVerksamhetList: UtforandeVerksamhet[]): TreeNode | null {
let treeNode: TreeNode | null = null;
if (!utforandeVerksamhetList || utforandeVerksamhetList.length === 0 || !Array.isArray(utforandeVerksamhetList)) {
@@ -67,7 +62,7 @@ export class UtforandeVerksamheterService {
childItemType: 'Adresser',
children: utforandeVerksamhet.adresser
? utforandeVerksamhet.adresser.map(adress => {
return { label: adress.namn, isSelected: false, value: adress };
return { label: adress.name, isSelected: false, value: adress };
})
: [],
};
@@ -80,8 +75,8 @@ export class UtforandeVerksamheterService {
return treeNode;
}
getSelectedUtforandeVerksamheterFromTreeNode(treeNode: TreeNode): Array<UtforandeVerksamhet> {
let utforandeVerksamhetList: Array<UtforandeVerksamhet> = [];
getSelectedUtforandeVerksamheterFromTreeNode(treeNode: TreeNode): UtforandeVerksamhet[] {
let utforandeVerksamhetList: UtforandeVerksamhet[] = [];
if (!treeNode || !treeNode.children) {
return utforandeVerksamhetList;
@@ -95,7 +90,7 @@ export class UtforandeVerksamheterService {
name: originalUtforandeVerksamhet?.name,
id: originalUtforandeVerksamhet?.id,
adresser: utforandeVerksamhetNode.children.map(adressNode => {
return adressNode.value as UtforandeVerksamhetAdress;
return adressNode.value as UtforandeAdress;
}),
};
return utforandeVerksamhet;

View File

@@ -1,31 +1,42 @@
@import './variables/colors';
//Button properties
$msfa-button--padding: var(--digi-button--padding);
$msfa-button--margin: 0.5rem;
$msfa-button--border-radius: var(--digi-button--border-radius);
$msfa-button--transition: background 0.2s, border-color 0.2s, box-shadow 0.2s;
$msfa-button--border: var(--digi-button--border);
$msfa-button--text-decoration: none;
$msfa-button--font-weight: var(--digi-button--font-weight);
$msfa-button--font-font-size: var(--digi-button--font-size);
//A basic link button
@mixin msfa-button-template($backgroundcolor, $textcolor, $hovercolor) {
background: $backgroundcolor;
padding: $msfa-button--padding;
margin: $msfa-button--margin;
border-radius: $msfa-button--border-radius;
transition: $msfa-button--transition;
border: $msfa-button--border;
@mixin msfa-button($type: 'primary') {
padding: var(--digi-button--padding);
border-radius: var(--digi-button--border-radius);
transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s;
text-decoration: none;
font-weight: $msfa-button--font-weight;
font-size: $msfa-button--font-font-size;
color: $textcolor;
font-weight: var(--digi-button--font-weight);
font-size: var(--digi-button--font-size);
width: var(--digi-button--width);
display: var(--digi-button--display);
text-align: var(--digi-button--text-align);
border: var(--digi-button--border);
outline: var(--digi-button--outline);
border-color: var(--digi-button--border-color);
&:hover {
background: $hovercolor;
@if $type == 'secondary' {
background-color: var(--digi-button--background--secondary);
color: var(--digi-button--color--secondary);
} @else if $type == 'tertiary' {
background-color: transparent;
color: var(--digi-button--color--tertiary);
border-width: 0;
} @else {
background-color: var(--digi-button--background);
color: var(--digi-button--color);
}
&:hover,
&:focus {
outline: var(--digi-button--outline--focus);
border-color: var(--digi-button--border-color--hover);
@if $type == 'secondary' {
background-color: var(--digi-button--background--secondary--hover);
color: var(--digi-button--color--secondary);
} @else if $type == 'tertiary' {
color: var(--digi-button--color--tertiary--hover);
} @else {
background-color: var(--digi-button--background--hover);
color: var(--digi-button--color--hover);
}
}
}