From 85d18d8c08934ecfd2048485449fd7eea6b22ad8 Mon Sep 17 00:00:00 2001 From: nazarstig <45310972+nazarstig@users.noreply.github.com> Date: Mon, 29 May 2023 14:43:08 +0300 Subject: [PATCH] #2037 create edit form (#2089) * #2037 added edit form component * #2037 added dynamic form controls * #2037 added editing * #2037 added page reload and last input focus * #2041 added tab storing in state * #2037 added directions input * #2037 added close button, fixed editing when not all fields are present * #2037 fixed formatting, added autofocus, cleaned code * #2037 reverted some changes * #2037 resolved comments * fixed test, temporarily deleted test file for edit form * #2037 resolve comments 2 * fixed name in template * #2037 added access modifiers to variables * #2037 added translation --------- Co-authored-by: Nazarii Ivasyshyn --- .../institutions/institutions.service.ts | 4 + src/app/shared/store/admin.actions.ts | 2 +- src/app/shared/store/meta-data.actions.ts | 6 + src/app/shared/store/meta-data.state.ts | 8 +- src/app/shell/admin-tools/data/data.module.ts | 2 + ...ution-hierarchies-edit-form.component.html | 64 +++++++ ...ution-hierarchies-edit-form.component.scss | 24 +++ ...itution-hierarchies-edit-form.component.ts | 159 ++++++++++++++++++ ...nstitution-hierarchies-list.component.html | 2 +- ...itution-hierarchies-list.component.spec.ts | 3 +- ...-institution-hierarchies-list.component.ts | 24 ++- .../ins-hierarchy-table-record.ts | 4 +- .../directions-wrapper.component.html | 2 +- .../directions-wrapper.component.ts | 2 +- .../edit-ins-hierarchy-model.ts | 6 + src/assets/i18n/en.json | 11 +- src/assets/i18n/uk.json | 11 +- 17 files changed, 316 insertions(+), 18 deletions(-) create mode 100644 src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html create mode 100644 src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.scss create mode 100644 src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.ts create mode 100644 src/app/shell/admin-tools/data/directions-wrapper/edit-ins-hierarchy-model.ts diff --git a/src/app/shared/services/institutions/institutions.service.ts b/src/app/shared/services/institutions/institutions.service.ts index 252d25a663..ab3f5db522 100644 --- a/src/app/shared/services/institutions/institutions.service.ts +++ b/src/app/shared/services/institutions/institutions.service.ts @@ -38,4 +38,8 @@ export class InstitutionsService { return this.http.get(`/api/v1/InstitutionHierarchy/GetParents/${id}`, { params }); } + + editInstitutionHierarchy(insHierarchy: InstituitionHierarchy): Observable { + return this.http.put(`/api/v1/InstitutionHierarchy/Update`, insHierarchy); + } } diff --git a/src/app/shared/store/admin.actions.ts b/src/app/shared/store/admin.actions.ts index ce00dcea39..7c5ecfa5f6 100644 --- a/src/app/shared/store/admin.actions.ts +++ b/src/app/shared/store/admin.actions.ts @@ -299,4 +299,4 @@ export class OnUpdateRegionAdminFail { export class OnUpdateRegionAdminSuccess { static readonly type = '[admin] update Region Admin success'; constructor(public payload: RegionAdmin) {} -} +} \ No newline at end of file diff --git a/src/app/shared/store/meta-data.actions.ts b/src/app/shared/store/meta-data.actions.ts index b34b8fd277..e011c9d465 100644 --- a/src/app/shared/store/meta-data.actions.ts +++ b/src/app/shared/store/meta-data.actions.ts @@ -1,4 +1,5 @@ import { CodeficatorCategories } from '../enum/codeficator-categories'; +import { InstituitionHierarchy } from '../models/institution.model'; import { RateParameters } from '../models/rating'; export class GetDirections { @@ -70,6 +71,11 @@ export class ResetInstitutionHierarchy { constructor() {} } +export class UpdateInstitutionHierarchy { + static readonly type = '[meta-data] Update Institution Hierarchy'; + constructor(public payload: InstituitionHierarchy) {} +} + export class GetInstitutionHierarchyParentsById { static readonly type = '[meta-data] Get Institution Hierarchy Parents By Id'; diff --git a/src/app/shared/store/meta-data.state.ts b/src/app/shared/store/meta-data.state.ts index bf7aa26c74..6ea941876e 100644 --- a/src/app/shared/store/meta-data.state.ts +++ b/src/app/shared/store/meta-data.state.ts @@ -39,7 +39,8 @@ import { GetProviderTypes, GetRateByEntityId, GetSocialGroup, - ResetInstitutionHierarchy + ResetInstitutionHierarchy, + UpdateInstitutionHierarchy } from './meta-data.actions'; export interface MetaDataStateModel { @@ -299,6 +300,11 @@ export class MetaDataState { }); } + @Action(UpdateInstitutionHierarchy) + updateInstitutionHierarchy({ patchState }: StateContext, { payload }: UpdateInstitutionHierarchy): Observable> { + return this.institutionsService.editInstitutionHierarchy(payload).pipe(); + } + @Action(GetCodeficatorSearch) getCodeficatorSearch( { patchState }: StateContext, diff --git a/src/app/shell/admin-tools/data/data.module.ts b/src/app/shell/admin-tools/data/data.module.ts index b48208ed43..95e244fc7b 100644 --- a/src/app/shell/admin-tools/data/data.module.ts +++ b/src/app/shell/admin-tools/data/data.module.ts @@ -20,6 +20,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { AdminApplicationsComponent } from './admin-applications/admin-applications.component'; import { SharedCabinetModule } from '../../personal-cabinet/shared-cabinet/shared-cabinet.module'; import { StatisticsComponent } from './statistics/statistics.component'; +import { DirectionsInstitutionHierarchiesEditFormComponent } from './directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component'; @NgModule({ declarations: [ @@ -37,6 +38,7 @@ import { StatisticsComponent } from './statistics/statistics.component'; DirectionsInstitutionHierarchiesListComponent, AdminApplicationsComponent, StatisticsComponent, + DirectionsInstitutionHierarchiesEditFormComponent, ], imports: [ CommonModule, diff --git a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html new file mode 100644 index 0000000000..da0396e2de --- /dev/null +++ b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html @@ -0,0 +1,64 @@ +
+
+
+

{{ 'TITLES.EDIT_INSTITUTION_HIERARCHY_FORM_TITLE' | translate }}

+

+ {{ 'TITLES.EDIT_INSTITUTION_HIERARCHY_FORM_SUBTITLE' | translate }} +

+
+
+ + info_outline + +
+ {{ 'FORMS.EDIT_INSTITUTION_HIERARCHY_WARNING_MSG' | translate }} + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + {{ direction.title }} + cancel + + + + + {{ direction.title }} + + + + +
+ + +
+
\ No newline at end of file diff --git a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.scss b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.scss new file mode 100644 index 0000000000..1e29fb13e5 --- /dev/null +++ b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.scss @@ -0,0 +1,24 @@ +@import 'src/app/shared/styles/create-form-wrapper.scss'; +@import 'src/app/shared/styles/create-form.scss'; +@import 'src/app/shared/styles/buttons.scss'; +@import 'src/app/shared/styles/validation-form.scss'; +@import 'src/app/shared/styles/dropdown.scss'; + +.warning-box { + width: 410px; + height: 50px; + padding: 5px; + border-radius: 5px; + background-color: #ffdab9; + + i { + color: orange; + } +} + +mat-select { + img { + width: 20px; + height: 20px; + } +} \ No newline at end of file diff --git a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.ts b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.ts new file mode 100644 index 0000000000..d9bce2ddd8 --- /dev/null +++ b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.ts @@ -0,0 +1,159 @@ +import { Component, Inject, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatOption } from '@angular/material/core'; +import { MatSelect } from '@angular/material/select'; +import { Router } from '@angular/router'; +import { Select, Store } from '@ngxs/store'; +import { Observable, forkJoin, asyncScheduler } from 'rxjs'; +import { InstituitionHierarchy } from '../../../../../shared/models/institution.model'; +import { GetAllInstitutionsHierarchy, GetDirections, UpdateInstitutionHierarchy } from '../../../../../shared/store/meta-data.actions'; +import { MetaDataState } from '../../../../../shared/store/meta-data.state'; +import { Direction } from '../../../../../shared/models/category.model'; +import { DataItem } from '../../../../../shared/models/item.model'; +import { EditInsHierarchyModel } from '../edit-ins-hierarchy-model'; + +@Component({ + selector: 'app-directions-institution-hierarchies-edit-form', + templateUrl: './directions-institution-hierarchies-edit-form.component.html', + styleUrls: ['./directions-institution-hierarchies-edit-form.component.scss'] +}) +export class DirectionsInstitutionHierarchiesEditFormComponent implements AfterViewInit { + @ViewChild('editForm') editForm: ElementRef; + @ViewChild('select') select: MatSelect; + + @Select(MetaDataState.directions) directions$: Observable; + + readonly ministryControl: string = 'Ministry'; + readonly userDirectionsControl: string = 'USER_DIRECTIONS'; + + public editDirectionFormGroup: FormGroup; + public directionsControl: FormControl = new FormControl([]); + public fields: string[] = []; + + private lastInsHierarchy: InstituitionHierarchy; + private editedInsHierarchies: InstituitionHierarchy[] = []; + + constructor(private router: Router, private dialogRef: MatDialogRef, + private store: Store, @Inject(MAT_DIALOG_DATA) public data: EditInsHierarchyModel) { + this.store.dispatch(new GetDirections()); + this.lastInsHierarchy = this.getLastInsHierarchy(); + this.buildForm(); + } + + private buildForm(): void { + let directions = [...this.lastInsHierarchy.directions]; + const formGroupFields = this.getFormControlsFields(); + formGroupFields[this.userDirectionsControl] = new FormControl(directions); + this.editDirectionFormGroup = new FormGroup(formGroupFields); + this.directionsControl = this.editDirectionFormGroup.get(this.userDirectionsControl) as FormControl; + } + + private getLastInsHierarchy(): InstituitionHierarchy { + return this.data.element.insHierarchies[this.data.element.insHierarchies.length - 1]; + } + + private getFormControlsFields(): any { + const formGroupFields = {}; + formGroupFields[this.ministryControl] = new FormControl({value: this.data.element.insHierarchies[0].institution.title, disabled: true}); + this.fields.push(this.ministryControl); + let field, title; + for (let i = 0; i < this.data.columns.length; ++i) { + field = this.data.columns[i]; + title = this.data.element.insHierarchies[i]?.title; + if (title) { + formGroupFields[field] = new FormControl(title); + } + else { + formGroupFields[field] = new FormControl({value: null, disabled: true}); + } + this.fields.push(field); + } + return formGroupFields; + } + + private editInstitutionalHierarchy(insHierarchy: InstituitionHierarchy): Observable> { + return this.store.dispatch(new UpdateInstitutionHierarchy(insHierarchy)); + } + + private lastInputFocus(): void { + let inputs = this.editForm.nativeElement.getElementsByTagName('input') as HTMLInputElement[]; + let lastInput = inputs[inputs.length - 1]; + lastInput.focus(); + } + + private reloadPage(): void { + const currentUrl = this.router.url; + this.router.navigateByUrl('/', {skipLocationChange: true}).then(() => { + this.router.navigate([currentUrl]); + }); + } + + private closeDialog(): void { + this.dialogRef.close(); + } + + private compareTwoArrays(array1: Direction[], array2: Direction[]): boolean { + return ( + array1.length === array2.length && + array1.every((first: Direction) => + array2.some((second: Direction) => + Object.keys(first).every((key) => first[key] === second[key]) + ) + ) + ); + } + + public ngAfterViewInit(): void { + asyncScheduler.schedule(() => { + if (this.editForm) { + this.lastInputFocus(); + } + }, 0); + } + + public onCancel(): void { + this.closeDialog(); + } + + public onSubmit(): void { + for (let i = 0; i < this.data.columns.length; ++i) { + const fieldName = this.data.columns[i]; + const field = this.editDirectionFormGroup.controls[fieldName]; + if (field.value != this.data.element.name[i]) { + let editedInsHierarchy = this.data.element.insHierarchies[i]; + editedInsHierarchy.title = field.value; + this.editedInsHierarchies.push(editedInsHierarchy); + } + } + + if (!this.compareTwoArrays(this.directionsControl.value, this.lastInsHierarchy.directions)) { + let editedInsHierarchy = this.editedInsHierarchies.find((ins: InstituitionHierarchy) => ins.id === this.lastInsHierarchy.id); + if (editedInsHierarchy) { + editedInsHierarchy.directions = this.directionsControl.value; + } + else { + editedInsHierarchy = this.lastInsHierarchy; + editedInsHierarchy.directions = this.directionsControl.value; + this.editedInsHierarchies.push(editedInsHierarchy); + } + } + + forkJoin( + this.editedInsHierarchies.map((ins: InstituitionHierarchy) => this.editInstitutionalHierarchy(ins))).subscribe((result) => { + this.store.dispatch(new GetAllInstitutionsHierarchy()); + this.reloadPage(); + }); + + this.closeDialog(); + } + + public compareItems(item1: DataItem, item2: DataItem): boolean { + return item1.id === item2.id; + } + + public onRemoveItem(direction: DataItem): void { + this.directionsControl.value.splice(this.directionsControl.value.indexOf(direction), 1); + this.select.options.find((option: MatOption) => option.value.id === direction.id).deselect(); + } +} diff --git a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-list/directions-institution-hierarchies-list.component.html b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-list/directions-institution-hierarchies-list.component.html index 34197ed798..912b8aafb9 100644 --- a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-list/directions-institution-hierarchies-list.component.html +++ b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-list/directions-institution-hierarchies-list.component.html @@ -24,7 +24,7 @@ -