blob: 0b54c5b6c6c9a2bf9f930ef1b4fd1d0fa3ff6262 [file] [log] [blame]
/********************************************************************************
* Copyright © 2020 Basys GmbH.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {Component, Injector, OnDestroy, OnInit} from '@angular/core';
import {FormArray, FormControl, Validators} from '@angular/forms';
import {UtilService} from '@core/services/util.service';
import {MasterdataService} from '@masterdata/services/masterdata.service';
import {ReportingService} from '@reporting/services/reporting.service';
import {AbstractFormComponent} from '@shared/abstract/abstract-form/abstract-form.component';
import {CyclicReportObject} from '@shared/model/CyclicReportObject';
import {SelectOptionObject} from '@shared/model/SelectOptionObject';
import {FormUtil} from '@shared/utils/form.util';
import {combineLatest, defer, EMPTY, Observable, of, Subscription} from 'rxjs';
import {catchError, map, switchMap, tap} from 'rxjs/operators';
import {CyclicReportingService} from '../../services/cyclic-reporting.service';
import {CyclicReportingUtilService} from '../../services/cyclic-reporting-util.service';
import {CyclicReportValidators} from '../../validators/cyclic-report.validators';
@Component({
selector: 'ok-cyclic-report-form',
styleUrls: ['cyclic-report-form.component.scss'],
templateUrl: 'cyclic-report-form.component.html'
})
export class CyclicReportFormComponent extends AbstractFormComponent implements OnInit, OnDestroy {
public dateTokens = this.cyclicReportingUtilService.dateReplacementTokens;
public defaultValue: CyclicReportObject = {
id: undefined,
name: '',
fileNamePattern: '{Date}_{Time}_{Week}',
subject: '',
to: [],
emailText: '',
reportName: '',
printFormat: this.cyclicReportingUtilService.printFormatOptions[0].value,
standByListId: Number.NEGATIVE_INFINITY,
statusId: this.cyclicReportingUtilService.planStatusOptions[0].value,
triggerWeekDay: 1,
triggerHour: 8,
triggerMinute: 0,
validFromDayOffset: 0,
validFromHour: 8,
validFromMinute: 0,
validToDayOffset: 1,
validToHour: 8,
validToMinute: 0
};
public excludedReportNames: string[] = this.cyclicReportingUtilService.excludedReportNames;
public planStatusOptions = this.cyclicReportingUtilService.planStatusOptions;
public printFormats = this.cyclicReportingUtilService.printFormatOptions;
public report: CyclicReportObject;
public reportNameOptions: SelectOptionObject[] = [];
public standByListOptions: SelectOptionObject[] = [];
public toFormArray: FormArray;
public triggerMinuteStep = 5;
public weekDayOptions = this.cyclicReportingUtilService.weekDayOptions;
private subscriptions: Subscription[] = [];
public constructor(
injector: Injector,
public utilService: UtilService,
public masterdataService: MasterdataService,
public reportingService: ReportingService,
public cyclicReportingService: CyclicReportingService,
public cyclicReportingUtilService: CyclicReportingUtilService
) {
super(injector);
}
public ngOnInit() {
this.subscriptions.push(this.initializeForm().subscribe());
}
public ngOnDestroy() {
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
}
public submit() {
this.form.markAsTouched();
if (!FormUtil.validate(this.form)) {
return;
}
this.subscriptions.push(...[
of(this.form.value).pipe(
switchMap((value) => {
this.form.disable();
value = {
...value,
to: value.to.filter((_) => _ !== '')
};
return value.id == null ?
this.cyclicReportingService.putCyclicReport(value)
: this.cyclicReportingService.postCyclicReport(value);
}),
switchMap(() => this.navigateToOverview()),
catchError(() => {
this.form.enable();
return EMPTY;
})
).subscribe()
]);
}
public delete() {
this.form.disable();
this.subscriptions.push(...[
this.cyclicReportingService.deleteCyclicReport(this.report.id).pipe(
switchMap(() => this.navigateToOverview()),
catchError(() => {
this.form.enable();
return EMPTY;
})
).subscribe()
]);
}
public addEmailControl() {
this.toFormArray.push(this.createEmailControl(''));
}
public removeEmailControlAt(index: number) {
this.toFormArray.removeAt(index);
}
public navigateToOverview() {
return this.router.navigate(['..'], { relativeTo: this.route });
}
private initializeForm() {
return defer(() => {
this.createForm({...this.defaultValue});
this.form.disable();
return combineLatest(this.fetchReport(), this.fetchReportNameOptions(), this.fetchStandByListOptions());
}).pipe(
tap(([report, reportNameOptions, standByListOptions]) => {
this.reportNameOptions = reportNameOptions.filter((option) => !this.excludedReportNames.includes(option.value));
this.standByListOptions = standByListOptions;
this.form.enable();
this.createForm({
...this.defaultValue,
...report,
standByListId: extractValueFromOption(
report == null ? this.standByListOptions[0] : findInOptions(report.standByListId, this.standByListOptions)
),
reportName: extractValueFromOption(
report == null ? this.reportNameOptions[0] : findInOptions(report.reportName, this.reportNameOptions)
)
});
}),
catchError(() => {
this.report = undefined;
return EMPTY;
})
);
}
private fetchReport(): Observable<CyclicReportObject> {
return this.route.params.pipe(
map((params) => params.id),
switchMap((id) => {
return id === 'new' ? of(null) : this.cyclicReportingService.getCyclicReports().pipe(
map((reports) => {
id = parseInt(id, 10);
const result = reports.find((entry) => entry.id === id);
if (result == null) {
throw new Error('Entry not found');
}
return result;
}));
})
);
}
private fetchReportNameOptions(): Observable<SelectOptionObject<string>[]> {
return this.reportingService.getReportData().pipe(
map((data) => data.map((reportObject) => ({
...reportObject,
value: reportObject.reportName,
label: reportObject.reportName
})))
);
}
private fetchStandByListOptions(): Observable<SelectOptionObject<number>[]> {
return this.masterdataService.getStandbyListSelection().pipe(
map((data) => data.map((reportObject) => ({
...reportObject,
value: reportObject.id,
label: reportObject.title
})))
);
}
private createForm(report: CyclicReportObject) {
this.report = report;
const to = Array.isArray(report.to) && report.to.length > 0 ? report.to : [''];
this.toFormArray = this.fb.array(to.map((email) => this.createEmailControl(email)));
this.form = this.fb.group({...report, to: this.toFormArray});
Object.values(this.form.controls)
.forEach((control) => control.setValidators(Validators.required));
this.form.get('id').clearValidators();
this.form.get('emailText').clearValidators();
this.form.get('name').setValidators([Validators.required, Validators.maxLength(256)]);
this.form.get('fileNamePattern').setValidators([Validators.required, Validators.maxLength(128)]);
this.form.get('subject').setValidators([Validators.required, Validators.maxLength(128)]);
this.form.setValidators([CyclicReportValidators.validationDate]);
}
private createEmailControl(value: string): FormControl {
return this.fb.control(value, [Validators.email]);
}
}
function extractValueFromOption<T>(option: SelectOptionObject<T>) {
return option == null ? undefined : option.value;
}
function findInOptions<T>(value: T, options: SelectOptionObject<T>[]) {
const selected = options.find((option) => option.value === value);
return selected == null ? undefined : selected;
}