| /******************************************************************************** |
| * Copyright (c) 2020 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ********************************************************************************/ |
| import { loadAddressCommunities } from '@grid-failure-information-app/shared/store/actions/grid-failures.action'; |
| import { Injectable } from '@angular/core'; |
| import { Router } from '@angular/router'; |
| import { SafetyQueryDialogComponent } from '@grid-failure-information-app/shared/components/dialogs/safety-query-dialog/safety-query-dialog.component'; |
| import { InternExternEnum, PressureLevelEnum, PublicationStatusEnum, StateEnum, VoltageLevelEnum } from '@grid-failure-information-app/shared/constants/enums'; |
| import { Globals } from '@grid-failure-information-app/shared/constants/globals'; |
| import { |
| FailureAddress, |
| FailureBranch, |
| FailureClassification, |
| FailureCoords, |
| FailureExpectedReason, |
| FailureHousenumber, |
| FailureRadius, |
| FailureState, |
| FailureStation, |
| FailureType, |
| GridFailure, |
| } from '@grid-failure-information-app/shared/models'; |
| import { BaseFormSandbox } from '@grid-failure-information-app/shared/sandbox/base-form.sandbox'; |
| import * as store from '@grid-failure-information-app/shared/store'; |
| import * as gridFailureActions from '@grid-failure-information-app/shared/store/actions/grid-failures.action'; |
| import * as fromGridFailuresDetailFormReducer from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer'; |
| import * as gridFailuresDetailFormReducer from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer'; |
| import { navigateHome, stationToStationNameConverter as stationToStationDescriptionConverter } from '@grid-failure-information-app/shared/utility'; |
| import { unboxProperties } from '@grid-failure-information-app/shared/utility/form-utils'; |
| import { UtilService } from '@grid-failure-information-app/shared/utility/utility.service'; |
| import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; |
| import { ofType } from '@ngrx/effects'; |
| import { ActionsSubject, Store } from '@ngrx/store'; |
| import { Observable } from 'rxjs'; |
| import { debounceTime, distinctUntilChanged, map, take, takeUntil } from 'rxjs/operators'; |
| import { FORM_ID, NO_BRANCH_ID_KEY } from '@grid-failure-information-app/shared/store/reducers/grid-failures/grid-failure-details-form.reducer'; |
| import { FormGroupState, NgrxValueConverter, SetValueAction, ResetAction, EnableAction, SetUserDefinedPropertyAction, DisableAction } from 'ngrx-forms'; |
| |
| @Injectable() |
| export class GridFailureDetailsSandbox extends BaseFormSandbox<GridFailure> { |
| public Globals = Globals; |
| public StateEnum = StateEnum; |
| public gridFailureDetailsFormState$: Observable<FormGroupState<GridFailure>> = this.appState$.select(store.getGridFailuresDetails); |
| public currentFormState: FormGroupState<GridFailure>; |
| public gridFailureClassifications$: Observable<FailureClassification[]> = this.appState$.select(store.getGridFailureClassificationsData); |
| public gridFailureTypes$: Observable<FailureType[]> = this.appState$.select(store.getGridFailureTypesData); |
| public gridFailureBranches$: Observable<FailureBranch[]> = this.appState$.select(store.getGridFailureBranchesData); |
| public gridFailureActions = gridFailureActions; |
| public gridFailureInternalStates$: Observable<FailureState[]> = this.appState$ |
| .select(store.getGridFailureStatesData) |
| .pipe(map(states => states.filter(item => item.internal))); |
| public gridFailureExternalStates$: Observable<FailureState[]> = this.appState$ |
| .select(store.getGridFailureStatesData) |
| .pipe(map(states => states.filter(item => item.external))); |
| public gridFailureRadii$: Observable<FailureRadius[]> = this.appState$.select(store.getGridFailureRadiiData); |
| public gridFailureExpectedReasons$: Observable<FailureExpectedReason[]> = this.appState$.select(store.getGridFailureExpectedReasonsData); |
| public voltageLevelEnum = VoltageLevelEnum; |
| public pressureLevelEnum = PressureLevelEnum; |
| public publicationStatusEnum = PublicationStatusEnum; |
| public internExternEnum = InternExternEnum; |
| public maxVersionNumber: number; |
| public currentGridFailureDetailsCoords: FailureCoords = new FailureCoords(); |
| public noBranchId: string; |
| public isFieldRequiredDependingOnBranchId: boolean = false; |
| |
| public addressCommunities$: Observable<Array<string>> = this.actionsSubject.pipe( |
| ofType(gridFailureActions.loadAddressCommunitiesSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ); |
| public addressDistricts$: Observable<Array<string>> = this.actionsSubject.pipe( |
| ofType(gridFailureActions.loadAddressDistrictsSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ); |
| public addressStreets$: Observable<Array<string>> = this.actionsSubject.pipe( |
| ofType(gridFailureActions.loadAddressStreetsSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ); |
| public addressHouseNumbers$: Observable<Array<string>> = this.actionsSubject.pipe( |
| ofType(gridFailureActions.loadAddressHouseNumbersSuccess), |
| map(action => action.payload), |
| map(payload => payload.map(adrs => adrs.housenumber)), |
| takeUntil(this._endSubscriptions$) |
| ); |
| |
| public addressHouseNumbers: Array<FailureHousenumber>; |
| public showQualifyButton: boolean = false; |
| public showStornoButton: boolean = false; |
| public showCreatedButton: boolean = false; |
| public showUpdateButton: boolean = false; |
| public gridFailureAddress: FailureAddress; |
| private _gridFailureStations: Array<FailureStation> = new Array<FailureStation>(); |
| private _gridFailureId: string; |
| private _addressPostalcodes: Array<string> = []; |
| |
| constructor( |
| protected appState$: Store<store.State>, |
| protected actionsSubject: ActionsSubject, |
| private _router: Router, |
| private _utilService: UtilService, |
| private _modalService: NgbModal |
| ) { |
| super(appState$); |
| this.init(); |
| } |
| |
| public init() { |
| this.actionsSubject |
| .pipe( |
| ofType(gridFailureActions.loadAddressPostalcodesSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ) |
| .subscribe((items: Array<string>) => { |
| this._addressPostalcodes = items; |
| }); |
| |
| this.setNoBranchId(); |
| } |
| |
| public loadGridFailure(gridFailureId: string): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureDetail({ payload: gridFailureId })); |
| } |
| |
| public loadGridFailureBranches(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureBranches()); |
| } |
| |
| public loadGridFailureClassifications(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureClassifications()); |
| } |
| |
| public loadGridFailureTypes(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureTypes()); |
| } |
| |
| public loadGridFailureStates(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureStates()); |
| } |
| |
| public loadGridFailureRadii(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureRadii()); |
| } |
| |
| public loadGridFailureExpectedReasons(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureExpectedReasons()); |
| } |
| |
| public loadGridFailureStations(): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureStations()); |
| } |
| |
| public loadGridFailureVersions(gridFailureId: string): void { |
| this._gridFailureId = gridFailureId; |
| this.appState$.dispatch(gridFailureActions.loadGridFailureVersions({ payload: gridFailureId })); |
| } |
| |
| public loadGridFailureVersion(versionNumber: number): void { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureVersion({ gridFailureId: this._gridFailureId, versionNumber: versionNumber })); |
| if (versionNumber < this.maxVersionNumber) { |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.FORM_ID)); |
| } else { |
| this.appState$.dispatch(new EnableAction(fromGridFailuresDetailFormReducer.FORM_ID)); |
| } |
| } |
| |
| public setState(newState: string): void { |
| this.gridFailureInternalStates$ |
| .pipe( |
| map(states => states.filter(item => item.status === newState)), |
| take(1), |
| takeUntil(this._endSubscriptions$) |
| ) |
| .subscribe(states => { |
| if (states && states.length > 0) { |
| this.appState$.dispatch(new SetValueAction(gridFailuresDetailFormReducer.INITIAL_STATE.controls.statusInternId.id, states[0].id)); |
| this.saveGridFailure(); |
| } |
| }); |
| } |
| |
| public cancel(): void { |
| if (!this.currentFormState.isPristine) { |
| const modalRef = this._modalService.open(SafetyQueryDialogComponent); |
| modalRef.componentInstance.title = 'ConfirmDialog.Action.edit'; |
| modalRef.componentInstance.body = 'ConfirmDialog.Content'; |
| modalRef.result.then( |
| () => { |
| this._clear(); |
| }, |
| () => {} |
| ); |
| } else { |
| this._clear(); |
| } |
| } |
| |
| public saveGridFailure(): void { |
| if (this.currentFormState.isValid) { |
| const gridFailure = unboxProperties(this.currentFormState.value) as GridFailure; |
| |
| this.appState$.dispatch( |
| gridFailureActions.saveGridFailure({ |
| payload: gridFailure, |
| }) |
| ); |
| this.actionsSubject.pipe(ofType(gridFailureActions.saveGridFailureSuccess), take(1), takeUntil(this._endSubscriptions$)).subscribe(() => { |
| this._clear(); |
| }); |
| } else { |
| this._utilService.displayNotification('MandatoryFieldError', 'alert'); |
| } |
| } |
| |
| public setLatLong(hsnr: string): void { |
| const test$ = this.actionsSubject.pipe( |
| ofType(gridFailureActions.loadAddressHouseNumbersSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ); |
| if (this.addressHouseNumbers.length > 0) { |
| const failureHousenumber: FailureHousenumber = this.addressHouseNumbers.find((housenumber: FailureHousenumber) => { |
| return housenumber.housenumber === hsnr; |
| }); |
| if (!!failureHousenumber) { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureAddress({ payload: failureHousenumber.uuid })); |
| } |
| return; |
| } |
| test$.pipe(take(1)).subscribe(addresses => { |
| const failureHousenumber: FailureHousenumber = addresses.find((housenumber: FailureHousenumber) => { |
| return housenumber.housenumber === hsnr; |
| }); |
| if (!!failureHousenumber) { |
| this.appState$.dispatch(gridFailureActions.loadGridFailureAddress({ payload: failureHousenumber.uuid })); |
| } |
| }); |
| } |
| public registerEvents(): void { |
| this.actionsSubject |
| .pipe( |
| ofType(gridFailureActions.loadAddressHouseNumbersSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ) |
| .subscribe(hnr => (this.addressHouseNumbers = hnr)); |
| |
| this.gridFailureDetailsFormState$.pipe(takeUntil(this._endSubscriptions$)).subscribe((formState: FormGroupState<GridFailure>) => { |
| this.currentFormState = formState; |
| this._showButtonsByState(formState.value.statusIntern); |
| this.setDynamicRequired(); |
| |
| if (!formState.value || !formState.controls) return; |
| switch (formState.userDefinedProperties[fromGridFailuresDetailFormReducer.DEPENDENT_FIELD_KEY]) { |
| case formState.id: |
| this._loadInitialDependentFieldValues(formState); |
| break; |
| |
| case formState.controls.postcode.id: |
| this.appState$.dispatch(gridFailureActions.loadAddressCommunities({ payload: formState.value.postcode })); |
| break; |
| |
| case formState.controls.city.id: |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressDistricts({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| }) |
| ); |
| break; |
| |
| case formState.controls.district.id: |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressStreets({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| district: formState.value.district, |
| }) |
| ); |
| break; |
| |
| case formState.controls.street.id: |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressHouseNumbers({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| street: formState.value.street, |
| }) |
| ); |
| break; |
| case formState.controls.housenumber.id: |
| this.setLatLong(formState.controls.housenumber.value); |
| break; |
| |
| default: |
| break; |
| } |
| }); |
| |
| this.actionsSubject |
| .pipe( |
| ofType(gridFailureActions.loadGridFailureVersionsSuccess), |
| takeUntil(this._endSubscriptions$), |
| map(action => { |
| const gridFailures: GridFailure[] = action['payload']; |
| return !!gridFailures && Math.max(...gridFailures.map(o => o.versionNumber)); |
| }) |
| ) |
| .subscribe(versionNumber => (this.maxVersionNumber = versionNumber)); |
| |
| this.actionsSubject |
| .pipe( |
| ofType(gridFailureActions.loadGridFailureStationsSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ) |
| .subscribe((stations: Array<FailureStation>) => { |
| this._gridFailureStations = stations; |
| }); |
| |
| this.actionsSubject |
| .pipe( |
| ofType(gridFailureActions.loadGridFailureAddressSuccess), |
| map(action => action.payload), |
| takeUntil(this._endSubscriptions$) |
| ) |
| .subscribe((address: FailureAddress) => { |
| this.gridFailureAddress = address; |
| const event = { longitude: address.longitude, latitude: address.latitude }; |
| this.latLonMapping(event); |
| }); |
| |
| this.gridFailureDetailsFormState$.subscribe(gridFailureDetails => { |
| if ( |
| this.currentGridFailureDetailsCoords.latitude !== gridFailureDetails.value.latitude || |
| this.currentGridFailureDetailsCoords.longitude !== gridFailureDetails.value.longitude |
| ) { |
| this.currentGridFailureDetailsCoords = new FailureCoords(gridFailureDetails.value); |
| } |
| }); |
| } |
| |
| public searchForStation = (text$: Observable<string>) => |
| text$.pipe( |
| debounceTime(200), |
| distinctUntilChanged(), |
| map(term => (term.length < 2 ? [] : this._gridFailureStations.filter(s => s.failureStationSearchString.toLowerCase().indexOf(term.toLowerCase()) > -1))) |
| ); |
| |
| public formatter = (s: FailureStation | string) => { |
| if (s instanceof FailureStation) return s.failureStationSearchString; |
| else return s; |
| }; |
| |
| public stationValueConverter: NgrxValueConverter<any | null, string | null> = stationToStationDescriptionConverter; |
| |
| public latLonMapping(data: { longitude: number; latitude: number }): void { |
| !!data && |
| this.appState$.dispatch( |
| new SetValueAction(this.currentFormState.id, { |
| ...this.currentFormState.value, |
| longitude: data.longitude, |
| latitude: data.latitude, |
| }) |
| ); |
| } |
| |
| public setStationId(stationId: string): void { |
| !!stationId && |
| this.appState$.dispatch( |
| new SetValueAction(this.currentFormState.id, { |
| ...this.currentFormState.value, |
| stationId: stationId, |
| }) |
| ); |
| } |
| |
| public resetCoords(): void { |
| this.appState$.dispatch( |
| new SetValueAction(this.currentFormState.id, { |
| ...this.currentFormState.value, |
| longitude: null, |
| latitude: null, |
| }) |
| ); |
| } |
| |
| public resetStationId() { |
| this.appState$.dispatch( |
| new SetValueAction(this.currentFormState.id, { |
| ...this.currentFormState.value, |
| stationId: null, |
| }) |
| ); |
| } |
| |
| public searchForAddressPostalcodes = (text$: Observable<string>) => |
| text$.pipe( |
| debounceTime(300), |
| distinctUntilChanged(), |
| map(term => (term.length < 2 ? [] : this._addressPostalcodes.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1))) |
| ); |
| |
| public resetFailureLocationValues() { |
| this.appState$.dispatch( |
| new SetValueAction(this.currentFormState.id, { |
| ...this.currentFormState.value, |
| stationDescription: null, |
| stationId: null, |
| latitude: null, |
| longitude: null, |
| postcode: null, |
| district: null, |
| city: null, |
| street: null, |
| housenumber: null, |
| radius: null, |
| radiusId: null, |
| }) |
| ); |
| } |
| |
| public disableUnnecessaryRequiredProperties(part: string): void { |
| switch (part) { |
| case Globals.FAILURE_LOCATION_NS: |
| this.appState$.dispatch(new EnableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.postcode.id)); |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.radiusId.id)); |
| break; |
| case Globals.FAILURE_LOCATION_MS: |
| this._disableAddressControls(); |
| this.appState$.dispatch(new EnableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.radiusId.id)); |
| break; |
| case Globals.FAILURE_LOCATION_MAP: |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.radiusId.id)); |
| this._disableAddressControls(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| private _disableAddressControls(): void { |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.postcode.id)); |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.city.id)); |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.district.id)); |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.street.id)); |
| this.appState$.dispatch(new DisableAction(fromGridFailuresDetailFormReducer.INITIAL_STATE.controls.housenumber.id)); |
| } |
| |
| public isAddressLoaded(): Observable<boolean> { |
| return this.actionsSubject.pipe( |
| ofType(loadAddressCommunities.type), |
| map(item => true), |
| take(1) |
| ); |
| } |
| private _loadInitialDependentFieldValues(formState: FormGroupState<GridFailure>) { |
| if (!formState.value || !formState.controls) return; |
| this.appState$.dispatch(gridFailureActions.loadAddressCommunities({ payload: formState.value.postcode })); |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressDistricts({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| }) |
| ); |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressStreets({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| district: formState.value.district, |
| }) |
| ); |
| this.appState$.dispatch( |
| gridFailureActions.loadAddressHouseNumbers({ |
| postcode: formState.value.postcode, |
| community: formState.value.city, |
| street: formState.value.street, |
| }) |
| ); |
| } |
| |
| public loadAddressPostalcodes(): void { |
| this.appState$.dispatch(gridFailureActions.loadAddressPostalcodes()); |
| } |
| |
| private setNoBranchId(): void { |
| this.gridFailureBranches$.subscribe((branches: FailureBranch[]) => { |
| if (branches.length > 0) { |
| const noBranch: FailureBranch = branches.find(branch => branch.name === Globals.NO_BRANCH_NAME); |
| this.noBranchId = !!noBranch ? noBranch.id : null; |
| this.appState$.dispatch(new SetUserDefinedPropertyAction(FORM_ID, NO_BRANCH_ID_KEY, this.noBranchId)); |
| } |
| }); |
| } |
| |
| private _clear(): void { |
| this.appState$.dispatch(new SetValueAction(fromGridFailuresDetailFormReducer.FORM_ID, fromGridFailuresDetailFormReducer.INITIAL_STATE.value)); |
| this.appState$.dispatch(new ResetAction(fromGridFailuresDetailFormReducer.FORM_ID)); |
| this.appState$.dispatch(new EnableAction(fromGridFailuresDetailFormReducer.FORM_ID)); |
| this._gridFailureId = null; |
| this.maxVersionNumber = null; |
| navigateHome(this._router); |
| } |
| |
| private setDynamicRequired(): void { |
| this.isFieldRequiredDependingOnBranchId = |
| !!this.currentFormState.controls && !!this.currentFormState.controls.branchId ? this.currentFormState.controls.branchId.value !== this.noBranchId : null; |
| } |
| |
| private _showButtonsByState(state: string): void { |
| this.showQualifyButton = false; |
| this.showStornoButton = false; |
| this.showCreatedButton = false; |
| this.showUpdateButton = false; |
| |
| switch (state) { |
| case StateEnum.NEW: |
| case StateEnum.PLANNED: |
| this.showCreatedButton = true; |
| break; |
| case StateEnum.CREATED: |
| case StateEnum.UPDATED: |
| this.showQualifyButton = true; |
| this.showStornoButton = true; |
| break; |
| case StateEnum.QUALIFIED: |
| this.showUpdateButton = true; |
| break; |
| default: |
| break; |
| } |
| } |
| } |