From 377c4891e4193631c51a58b10860f697c434f8e5 Mon Sep 17 00:00:00 2001 From: Karan Takalkar Date: Sat, 23 May 2020 21:09:51 +0530 Subject: [PATCH] feat: add groups view page (datatable-tabs) (#793) Fixes: #776 Fixes: #777 Fixes: #791 --- .../group-datatable.resolver.ts | 32 +++ .../group-datatables.resolver.ts | 30 +++ src/app/groups/groups-routing.module.ts | 23 +- .../committee-tab.component.html | 62 +++--- .../committee-tab.component.scss | 5 +- .../datatable-tabs.component.html | 4 + .../datatable-tabs.component.scss | 0 .../datatable-tabs.component.spec.ts | 25 +++ .../datatable-tabs.component.ts | 31 +++ .../multi-row/multi-row.component.html | 33 +++ .../multi-row/multi-row.component.scss | 10 + .../multi-row/multi-row.component.spec.ts | 25 +++ .../multi-row/multi-row.component.ts | 184 ++++++++++++++++ .../single-row/single-row.component.html | 29 +++ .../single-row/single-row.component.scss | 7 + .../single-row/single-row.component.spec.ts | 25 +++ .../single-row/single-row.component.ts | 207 ++++++++++++++++++ .../general-tab/general-tab.component.html | 16 +- .../general-tab/general-tab.component.scss | 8 +- .../groups-view/groups-view.component.html | 7 + .../groups-view/groups-view.component.ts | 5 +- src/app/groups/groups.module.ts | 8 +- src/app/groups/groups.service.ts | 67 +++++- 23 files changed, 785 insertions(+), 58 deletions(-) create mode 100644 src/app/groups/common-resolvers/group-datatable.resolver.ts create mode 100644 src/app/groups/common-resolvers/group-datatables.resolver.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.html create mode 100644 src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.scss create mode 100644 src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.spec.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.html create mode 100644 src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.scss create mode 100644 src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.spec.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.html create mode 100644 src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.scss create mode 100644 src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.spec.ts create mode 100644 src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.ts diff --git a/src/app/groups/common-resolvers/group-datatable.resolver.ts b/src/app/groups/common-resolvers/group-datatable.resolver.ts new file mode 100644 index 000000000..53f83a165 --- /dev/null +++ b/src/app/groups/common-resolvers/group-datatable.resolver.ts @@ -0,0 +1,32 @@ +/** 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 Datatable data resolver. + */ +@Injectable() +export class GroupDatatableResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Group's Datatable data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const groupId = route.parent.parent.paramMap.get('groupId'); + const datatableName = route.paramMap.get('datatableName'); + return this.groupsService.getGroupDatatable(groupId, datatableName); + } + +} diff --git a/src/app/groups/common-resolvers/group-datatables.resolver.ts b/src/app/groups/common-resolvers/group-datatables.resolver.ts new file mode 100644 index 000000000..a0187932f --- /dev/null +++ b/src/app/groups/common-resolvers/group-datatables.resolver.ts @@ -0,0 +1,30 @@ +/** 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 Datatables data resolver. + */ +@Injectable() +export class GroupDatatablesResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Group's Datatables data. + * @returns {Observable} + */ + resolve(): Observable { + return this.groupsService.getGroupDatatables(); + } + +} diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts index 1be2dd4bb..6f9c7314e 100644 --- a/src/app/groups/groups-routing.module.ts +++ b/src/app/groups/groups-routing.module.ts @@ -15,6 +15,7 @@ import { GeneralTabComponent } from './groups-view/general-tab/general-tab.compo import { NotesTabComponent } from './groups-view/notes-tab/notes-tab.component'; import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab.component'; import { CreateGroupComponent } from './create-group/create-group.component'; +import { DatatableTabsComponent } from './groups-view/datatable-tabs/datatable-tabs.component'; /** Custom Resolvers */ import { GroupViewResolver } from './common-resolvers/group-view.resolver'; @@ -22,6 +23,8 @@ import { GroupAccountsResolver } from './common-resolvers/group-account.resolver import { GroupSummaryResolver } from './common-resolvers/group-summary.resolver'; import { GroupNotesResolver } from './common-resolvers/group-notes.resolver'; import { OfficesResolver } from 'app/accounting/common-resolvers/offices.resolver'; +import { GroupDatatablesResolver } from './common-resolvers/group-datatables.resolver'; +import { GroupDatatableResolver } from './common-resolvers/group-datatable.resolver'; /** Groups Routes */ const routes: Routes = [ @@ -47,7 +50,8 @@ const routes: Routes = [ component: GroupsViewComponent, data: { title: extract('View Group'), routeParamBreadcrumb: 'groupId' }, resolve: { - groupViewData: GroupViewResolver + groupViewData: GroupViewResolver, + groupDatatables: GroupDatatablesResolver }, children: [ { @@ -71,6 +75,19 @@ const routes: Routes = [ path: 'committee', component: CommitteeTabComponent, data: { title: extract('Committee'), breadcrumb: 'Committee', routeParamBreadcrumb: false } + }, + { + path: 'datatables', + children: [ + { + path: ':datatableName', + component: DatatableTabsComponent, + data: { title: extract('View Data Table'), routeParamBreadcrumb: 'datatableName' }, + resolve: { + groupDatatable: GroupDatatableResolver + } + } + ] } ] } @@ -90,6 +107,8 @@ const routes: Routes = [ providers: [GroupViewResolver, GroupAccountsResolver, GroupSummaryResolver, - GroupNotesResolver] + GroupNotesResolver, + GroupDatatablesResolver, + GroupDatatableResolver] }) export class GroupsRoutingModule { } diff --git a/src/app/groups/groups-view/committee-tab/committee-tab.component.html b/src/app/groups/groups-view/committee-tab/committee-tab.component.html index 7e6a73bd9..54d509033 100644 --- a/src/app/groups/groups-view/committee-tab/committee-tab.component.html +++ b/src/app/groups/groups-view/committee-tab/committee-tab.component.html @@ -1,6 +1,6 @@
-
+

Client Members

@@ -11,39 +11,43 @@
- +
+ +
- - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - + + -
Name {{element.clientName}} Name {{element.clientName}} Role {{element.role.name}} Role {{element.role.name}} Client Id {{element.clientId}} Client Id {{element.clientId}} Actions - - - - Actions + + + +
+ + +
diff --git a/src/app/groups/groups-view/committee-tab/committee-tab.component.scss b/src/app/groups/groups-view/committee-tab/committee-tab.component.scss index 4110ebc68..aaafd7b18 100644 --- a/src/app/groups/groups-view/committee-tab/committee-tab.component.scss +++ b/src/app/groups/groups-view/committee-tab/committee-tab.component.scss @@ -4,14 +4,11 @@ h3 { margin:1% auto; } - .table-header { - .action-button{ + .action-button { margin-left: auto; - } } table { width: 100%; - margin-bottom: 30px; .account-action-button{ min-width: 26px; padding: 0 6px; diff --git a/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.html b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.html new file mode 100644 index 000000000..3207b7197 --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.scss b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.spec.ts b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.spec.ts new file mode 100644 index 000000000..0f1dfa604 --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DatatableTabsComponent } from './datatable-tabs.component'; + +describe('DatatableTabsComponent', () => { + let component: DatatableTabsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DatatableTabsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DatatableTabsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.ts b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.ts new file mode 100644 index 000000000..e4aae10db --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/datatable-tabs.component.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Groups Datatable Tabs Component + */ +@Component({ + selector: 'mifosx-datatable-tabs', + templateUrl: './datatable-tabs.component.html', + styleUrls: ['./datatable-tabs.component.scss'] +}) +export class DatatableTabsComponent { + + /** Group Datatable */ + groupDatatable: any; + /** Multi Row Datatable Flag */ + multiRowDatatableFlag: boolean; + + /** + * Fetches data table data from `resolve` + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { groupDatatable: any }) => { + this.groupDatatable = data.groupDatatable; + this.multiRowDatatableFlag = this.groupDatatable.columnHeaders[0].columnName === 'id' ? true : false; + }); + } + +} diff --git a/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.html b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.html new file mode 100644 index 000000000..c339f8643 --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.html @@ -0,0 +1,33 @@ +
+ +
+
+

{{datatableName}}

+
+
+ + + + + + +
+
+ + + + + + + + + + + +
{{datatableColumn}} {{data.row[i]}}
+ +
diff --git a/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.scss b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.scss new file mode 100644 index 000000000..6fa6a5f4e --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.scss @@ -0,0 +1,10 @@ +.tab-container { + padding: 1%; + margin: 1%; + .action-button{ + margin-left: auto; + } + table { + width: 100%; + } +} diff --git a/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.spec.ts b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.spec.ts new file mode 100644 index 000000000..dd46589d8 --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MultiRowComponent } from './multi-row.component'; + +describe('MultiRowComponent', () => { + let component: MultiRowComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MultiRowComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MultiRowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.ts b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.ts new file mode 100644 index 000000000..d622cac21 --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/multi-row/multi-row.component.ts @@ -0,0 +1,184 @@ +/** Angular Imports */ +import { Component, OnChanges, OnInit, Input, ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MatTable } from '@angular/material/table'; +import { MatDialog } from '@angular/material'; +import { DatePipe } from '@angular/common'; + +/** Custom Dialogs */ +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { DeleteDialogComponent } from '../../../../shared/delete-dialog/delete-dialog.component'; + +/** Custom Models */ +import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; +import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; +import { CheckboxBase } from 'app/shared/form-dialog/formfield/model/checkbox-base'; +import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; + +/** Custom Services */ +import { GroupsService } from '../../../groups.service'; + +/** + * Group Multi Row Data Tables + */ +@Component({ + selector: 'mifosx-multi-row', + templateUrl: './multi-row.component.html', + styleUrls: ['./multi-row.component.scss'] +}) +export class MultiRowComponent implements OnInit, OnChanges { + + /** Data Object */ + @Input() dataObject: any; + + /** Data Table Name */ + datatableName: string; + /** Data Table Columns */ + datatableColumns: string[] = []; + /** Data Table Data */ + datatableData: any; + /** Group Id */ + groupId: string; + /** Toggle button visibility */ + showDeleteBotton: boolean; + + /** Data Table Reference */ + @ViewChild('dataTable') dataTableRef: MatTable; + + /** + * Fetches group Id from parent route params. + * @param {ActivatedRoute} route Activated Route. + * @param {DatePipe} datePipe Date Pipe. + * @param {GroupsService} groupsService Groups Service. + * @param {MatDialog} dialog Mat Dialog. + */ + constructor(private route: ActivatedRoute, + private datePipe: DatePipe, + private groupsService: GroupsService, + private dialog: MatDialog) { + this.groupId = this.route.parent.parent.snapshot.paramMap.get('groupId'); + } + + /** + * Updates related variables on changes to dataObject. + */ + ngOnChanges() { + this.datatableColumns = this.dataObject.columnHeaders.map((columnHeader: any) => { + return columnHeader.columnName; + }); + this.datatableData = this.dataObject.data; + this.showDeleteBotton = this.datatableData[0] ? true : false; + } + + /** + * Fetches data table name from route params. + * subscription is required due to asynchronicity. + */ + ngOnInit() { + this.route.params.subscribe((routeParams: any) => { + this.datatableName = routeParams.datatableName; + }); + } + + /** + * Adds a new row to the given multi row data table. + */ + add() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'group_id')); + }); + const formfields: FormfieldBase[] = columns.map((column: any) => { + switch (column.columnDisplayType) { + case 'INTEGER': + case 'STRING': + case 'DECIMAL': + case 'TEXT': return new InputBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: (column.columnDisplayType === 'INTEGER' || column.columnDisplayType === 'DECIMAL') ? 'number' : 'text', + required: (column.isColumnNullable) ? false : true + }); + case 'BOOLEAN': return new CheckboxBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'checkbox', + required: (column.isColumnNullable) ? false : true + }); + case 'CODELOOKUP': return new SelectBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + options: { label: 'value', value: 'id', data: column.columnValues }, + required: (column.isColumnNullable) ? false : true + }); + case 'DATE': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'date', + required: (column.isColumnNullable) ? false : true + }); + } + case 'DATETIME': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd HH:mm'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'datetime-local', + required: (column.isColumnNullable) ? false : true + }); + } + } + }); + const data = { + title: 'Add ' + this.datatableName, + formfields: formfields + }; + const addDialogRef = this.dialog.open(FormDialogComponent, { data }); + addDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.groupsService.addGroupDatatableEntry(this.groupId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.groupsService.getGroupDatatable(this.groupId, this.datatableName).subscribe((dataObject: any) => { + this.datatableData = dataObject.data; + this.dataTableRef.renderRows(); + }); + }); + } + }); + } + + /** + * Deletes all rows of the given multi row data table. + */ + delete() { + const deleteDataTableDialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: `the contents of ${this.datatableName}` } + }); + deleteDataTableDialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.groupsService.deleteDatatableContent(this.groupId, this.datatableName).subscribe(() => { + this.groupsService.getGroupDatatable(this.groupId, this.datatableName).subscribe((dataObject: any) => { + this.datatableData = dataObject.data; + this.showDeleteBotton = false; + this.dataTableRef.renderRows(); + }); + }); + } + }); + } + +} diff --git a/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.html b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.html new file mode 100644 index 000000000..c2536b86a --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.html @@ -0,0 +1,29 @@ +
+ +

{{datatableName}}

+ +
+ + + + + + + + + +
+ + + + {{columnHeader.columnName}} : {{dataObject.data[0].row[i]}} + + + +
diff --git a/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.scss b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.scss new file mode 100644 index 000000000..63d2cfc9e --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.scss @@ -0,0 +1,7 @@ +.tab-container { + padding: 1%; + margin: 1%; + .delete-button { + margin-left: 1%; + } +} diff --git a/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.spec.ts b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.spec.ts new file mode 100644 index 000000000..8aece650c --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SingleRowComponent } from './single-row.component'; + +describe('SingleRowComponent', () => { + let component: SingleRowComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SingleRowComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SingleRowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.ts b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.ts new file mode 100644 index 000000000..957c03ebb --- /dev/null +++ b/src/app/groups/groups-view/datatable-tabs/single-row/single-row.component.ts @@ -0,0 +1,207 @@ +/** Angular Imports */ +import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MatDialog } from '@angular/material'; +import { DatePipe } from '@angular/common'; + +/** Custom Components */ +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { DeleteDialogComponent } from '../../../../shared/delete-dialog/delete-dialog.component'; + +/** Custom Models */ +import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; +import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; +import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; +import { CheckboxBase } from 'app/shared/form-dialog/formfield/model/checkbox-base'; + +/** Custom Services */ +import { GroupsService } from '../../../groups.service'; + + +/** + * Groups Single Row Data Tables + */ +@Component({ + selector: 'mifosx-single-row', + templateUrl: './single-row.component.html', + styleUrls: ['./single-row.component.scss'] +}) +export class SingleRowComponent implements OnInit { + + /** Data Object */ + @Input() dataObject: any; + + /** Data Table Name */ + datatableName: string; + /** Group Id */ + groupId: string; + + /** + * Fetches group Id from parent route params. + * @param {ActivatedRoute} route Activated Route. + * @param {DatePipe} datePipe Date Pipe. + * @param {GroupsService} groupsService Groups Service. + * @param {MatDialog} dialog Mat Dialog. + */ + constructor(private route: ActivatedRoute, + private datePipe: DatePipe, + private dialog: MatDialog, + private groupsService: GroupsService) { + this.groupId = this.route.parent.parent.snapshot.paramMap.get('groupId'); + } + + /** + * Fetches data table name from route params. + * subscription is required due to asynchronicity. + */ + ngOnInit() { + this.route.params.subscribe((routeParams: any) => { + this.datatableName = routeParams.datatableName; + }); + } + + /** + * Creates a new instance of the given single row data table. + */ + add() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'group_id')); + }); + const formfields: FormfieldBase[] = this.getFormfields(columns, dateTransformColumns, dataTableEntryObject); + const data = { + title: 'Add ' + this.datatableName, + formfields: formfields + }; + const addDialogRef = this.dialog.open(FormDialogComponent, { data }); + addDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.groupsService.addGroupDatatableEntry(this.groupId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.groupsService.getGroupDatatable(this.groupId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Edits the current instance of single row data table. + */ + edit() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'group_id')); + }); + let formfields: FormfieldBase[] = this.getFormfields(columns, dateTransformColumns, dataTableEntryObject); + formfields = formfields.map((formfield: FormfieldBase, index: number) => { + formfield.value = (this.dataObject.data[0].row[index + 1]) ? this.dataObject.data[0].row[index + 1] : ''; + return formfield; + }); + const data = { + title: 'Edit ' + this.datatableName, + layout: { addButtonText: 'Confirm' }, + formfields: formfields + }; + const editDialogRef = this.dialog.open(FormDialogComponent, { data }); + editDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.groupsService.editGroupDatatableEntry(this.groupId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.groupsService.getGroupDatatable(this.groupId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Deletes the current instance of single row data table. + */ + delete() { + const deleteDataTableDialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: `the contents of ${this.datatableName}` } + }); + deleteDataTableDialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.groupsService.deleteDatatableContent(this.groupId, this.datatableName) + .subscribe(() => { + this.groupsService.getGroupDatatable(this.groupId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Maps API response to data table form fields. + * @param {any} columns Data Table Columns. + * @param {string[]} dateTransformColumns Columns transformed with date pipe. + * @param {any} dataTableEntryObject Additional data table details. + */ + getFormfields(columns: any, dateTransformColumns: string[], dataTableEntryObject: any) { + return columns.map((column: any) => { + switch (column.columnDisplayType) { + case 'INTEGER': + case 'STRING': + case 'DECIMAL': + case 'TEXT': return new InputBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: (column.columnDisplayType === 'INTEGER' || column.columnDisplayType === 'DECIMAL') ? 'number' : 'text', + required: (column.isColumnNullable) ? false : true + }); + case 'BOOLEAN': return new CheckboxBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'checkbox', + required: (column.isColumnNullable) ? false : true + }); + case 'CODELOOKUP': return new SelectBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + options: { label: 'value', value: 'id', data: column.columnValues }, + required: (column.isColumnNullable) ? false : true + }); + case 'DATE': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'date', + required: (column.isColumnNullable) ? false : true + }); + } + case 'DATETIME': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd HH:mm'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'datetime-local', + required: (column.isColumnNullable) ? false : true + }); + } + } + }); + } + +} diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.html b/src/app/groups/groups-view/general-tab/general-tab.component.html index a97716937..669b2ac33 100644 --- a/src/app/groups/groups-view/general-tab/general-tab.component.html +++ b/src/app/groups/groups-view/general-tab/general-tab.component.html @@ -2,7 +2,7 @@

Group Details

-
+

Active Client Loans: {{groupSummary?.activeClientLoans}}
Active Client Borrowers: {{groupSummary?.activeClientBorrowers}}
@@ -24,7 +24,7 @@

Client Members

+ class="mat-elevation-z1 m-b-30"> @@ -68,7 +68,7 @@

Loan Accounts

-
+
@@ -76,7 +76,7 @@
Name
+ class="mat-elevation-z1 m-b-30"> @@ -142,7 +142,7 @@
Account No.
+ class="mat-elevation-z1 m-b-30"> @@ -199,7 +199,7 @@

Saving Accounts

-
+
@@ -207,7 +207,7 @@
Account No.
+ class="mat-elevation-z1 m-b-30"> @@ -261,7 +261,7 @@
Account No.
+ class="mat-elevation-z1 m-b-30"> diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.scss b/src/app/groups/groups-view/general-tab/general-tab.component.scss index 8bb6e3775..7624c1d93 100644 --- a/src/app/groups/groups-view/general-tab/general-tab.component.scss +++ b/src/app/groups/groups-view/general-tab/general-tab.component.scss @@ -7,12 +7,9 @@ .group-details-container { border: 1px solid; padding: 1%; - margin-bottom: 30px; } - .table-header { - .action-button{ - margin-left: auto; - } + .action-button{ + margin-left: auto; } table { width: 100%; @@ -25,7 +22,6 @@ tr.select-row:hover { cursor: pointer; } - margin-bottom: 30px; } i:hover { cursor: pointer; diff --git a/src/app/groups/groups-view/groups-view.component.html b/src/app/groups/groups-view/groups-view.component.html index e9fbd9e89..c2b97022c 100644 --- a/src/app/groups/groups-view/groups-view.component.html +++ b/src/app/groups/groups-view/groups-view.component.html @@ -108,6 +108,13 @@ [active]="committee.isActive"> Committee + + + {{groupDatatable.registeredTableName}} + + diff --git a/src/app/groups/groups-view/groups-view.component.ts b/src/app/groups/groups-view/groups-view.component.ts index 00d0555b7..26bc42fc9 100644 --- a/src/app/groups/groups-view/groups-view.component.ts +++ b/src/app/groups/groups-view/groups-view.component.ts @@ -14,14 +14,17 @@ export class GroupsViewComponent { /** Group view data */ groupViewData: any; + /** Group datatables data */ + groupDatatables: any; /** * Fetches group data from `resolve` * @param {ActivatedRoute} route Activated Route */ constructor(private route: ActivatedRoute) { - this.route.data.subscribe((data: { groupViewData: any }) => { + this.route.data.subscribe((data: { groupViewData: any, groupDatatables: any }) => { this.groupViewData = data.groupViewData; + this.groupDatatables = data.groupDatatables; }); } diff --git a/src/app/groups/groups.module.ts b/src/app/groups/groups.module.ts index 1d9160e0c..a191dd8b1 100644 --- a/src/app/groups/groups.module.ts +++ b/src/app/groups/groups.module.ts @@ -15,6 +15,9 @@ import { GeneralTabComponent } from './groups-view/general-tab/general-tab.compo import { NotesTabComponent } from './groups-view/notes-tab/notes-tab.component'; import { CommitteeTabComponent } from './groups-view/committee-tab/committee-tab.component'; import { CreateGroupComponent } from './create-group/create-group.component'; +import { DatatableTabsComponent } from './groups-view/datatable-tabs/datatable-tabs.component'; +import { SingleRowComponent } from './groups-view/datatable-tabs/single-row/single-row.component'; +import { MultiRowComponent } from './groups-view/datatable-tabs/multi-row/multi-row.component'; /** * Groups Module @@ -34,7 +37,10 @@ import { CreateGroupComponent } from './create-group/create-group.component'; GeneralTabComponent, NotesTabComponent, CommitteeTabComponent, - CreateGroupComponent + CreateGroupComponent, + DatatableTabsComponent, + SingleRowComponent, + MultiRowComponent ], providers: [DatePipe] }) diff --git a/src/app/groups/groups.service.ts b/src/app/groups/groups.service.ts index c7fc5db30..889de7a50 100644 --- a/src/app/groups/groups.service.ts +++ b/src/app/groups/groups.service.ts @@ -100,28 +100,80 @@ export class GroupsService { * @param groupId Group Id of group to edit note for. * @param noteId Note Id * @param noteData Note Data + * @returns {Observable} */ - editGroupNote(groupId: string, noteId: string, noteData: any) { + editGroupNote(groupId: string, noteId: string, noteData: any): Observable { return this.http.put(`/groups/${groupId}/notes/${noteId}`, noteData); } /** * @param groupId Group Id of group to delete note for. * @param noteId Note Id + * @returns {Observable} */ - deleteGroupNote(groupId: string, noteId: string) { + deleteGroupNote(groupId: string, noteId: string): Observable { return this.http.delete(`/groups/${groupId}/notes/${noteId}`); } + /** + * @returns {Observable} + */ + getGroupDatatables(): Observable { + const httpParams = new HttpParams().set('apptable', 'm_group'); + return this.http.get(`/datatables`, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get datatable for. + * @param datatableName Data table name. + * @returns {Observable} + */ + getGroupDatatable(groupId: string, datatableName: string): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.get(`/datatables/${datatableName}/${groupId}`, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get add datatable entry for. + * @param datatableName Data Table name. + * @param data Data. + * @returns {Observable} + */ + addGroupDatatableEntry(groupId: string, datatableName: string, data: any): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.post(`/datatables/${datatableName}/${groupId}`, data, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get add datatable entry for. + * @param datatableName Data Table name. + * @param data Data. + * @returns {Observable} + */ + editGroupDatatableEntry(groupId: string, datatableName: string, data: any): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.put(`/datatables/${datatableName}/${groupId}`, data, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get add datatable entry for. + * @param datatableName Data Table name. + * @returns {Observable} + */ + deleteDatatableContent(groupId: string, datatableName: string): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.delete(`/datatables/${datatableName}/${groupId}`, { params: httpParams }); + } + /** * @param {number} officeId Office Id of office to get staff for. * @returns {Observable} */ - getStaff(id: number) { - const httpParams = new HttpParams() - .set('officeId', id.toString()) - .set('staffInSelectedOfficeOnly', 'true'); - return this.http.get('/groups/template', { params: httpParams }); + getStaff(id: number): Observable { + const httpParams = new HttpParams() + .set('officeId', id.toString()) + .set('staffInSelectedOfficeOnly', 'true'); + return this.http.get('/groups/template', { params: httpParams }); } /** @@ -132,4 +184,5 @@ export class GroupsService { return this.http.post('/groups', group); } + }
Account No.