From b3abac32f53af0c81e06278e67e1c92be10c2cbe Mon Sep 17 00:00:00 2001 From: Karan Takalkar Date: Wed, 8 Jul 2020 15:37:38 +0530 Subject: [PATCH] feat: group actions (assign/unassign staff) (#1029) Fixes #1028 --- .../group-actions.resolver.ts | 38 ++++++++++ src/app/groups/groups-routing.module.ts | 13 +++- .../unassign-staff-dialog.component.html | 8 +++ .../unassign-staff-dialog.component.scss | 0 .../unassign-staff-dialog.component.spec.ts | 25 +++++++ .../unassign-staff-dialog.component.ts | 20 ++++++ .../group-actions.component.html | 1 + .../group-actions.component.scss | 0 .../group-actions.component.spec.ts | 25 +++++++ .../group-actions/group-actions.component.ts | 30 ++++++++ .../group-assign-staff.component.html | 36 ++++++++++ .../group-assign-staff.component.scss | 3 + .../group-assign-staff.component.spec.ts | 25 +++++++ .../group-assign-staff.component.ts | 69 +++++++++++++++++++ .../groups-view/groups-view.component.html | 6 +- .../groups-view/groups-view.component.ts | 54 ++++++++++++++- src/app/groups/groups.module.ts | 11 ++- 17 files changed, 356 insertions(+), 8 deletions(-) create mode 100644 src/app/groups/common-resolvers/group-actions.resolver.ts create mode 100644 src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.html create mode 100644 src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.scss create mode 100644 src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.spec.ts create mode 100644 src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.ts create mode 100644 src/app/groups/groups-view/group-actions/group-actions.component.html create mode 100644 src/app/groups/groups-view/group-actions/group-actions.component.scss create mode 100644 src/app/groups/groups-view/group-actions/group-actions.component.spec.ts create mode 100644 src/app/groups/groups-view/group-actions/group-actions.component.ts create mode 100644 src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.html create mode 100644 src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.scss create mode 100644 src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.spec.ts create mode 100644 src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.ts diff --git a/src/app/groups/common-resolvers/group-actions.resolver.ts b/src/app/groups/common-resolvers/group-actions.resolver.ts new file mode 100644 index 000000000..500c2bd53 --- /dev/null +++ b/src/app/groups/common-resolvers/group-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 { GroupsService } from '../groups.service'; + +/** + * Group Actions data resolver. + */ +@Injectable() +export class GroupActionsResolver implements Resolve { + + /** + * @param {GroupsService} groupsService Savings service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Savings account actions data. + * @param {ActivatedRouteSnapshot} route Route Snapshot + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const actionName = route.paramMap.get('name'); + const groupId = route.paramMap.get('groupId') || route.parent.parent.paramMap.get('groupId'); + switch (actionName) { + case 'Assign Staff': + return this.groupsService.getGroupData(groupId, 'true'); + default: + return undefined; + } + } + +} diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts index 4d2bc90f7..d0d479914 100644 --- a/src/app/groups/groups-routing.module.ts +++ b/src/app/groups/groups-routing.module.ts @@ -17,6 +17,7 @@ import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab import { CreateGroupComponent } from './create-group/create-group.component'; import { DatatableTabsComponent } from './groups-view/datatable-tabs/datatable-tabs.component'; import { AddRoleComponent } from './groups-view/add-role/add-role.component'; +import { GroupActionsComponent } from './groups-view/group-actions/group-actions.component'; /** Custom Resolvers */ import { GroupViewResolver } from './common-resolvers/group-view.resolver'; @@ -27,6 +28,7 @@ import { OfficesResolver } from 'app/accounting/common-resolvers/offices.resolve import { GroupDatatablesResolver } from './common-resolvers/group-datatables.resolver'; import { GroupDatatableResolver } from './common-resolvers/group-datatable.resolver'; import { GroupDataAndTemplateResolver } from './common-resolvers/group-data-and-template.resolver'; +import { GroupActionsResolver } from './common-resolvers/group-actions.resolver'; /** Groups Routes */ const routes: Routes = [ @@ -113,6 +115,14 @@ const routes: Routes = [ }, ] }, + { + path: 'actions/:name', + data: { title: extract('Group Actions'), routeParamBreadcrumb: 'name' }, + component: GroupActionsComponent, + resolve: { + groupActionData: GroupActionsResolver + } + }, { path: 'savingsaccounts', loadChildren: '../savings/savings.module#SavingsModule' @@ -138,6 +148,7 @@ const routes: Routes = [ GroupNotesResolver, GroupDatatablesResolver, GroupDatatableResolver, - GroupDataAndTemplateResolver] + GroupDataAndTemplateResolver, + GroupActionsResolver] }) export class GroupsRoutingModule { } diff --git a/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.html b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.html new file mode 100644 index 000000000..054539569 --- /dev/null +++ b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.html @@ -0,0 +1,8 @@ +

Unassign Staff

+
+

Are you sure you want to unassign staff for this group ?

+
+ + + + diff --git a/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.scss b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.spec.ts b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.spec.ts new file mode 100644 index 000000000..1eaed45f3 --- /dev/null +++ b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UnassignStaffDialogComponent } from './unassign-staff-dialog.component'; + +describe('UnassignStaffDialogComponent', () => { + let component: UnassignStaffDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UnassignStaffDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UnassignStaffDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.ts b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.ts new file mode 100644 index 000000000..84628e6b8 --- /dev/null +++ b/src/app/groups/groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component.ts @@ -0,0 +1,20 @@ +/** Angular Imports */ +import { Component, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; + +/** + * Unassign staff dialog component. + */ +@Component({ + selector: 'mifosx-unassign-staff-dialog', + templateUrl: './unassign-staff-dialog.component.html', + styleUrls: ['./unassign-staff-dialog.component.scss'] +}) +export class UnassignStaffDialogComponent { + + /** + * @param {MatDialogRef} dialogRef Component reference to dialog. + */ + constructor(public dialogRef: MatDialogRef) { } + +} diff --git a/src/app/groups/groups-view/group-actions/group-actions.component.html b/src/app/groups/groups-view/group-actions/group-actions.component.html new file mode 100644 index 000000000..6d3f292e7 --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-actions.component.html @@ -0,0 +1 @@ + diff --git a/src/app/groups/groups-view/group-actions/group-actions.component.scss b/src/app/groups/groups-view/group-actions/group-actions.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/groups/groups-view/group-actions/group-actions.component.spec.ts b/src/app/groups/groups-view/group-actions/group-actions.component.spec.ts new file mode 100644 index 000000000..bb65cca10 --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-actions.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GroupActionsComponent } from './group-actions.component'; + +describe('GroupActionsComponent', () => { + let component: GroupActionsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ GroupActionsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GroupActionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/group-actions/group-actions.component.ts b/src/app/groups/groups-view/group-actions/group-actions.component.ts new file mode 100644 index 000000000..7435a27d8 --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-actions.component.ts @@ -0,0 +1,30 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Group actions component. + */ +@Component({ + selector: 'mifosx-group-actions', + templateUrl: './group-actions.component.html', + styleUrls: ['./group-actions.component.scss'] +}) +export class GroupActionsComponent { + + /** Flag object to store possible actions and render appropriate UI to the user */ + actions: { + 'Assign Staff': boolean + } = { + 'Assign Staff': false + }; + + /** + * @param {ActivatedRoute} route Activated Route + */ + constructor(private route: ActivatedRoute) { + const name = this.route.snapshot.params['name']; + this.actions[name] = true; + } + +} diff --git a/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.html b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.html new file mode 100644 index 000000000..6e73ef791 --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.html @@ -0,0 +1,36 @@ +
+ + + +
+ + + +
+ + + Staff + + + {{ staff.displayName }} + + + + Staff is required + + + +
+ +
+ + + + + + +
+ +
+ +
diff --git a/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.scss b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.scss new file mode 100644 index 000000000..d774f68da --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.scss @@ -0,0 +1,3 @@ +.container { + max-width: 37rem; +} diff --git a/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.spec.ts b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.spec.ts new file mode 100644 index 000000000..05ae8c3ab --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GroupAssignStaffComponent } from './group-assign-staff.component'; + +describe('GroupAssignStaffComponent', () => { + let component: GroupAssignStaffComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ GroupAssignStaffComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GroupAssignStaffComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.ts b/src/app/groups/groups-view/group-actions/group-assign-staff/group-assign-staff.component.ts new file mode 100644 index 000000000..43bb08da0 --- /dev/null +++ b/src/app/groups/groups-view/group-actions/group-assign-staff/group-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 { GroupsService } from 'app/groups/groups.service'; + +/** + * Groups Assign Staff Component + */ +@Component({ + selector: 'mifosx-group-assign-staff', + templateUrl: './group-assign-staff.component.html', + styleUrls: ['./group-assign-staff.component.scss'] +}) +export class GroupAssignStaffComponent implements OnInit { + + /** Group Assign Staff form. */ + groupAssignStaffForm: FormGroup; + /** Field Officer Data */ + staffData: any; + /** Group Data */ + groupData: any; + + /** + * Fetches Group 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 groupsService: GroupsService, + private route: ActivatedRoute, + private router: Router) { + this.route.data.subscribe((data: { groupActionData: any }) => { + this.groupData = data.groupActionData; + }); + } + + /** + * Creates the group assign staff form. + */ + ngOnInit() { + this.staffData = this.groupData.staffOptions; + this.createGroupAssignStaffForm(); + } + + /** + * Creates the group assign staff form. + */ + createGroupAssignStaffForm() { + this.groupAssignStaffForm = this.formBuilder.group({ + 'staffId': [''] + }); + } + + /** + * Submits the form and assigns staff for the group. + */ + submit() { + this.groupsService.executeGroupCommand(this.groupData.id, 'assignStaff', this.groupAssignStaffForm.value) + .subscribe(() => { + this.router.navigate(['../../'], { relativeTo: this.route }); + }); + } + +} diff --git a/src/app/groups/groups-view/groups-view.component.html b/src/app/groups/groups-view/groups-view.component.html index 3012d916e..a2fb6fd52 100644 --- a/src/app/groups/groups-view/groups-view.component.html +++ b/src/app/groups/groups-view/groups-view.component.html @@ -20,7 +20,7 @@

- Group #: {{groupViewData.id}} | Center Name: {{groupViewData.centerName}} | Staff: {{groupViewData.staffName}}
+ Group #: {{groupViewData.id}} | Center Name: {{groupViewData.centerName}} | Staff: {{groupViewData.staffName || 'Unassigned'}}
Office Name: {{groupViewData.officeName}}
Activation Date : {{(groupViewData.activationDate)?(groupViewData.activationDate|date) :'Not Activated'}}
@@ -80,9 +80,9 @@ - + - + diff --git a/src/app/groups/groups-view/groups-view.component.ts b/src/app/groups/groups-view/groups-view.component.ts index 26bc42fc9..e7a90fb40 100644 --- a/src/app/groups/groups-view/groups-view.component.ts +++ b/src/app/groups/groups-view/groups-view.component.ts @@ -1,6 +1,13 @@ /** Angular Imports */ import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; +import { MatDialog } from '@angular/material'; + +/** Custom Dialogs */ +import { UnassignStaffDialogComponent } from './custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; /** * Groups View Component. @@ -21,11 +28,54 @@ export class GroupsViewComponent { * Fetches group data from `resolve` * @param {ActivatedRoute} route Activated Route */ - constructor(private route: ActivatedRoute) { + constructor(private route: ActivatedRoute, + private groupsService: GroupsService, + private router: Router, + public dialog: MatDialog) { this.route.data.subscribe((data: { groupViewData: any, groupDatatables: any }) => { this.groupViewData = data.groupViewData; this.groupDatatables = data.groupDatatables; }); } + /** + * Performs action button/option action. + * @param {string} name action name. + */ + doAction(name: string) { + switch (name) { + case 'Assign Staff': + this.router.navigate([`actions/${name}`], { relativeTo: this.route }); + break; + case 'Unassign Staff': + this.unassignStaff(); + break; + } + } + + /** + * 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(`/groups`, {skipLocationChange: true}) + .then(() => this.router.navigate([url])); + } + + /** + * Unassign's the group's staff. + */ + private unassignStaff() { + const unAssignStaffDialogRef = this.dialog.open(UnassignStaffDialogComponent); + unAssignStaffDialogRef.afterClosed().subscribe((response: { confirm: any }) => { + if (response.confirm) { + this.groupsService.executeGroupCommand(this.groupViewData.id, 'unassignStaff', { staffId: this.groupViewData.staffId }) + .subscribe(() => { + this.reload(); + }); + } + }); + } + } diff --git a/src/app/groups/groups.module.ts b/src/app/groups/groups.module.ts index 90b50a23e..c44ecd6ca 100644 --- a/src/app/groups/groups.module.ts +++ b/src/app/groups/groups.module.ts @@ -20,6 +20,9 @@ import { SingleRowComponent } from './groups-view/datatable-tabs/single-row/sing import { MultiRowComponent } from './groups-view/datatable-tabs/multi-row/multi-row.component'; import { AddRoleComponent } from './groups-view/add-role/add-role.component'; import { UnassignRoleDialogComponent } from './groups-view/custom-dialogs/unassign-role-dialog/unassign-role-dialog.component'; +import { GroupActionsComponent } from './groups-view/group-actions/group-actions.component'; +import { GroupAssignStaffComponent } from './groups-view/group-actions/group-assign-staff/group-assign-staff.component'; +import { UnassignStaffDialogComponent } from './groups-view/custom-dialogs/unassign-staff-dialog/unassign-staff-dialog.component'; /** * Groups Module @@ -44,10 +47,14 @@ import { UnassignRoleDialogComponent } from './groups-view/custom-dialogs/unassi SingleRowComponent, MultiRowComponent, AddRoleComponent, - UnassignRoleDialogComponent + UnassignRoleDialogComponent, + GroupActionsComponent, + GroupAssignStaffComponent, + UnassignStaffDialogComponent ], entryComponents: [ - UnassignRoleDialogComponent + UnassignRoleDialogComponent, + UnassignStaffDialogComponent ], providers: [DatePipe] })