From 96f881e909bbd5aee063a37ae3e210c10f9e6cad Mon Sep 17 00:00:00 2001 From: Muskan Khedia <36980003+muskankhedia@users.noreply.github.com> Date: Tue, 14 Jul 2020 11:33:27 +0530 Subject: [PATCH] feat: add centers action (assign and unassign staff) (#1091) Fixes: #1090 --- src/app/centers/centers-routing.module.ts | 9 ++- .../center-actions.component.html | 1 + .../center-actions.component.ts | 4 +- .../center-assign-staff.component.html | 36 ++++++++++ .../center-assign-staff.component.scss | 3 + .../center-assign-staff.component.spec.ts | 25 +++++++ .../center-assign-staff.component.ts | 69 +++++++++++++++++++ .../centers-view/centers-view.component.html | 4 +- .../centers-view/centers-view.component.ts | 40 ++++++++++- src/app/centers/centers.module.ts | 4 +- src/app/centers/centers.service.ts | 22 ++++++ .../center-actions.resolver.ts | 38 ++++++++++ .../confirmation-dialog.component.html | 8 +++ .../confirmation-dialog.component.scss | 0 .../confirmation-dialog.component.spec.ts | 25 +++++++ .../confirmation-dialog.component.ts | 25 +++++++ src/app/shared/shared.module.ts | 7 +- 17 files changed, 311 insertions(+), 9 deletions(-) create mode 100644 src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.html create mode 100644 src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.scss create mode 100644 src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.spec.ts create mode 100644 src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.ts create mode 100644 src/app/centers/common-resolvers/center-actions.resolver.ts create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.html create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.scss create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts create mode 100644 src/app/shared/confirmation-dialog/confirmation-dialog.component.ts diff --git a/src/app/centers/centers-routing.module.ts b/src/app/centers/centers-routing.module.ts index 62b1fd5cf..4abeb6533 100644 --- a/src/app/centers/centers-routing.module.ts +++ b/src/app/centers/centers-routing.module.ts @@ -25,6 +25,7 @@ import { CenterNotesResolver } from './common-resolvers/center-notes.resolver'; import { CenterDatatableResolver } from './common-resolvers/center-datatable.resolver'; import { CenterDatatablesResolver } from './common-resolvers/center-datatables.resolver'; import { CenterActionsComponent } from './centers-view/center-actions/center-actions.component'; +import { CenterActionsResolver } from './common-resolvers/center-actions.resolver'; const routes: Routes = [ Route.withShell([ @@ -91,7 +92,10 @@ const routes: Routes = [ { path: 'actions/:name', data: { title: extract('Center Actions'), routeParamBreadcrumb: 'name' }, - component: CenterActionsComponent + component: CenterActionsComponent, + resolve: { + centersActionData: CenterActionsResolver + } }, ] } @@ -111,7 +115,8 @@ const routes: Routes = [ CenterSummaryResolver, CenterNotesResolver, CenterDatatableResolver, - CenterDatatablesResolver + CenterDatatablesResolver, + CenterActionsResolver ] }) export class CentersRoutingModule { } diff --git a/src/app/centers/centers-view/center-actions/center-actions.component.html b/src/app/centers/centers-view/center-actions/center-actions.component.html index 59caaa7ec..862d48e2f 100644 --- a/src/app/centers/centers-view/center-actions/center-actions.component.html +++ b/src/app/centers/centers-view/center-actions/center-actions.component.html @@ -1 +1,2 @@ + diff --git a/src/app/centers/centers-view/center-actions/center-actions.component.ts b/src/app/centers/centers-view/center-actions/center-actions.component.ts index dc031d75e..58cfdbd46 100644 --- a/src/app/centers/centers-view/center-actions/center-actions.component.ts +++ b/src/app/centers/centers-view/center-actions/center-actions.component.ts @@ -14,9 +14,11 @@ export class CenterActionsComponent { /** Flag object to store possible actions and render appropriate UI to the user */ actions: { - 'Activate': boolean + 'Activate': boolean, + 'Assign Staff': boolean } = { 'Activate': false, + 'Assign Staff': false }; /** diff --git a/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.html b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.html new file mode 100644 index 000000000..eafb53f63 --- /dev/null +++ b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.html @@ -0,0 +1,36 @@ +
+ + + +
+ + + +
+ + + Staff + + + {{ staff.displayName }} + + + + Staff is required + + + +
+ +
+ + + + + + +
+ +
+ +
diff --git a/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.scss b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.scss new file mode 100644 index 000000000..f6edc1a09 --- /dev/null +++ b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.scss @@ -0,0 +1,3 @@ +.container { + max-width: 37rem; +} diff --git a/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.spec.ts b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.spec.ts new file mode 100644 index 000000000..5b6ef4b5a --- /dev/null +++ b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CenterAssignStaffComponent } from './center-assign-staff.component'; + +describe('CenterAssignStaffComponent', () => { + let component: CenterAssignStaffComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CenterAssignStaffComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CenterAssignStaffComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.ts b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.ts new file mode 100644 index 000000000..96baf6cb6 --- /dev/null +++ b/src/app/centers/centers-view/center-actions/center-assign-staff/center-assign-staff.component.ts @@ -0,0 +1,69 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormBuilder } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; + +/** Custom Services */ +import { CentersService } from 'app/centers/centers.service'; + +/** + * Centers Assign Staff Component + */ +@Component({ + selector: 'mifosx-center-assign-staff', + templateUrl: './center-assign-staff.component.html', + styleUrls: ['./center-assign-staff.component.scss'] +}) +export class CenterAssignStaffComponent implements OnInit { + + /** Center Assign Staff form. */ + centerAssignStaffForm: FormGroup; + /** Field Officer Data */ + staffData: any; + /** Center Data */ + centerData: any; + + /** + * Fetches Center Action Data from `resolve` + * @param {FormBuilder} formBuilder Form Builder + * @param {SavingsService} savingsService Savings Service + * @param {ActivatedRoute} route Activated Route + * @param {Router} router Router + */ + constructor(private formBuilder: FormBuilder, + private centersService: CentersService, + private route: ActivatedRoute, + private router: Router) { + this.route.data.subscribe((data: { centersActionData: any }) => { + this.centerData = data.centersActionData; + }); + } + + /** + * Creates the center assign staff form. + */ + ngOnInit() { + this.staffData = this.centerData.staffOptions; + this.createCenterAssignStaffForm(); + } + + /** + * Creates the center assign staff form. + */ + createCenterAssignStaffForm() { + this.centerAssignStaffForm = this.formBuilder.group({ + 'staffId': [''] + }); + } + + /** + * Submits the form and assigns staff for the center. + */ + submit() { + this.centersService.executeGroupActionCommand(this.centerData.id, 'assignStaff', this.centerAssignStaffForm.value) + .subscribe(() => { + this.router.navigate(['../../'], { relativeTo: this.route }); + }); + } + +} diff --git a/src/app/centers/centers-view/centers-view.component.html b/src/app/centers/centers-view/centers-view.component.html index 910321907..ac2b67c45 100644 --- a/src/app/centers/centers-view/centers-view.component.html +++ b/src/app/centers/centers-view/centers-view.component.html @@ -65,10 +65,10 @@ - + - + diff --git a/src/app/centers/centers-view/centers-view.component.ts b/src/app/centers/centers-view/centers-view.component.ts index 5287a79c4..3d5e5f0a7 100644 --- a/src/app/centers/centers-view/centers-view.component.ts +++ b/src/app/centers/centers-view/centers-view.component.ts @@ -3,6 +3,12 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { MatDialog } from '@angular/material'; +/** Dialog Imports */ +import { ConfirmationDialogComponent } from 'app/shared/confirmation-dialog/confirmation-dialog.component'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + /** * Create Center View */ @@ -26,7 +32,8 @@ export class CentersViewComponent implements OnInit { */ constructor(private route: ActivatedRoute, private router: Router, - public dialog: MatDialog) { + public dialog: MatDialog, + public centersService: CentersService) { this.route.data.subscribe((data: { centerViewData: any, centerDatatables: any @@ -49,9 +56,40 @@ export class CentersViewComponent implements OnInit { doAction(name: string) { switch (name) { case 'Activate': + case 'Assign Staff': this.router.navigate([`actions/${name}`], { relativeTo: this.route }); break; + case 'Unassign Staff': + this.centersUnassignStaff(); + break; } } + /** + * Unassign's the centers's staff. + */ + private centersUnassignStaff() { + const unAssignStaffDialogRef = this.dialog.open(ConfirmationDialogComponent, { + data: { heading: 'Unassign Staff', dialogContext: 'Are you sure you want Unassign Staff ?' } + }); + unAssignStaffDialogRef.afterClosed().subscribe((response: { confirm: any }) => { + if (response.confirm) { + this.centersService.executeGroupActionCommand(this.centerViewData.id, 'unassignStaff', { staffId: this.centerViewData.staffId }) + .subscribe(() => { + this.reload(); + }); + } + }); + } + + /** + * Refetches data for the component + * TODO: Replace by a custom reload component instead of hard-coded back-routing. + */ + reload() { + const url: string = this.router.url; + this.router.navigateByUrl(`/centers`, {skipLocationChange: true}) + .then(() => this.router.navigate([url])); + } + } diff --git a/src/app/centers/centers.module.ts b/src/app/centers/centers.module.ts index 251cdab39..17595fdc2 100644 --- a/src/app/centers/centers.module.ts +++ b/src/app/centers/centers.module.ts @@ -18,6 +18,7 @@ import { MultiRowComponent } from './centers-view/datatable-tab/multi-row/multi- import { SingleRowComponent } from './centers-view/datatable-tab/single-row/single-row.component'; import { CenterActionsComponent } from './centers-view/center-actions/center-actions.component'; import { ActivateCenterComponent } from './centers-view/center-actions/activate-center/activate-center.component'; +import { CenterAssignStaffComponent } from './centers-view/center-actions/center-assign-staff/center-assign-staff.component'; /** * Centers Module @@ -41,7 +42,8 @@ import { ActivateCenterComponent } from './centers-view/center-actions/activate- MultiRowComponent, SingleRowComponent, CenterActionsComponent, - ActivateCenterComponent + ActivateCenterComponent, + CenterAssignStaffComponent ] }) export class CentersModule { } diff --git a/src/app/centers/centers.service.ts b/src/app/centers/centers.service.ts index b5b4d9f45..74ced0628 100644 --- a/src/app/centers/centers.service.ts +++ b/src/app/centers/centers.service.ts @@ -187,4 +187,26 @@ export class CentersService { return this.http.post(`/centers/${centerId}`, data, { params: httpParams }); } + /** + * @param {string} centerId Center Id + * @param {string} command Command + * @param {any} data Data + * @returns {Observable} + */ + executeGroupActionCommand(centerId: string, command: string, data: any): Observable { + const httpParams = new HttpParams().set('command', command); + return this.http.post(`/groups/${centerId}`, data, { params: httpParams }); + } + + /** + * @param centerId Center Id of center to get data for. + * @returns {Observable} Center data. + */ + getGroupStaffData(centerId: string): Observable { + const httpParams = new HttpParams().set('groupOrCenter', 'centers') + .set('staffInSelectedOfficeOnly', 'true') + .set('template', 'true'); + return this.http.get(`/groups/${centerId}`, { params: httpParams }); + } + } diff --git a/src/app/centers/common-resolvers/center-actions.resolver.ts b/src/app/centers/common-resolvers/center-actions.resolver.ts new file mode 100644 index 000000000..b8edc24b3 --- /dev/null +++ b/src/app/centers/common-resolvers/center-actions.resolver.ts @@ -0,0 +1,38 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + +/** + * Group Actions data resolver. + */ +@Injectable() +export class CenterActionsResolver implements Resolve { + + /** + * @param {CentersService} centersService Savings service. + */ + constructor(private centersService: CentersService) { } + + /** + * Returns the Centers account actions data. + * @param {ActivatedRouteSnapshot} route Route Snapshot + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const actionName = route.paramMap.get('name'); + const centerId = route.paramMap.get('centerId') || route.parent.parent.paramMap.get('centerId'); + switch (actionName) { + case 'Assign Staff': + return this.centersService.getGroupStaffData(centerId); + default: + return undefined; + } + } + +} diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.html b/src/app/shared/confirmation-dialog/confirmation-dialog.component.html new file mode 100644 index 000000000..0e0295502 --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.html @@ -0,0 +1,8 @@ +

{{data.heading}}

+
+

{{ data.dialogContext }} ?

+
+ + + + diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.scss b/src/app/shared/confirmation-dialog/confirmation-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts b/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts new file mode 100644 index 000000000..4610829b9 --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ConfirmationDialogComponent } from './confirmation-dialog.component'; + +describe('ConfirmationDialogComponent', () => { + let component: ConfirmationDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ConfirmationDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmationDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts b/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts new file mode 100644 index 000000000..3f9be5997 --- /dev/null +++ b/src/app/shared/confirmation-dialog/confirmation-dialog.component.ts @@ -0,0 +1,25 @@ +/** Angular Imports */ +import { Component, OnInit, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; + +/** + * Delete dialog component. + */ +@Component({ + selector: 'mifosx-confirmation-dialog', + templateUrl: './confirmation-dialog.component.html', + styleUrls: ['./confirmation-dialog.component.scss'] +}) +export class ConfirmationDialogComponent implements OnInit { + + /** + * @param {MatDialogRef} dialogRef Component reference to dialog. + * @param {any} data Provides a deleteContext. + */ + constructor(public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any) { } + + ngOnInit() { + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index b0d1a99df..9ad6b1d6f 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -14,6 +14,7 @@ import { ThemePickerComponent } from './theme-picker/theme-picker.component'; import { ChangePasswordDialogComponent } from './change-password-dialog/change-password-dialog.component'; import { EnableDialogComponent } from './enable-dialog/enable-dialog.component'; import { DisableDialogComponent } from './disable-dialog/disable-dialog.component'; +import { ConfirmationDialogComponent } from './confirmation-dialog/confirmation-dialog.component'; /** Custom Modules */ import { IconsModule } from './icons.module'; @@ -41,7 +42,8 @@ import { MaterialModule } from './material.module'; ThemePickerComponent, ChangePasswordDialogComponent, EnableDialogComponent, - DisableDialogComponent + DisableDialogComponent, + ConfirmationDialogComponent ], exports: [ FileUploadComponent, @@ -59,7 +61,8 @@ import { MaterialModule } from './material.module'; DeleteDialogComponent, ChangePasswordDialogComponent, EnableDialogComponent, - DisableDialogComponent + DisableDialogComponent, + ConfirmationDialogComponent ] }) export class SharedModule { }