feat(gemensam-planering): Implemented gemensam-planering form. (TV-700)
Squashed commit of the following: commit 2d07f37e30009c7f701af35aed65839535044bb3 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 09:33:21 2021 +0200 Updated error handling commit 12290b9436a06ecf0b2b8509016b14748ca17a18 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 09:10:48 2021 +0200 Updated after PR commit cc2fb38528069819acbc39c7b1f6d71ecae666a1 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 08:46:33 2021 +0200 Updated proxy.conf commit ee919de929d7b7316cd7050015fbad9c662b8718 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 08:44:00 2021 +0200 Updated api-endpoint commit 249ef70e14fa8db0c388ffb27f5173815a07c768 Merge: c8296cbfcc0a9aaeAuthor: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 08:39:43 2021 +0200 Merge branch 'develop' into feature/TV-700-erik commit c8296cbff42d747df8c17cf3858f22956fd1e910 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 07:44:41 2021 +0200 Fixed some linting and tests commit ec0bf7cd3616859742e461ffd65a2289f5c50cd6 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Wed Oct 6 07:37:28 2021 +0200 Changes after PR commit aa6cee5248299056e043170b8803335529277062 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Oct 5 14:56:45 2021 +0200 Fixed some styling commit 86de8306679fcff5ed8595f97f696cb43f38f4ac Merge: 3b1822d85cee9695Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Oct 5 14:46:52 2021 +0200 Merged develop and resolved conflicts commit 3b1822d8c8f197b789d1db5832b8e99351e8afa3 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Oct 5 14:22:06 2021 +0200 Updated GP commit a63dfb716a3888f3e5830fe224de4cd16b1922c2 Merge: e2a8cb1c07ec3c4aAuthor: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Oct 5 07:29:23 2021 +0200 Merge branch 'develop' into feature/TV-700 commit e2a8cb1cef2ada931f8a82ae0e9849aabb77ac4d Author: Chingiz <chingiz.esenbaev@arbetsformedlingen.se> Date: Mon Oct 4 20:16:42 2021 +0200 lamnas over till team 1
This commit is contained in:
@@ -42,12 +42,12 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="avrop__progress-bar" *ngIf="currentStep < 4">
|
<div class="avrop__progress-bar">
|
||||||
<span>Steg {{ currentStep }} av {{ totalAmountOfSteps }}:</span>
|
<digi-progressbar
|
||||||
<digi-ng-progress-progressbar
|
[afTotalSteps]="totalAmountOfSteps"
|
||||||
[afSteps]="totalAmountOfSteps"
|
[afCompletedSteps]="currentStep - 1"
|
||||||
[afActiveStep]="currentStep"
|
af-steps-label="steg avklarade"
|
||||||
></digi-ng-progress-progressbar>
|
></digi-progressbar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="avrop__content" *ngIf="avropData.data.length; else noAvrop">
|
<div class="avrop__content" *ngIf="avropData.data.length; else noAvrop">
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
&__progress-bar {
|
&__progress-bar {
|
||||||
z-index: $msfa__z-index-default;
|
z-index: $msfa__z-index-default;
|
||||||
|
min-width: 12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__select-handledare {
|
&__select-handledare {
|
||||||
|
|||||||
@@ -1,55 +1,47 @@
|
|||||||
<section class="report-layout" *ngIf="contactInformation$ | async as contactInformation; else skeletonRef">
|
<section class="report-layout">
|
||||||
|
<digi-typography>
|
||||||
<h1>{{ reportTitle }}</h1>
|
<h1>{{ reportTitle }}</h1>
|
||||||
<p class="report-layout__description">{{description}}</p>
|
<p class="report-layout__description" *ngIf="description">{{description}}</p>
|
||||||
<div class="report-layout__deltagare-info">
|
<div class="report-layout__deltagare-info" *ngIf="avrop">
|
||||||
<h2>{{reportSubTitle}}</h2>
|
<h2 *ngIf="reportSubTitle">{{reportSubTitle}}</h2>
|
||||||
<div class="report-layout__name">{{contactInformation.firstName + ' ' + contactInformation.lastName}}</div>
|
<dl>
|
||||||
<div class="report-layout__personnummer">
|
<dt>Namn</dt>
|
||||||
<span>Personnummer:</span>
|
<dd>{{avrop.fullName}}</dd>
|
||||||
<msfa-hide-text
|
</dl>
|
||||||
symbols="********-****"
|
<dl>
|
||||||
[changingText]="contactInformation.ssn"
|
<dt>Personnummer</dt>
|
||||||
ariaLabelType="Personnumer"
|
<dd>
|
||||||
></msfa-hide-text>
|
<msfa-hide-text
|
||||||
</div>
|
symbols="********-****"
|
||||||
<span *ngIf="service">Tjänst: KROM</span>
|
[changingText]="avrop.ssn"
|
||||||
<ng-container *ngIf="startDate && endDate && !isPeriodDate">
|
ariaLabelType="Personnummer"
|
||||||
<span>Startdatum: {{startDate}}</span>
|
></msfa-hide-text>
|
||||||
<span>Slutdatum: {{endDate}}</span>
|
</dd>
|
||||||
</ng-container>
|
<dt>Tjänst</dt>
|
||||||
<span *ngIf="startDate && endDate && isPeriodDate">Avser period: {{startDate}} - {{endDate}}</span>
|
<dd>{{avrop.tjanst}}</dd>
|
||||||
|
<ng-container *ngIf="!isPeriodDate; else periodDateRef">
|
||||||
|
<dt>Startdatum</dt>
|
||||||
|
<dd>{{avrop.startDate | date:'longDate'}}</dd>
|
||||||
|
<dt>Slutdatum</dt>
|
||||||
|
<dd>{{avrop.endDate | date:'longDate'}}</dd>
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #periodDateRef>
|
||||||
|
<dt>Avser period</dt>
|
||||||
|
<dd>{{avrop.startDate | date:'longDate'}} - {{avrop.endDate | date:'longDate'}}</dd>
|
||||||
|
</ng-template>
|
||||||
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="report-layout__notification-alert">
|
<div class="report-layout__progress-bar">
|
||||||
<digi-notification-alert
|
<digi-progressbar
|
||||||
*ngIf="showSuccessNotification"
|
[afTotalSteps]="totalAmountOfSteps"
|
||||||
af-variation="success"
|
[afCompletedSteps]="currentStep - 1"
|
||||||
af-heading="Allt gick bra"
|
af-steps-label="steg avklarade"
|
||||||
af-heading-level="h3"
|
></digi-progressbar>
|
||||||
>
|
|
||||||
<p>Din {{reportTitle.toLocaleLowerCase()}} är nu inskickad till Arbetsförmedlingen.</p>
|
|
||||||
</digi-notification-alert>
|
|
||||||
|
|
||||||
<digi-notification-alert
|
|
||||||
*ngIf="showDangerNotification"
|
|
||||||
af-variation="danger"
|
|
||||||
af-heading="Någonting gick fel"
|
|
||||||
af-heading-level="h3"
|
|
||||||
>
|
|
||||||
<p>Vi kunde inte skicka in din {{reportTitle.toLocaleLowerCase()}}.</p>
|
|
||||||
</digi-notification-alert>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<digi-ng-progress-progressbar
|
|
||||||
[afSteps]="totalAmountOfSteps"
|
|
||||||
[afActiveStep]="currentStep"
|
|
||||||
></digi-ng-progress-progressbar>
|
|
||||||
|
|
||||||
<div class="report-layout__main-content">
|
<div class="report-layout__main-content">
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
</digi-typography>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<ng-template #skeletonRef>
|
|
||||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar skapa rapportsida"></digi-ng-skeleton-base>
|
|
||||||
</ng-template>
|
|
||||||
|
|||||||
@@ -1,32 +1,11 @@
|
|||||||
@import 'apps/mina-sidor-fa/src/styles/variables/gutters';
|
@import 'apps/mina-sidor-fa/src/styles/variables/gutters';
|
||||||
|
|
||||||
.report-layout {
|
.report-layout {
|
||||||
&__name {
|
|
||||||
margin-top: 0;
|
|
||||||
font-weight: var(--digi--typography--font-weight--semibold);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__deltagare-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: $digi--layout--gutter--xl;
|
|
||||||
font-size: var(--digi--typography--font-size--m);
|
|
||||||
font-weight: var(--digi--typography--font-weight--semibold);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__personnummer {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__personnummer msfa-hide-text {
|
|
||||||
margin-left: var(--digi--layout--gutter--s);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__notification-alert {
|
&__notification-alert {
|
||||||
margin-bottom: $digi--layout--gutter--xl;
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__main-content {
|
&__progress-bar {
|
||||||
margin: $digi--layout--gutter--xl 0;
|
margin: $digi--layout--gutter--xl 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { Avrop } from '@msfa-models/avrop.model';
|
||||||
import { ContactInformation } from '@msfa-models/contact-information.model';
|
|
||||||
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { switchMap } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'msfa-report-layout',
|
selector: 'msfa-report-layout',
|
||||||
@@ -12,23 +8,17 @@ import { switchMap } from 'rxjs/operators';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ReportLayoutComponent {
|
export class ReportLayoutComponent {
|
||||||
@Input() reportTitle = 'Report Title';
|
@Input() reportTitle: string;
|
||||||
@Input() reportSubTitle = 'Report Sub Title';
|
@Input() reportSubTitle: string;
|
||||||
@Input() description = 'Report description ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem';
|
@Input() description: string;
|
||||||
@Input() startDate: string;
|
@Input() startDate: string;
|
||||||
@Input() endDate: string;
|
@Input() endDate: string;
|
||||||
@Input() service: string;
|
@Input() service: string;
|
||||||
@Input() isPeriodDate = false;
|
@Input() isPeriodDate = false;
|
||||||
|
@Input() avrop: Avrop;
|
||||||
@Input() totalAmountOfSteps = 3;
|
@Input() totalAmountOfSteps = 3;
|
||||||
@Input() currentStep = 1;
|
@Input() currentStep = 1;
|
||||||
@Input() showSuccessNotification = false;
|
@Input() showSuccessNotification = false;
|
||||||
@Input() showDangerNotification = false;
|
@Input() showDangerNotification = false;
|
||||||
|
@Input() submitted = false;
|
||||||
contactInformation$: Observable<ContactInformation> = this.activatedRoute.params.pipe(
|
|
||||||
switchMap(({ genomforandeReferens }) =>
|
|
||||||
this.deltagareApiService.fetchContactInformation$(genomforandeReferens)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
constructor(private deltagareApiService: DeltagareApiService, private activatedRoute: ActivatedRoute) { }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
|
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { HideTextModule } from '@msfa-shared/components/hide-text/hide-text.module';
|
||||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||||
import { ReportLayoutComponent } from './report-layout.component';
|
import { ReportLayoutComponent } from './report-layout.component';
|
||||||
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
|
||||||
import { HideTextModule } from '@msfa-shared/components/hide-text/hide-text.module';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
declarations: [ReportLayoutComponent],
|
declarations: [ReportLayoutComponent],
|
||||||
imports: [
|
imports: [CommonModule, RouterModule, LayoutModule, DigiNgProgressProgressbarModule, HideTextModule],
|
||||||
CommonModule,
|
|
||||||
RouterModule,
|
|
||||||
LayoutModule,
|
|
||||||
DigiNgProgressProgressbarModule,
|
|
||||||
DigiNgSkeletonBaseModule,
|
|
||||||
HideTextModule],
|
|
||||||
exports: [ReportLayoutComponent],
|
exports: [ReportLayoutComponent],
|
||||||
})
|
})
|
||||||
export class ReportLayoutModule {}
|
export class ReportLayoutModule {}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { LayoutComponent } from '@msfa-shared/components/layout/layout.component';
|
import { LayoutComponent } from '@msfa-shared/components/layout/layout.component';
|
||||||
import { DeltagareAvvikelseComponent } from './deltagare-avvikelse.component';
|
import { DeltagareAvvikelseComponent } from './deltagare-avvikelse.component';
|
||||||
|
import { DeltagareAvvikelseService } from './deltagare-avvikelse.service';
|
||||||
|
|
||||||
describe('DeltagareAvvikelseComponent', () => {
|
describe('DeltagareAvvikelseComponent', () => {
|
||||||
let component: DeltagareAvvikelseComponent;
|
let component: DeltagareAvvikelseComponent;
|
||||||
@@ -22,8 +22,9 @@ describe('DeltagareAvvikelseComponent', () => {
|
|||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
DigiNgFormRadiobuttonGroupModule,
|
DigiNgFormRadiobuttonGroupModule,
|
||||||
DigiNgFormDatepickerModule
|
DigiNgFormDatepickerModule,
|
||||||
]
|
],
|
||||||
|
providers: [DeltagareAvvikelseService],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,126 @@
|
|||||||
<msfa-layout>
|
<msfa-layout>
|
||||||
<form [formGroup]="planeringFormGroup" (ngSubmit)="onFormSubmitted()">
|
<msfa-report-layout
|
||||||
<msfa-report-layout
|
*ngIf="avrop$ | async as avrop; else skeletonRef"
|
||||||
reportTitle="Gemensam Planering"
|
reportTitle="Gemensam planering"
|
||||||
reportSubTitle="Aktiviteter"
|
[totalAmountOfSteps]="totalAmountOfSteps"
|
||||||
[totalAmountOfSteps]="totalAmountOfSteps"
|
[currentStep]="currentStep"
|
||||||
[isPeriodDate]="true"
|
[avrop]="avrop"
|
||||||
[currentStep]="currentStep"
|
[submitted]="lastSubmittedGP$ | async"
|
||||||
[startDate]="'2021-09-01'"
|
[isPeriodDate]="true"
|
||||||
[endDate]="'2021-09-30'"
|
>
|
||||||
(currentStepEvent)="currentStep = $event"
|
<div class="gemensam-planering" *ngIf="currentGenomforandeReferens$ | async as genomforandeReferens">
|
||||||
(sendRequestEvent)="sendRequest = $event"
|
<div class="gemensam-planering__confirmation" *ngIf="lastSubmittedGP$ | async as lastSubmittedGP; else formRef">
|
||||||
>
|
<digi-notification-alert af-variation="success" af-heading="Allt gick bra" af-heading-level="h3">
|
||||||
<div class="gemensam-planering_activity" *ngIf="currentStep === 1">
|
<p>
|
||||||
<h3>Deltar arbetssökande på distans?</h3>
|
Gemensam planering för deltagare {{avrop.fullName}} är nu inskickad till Arbetsförmedlingen och inväntar
|
||||||
<digi-ng-form-radiobutton-group
|
godkännande.
|
||||||
[afRadiobuttons]="distanceChoice"
|
</p>
|
||||||
[formControlName]="participatedOnDistansFormControlName"
|
<dl>
|
||||||
[afRadiobuttonGroupDirection]="direction"
|
<dt>Datum</dt>
|
||||||
></digi-ng-form-radiobutton-group>
|
<dd>{{lastSubmittedGP | date:'longDate'}} kl {{lastSubmittedGP | date:'shortTime'}}</dd>
|
||||||
|
</dl>
|
||||||
|
</digi-notification-alert>
|
||||||
|
<msfa-back-link [route]="['/deltagare/'+ genomforandeReferens]">Tillbaka till deltagaren</msfa-back-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="gemensam-planering_activity" *ngIf="currentStep === 2">Förhandsgranska</div>
|
<ng-template #formRef>
|
||||||
<div class="gemensam-planering__step-buttons-wrapper">
|
<form
|
||||||
<ng-container *ngIf="currentStep > 1">
|
class="gemensam-planering__form"
|
||||||
<digi-button
|
[formGroup]="gpFormGroup"
|
||||||
class="gemensam-planering__step-buttons-wrapper--space-right"
|
(ngSubmit)="openConfirmDialog()"
|
||||||
af-variation="secondary"
|
id="gemensam-planering-form"
|
||||||
af-size="m"
|
>
|
||||||
(afOnClick)="previousStep()"
|
<ng-container *ngIf="currentStep === 1">
|
||||||
>
|
<digi-form-fieldset
|
||||||
Tillbaka
|
af-legend="Deltar arbetssökande på distans?"
|
||||||
</digi-button>
|
af-name="distance"
|
||||||
</ng-container>
|
af-form="gemensam-planering-form"
|
||||||
<ng-container *ngIf="currentStep === (totalAmountOfSteps -1)">
|
>
|
||||||
<digi-button af-size="m" (afOnClick)="nextStep()"> Förhandsgranska </digi-button>
|
<digi-ng-form-radiobutton-group
|
||||||
</ng-container>
|
[afRadiobuttons]="distanceRadiobuttons"
|
||||||
<ng-container *ngIf="currentStep === totalAmountOfSteps">
|
formControlName="distance"
|
||||||
<digi-button af-size="m" (afOnClick)="sendRequest(true)"> Skicka in </digi-button>
|
[afRequired]="true"
|
||||||
</ng-container>
|
[afRadiobuttonGroupDirection]="RadiobuttonGroupDirection.HORIZONTAL"
|
||||||
</div>
|
></digi-ng-form-radiobutton-group>
|
||||||
</msfa-report-layout>
|
</digi-form-fieldset>
|
||||||
</form>
|
<digi-form-fieldset af-legend="Aktiviteter" af-name="aktivitetsIds" af-form="gemensam-planering-form">
|
||||||
|
<p>
|
||||||
|
Varje gemensam planering måste innehålla de två obligatoriska aktiviteterna samt en frivillig aktivitet
|
||||||
|
som en del av det individuella stödet för varje deltagare.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ng-container *ngIf="activities$ | async as activities; else loadingRef">
|
||||||
|
<ul class="gemensam-planering__activity-list">
|
||||||
|
<li class="gemensam-planering__activity-item" *ngFor="let activity of activities;">
|
||||||
|
<digi-form-checkbox
|
||||||
|
[afLabel]="activity.name + (isActivityObligatory(activity.id) ? ' (obligatorisk)' : '')"
|
||||||
|
[afValue]="activity.id"
|
||||||
|
[afValidation]="showActivityAsInvalid(activity.id) ? 'error' : 'neutral'"
|
||||||
|
[afChecked]="isActivityChecked(activity.id) || isActivityObligatory(activity.id)"
|
||||||
|
(afOnChange)="updateActivityIds(activity.id, $event.detail.target.checked)"
|
||||||
|
></digi-form-checkbox>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<digi-form-validation-message
|
||||||
|
*ngIf="shouldValidate && gpFormGroup.errors?.activityIds"
|
||||||
|
af-variation="error"
|
||||||
|
>{{gpFormGroup.errors.activityIds}}</digi-form-validation-message
|
||||||
|
>
|
||||||
|
</ng-container>
|
||||||
|
</digi-form-fieldset>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="currentStep === 2">
|
||||||
|
<dl>
|
||||||
|
<dt>Deltar arbetssökande på distans?</dt>
|
||||||
|
<dd>{{gpFormGroup.value.distance ? 'Ja' : 'Nej'}}</dd>
|
||||||
|
<dt>Aktiviteter</dt>
|
||||||
|
<dd>
|
||||||
|
<ul class="gemensam-planering__activity-list" *ngFor="let activity of activities$ | async">
|
||||||
|
<li
|
||||||
|
class="gemensam-planering__activity-item"
|
||||||
|
*ngIf="activityIdsFormArray.value.includes(activity.id)"
|
||||||
|
>
|
||||||
|
<digi-icon-check-circle
|
||||||
|
class="msfa__digi-icon gemensam-planering__activity-check"
|
||||||
|
aria-hidden="true"
|
||||||
|
></digi-icon-check-circle>
|
||||||
|
{{activity.name}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</ng-container>
|
||||||
|
<footer class="gemensam-planering__footer">
|
||||||
|
<ng-container *ngIf="currentStep > 1">
|
||||||
|
<digi-button
|
||||||
|
class="gemensam-planering__step-buttons-wrapper--space-right"
|
||||||
|
af-variation="secondary"
|
||||||
|
af-size="m"
|
||||||
|
(afOnClick)="goToStep1()"
|
||||||
|
>Tillbaka</digi-button
|
||||||
|
>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="currentStep === 1">
|
||||||
|
<digi-button af-size="m" (afOnClick)="goToPreview()">Förhandsgranska</digi-button>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="currentStep === 2">
|
||||||
|
<digi-button af-type="submit" af-size="m">Bekräfta och skicka in</digi-button>
|
||||||
|
</ng-container>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
<msfa-confirm-dialog
|
||||||
|
[openConfirmDialog]="confirmDialogOpen"
|
||||||
|
reportToConfirm="gemensam planering"
|
||||||
|
(confirmDialogChanged)="closeConfirmDialogAndProceed($event, genomforandeReferens)"
|
||||||
|
></msfa-confirm-dialog>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</msfa-report-layout>
|
||||||
</msfa-layout>
|
</msfa-layout>
|
||||||
|
|
||||||
|
<ng-template #skeletonRef>
|
||||||
|
<digi-ng-skeleton-base [afCount]="3" afText="Laddar data för gemensam planering"></digi-ng-skeleton-base>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #loadingRef>
|
||||||
|
<msfa-loader type="padded"></msfa-loader>
|
||||||
|
</ng-template>
|
||||||
|
|||||||
@@ -1,8 +1,43 @@
|
|||||||
|
@import 'mixins/list';
|
||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
.gemensam-planering {
|
.gemensam-planering {
|
||||||
&__pages {
|
&__confirmation,
|
||||||
margin: 5rem 0rem;
|
&__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $digi--layout--gutter--l;
|
||||||
}
|
}
|
||||||
&__step-buttons-wrapper--space-right {
|
|
||||||
margin-right: 1rem;
|
&__activity-list {
|
||||||
|
@include msfa__reset-list;
|
||||||
|
margin-bottom: var(--digi--layout--gutter--s);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__activity-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--digi--layout--gutter--s);
|
||||||
|
margin-top: var(--digi--layout--gutter--s);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__activity-check {
|
||||||
|
color: var(--digi--ui--color--border--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--digi--layout--gutter);
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.digi-form-fieldset {
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&__legend {
|
||||||
|
margin-bottom: var(--digi--layout--gutter--s);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
|
||||||
import { RadiobuttonGroupDirection, RadiobuttonModel } from '@af/digi-ng/_form/form-radiobutton-group';
|
import { RadiobuttonGroupDirection, RadiobuttonModel } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { RequiredValidator } from '@msfa-validators/required.validator';
|
import { FormArray, FormControl, FormGroup } from '@angular/forms';
|
||||||
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ConfirmDialog } from '@msfa-enums/confirm-dialog.enum';
|
||||||
|
import { Activity } from '@msfa-models/activity.model';
|
||||||
|
import { Avrop } from '@msfa-models/avrop.model';
|
||||||
|
import {
|
||||||
|
GemensamPlanering,
|
||||||
|
mapGemensamPlaneringToGemensamPlaneringPostRequest,
|
||||||
|
} from '@msfa-models/gemensam-planering.model';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { distinctUntilChanged, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||||
|
import { GemensamPlaneringService } from './gemensam-planering.service';
|
||||||
|
import { GemensamPlaneringValidator } from './gemensam-planering.validator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'msfa-deltagare-gemensam-planering',
|
selector: 'msfa-deltagare-gemensam-planering',
|
||||||
@@ -10,54 +20,124 @@ import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planeri
|
|||||||
styleUrls: ['./deltagare-gemensam-planering.component.scss'],
|
styleUrls: ['./deltagare-gemensam-planering.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class DeltagareGemensamPlaneringComponent implements OnInit {
|
export class DeltagareGemensamPlaneringComponent {
|
||||||
totalAmountOfSteps = 2;
|
totalAmountOfSteps = 2;
|
||||||
currentStep = 1;
|
currentStep = 1;
|
||||||
direction = RadiobuttonGroupDirection.HORIZONTAL;
|
obligatoryActivityIds = [165, 188];
|
||||||
planeringFormGroup: FormGroup | null = null;
|
shouldValidate = false;
|
||||||
|
RadiobuttonGroupDirection = RadiobuttonGroupDirection;
|
||||||
|
confirmDialogOpen = false;
|
||||||
|
private _lastSubmittedGP$ = new BehaviorSubject<Date>(null);
|
||||||
|
lastSubmittedGP$: Observable<Date> = this._lastSubmittedGP$.asObservable();
|
||||||
|
|
||||||
readonly participatedOnDistansFormControlName = 'participatedOnDistans';
|
activities$: Observable<Activity[]> = this.gemensamPlaneringService.activities$;
|
||||||
distanceChoice: RadiobuttonModel[] = [
|
currentGenomforandeReferens$: Observable<number> = this.activatedRoute.params.pipe(
|
||||||
|
map(params => params.genomforandeReferens as string),
|
||||||
|
distinctUntilChanged(
|
||||||
|
([prevGenomforandeReferens], [currGenomforandeReferens]) => prevGenomforandeReferens === currGenomforandeReferens
|
||||||
|
),
|
||||||
|
map(genomforandeReferens => +genomforandeReferens)
|
||||||
|
);
|
||||||
|
avrop$: Observable<Avrop> = this.currentGenomforandeReferens$.pipe(
|
||||||
|
switchMap(genomforandeReferens => this.gemensamPlaneringService.fetchAvropInformation$(genomforandeReferens)),
|
||||||
|
shareReplay(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
gpFormGroup = new FormGroup(
|
||||||
{
|
{
|
||||||
label: 'Ja',
|
distance: new FormControl(false),
|
||||||
value: 'Ja',
|
activityIds: new FormArray(this.obligatoryActivityIds.map(id => new FormControl(id))),
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Nej',
|
|
||||||
value: 'Nej',
|
|
||||||
},
|
},
|
||||||
|
[GemensamPlaneringValidator.isGemensamPlaneringValid(this.obligatoryActivityIds)]
|
||||||
|
);
|
||||||
|
|
||||||
|
distanceRadiobuttons: RadiobuttonModel[] = [
|
||||||
|
{ label: 'Ja', value: true },
|
||||||
|
{ label: 'Nej', value: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(private gemensamPlaneringService: GemensamPlaneringApiService) {}
|
get activityIdsFormArray(): FormArray {
|
||||||
|
return this.gpFormGroup.get('activityIds') as FormArray;
|
||||||
get participatedOnDistansFormControl(): AbstractControl | undefined {
|
|
||||||
return this.planeringFormGroup?.get(this.participatedOnDistansFormControlName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
get selectedActivityIds(): number[] {
|
||||||
this.planeringFormGroup = new FormGroup({
|
return this.activityIdsFormArray.value as number[];
|
||||||
participatedOnDistans: new FormControl('', [RequiredValidator()]),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextStep(): void {
|
get selectedActivityIdsExcludingObligatory(): number[] {
|
||||||
if (this.planeringFormGroup?.valid && this.currentStep < this.totalAmountOfSteps) {
|
return this.selectedActivityIds.filter(id => this.obligatoryActivityIds.indexOf(id) === -1);
|
||||||
console.log(this.participatedOnDistansFormControl.value);
|
}
|
||||||
this.currentStep++;
|
|
||||||
console.log(this.currentStep);
|
isActivityChecked(id: number): boolean {
|
||||||
|
return this.selectedActivityIds.includes(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
isActivityObligatory(id: number): boolean {
|
||||||
|
return this.obligatoryActivityIds.includes(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
showActivityAsInvalid(id: number): boolean {
|
||||||
|
if (this.shouldValidate) {
|
||||||
|
if (this.isActivityObligatory(id) && !this.isActivityChecked(id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!this.isActivityObligatory(id) && !this.selectedActivityIdsExcludingObligatory.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private gemensamPlaneringService: GemensamPlaneringService, private activatedRoute: ActivatedRoute) {}
|
||||||
|
|
||||||
|
updateActivityIds(activityId: string, checked: boolean): void {
|
||||||
|
if (checked) {
|
||||||
|
this.activityIdsFormArray.push(new FormControl(+activityId));
|
||||||
|
} else {
|
||||||
|
const index: number = this.selectedActivityIds.findIndex(id => id === +activityId);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
this.activityIdsFormArray.removeAt(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previousStep(): void {
|
goToPreview(): void {
|
||||||
if (this.currentStep > 1) {
|
this.shouldValidate = true;
|
||||||
this.currentStep--;
|
|
||||||
console.log(this.currentStep);
|
if (this.gpFormGroup.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentStep = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
goToStep1(): void {
|
||||||
|
this.shouldValidate = false;
|
||||||
|
this.currentStep = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
openConfirmDialog(): void {
|
||||||
|
this.confirmDialogOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeConfirmDialogAndProceed(confirmDialogAnswer: ConfirmDialog, genomforandeReferens: number): void {
|
||||||
|
if (confirmDialogAnswer === ConfirmDialog.ACCEPTED) {
|
||||||
|
const distance = this.gpFormGroup.get('distance').value as boolean;
|
||||||
|
const activityIds = this.gpFormGroup.get('activityIds').value as number[];
|
||||||
|
|
||||||
|
void this.postGemensamPlanering({ distance, activityIds, genomforandeReferens });
|
||||||
|
} else {
|
||||||
|
this.confirmDialogOpen = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRequest(val: boolean): boolean {
|
async postGemensamPlanering(postRequest: GemensamPlanering): Promise<void> {
|
||||||
return val;
|
return this.gemensamPlaneringService
|
||||||
|
.postGemensamPlanering(mapGemensamPlaneringToGemensamPlaneringPostRequest(postRequest))
|
||||||
|
.then(() => {
|
||||||
|
this._lastSubmittedGP$.next(new Date());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onFormSubmitted(): void {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
||||||
|
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
|
||||||
import { DeltagareGemensamPlaneringComponent } from './deltagare-gemensam-planering.component';
|
|
||||||
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
|
||||||
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { BackLinkModule } from '@msfa-shared/components/back-link/back-link.module';
|
||||||
|
import { ConfirmDialogModule } from '@msfa-shared/components/confirm-dialog/confirm-dialog.module';
|
||||||
|
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||||
|
import { LoaderModule } from '@msfa-shared/components/loader/loader.module';
|
||||||
import { ReportLayoutModule } from '../components/report-layout/report-layout.module';
|
import { ReportLayoutModule } from '../components/report-layout/report-layout.module';
|
||||||
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
import { DeltagareGemensamPlaneringComponent } from './deltagare-gemensam-planering.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
@@ -20,6 +24,10 @@ import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
|||||||
DigiNgFormRadiobuttonGroupModule,
|
DigiNgFormRadiobuttonGroupModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
ReportLayoutModule,
|
ReportLayoutModule,
|
||||||
|
ConfirmDialogModule,
|
||||||
|
BackLinkModule,
|
||||||
|
LoaderModule,
|
||||||
|
DigiNgSkeletonBaseModule,
|
||||||
DigiNgFormCheckboxModule,
|
DigiNgFormCheckboxModule,
|
||||||
],
|
],
|
||||||
exports: [DeltagareGemensamPlaneringComponent],
|
exports: [DeltagareGemensamPlaneringComponent],
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Activity } from '@msfa-models/activity.model';
|
||||||
|
import { GemensamPlaneringPostRequest } from '@msfa-models/api/gemensam-planering.request.model';
|
||||||
|
import { Avrop } from '@msfa-models/avrop.model';
|
||||||
|
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
|
||||||
|
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class GemensamPlaneringService {
|
||||||
|
public activities$: Observable<Activity[]> = this.gemensamPlaneringApiService.fetchActivities$();
|
||||||
|
private _error$ = new BehaviorSubject<string>(null);
|
||||||
|
public error$: Observable<string> = this._error$.asObservable();
|
||||||
|
|
||||||
|
public fetchAvropInformation$(genomforandeReferens: number): Observable<Avrop> {
|
||||||
|
return this.gemensamPlaneringApiService.fetchAvropInformation$(genomforandeReferens);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async postGemensamPlanering(requestData: GemensamPlaneringPostRequest): Promise<void> {
|
||||||
|
// TODO: When API has been updated we can activate the real post
|
||||||
|
return of(undefined as void).toPromise();
|
||||||
|
return this.gemensamPlaneringApiService.postGemensamPlanering(requestData);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private gemensamPlaneringApiService: GemensamPlaneringApiService) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||||
|
|
||||||
|
export class GemensamPlaneringValidator {
|
||||||
|
static isGemensamPlaneringValid(obligatoryActivityIds: number[] = []): ValidatorFn {
|
||||||
|
return (c: AbstractControl): { [key: string]: string } => {
|
||||||
|
let errors: { [key: string]: string } = null;
|
||||||
|
const activityIds = (c.get('activityIds')?.value as number[]) || [];
|
||||||
|
const obligatoryActivityIdsMissing = !obligatoryActivityIds.every(id => activityIds.includes(id));
|
||||||
|
const activityIdsWithoutObligatoryActivityIds = activityIds.filter(
|
||||||
|
id => obligatoryActivityIds.indexOf(id) === -1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (obligatoryActivityIdsMissing && !activityIdsWithoutObligatoryActivityIds.length) {
|
||||||
|
errors = {
|
||||||
|
...errors,
|
||||||
|
activityIds: 'Obligatoriska aktiviteter och minst en frivillig aktivitet måste väljas',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if (obligatoryActivityIdsMissing) {
|
||||||
|
errors = {
|
||||||
|
...errors,
|
||||||
|
activityIds: 'Obligatoriska aktiviteter måste väljas',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activityIdsWithoutObligatoryActivityIds.length) {
|
||||||
|
errors = {
|
||||||
|
...errors,
|
||||||
|
activityIds: 'Minst en frivillig aktivitet måste väljas',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { DeltagarePeriodiskRedovisningComponent } from './deltagare-periodisk-redovisning.component';
|
import { DeltagarePeriodiskRedovisningComponent } from './deltagare-periodisk-redovisning.component';
|
||||||
|
|
||||||
describe('PeriodiskRedovisningComponent', () => {
|
describe('DeltagarePeriodiskRedovisningComponent', () => {
|
||||||
let component: DeltagarePeriodiskRedovisningComponent;
|
let component: DeltagarePeriodiskRedovisningComponent;
|
||||||
let fixture: ComponentFixture<DeltagarePeriodiskRedovisningComponent>;
|
let fixture: ComponentFixture<DeltagarePeriodiskRedovisningComponent>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { RadiobuttonGroupDirection } from '@af/digi-ng/_form/form-radiobutton-group';
|
import { RadiobuttonGroupDirection } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
|
import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
import { Activity, SubActivity } from '@msfa-models/activity.model';
|
import { Activity, SubActivity } from '@msfa-models/activity.model';
|
||||||
import { ActivitiesApiService } from '@msfa-services/api/activities-api.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'msfa-deltagare-periodisk-redovisning',
|
selector: 'msfa-deltagare-periodisk-redovisning',
|
||||||
@@ -10,7 +9,7 @@ import { ActivitiesApiService } from '@msfa-services/api/activities-api.service'
|
|||||||
styleUrls: ['./deltagare-periodisk-redovisning.component.scss'],
|
styleUrls: ['./deltagare-periodisk-redovisning.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class DeltagarePeriodiskRedovisningComponent implements OnInit {
|
export class DeltagarePeriodiskRedovisningComponent {
|
||||||
radiobuttonGroupDirection = RadiobuttonGroupDirection;
|
radiobuttonGroupDirection = RadiobuttonGroupDirection;
|
||||||
totalAmountOfSteps = 3;
|
totalAmountOfSteps = 3;
|
||||||
currentStep = 1;
|
currentStep = 1;
|
||||||
@@ -25,8 +24,6 @@ export class DeltagarePeriodiskRedovisningComponent implements OnInit {
|
|||||||
readonly datesForActivitiesFormArrayName = 'datesForActivities';
|
readonly datesForActivitiesFormArrayName = 'datesForActivities';
|
||||||
readonly subActivitiesFormArrayName = 'subActivities';
|
readonly subActivitiesFormArrayName = 'subActivities';
|
||||||
|
|
||||||
constructor(private activitiesApiService: ActivitiesApiService) {}
|
|
||||||
|
|
||||||
get lamnatJobbForslagFormControl(): AbstractControl {
|
get lamnatJobbForslagFormControl(): AbstractControl {
|
||||||
return this.periodiskRedovisningFormGroup.get(this.lamnatJobbForslagFormControlName);
|
return this.periodiskRedovisningFormGroup.get(this.lamnatJobbForslagFormControlName);
|
||||||
}
|
}
|
||||||
@@ -39,12 +36,6 @@ export class DeltagarePeriodiskRedovisningComponent implements OnInit {
|
|||||||
return this.periodiskRedovisningFormGroup.get(this.activitiesFormArrayName) as FormArray;
|
return this.periodiskRedovisningFormGroup.get(this.activitiesFormArrayName) as FormArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.activitiesApiService
|
|
||||||
.getActivities$()
|
|
||||||
.subscribe(activities => this.initializePeriodiskRedovisningFormGroup(activities));
|
|
||||||
}
|
|
||||||
|
|
||||||
initializePeriodiskRedovisningFormGroup(activitiesList: Activity[]): void {
|
initializePeriodiskRedovisningFormGroup(activitiesList: Activity[]): void {
|
||||||
this.periodiskRedovisningFormGroup = new FormGroup({
|
this.periodiskRedovisningFormGroup = new FormGroup({
|
||||||
lamnatJobbForslag: new FormControl(null, [Validators.required]),
|
lamnatJobbForslag: new FormControl(null, [Validators.required]),
|
||||||
@@ -70,9 +61,8 @@ export class DeltagarePeriodiskRedovisningComponent implements OnInit {
|
|||||||
getActivtiesFormField(formCtrlName: string, activity: Activity): FormArray | FormControl {
|
getActivtiesFormField(formCtrlName: string, activity: Activity): FormArray | FormControl {
|
||||||
if (formCtrlName === 'datesForActivities') {
|
if (formCtrlName === 'datesForActivities') {
|
||||||
return new FormArray([]);
|
return new FormArray([]);
|
||||||
} else if (formCtrlName === 'subActivities') {
|
|
||||||
return this.addSubActivitesFormArray(activity?.subActivities, activity.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FormControl(null, []);
|
return new FormControl(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||||
import { ReportLayoutModule } from '../components/report-layout/report-layout.module';
|
import { ReportLayoutModule } from '../components/report-layout/report-layout.module';
|
||||||
import { DeltagarePeriodiskRedovisningComponent } from './deltagare-periodisk-redovisning.component';
|
|
||||||
import { PeriodiskRedovisningFormModule } from './components/periodisk-redovisning-form/periodisk-redovisning-form.module';
|
import { PeriodiskRedovisningFormModule } from './components/periodisk-redovisning-form/periodisk-redovisning-form.module';
|
||||||
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
import { DeltagarePeriodiskRedovisningComponent } from './deltagare-periodisk-redovisning.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
<msfa-layout>
|
<msfa-layout>
|
||||||
<ng-container *ngIf="(showUnauthorizedError$ | async) === false; else roleError">
|
<ng-container *ngIf="(showUnauthorizedError$ | async) === false; else roleError">
|
||||||
<section *ngIf="allDeltagareData$ | async as allDeltagareData; else loadingRef" class="deltagare">
|
<digi-typography>
|
||||||
<header class="deltagare__header">
|
<section *ngIf="allDeltagareData$ | async as allDeltagareData; else loadingRef" class="deltagare">
|
||||||
<h1>Deltagarlista</h1>
|
<header class="deltagare__header">
|
||||||
<p>
|
<h1>Deltagarlista</h1>
|
||||||
Här ser du en lista på de deltagare som tillhör din organisation. Klicka på deltagarens namn för att öppna
|
<p>
|
||||||
och se mer information om deltagarna.
|
Här ser du en lista på de deltagare som tillhör din organisation. Klicka på deltagarens namn för att öppna
|
||||||
</p>
|
och se mer information om deltagarna.
|
||||||
</header>
|
</p>
|
||||||
<div class="deltagare__filter">
|
</header>
|
||||||
<digi-form-checkbox
|
<div class="deltagare__filter">
|
||||||
(afOnChange)="setOnlyMyDeltagare($event.detail.target.checked)"
|
<digi-form-checkbox
|
||||||
[afChecked]="onlyMyDeltagare$ | async"
|
(afOnChange)="setOnlyMyDeltagare($event.detail.target.checked)"
|
||||||
af-label="Visa endast mina tilldelade deltagare"
|
[afChecked]="onlyMyDeltagare$ | async"
|
||||||
class="deltagare__only-my-deltagare"
|
af-label="Visa endast mina tilldelade deltagare"
|
||||||
></digi-form-checkbox>
|
class="deltagare__only-my-deltagare"
|
||||||
</div>
|
></digi-form-checkbox>
|
||||||
<msfa-deltagare-list-table
|
</div>
|
||||||
(paginated)="setNewPage($event)"
|
<msfa-deltagare-list-table
|
||||||
(sorted)="handleDeltagareSort($event)"
|
(paginated)="setNewPage($event)"
|
||||||
*ngIf="allDeltagareData.data.length; else noDeltagare"
|
(sorted)="handleDeltagareSort($event)"
|
||||||
[deltagareLoading]="deltagareLoading$ | async"
|
*ngIf="allDeltagareData.data.length; else noDeltagare"
|
||||||
[deltagare]="allDeltagareData.data"
|
[deltagareLoading]="deltagareLoading$ | async"
|
||||||
[paginationMeta]="allDeltagareData.meta"
|
[deltagare]="allDeltagareData.data"
|
||||||
[sort]="sort$ | async"
|
[paginationMeta]="allDeltagareData.meta"
|
||||||
></msfa-deltagare-list-table>
|
[sort]="sort$ | async"
|
||||||
</section>
|
></msfa-deltagare-list-table>
|
||||||
|
</section>
|
||||||
|
</digi-typography>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</msfa-layout>
|
</msfa-layout>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ConfirmDialog } from '@msfa-enums/confirm-dialog.enum';
|
|||||||
selector: 'msfa-confirm-dialog',
|
selector: 'msfa-confirm-dialog',
|
||||||
templateUrl: './confirm-dialog.component.html',
|
templateUrl: './confirm-dialog.component.html',
|
||||||
styleUrls: ['./confirm-dialog.component.scss'],
|
styleUrls: ['./confirm-dialog.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ConfirmDialogComponent {
|
export class ConfirmDialogComponent {
|
||||||
@Input() openConfirmDialog: boolean;
|
@Input() openConfirmDialog: boolean;
|
||||||
@@ -21,5 +21,4 @@ export class ConfirmDialogComponent {
|
|||||||
this.openConfirmDialog = false;
|
this.openConfirmDialog = false;
|
||||||
this.confirmDialogChanged.emit(ConfirmDialog.DISMISSED);
|
this.confirmDialogChanged.emit(ConfirmDialog.DISMISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
export interface Activity {
|
export interface Activity {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
|
||||||
subActivities: SubActivity[];
|
|
||||||
}
|
}
|
||||||
export interface SubActivity {
|
export interface SubActivity {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -12,15 +10,12 @@ export interface SubActivity {
|
|||||||
export interface ActivityResponse {
|
export interface ActivityResponse {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
|
||||||
subActivities: SubActivity[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapResponseToActivity(data: ActivityResponse): Activity {
|
export function mapResponseToActivity(data: ActivityResponse): Activity {
|
||||||
const { id, name, description, subActivities } = data;
|
const { id, name } = data;
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
description,
|
|
||||||
subActivities,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface GemensamPlaneringPostRequest {
|
||||||
|
genomforandeReferens: string;
|
||||||
|
distans: boolean;
|
||||||
|
aktivitetsIds: number[];
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { TrackName } from '@msfa-enums/track-name.enum';
|
import { TrackName } from '@msfa-enums/track-name.enum';
|
||||||
|
import { mapStringToSsn } from '@msfa-utils/map-string-to-ssn.util';
|
||||||
import { AvropResponse } from './api/avrop.response.model';
|
import { AvropResponse } from './api/avrop.response.model';
|
||||||
import { PaginationMeta } from './pagination-meta.model';
|
import { PaginationMeta } from './pagination-meta.model';
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ export interface AvropCompact {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Avrop extends AvropCompact {
|
export interface Avrop extends AvropCompact {
|
||||||
|
ssn: string; // personnummer
|
||||||
genomforandeReferens: number; // genomforandeReferens
|
genomforandeReferens: number; // genomforandeReferens
|
||||||
participationFrequency: number; // deltagandeGrad
|
participationFrequency: number; // deltagandeGrad
|
||||||
utforandeVerksamhet: string; // utforandeverksamhet
|
utforandeVerksamhet: string; // utforandeverksamhet
|
||||||
@@ -41,6 +43,7 @@ export function mapAvropResponseToAvrop(data: AvropResponse): Avrop {
|
|||||||
sprakstod,
|
sprakstod,
|
||||||
adress,
|
adress,
|
||||||
sparkod,
|
sparkod,
|
||||||
|
personnummer,
|
||||||
genomforandeReferens,
|
genomforandeReferens,
|
||||||
deltagandeGrad,
|
deltagandeGrad,
|
||||||
utforandeverksamhet,
|
utforandeverksamhet,
|
||||||
@@ -60,6 +63,7 @@ export function mapAvropResponseToAvrop(data: AvropResponse): Avrop {
|
|||||||
utforandeAdress: adress,
|
utforandeAdress: adress,
|
||||||
trackCode: sparkod,
|
trackCode: sparkod,
|
||||||
trackName: (TrackName[sparkod] || TrackName.UNKNOWN) as TrackName,
|
trackName: (TrackName[sparkod] || TrackName.UNKNOWN) as TrackName,
|
||||||
|
ssn: mapStringToSsn(personnummer),
|
||||||
genomforandeReferens,
|
genomforandeReferens,
|
||||||
participationFrequency: deltagandeGrad,
|
participationFrequency: deltagandeGrad,
|
||||||
utforandeVerksamhet: utforandeverksamhet,
|
utforandeVerksamhet: utforandeverksamhet,
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
import { GemensamPlaneringPostRequest } from './api/gemensam-planering.request.model';
|
||||||
|
|
||||||
|
export interface GemensamPlanering {
|
||||||
|
genomforandeReferens: number;
|
||||||
|
distance: boolean;
|
||||||
|
activityIds: number[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface Activity {
|
export interface Activity {
|
||||||
activityId: string;
|
activityId: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -9,3 +17,15 @@ export interface SubActivity {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mapGemensamPlaneringToGemensamPlaneringPostRequest(
|
||||||
|
gemensamPlanering: GemensamPlanering
|
||||||
|
): GemensamPlaneringPostRequest {
|
||||||
|
const { genomforandeReferens, distance, activityIds } = gemensamPlanering;
|
||||||
|
|
||||||
|
return {
|
||||||
|
genomforandeReferens: genomforandeReferens.toString(),
|
||||||
|
distans: distance,
|
||||||
|
aktivitetsIds: activityIds,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,21 +2,48 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { environment } from '@msfa-environment';
|
import { environment } from '@msfa-environment';
|
||||||
import { Activity, ActivityResponse, mapResponseToActivity } from '@msfa-models/activity.model';
|
import { Activity, ActivityResponse, mapResponseToActivity } from '@msfa-models/activity.model';
|
||||||
|
import { GemensamPlaneringPostRequest } from '@msfa-models/api/gemensam-planering.request.model';
|
||||||
|
import { Avrop } from '@msfa-models/avrop.model';
|
||||||
|
import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error';
|
||||||
|
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { filter, map } from 'rxjs/operators';
|
import { catchError, filter, map, shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class GemensamPlaneringApiService {
|
export class GemensamPlaneringApiService {
|
||||||
private _apiBaseUrl = `${environment.api.url}`;
|
private _apiBaseUrl = `${environment.api.url}/rapporter/gemensam-planering`;
|
||||||
|
|
||||||
constructor(private httpClient: HttpClient) {}
|
public fetchActivities$(): Observable<Activity[]> {
|
||||||
|
return this.httpClient.get<{ data: ActivityResponse[] }>(`${this._apiBaseUrl}/aktiviteter`).pipe(
|
||||||
public getActivities$(): Observable<Activity[]> {
|
|
||||||
return this.httpClient.get<{ data: ActivityResponse[] }>(`${this._apiBaseUrl}/activities`).pipe(
|
|
||||||
filter(response => !!response?.data),
|
filter(response => !!response?.data),
|
||||||
map(({ data }) => data.map(aktivitet => mapResponseToActivity(aktivitet)))
|
map(({ data }) => data.map(activity => mapResponseToActivity(activity))),
|
||||||
|
catchError((error: Error & { status: number }) => {
|
||||||
|
throw new CustomError(
|
||||||
|
errorToCustomError({ ...error, message: `Kunde inte hämta aktiviteter.\n\n${error.message}` })
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
shareReplay(1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fetchAvropInformation$(genomforandeReferens: number): Observable<Avrop> {
|
||||||
|
return this.deltagareApiService.fetchAvropInformation$(genomforandeReferens);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async postGemensamPlanering(requestData: GemensamPlaneringPostRequest): Promise<void> {
|
||||||
|
return this.httpClient
|
||||||
|
.post<void>(`${this._apiBaseUrl}`, requestData)
|
||||||
|
.pipe(
|
||||||
|
catchError((error: Error & { status: number }) => {
|
||||||
|
throw new CustomError(
|
||||||
|
errorToCustomError({ ...error, message: `Kunde inte spara gemensam planering.\n\n${error.message}` })
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient, private deltagareApiService: DeltagareApiService) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
|
"/api/rapporter/gemensam-planering": {
|
||||||
|
"target": "https://mina-sidor-fa-utv.tocp.arbetsformedlingen.se",
|
||||||
|
"secure": false,
|
||||||
|
"changeOrigin": true
|
||||||
|
},
|
||||||
"/api": {
|
"/api": {
|
||||||
"target": "https://mina-sidor-fa-test.tocp.arbetsformedlingen.se",
|
"target": "https://mina-sidor-fa-test.tocp.arbetsformedlingen.se",
|
||||||
"secure": false,
|
"secure": false,
|
||||||
|
|||||||
Reference in New Issue
Block a user