From e766a91ecf4a53fcee03e0f91b72df009f9cf6a7 Mon Sep 17 00:00:00 2001 From: Chirag Gupta Date: Tue, 21 May 2019 20:19:41 +0530 Subject: [PATCH] feat(system): view, edit, delete code (#380) - Add view code component - Add edit code component Fixes: #379 --- src/app/system/codes/code.resolver.ts | 31 +++ src/app/system/codes/codes.component.html | 2 +- src/app/system/codes/codes.component.scss | 4 + .../create-code/create-code.component.ts | 4 +- .../codes/edit-code/edit-code.component.html | 32 +++ .../codes/edit-code/edit-code.component.scss | 3 + .../edit-code/edit-code.component.spec.ts | 25 +++ .../codes/edit-code/edit-code.component.ts | 67 ++++++ .../codes/view-code/code-values.resolver.ts | 31 +++ .../codes/view-code/view-code.component.html | 87 ++++++++ .../codes/view-code/view-code.component.scss | 18 ++ .../view-code/view-code.component.spec.ts | 25 +++ .../codes/view-code/view-code.component.ts | 206 ++++++++++++++++++ src/app/system/system-routing.module.ts | 28 +++ src/app/system/system.module.ts | 4 + src/app/system/system.service.ts | 61 ++++++ 16 files changed, 625 insertions(+), 3 deletions(-) create mode 100644 src/app/system/codes/code.resolver.ts create mode 100644 src/app/system/codes/edit-code/edit-code.component.html create mode 100644 src/app/system/codes/edit-code/edit-code.component.scss create mode 100644 src/app/system/codes/edit-code/edit-code.component.spec.ts create mode 100644 src/app/system/codes/edit-code/edit-code.component.ts create mode 100644 src/app/system/codes/view-code/code-values.resolver.ts create mode 100644 src/app/system/codes/view-code/view-code.component.html create mode 100644 src/app/system/codes/view-code/view-code.component.scss create mode 100644 src/app/system/codes/view-code/view-code.component.spec.ts create mode 100644 src/app/system/codes/view-code/view-code.component.ts diff --git a/src/app/system/codes/code.resolver.ts b/src/app/system/codes/code.resolver.ts new file mode 100644 index 000000000..b40a772d8 --- /dev/null +++ b/src/app/system/codes/code.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { SystemService } from '../system.service'; + +/** + * Code data resolver. + */ +@Injectable() +export class CodeResolver implements Resolve { + + /** + * @param {SystemService} systemService System service. + */ + constructor(private systemService: SystemService) {} + + /** + * Returns the Code data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const id = route.paramMap.get('id'); + return this.systemService.getCode(id); + } + +} diff --git a/src/app/system/codes/codes.component.html b/src/app/system/codes/codes.component.html index ae425eee1..d1543dd58 100644 --- a/src/app/system/codes/codes.component.html +++ b/src/app/system/codes/codes.component.html @@ -30,7 +30,7 @@ - + diff --git a/src/app/system/codes/codes.component.scss b/src/app/system/codes/codes.component.scss index 3a95ea579..415812246 100644 --- a/src/app/system/codes/codes.component.scss +++ b/src/app/system/codes/codes.component.scss @@ -1,5 +1,9 @@ table { width: 100%; + + .select-row:hover { + cursor: pointer; + } } // TODO: CONFIGURE THESE CLASSES GLOBALLY diff --git a/src/app/system/codes/create-code/create-code.component.ts b/src/app/system/codes/create-code/create-code.component.ts index 5cdb79f10..a9f283a3b 100644 --- a/src/app/system/codes/create-code/create-code.component.ts +++ b/src/app/system/codes/create-code/create-code.component.ts @@ -45,12 +45,12 @@ export class CreateCodeComponent implements OnInit { /** * Submits the code form and creates a code, - * if successful redirects to view code. + * if successful redirects to view created code. */ submit() { this.systemService.createCode(this.codeForm.value) .subscribe((response: any) => { - this.router.navigate(['/system/codes'], { relativeTo: this.route }); + this.router.navigate(['../', response.resourceId], { relativeTo: this.route }); }); } diff --git a/src/app/system/codes/edit-code/edit-code.component.html b/src/app/system/codes/edit-code/edit-code.component.html new file mode 100644 index 000000000..cf3d2d683 --- /dev/null +++ b/src/app/system/codes/edit-code/edit-code.component.html @@ -0,0 +1,32 @@ +
+ + + +
+ + + +
+ + + Code Name + + + Code Name is required + + + +
+ +
+ + + + + + +
+ +
+ +
diff --git a/src/app/system/codes/edit-code/edit-code.component.scss b/src/app/system/codes/edit-code/edit-code.component.scss new file mode 100644 index 000000000..1915ad6d3 --- /dev/null +++ b/src/app/system/codes/edit-code/edit-code.component.scss @@ -0,0 +1,3 @@ +.container { + max-width: 37rem; +} diff --git a/src/app/system/codes/edit-code/edit-code.component.spec.ts b/src/app/system/codes/edit-code/edit-code.component.spec.ts new file mode 100644 index 000000000..39bde715a --- /dev/null +++ b/src/app/system/codes/edit-code/edit-code.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditCodeComponent } from './edit-code.component'; + +describe('EditCodeComponent', () => { + let component: EditCodeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ EditCodeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(EditCodeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/system/codes/edit-code/edit-code.component.ts b/src/app/system/codes/edit-code/edit-code.component.ts new file mode 100644 index 000000000..4f8dc5289 --- /dev/null +++ b/src/app/system/codes/edit-code/edit-code.component.ts @@ -0,0 +1,67 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; + +/** Custom Services */ +import { SystemService } from '../../system.service'; + +/** + * Edit Code Component. + */ +@Component({ + selector: 'mifosx-edit-code', + templateUrl: './edit-code.component.html', + styleUrls: ['./edit-code.component.scss'] +}) +export class EditCodeComponent implements OnInit { + + /** Code Form */ + codeForm: FormGroup; + /** Code Data */ + codeData: any; + + /** + * Retrieves the code data from `resolve`. + * @param {FormBuilder} formBuilder Form Builder. + * @param {SystemService} systemService System Service. + * @param {ActivatedRoute} route Activated Route. + * @param {Router} router Router for navigation. + */ + constructor(private formBuilder: FormBuilder, + private systemService: SystemService, + private route: ActivatedRoute, + private router: Router) { + this.route.data.subscribe((data: { code: any }) => { + this.codeData = data.code; + }); + } + + /** + * Creates and sets the code form. + */ + ngOnInit() { + this.createCodeForm(); + } + + /** + * Creates and sets code form. + */ + createCodeForm() { + this.codeForm = this.formBuilder.group({ + 'name': [this.codeData.name, Validators.required] + }); + } + + /** + * Submits the code form and updates code, + * if successful redirects to view updated code. + */ + submit() { + this.systemService.updateCode(this.codeForm.value, this.codeData.id) + .subscribe((response: any) => { + this.router.navigate(['../../', response.resourceId], { relativeTo: this.route }); + }); + } + +} diff --git a/src/app/system/codes/view-code/code-values.resolver.ts b/src/app/system/codes/view-code/code-values.resolver.ts new file mode 100644 index 000000000..d248d22d2 --- /dev/null +++ b/src/app/system/codes/view-code/code-values.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { SystemService } from '../../system.service'; + +/** + * Code Values data resolver. + */ +@Injectable() +export class CodeValuesResolver implements Resolve { + + /** + * @param {SystemService} systemService System service. + */ + constructor(private systemService: SystemService) {} + + /** + * Returns the Code Values data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const codeId = route.paramMap.get('id'); + return this.systemService.getCodeValues(codeId); + } + +} diff --git a/src/app/system/codes/view-code/view-code.component.html b/src/app/system/codes/view-code/view-code.component.html new file mode 100644 index 000000000..3fed79fd3 --- /dev/null +++ b/src/app/system/codes/view-code/view-code.component.html @@ -0,0 +1,87 @@ +
+ + + + + + + +
+ +
+ + + + {{ codeData.name }} + +
+ + + +
+ +
+ + + Name + + + Name is required + + + + + Description + + + + + Position + + + Name is required + + + +
+ Active +
+ +
+ + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
diff --git a/src/app/system/codes/view-code/view-code.component.scss b/src/app/system/codes/view-code/view-code.component.scss new file mode 100644 index 000000000..ba8aa6820 --- /dev/null +++ b/src/app/system/codes/view-code/view-code.component.scss @@ -0,0 +1,18 @@ +@media (min-width: 992px) { + + .active-wrapper { + position: relative; + + .active { + padding: 0 0 17.5px 0; + position: absolute; + bottom: 0; + right: 0; + } + } + +} + +.options-wrapper { + padding: 18px 0 0 0; +} diff --git a/src/app/system/codes/view-code/view-code.component.spec.ts b/src/app/system/codes/view-code/view-code.component.spec.ts new file mode 100644 index 000000000..5d0c6571a --- /dev/null +++ b/src/app/system/codes/view-code/view-code.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ViewCodeComponent } from './view-code.component'; + +describe('ViewCodeComponent', () => { + let component: ViewCodeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ViewCodeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ViewCodeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/system/codes/view-code/view-code.component.ts b/src/app/system/codes/view-code/view-code.component.ts new file mode 100644 index 000000000..90940da33 --- /dev/null +++ b/src/app/system/codes/view-code/view-code.component.ts @@ -0,0 +1,206 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms'; +import { MatDialog } from '@angular/material'; + +/** Custom Services */ +import { SystemService } from 'app/system/system.service'; + +/** Custom Components */ +import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component'; + +/** + * View Code Component. + */ +@Component({ + selector: 'mifosx-view-code', + templateUrl: './view-code.component.html', + styleUrls: ['./view-code.component.scss'] +}) +export class ViewCodeComponent implements OnInit { + + /** Code Data */ + codeData: any; + /** Code Values Data */ + codeValuesData: any[]; + /** Code Values Form */ + codeValuesForm: FormGroup; + /** Code Value Row Status */ + codeValueRowStatus: string[] = []; + + /** + * Retrieves the codes and code values data from `resolve`. + * @param {ActivatedRoute} route Activated Route. + * @param {SystemService} systemService System Service. + * @param {Router} router Router for navigation. + * @param {FormBuilder} formBuilder Form Builder. + * @param {MatDialog} dialog Dialog reference. + */ + constructor(private route: ActivatedRoute, + private systemService: SystemService, + private router: Router, + private formBuilder: FormBuilder, + private dialog: MatDialog) { + this.route.data.subscribe((data: { code: any, codeValues: any }) => { + this.codeData = data.code; + this.codeValuesData = data.codeValues; + }); + } + + /** + * Creates and initializes the code values form. + */ + ngOnInit() { + this.createCodeValuesForm(); + this.initCodeValuesForm(); + } + + /** + * Initializes the code values form. + */ + initCodeValuesForm() { + this.codeValuesData.forEach((codeValue: any) => { + this.codeValues.push(this.createCodeValuesRow(codeValue)); + this.codeValueRowStatus.push('disabled'); + }); + } + + /** + * Gets the code values form array. + * @returns {FormArray} Code values form array. + */ + get codeValues(): FormArray { + return this.codeValuesForm.get('codeValues') as FormArray; + } + + /** + * Creates the code values form. + */ + createCodeValuesForm() { + this.codeValuesForm = this.formBuilder.group({ + 'codeValues': this.formBuilder.array([]) + }); + } + + /** + * Adds a row to the code values form. + */ + addCodeValueRow() { + this.codeValues.push(this.createCodeValuesRow()); + this.codeValues.at(this.codeValues.length - 1).enable(); + this.codeValueRowStatus.push('new'); + } + + /** + * Creates a code value row in code values form. + * @param {any} codeValue Code value. + */ + createCodeValuesRow(codeValue?: any): FormGroup { + return this.formBuilder.group({ + 'name': [{ value: codeValue ? codeValue.name : '', disabled: true }, Validators.required], + 'description': [{ value: codeValue ? codeValue.description : '', disabled: true }], + 'position': [{ value: codeValue ? codeValue.position : 0, disabled: true }, Validators.required], + 'isActive': [{ value: codeValue ? codeValue.active : false, disabled: true }] + }); + } + + /** + * Deletes the particular code value. + * @param {number} index Index of the row. + */ + deleteCodeValue(index: number) { + const codeValueId = this.codeValuesData[index].id; + this.systemService.deleteCodeValue(this.codeData.id, codeValueId) + .subscribe((response: any) => { + this.codeValuesData.splice(index, 1); + this.codeValues.removeAt(index); + this.codeValueRowStatus.splice(index, 1); + }); + } + + /** + * Removes/Deletes the particular code value which has not been intialised. + * @param {number} index Index of the row. + */ + removeNewCodeValue(index: number) { + this.codeValues.removeAt(index); + this.codeValueRowStatus.splice(index, 1); + } + + /** + * Updates the particular code value. + * @param {number} index Index of the row. + */ + updateCodeValue(index: number) { + const updatedCodeValue: { name: string, description: string, position: number, isActive: boolean } = this.codeValues.at(index).value; + this.systemService.updateCodeValue(this.codeData.id, this.codeValuesData[index].id, updatedCodeValue) + .subscribe((response: any) => { + this.codeValues.at(index).disable(); + this.codeValueRowStatus[index] = 'disabled'; + this.codeValues.at(index).markAsPristine(); + }); + } + + /** + * Deletes the code. + */ + delete() { + const deleteCodeDialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: `code ${this.codeData.name}` } + }); + deleteCodeDialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.systemService.deleteCode(this.codeData.id) + .subscribe(() => { + this.router.navigate(['/system/codes']); + }); + } + }); + } + + /** + * Disables the particular row. + * @param {number} index Index of the row. + */ + disableRow(index: number) { + this.codeValues.at(index).get('name').setValue(this.codeValuesData[index].name); + this.codeValues.at(index).get('description').setValue(this.codeValuesData[index].description); + this.codeValues.at(index).get('position').setValue(this.codeValuesData[index].position); + this.codeValues.at(index).get('isActive').setValue(this.codeValuesData[index].isActive); + this.codeValues.at(index).disable(); + this.codeValueRowStatus[index] = 'disabled'; + this.codeValues.at(index).markAsPristine(); + } + + /** + * Adds the given code value. + * @param {number} index Index of the row. + */ + addCodeValue(index: number) { + const newCodeValue: { name: string, description: string, position: string, isActive: boolean } = this.codeValues.at(index).value; + this.systemService.createCodeValue(this.codeData.id, newCodeValue) + .subscribe((response: any) => { + this.codeValues.at(index).disable(); + this.codeValueRowStatus[index] = 'disabled'; + this.codeValuesData.push({ + id: response.subResourceId, + name: this.codeValues.at(index).get('name').value, + description: this.codeValues.at(index).get('description').value, + position: this.codeValues.at(index).get('position').value, + isActive: this.codeValues.at(index).get('isActive').value + }); + this.codeValues.at(index).markAsPristine(); + }); + } + + /** + * Enables the given row. + * @param {number} index Index of the row. + */ + enableRow(index: number) { + this.codeValues.at(index).enable(); + this.codeValueRowStatus[index] = 'edit'; + } + +} diff --git a/src/app/system/system-routing.module.ts b/src/app/system/system-routing.module.ts index 03803f226..b1eb8e95c 100644 --- a/src/app/system/system-routing.module.ts +++ b/src/app/system/system-routing.module.ts @@ -9,6 +9,8 @@ import { extract } from '../core/i18n/i18n.service'; import { SystemComponent } from './system.component'; import { CodesComponent } from './codes/codes.component'; import { CreateCodeComponent } from './codes/create-code/create-code.component'; +import { ViewCodeComponent } from './codes/view-code/view-code.component'; +import { EditCodeComponent } from './codes/edit-code/edit-code.component'; import { ExternalServicesComponent } from './external-services/external-services.component'; import { ManageDataTablesComponent } from './manage-data-tables/manage-data-tables.component'; import { ManageHooksComponent } from './manage-hooks/manage-hooks.component'; @@ -28,6 +30,8 @@ import { EditSMSComponent } from './external-services/sms/edit-sms/edit-sms.comp /** Custom Resolvers */ import { CodesResolver } from './codes/codes.resolver'; +import { CodeResolver } from './codes/code.resolver'; +import { CodeValuesResolver } from './codes/view-code/code-values.resolver'; import { ManageDataTablesResolver } from './manage-data-tables/manage-data-tables.resolver'; import { ManageHooksResolver } from './manage-hooks/manage-hooks.resolver'; import { RolesAndPermissionsResolver } from './roles-and-permissions/roles-and-permissions.resolver'; @@ -65,6 +69,28 @@ const routes: Routes = [ path: 'create', component: CreateCodeComponent, data: { title: extract('Create Code'), breadcrumb: 'Create' } + }, + { + path: ':id', + data: { title: extract('View Code'), routeParamBreadcrumb: 'id' }, + children: [ + { + path: '', + component: ViewCodeComponent, + resolve: { + code: CodeResolver, + codeValues: CodeValuesResolver + } + }, + { + path: 'edit', + component: EditCodeComponent, + data: { title: extract('Edit Code'), breadcrumb: 'Edit', routeParamBreadcrumb: false }, + resolve: { + code: CodeResolver + } + } + ] } ], @@ -235,6 +261,8 @@ const routes: Routes = [ exports: [RouterModule], providers: [ CodesResolver, + CodeResolver, + CodeValuesResolver, ManageDataTablesResolver, ManageHooksResolver, RolesAndPermissionsResolver, diff --git a/src/app/system/system.module.ts b/src/app/system/system.module.ts index 51b773792..9be4342c5 100644 --- a/src/app/system/system.module.ts +++ b/src/app/system/system.module.ts @@ -25,6 +25,8 @@ import { EditAmazonS3Component } from './external-services/amazon-s3/edit-amazon import { EditEmailComponent } from './external-services/email/edit-email/edit-email.component'; import { EditNotificationComponent } from './external-services/notification/edit-notification/edit-notification.component'; import { EditSMSComponent } from './external-services/sms/edit-sms/edit-sms.component'; +import { ViewCodeComponent } from './codes/view-code/view-code.component'; +import { EditCodeComponent } from './codes/edit-code/edit-code.component'; @NgModule({ imports: [ @@ -34,7 +36,9 @@ import { EditSMSComponent } from './external-services/sms/edit-sms/edit-sms.comp declarations: [ SystemComponent, CodesComponent, + ViewCodeComponent, CreateCodeComponent, + EditCodeComponent, ExternalServicesComponent, ManageDataTablesComponent, ManageHooksComponent, diff --git a/src/app/system/system.service.ts b/src/app/system/system.service.ts index 95f14d477..1640858f2 100644 --- a/src/app/system/system.service.ts +++ b/src/app/system/system.service.ts @@ -46,6 +46,67 @@ export class SystemService { return this.http.get('/codes'); } + /** + * @param codeId Code ID. + * @returns {Observable} Fetches Code. + */ + getCode(codeId: string): Observable { + return this.http.get(`/codes/${codeId}`); + } + + /** + * @param code Code. + * @param codeId Code ID. + * @returns {Observable} + */ + updateCode(code: any, codeId: string): Observable { + return this.http.put(`/codes/${codeId}`, code); + } + + /** + * @param codeId Code ID. + * @returns {Observable} Code Values. + */ + getCodeValues(codeId: string): Observable { + return this.http.get(`/codes/${codeId}/codevalues`); + } + + /** + * @param codeId Code ID. + * @param codeValueId Code value ID. + * @returns {Observable} + */ + deleteCodeValue(codeId: string, codeValueId: string): Observable { + return this.http.delete(`/codes/${codeId}/codevalues/${codeValueId}`); + } + + /** + * @param codeId Code ID. + * @param codeValueId Code value ID. + * @param codeValueChanges Code value changes. + * @returns {Observable} + */ + updateCodeValue(codeId: string, codeValueId: string, codeValueChanges: any): Observable { + return this.http.put(`/codes/${codeId}/codevalues/${codeValueId}`, codeValueChanges); + } + + /** + * @param codeId Code ID. + * @param codeValueId Code value. + * @returns {Observable} + */ + createCodeValue(codeId: string, codeValue: any): Observable { + return this.http.post(`/codes/${codeId}/codevalues`, codeValue); + } + + /** + * @param codeId Code ID. + * @returns {Observable} + */ + deleteCode(codeId: string): Observable { + return this.http.delete(`/codes/${codeId}`); + } + /** * @returns {Observable} Fetches Surveys. */