feat(export): Added export deltagare. (TV-872)
Squashed commit of the following: commit 9c06b7f1d44a4b48d7f31a22b6bfbd233e09d2f7 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 15:07:15 2021 +0100 Updated api endpoint commit f9bfbecda6d03b70d87febbada920d0eca798b1f Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 15:01:13 2021 +0100 Updated libs commit 9edb413d537288fa0708b8a04eb54f801ebc23a0 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 14:58:13 2021 +0100 Added @types/file-saver commit 624affac55ce771fd58e2770a0d4a98233a8e9ba Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 14:42:29 2021 +0100 Updated libs commit 65dae1d906bbcec474581692b2aced9e47d2484c Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 14:36:42 2021 +0100 Added utils lib config commit 223bd59724663523bdbaf87b5502396156ddb9eb Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 14:06:13 2021 +0100 Added validation commit 166dfcf0448155ac21c0eaa904b4ce1271f73193 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 13:25:35 2021 +0100 Changed styling and removed some fake data commit 3906f2793dd52b626b95c13e115495451332c894 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 13:18:52 2021 +0100 Added digi-ng datepicker commit de0d51434d15cac5476303d4b417c591da16fd8f Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Nov 2 12:31:48 2021 +0100 Added checkbox
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
|
||||
import { RoleEnum } from '@msfa-enums/role.enum';
|
||||
@@ -23,8 +23,8 @@ import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
|
||||
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
|
||||
import { ValidationErrorLink } from '@msfa-shared/components/error-list/error-list.component';
|
||||
import { TreeNodesSelectorService } from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
|
||||
import { uuid } from '@msfa-utils/uuid.util';
|
||||
import { EmployeeValidator } from '@msfa-utils/validators/employee.validator';
|
||||
import { uuid } from '@utils/uuid.util';
|
||||
import { EmployeeFormService } from '../services/employee-form.service';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { ExportsComponent } from './exports.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', data: { title: 'Exporter' }, component: ExportsComponent },
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'deltagare',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'deltagare',
|
||||
data: { title: 'Skapa export för deltagare' },
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
<digi-typography>
|
||||
<header class="exports__header">
|
||||
<h1>Exporter</h1>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut corporis voluptatum magnam cumque fugiat, neque, totam explicabo est reprehenderit perspiciatis ratione error ad eveniet inventore, tempora facilis nostrum earum! Unde!</p>
|
||||
</header>
|
||||
<main class="exports__contents"></main>
|
||||
<main class="exports__contents">
|
||||
|
||||
</main>
|
||||
</digi-typography>
|
||||
</section>
|
||||
</msfa-layout>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||
import { ExportsRoutingModule } from './exports-routing.module';
|
||||
import { ExportsComponent } from './exports.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [ExportsComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: ExportsComponent }]), LayoutModule],
|
||||
imports: [CommonModule, ExportsRoutingModule, LayoutModule, ReactiveFormsModule],
|
||||
})
|
||||
export class ExportsModule {}
|
||||
|
||||
@@ -1,10 +1,62 @@
|
||||
<msfa-layout>
|
||||
<section class="deltagare-export">
|
||||
<digi-typography>
|
||||
<digi-typography>
|
||||
<header class="deltagare-export__header">
|
||||
<h1>Deltagare export</h1>
|
||||
<h1>Exportera information om deltagare</h1>
|
||||
<p>
|
||||
Här kan du exportera deltagarinformation. Informationen laddas ner till din dator i CSV-format. Du kan endast
|
||||
exportera deltagare som du har behörighet att se. Detta innebär att du bara kan få ut de deltagare som är
|
||||
kopplade till samma utförande verksamhet och adress som du är inloggad på. Du kan även välja att inkludera
|
||||
deltagare som exporterats vid tidigare tillfälle. Deltagare som exporterats tidigare markeras i filen.
|
||||
</p>
|
||||
</header>
|
||||
<main class="deltagare-export__contents"></main>
|
||||
<form class="deltagare-export__form" [formGroup]="formGroup" (ngSubmit)="fetchExportFile()">
|
||||
<div
|
||||
class="deltagare-export__period-wrapper"
|
||||
[ngClass]="{'deltagare-export__period-wrapper--error': showPeriodError}"
|
||||
>
|
||||
<div class="deltagare-export__period-inputs">
|
||||
<digi-ng-form-datepicker
|
||||
[afDisableValidStyle]="true"
|
||||
[afMaxDate]="maxDate"
|
||||
[afInvalid]="showPeriodError"
|
||||
afLabel="Från datum"
|
||||
[formControl]="startDateFormControl"
|
||||
></digi-ng-form-datepicker>
|
||||
<digi-ng-form-datepicker
|
||||
[afDisableValidStyle]="true"
|
||||
[afMaxDate]="maxDate"
|
||||
[afInvalid]="showPeriodError"
|
||||
afLabel="Till och med datum"
|
||||
[formControl]="endDateFormControl"
|
||||
></digi-ng-form-datepicker>
|
||||
</div>
|
||||
<div aria-atomic="true" role="alert">
|
||||
<digi-form-validation-message *ngIf="showPeriodError" af-variation="error"
|
||||
>{{formErrors.datesMismatch}}</digi-form-validation-message
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<ui-checkbox
|
||||
[formControl]="includeExportedDeltagareFormControl"
|
||||
uiLabel="Inkludera redan exporterade deltagare"
|
||||
></ui-checkbox>
|
||||
<footer class="deltagare-export__footer">
|
||||
<digi-notification-alert
|
||||
*ngIf="fetchError$ | async as error"
|
||||
class="deltagare-export__alert"
|
||||
af-variation="danger"
|
||||
af-heading="Någonting gick fel"
|
||||
>
|
||||
<p>Kunde inte hämta exportfilen för deltagare. Ladda om sidan och försök igen.</p>
|
||||
<p class="msfa__small-text" *ngIf="error.message">{{error.message}}</p>
|
||||
</digi-notification-alert>
|
||||
<div class="deltagare-export__cta-wrapper">
|
||||
<digi-button af-type="submit" af-size="m">Exportera deltagare</digi-button>
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</digi-typography>
|
||||
</section>
|
||||
<ui-loader *ngIf="fetchIsLoading$ | async" uiType="absolute"></ui-loader>
|
||||
</section>
|
||||
</msfa-layout>
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
@import 'variables/gutters';
|
||||
@import 'variables/z-index';
|
||||
|
||||
.deltagare-export {
|
||||
&__contents {
|
||||
max-width: var(--digi--typography--text--max-width);
|
||||
position: relative;
|
||||
z-index: $msfa__z-index-default;
|
||||
|
||||
&__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $digi--layout--gutter--l;
|
||||
margin-top: $digi--layout--gutter--l;
|
||||
}
|
||||
|
||||
&__period-inputs {
|
||||
display: flex;
|
||||
gap: $digi--layout--gutter--xl;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--digi--layout--gutter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { UiCheckboxModule } from '@ui/checkbox/checkbox.module';
|
||||
import { DeltagareExportComponent } from './deltagare-export.component';
|
||||
import { DeltagareExportService } from './deltagare-export.service';
|
||||
|
||||
describe('DeltagareExportComponent', () => {
|
||||
let component: DeltagareExportComponent;
|
||||
@@ -13,7 +17,15 @@ describe('DeltagareExportComponent', () => {
|
||||
void TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [DeltagareExportComponent],
|
||||
imports: [HttpClientTestingModule, RouterTestingModule],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
DigiNgFormDatepickerModule,
|
||||
UiCheckboxModule,
|
||||
],
|
||||
providers: [DeltagareExportService],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { DeltagareExportRequest } from '@msfa-models/api/deltagare-export.request.model';
|
||||
import { CustomError } from '@msfa-models/error/custom-error';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { DeltagareExportFormData, DeltagareExportFormErrors } from './deltagare-export.model';
|
||||
import { DeltagareExportService } from './deltagare-export.service';
|
||||
import { DeltagareExportValidator } from './deltagare-export.validator';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-deltagare-export',
|
||||
@@ -6,4 +15,80 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
styleUrls: ['./deltagare-export.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DeltagareExportComponent {}
|
||||
export class DeltagareExportComponent {
|
||||
maxDate = new Date();
|
||||
shouldValidate$ = new BehaviorSubject<boolean>(false);
|
||||
fetchIsLoading$ = new BehaviorSubject<boolean>(false);
|
||||
fetchError$ = new BehaviorSubject<CustomError>(null);
|
||||
formGroup = new FormGroup(
|
||||
{
|
||||
startDate: new FormControl(null),
|
||||
endDate: new FormControl(null),
|
||||
includeExportedDeltagare: new FormControl(false),
|
||||
},
|
||||
[DeltagareExportValidator.isDeltagareExportValid()]
|
||||
);
|
||||
constructor(private deltagareExportService: DeltagareExportService) {}
|
||||
|
||||
get startDateFormControl(): FormControl {
|
||||
return this.formGroup.get('startDate') as FormControl;
|
||||
}
|
||||
get endDateFormControl(): FormControl {
|
||||
return this.formGroup.get('endDate') as FormControl;
|
||||
}
|
||||
get includeExportedDeltagareFormControl(): FormControl {
|
||||
return this.formGroup.get('includeExportedDeltagare') as FormControl;
|
||||
}
|
||||
|
||||
get deltagagareExportFormData(): DeltagareExportFormData {
|
||||
return this.formGroup.value as DeltagareExportFormData;
|
||||
}
|
||||
|
||||
get formErrors(): DeltagareExportFormErrors {
|
||||
return this.formGroup.errors as DeltagareExportFormErrors;
|
||||
}
|
||||
|
||||
get showPeriodError(): boolean {
|
||||
return this.formErrors?.datesMismatch && this.shouldValidate$.getValue();
|
||||
}
|
||||
|
||||
fetchExportFile(): void {
|
||||
if (this.formGroup.invalid) {
|
||||
this.shouldValidate$.next(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const requestData = this._formDataToRequestData(this.deltagagareExportFormData);
|
||||
|
||||
this.fetchIsLoading$.next(true);
|
||||
this.deltagareExportService
|
||||
.fetchExportFile$(requestData)
|
||||
.pipe(take(1))
|
||||
.subscribe({
|
||||
next: response => {
|
||||
const blob = new Blob([response], { type: 'application/csv' });
|
||||
saveAs(blob, 'deltagare-export.csv');
|
||||
this.fetchIsLoading$.next(false);
|
||||
},
|
||||
error: (customError: CustomError) => {
|
||||
this.fetchError$.next({ ...customError, message: customError.error.message });
|
||||
this.fetchIsLoading$.next(false);
|
||||
throw { ...customError, avoidToast: true };
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _formDataToRequestData(formData: DeltagareExportFormData): DeltagareExportRequest {
|
||||
const { startDate, endDate, includeExportedDeltagare } = formData;
|
||||
const requestData: DeltagareExportRequest = {
|
||||
includeExportedDeltagare,
|
||||
};
|
||||
if (startDate) {
|
||||
requestData.startDate = startDate;
|
||||
}
|
||||
if (endDate) {
|
||||
requestData.endDate = endDate;
|
||||
}
|
||||
return requestData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export interface DeltagareExportFormData {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
includeExportedDeltagare: boolean;
|
||||
}
|
||||
|
||||
export type DeltagareExportFormKeys = keyof DeltagareExportFormData;
|
||||
|
||||
export interface DeltagareExportFormErrors {
|
||||
datesMismatch?: string;
|
||||
}
|
||||
@@ -1,12 +1,27 @@
|
||||
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@msfa-shared/components/layout/layout.module';
|
||||
import { UiCheckboxModule } from '@ui/checkbox/checkbox.module';
|
||||
import { UiLoaderModule } from '@ui/loader/loader.module';
|
||||
import { DeltagareExportComponent } from './deltagare-export.component';
|
||||
import { DeltagareExportService } from './deltagare-export.service';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [DeltagareExportComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: DeltagareExportComponent }]), LayoutModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: DeltagareExportComponent }]),
|
||||
LayoutModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
UiCheckboxModule,
|
||||
UiLoaderModule,
|
||||
DigiNgFormDatepickerModule,
|
||||
],
|
||||
providers: [DeltagareExportService],
|
||||
})
|
||||
export class DeltagareExportModule {}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DeltagareExportRequest } from '@msfa-models/api/deltagare-export.request.model';
|
||||
import { ExportApiService } from '@msfa-services/api/export.api.service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class DeltagareExportService {
|
||||
constructor(private exportApiService: ExportApiService) {}
|
||||
|
||||
public fetchExportFile$(requestData: DeltagareExportRequest): Observable<Blob> {
|
||||
return this.exportApiService.fetchDeltagareExportFile$(requestData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { AbstractControl, ValidatorFn } from '@angular/forms';
|
||||
import { DeltagareExportFormData, DeltagareExportFormErrors } from './deltagare-export.model';
|
||||
|
||||
export class DeltagareExportValidator {
|
||||
static isDeltagareExportValid(): ValidatorFn {
|
||||
return (c: AbstractControl): DeltagareExportFormErrors => {
|
||||
let errors: DeltagareExportFormErrors = null;
|
||||
const { startDate, endDate } = c.value as DeltagareExportFormData;
|
||||
|
||||
if (startDate && endDate && startDate > endDate) {
|
||||
errors = {
|
||||
...errors,
|
||||
datesMismatch: 'Från datum får inte vara senare än till och med datum',
|
||||
};
|
||||
}
|
||||
return errors;
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user