Merge pull request #234 in TEA/mina-sidor-fa-web from feature/periodisk-redovisning-add-hours-to-activity to develop

Squashed commit of the following:

commit 01d637f78f28a68794ba4e8a12135f05fb91ddb7
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Oct 29 12:42:29 2021 +0200

    Added hours to PR incl. models

commit 8bea7c7ff17b80a2aa05416fd63d2bc697ba45a4
Author: Daniel Appelgren <daniel.appelgren@arbetsformedlingen.se>
Date:   Fri Oct 29 11:57:59 2021 +0200

    wip
This commit is contained in:
Erik Tiekstra
2021-10-29 12:45:26 +02:00
parent 5b50bc407b
commit e52f499f45
10 changed files with 109 additions and 30 deletions

View File

@@ -137,26 +137,47 @@
formControlName="isSelected"
[afLabel]="activitiesFormArrayMetadata[i].name"
></digi-ng-form-checkbox>
<div class="periodisk-redovisning-form__activity-location" *ngIf="isSelected.currentValue">
<digi-ng-form-checkbox
formControlName="performedRemotely"
[afInvalid]="activityLocationIsInvalid(activityFormGroup)"
afLabel="Utfört på distans"
></digi-ng-form-checkbox>
<digi-ng-form-checkbox
formControlName="performedPhysically"
[afInvalid]="activityLocationIsInvalid(activityFormGroup)"
afLabel="Utfört på plats"
></digi-ng-form-checkbox>
<div aria-atomic="true" role="alert">
<ng-container *ngIf="formControlIsInvalid(activityFormGroup)">
<div class="periodisk-redovisning-form__activity-details" *ngIf="isSelected.currentValue">
<div class="periodisk-redovisning-form__activity-group">
<digi-form-input
class="periodisk-redovisning-form__activity-hours"
af-label="Antal timmar under perioden"
af-type="number"
af-max="200"
af-min="0"
[afValidation]="activityHoursIsInvalid(activityFormGroup) ? 'error' : 'neutral'"
formControlName="hours"
ngDefaultControl
></digi-form-input>
<div aria-atomic="true" role="alert">
<digi-form-validation-message
*ngFor="let errorText of errorsToArray(activityFormGroup.errors)"
*ngIf="activityHoursIsInvalid(activityFormGroup)"
af-variation="error"
>
{{errorText}}
{{activityFormGroup.errors.hours}}
</digi-form-validation-message>
</ng-container>
</div>
</div>
<div class="periodisk-redovisning-form__activity-group">
<digi-ng-form-checkbox
formControlName="performedRemotely"
[afInvalid]="activityLocationIsInvalid(activityFormGroup)"
afLabel="Utfört på distans"
></digi-ng-form-checkbox>
<digi-ng-form-checkbox
formControlName="performedPhysically"
[afInvalid]="activityLocationIsInvalid(activityFormGroup)"
afLabel="Utfört på plats"
></digi-ng-form-checkbox>
<div aria-atomic="true" role="alert">
<digi-form-validation-message
*ngIf="activityLocationIsInvalid(activityFormGroup)"
af-variation="error"
>
{{activityFormGroup.errors.locationCheckboxes}}
</digi-form-validation-message>
</div>
</div>
</div>
</ng-container>
@@ -208,11 +229,7 @@
class="msfa__digi-icon periodisk-redovisning-form__activity-check"
aria-hidden="true"
></digi-icon-check-circle>
<span>
{{getActivityMetadata(activity.id).name}}: {{ activity.performedRemotely &&
activity.performedPhysically ? 'på distans och på plats' : activity.performedRemotely ? 'på
distans' : 'på plats'}}
</span>
<span>{{getActivityInfoAsString(activity)}}</span>
</dd>
</ng-template>
</ng-container>

View File

@@ -42,18 +42,27 @@
&__no-activities-has-been-conducted-checkbox,
&__activity,
&__activity-location {
&__activity-group {
display: flex;
flex-direction: column;
gap: var(--digi--layout--gutter--s);
}
&__activity-hours {
::ng-deep .digi-form-input__content {
max-width: 10rem;
}
}
&__no-activities-has-been-conducted-checkbox {
margin-bottom: $digi--layout--gutter--l;
}
&__activity-location {
margin-left: var(--digi--layout--gutter);
&__activity-details {
display: flex;
flex-direction: column;
gap: var(--digi--layout--gutter);
margin-left: 1.875rem;
margin-bottom: var(--digi--layout--gutter--s);
}

View File

@@ -181,6 +181,7 @@ export class PeriodiskRedovisningFormComponent implements OnInit {
isSelected: new FormControl(),
performedRemotely: new FormControl(),
performedPhysically: new FormControl(),
hours: new FormControl(),
},
PeriodiskRedovisningValidator.activityIsValid()
)
@@ -200,14 +201,20 @@ export class PeriodiskRedovisningFormComponent implements OnInit {
): PeriodiskRedovisningRequest {
const { period, hasOfferedJob, hasOfferedLanguageSupport } = formData;
const activities: PeriodiskRedovisningActivityRequest[] = formData.activities
.map(({ performedPhysically, performedRemotely, isSelected }, index) => ({
.map(({ performedPhysically, performedRemotely, isSelected, hours }, index) => ({
id: this.activitiesFormArrayMetadata[index].id,
performedPhysically: performedPhysically ?? false,
performedRemotely: performedRemotely ?? false,
hours: +hours,
isSelected,
}))
.filter(activity => activity.isSelected)
.map(({ id, performedPhysically, performedRemotely }) => ({ id, performedPhysically, performedRemotely }));
.map(({ id, performedPhysically, performedRemotely, hours }) => ({
id,
performedPhysically,
performedRemotely,
hours,
}));
return {
genomforandeReferens,
period,
@@ -226,10 +233,27 @@ export class PeriodiskRedovisningFormComponent implements OnInit {
return this.formControlIsInvalid(activityFormGroup) && !!errors.locationCheckboxes;
}
activityHoursIsInvalid(activityFormGroup: AbstractControl): boolean {
const errors = activityFormGroup.errors as ActivityFormErrors;
return this.formControlIsInvalid(activityFormGroup) && !!errors.hours;
}
getActivityMetadata(activityId: number): Activity {
return this.activitiesFormArrayMetadata.find(activity => activity.id === activityId);
}
getActivityInfoAsString(activity: PeriodiskRedovisningActivityRequest): string {
const { name } = this.getActivityMetadata(activity.id);
const hours = activity.hours === 1 ? '1 timme' : `${activity.hours} timmar`;
const location =
activity.performedRemotely && activity.performedPhysically
? 'på distans och på plats'
: activity.performedRemotely
? 'på distans'
: 'på plats';
return `${name}: ${hours} ${location}`;
}
openChangePeriodDialogIfValuesExist(): void {
const { activities, hasOfferedJob, hasOfferedLanguageSupport, noActivitiesHasBeenConducted } = this.formGroup
.value as PeriodiskRedovisningFormData;

View File

@@ -2,6 +2,7 @@ export interface PeriodiskRedovisningFormActivity {
isSelected: boolean;
performedRemotely: boolean;
performedPhysically: boolean;
hours: string;
}
export interface PeriodiskRedovisningFormData {
@@ -20,4 +21,5 @@ export interface PeriodiskRedovisningFormErrors {
export interface ActivityFormErrors {
locationCheckboxes?: string;
hours?: string;
}

View File

@@ -36,8 +36,10 @@ export class PeriodiskRedovisningValidator {
static activityIsValid(): ValidatorFn {
return (c: AbstractControl): ActivityFormErrors => {
let errors: ActivityFormErrors;
const controlValue = c.value as PeriodiskRedovisningFormActivity;
const { performedRemotely, performedPhysically, isSelected, hours } = controlValue;
const { performedRemotely, performedPhysically, isSelected } = c.value as PeriodiskRedovisningFormActivity;
if (isSelected && !performedPhysically && !performedRemotely) {
errors = {
...errors,
@@ -45,6 +47,15 @@ export class PeriodiskRedovisningValidator {
};
}
const isValidHours = hours?.length > 0 && Number.isInteger(+hours) && +hours >= 0 && +hours <= 200;
if (isSelected && !isValidHours) {
errors = {
...errors,
hours: 'Antal timmar måste vara ett heltal mellan 0 och 200',
};
}
return errors;
};
}

View File

@@ -20,8 +20,7 @@
class="msfa__digi-icon periodisk-redovisning-view__activity-check"
aria-hidden="true"
></digi-icon-check-circle>
{{activity.name}}: {{ activity.performedRemotely && activity.performedPhysically ? 'På distans och på
plats' : activity.performedRemotely ? 'På distans' : 'På plats'}}
{{getActivityInfoAsString(activity)}}
</li>
</ul>
</dd>

View File

@@ -2,10 +2,10 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Params } from '@msfa-models/api/params.model';
import { Avrop } from '@msfa-models/avrop.model';
import { PeriodiskRedovisning, PeriodiskRedovisningActivity } from '@msfa-models/periodisk-redovisning.model';
import { Observable } from 'rxjs';
import { map, shareReplay, switchMap } from 'rxjs/operators';
import { PeriodiskRedovisningViewService } from './periodisk-redovisning-view.service';
import { PeriodiskRedovisning } from '@msfa-models/periodisk-redovisning.model';
@Component({
selector: 'msfa-periodisk-redovisning-view',
@@ -34,6 +34,17 @@ export class PeriodiskRedovisningViewComponent {
shareReplay(1)
);
getActivityInfoAsString(activity: PeriodiskRedovisningActivity): string {
const hours = activity.hours === 1 ? '1 timme' : `${activity.hours} timmar`;
const location =
activity.performedRemotely && activity.performedPhysically
? 'på distans och på plats'
: activity.performedRemotely
? 'på distans'
: 'på plats';
return `${activity.name}: ${hours} ${location}`;
}
constructor(
private periodiskRedovisningViewService: PeriodiskRedovisningViewService,
private activatedRoute: ActivatedRoute

View File

@@ -2,6 +2,7 @@ export interface PeriodiskRedovisningActivityRequest {
id: number;
performedRemotely: boolean;
performedPhysically: boolean;
hours: number;
}
export interface PeriodiskRedovisningRequest {

View File

@@ -3,6 +3,7 @@ export interface PeriodiskRedovisningActivityResponse {
name: string;
performedRemotely: boolean;
performedPhysically: boolean;
hours: number;
}
export interface PeriodiskRedovisningResponse {
@@ -25,18 +26,21 @@ export function mockOnePeriodiskRedovisningResponse(): PeriodiskRedovisningRespo
name: 'Aktivitet 1',
performedRemotely: false,
performedPhysically: true,
hours: 25,
},
{
id: 19,
name: 'Aktivitet 2',
performedRemotely: true,
performedPhysically: false,
hours: 3,
},
{
id: 31,
name: 'Aktivitet 3',
performedRemotely: true,
performedPhysically: true,
hours: 2,
},
],
};

View File

@@ -5,6 +5,7 @@ export interface PeriodiskRedovisningActivity {
name: string;
performedRemotely: boolean;
performedPhysically: boolean;
hours: number;
}
export interface PeriodiskRedovisning {