diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts
index 342428bc5..cb6a40976 100644
--- a/src/app/groups/groups-routing.module.ts
+++ b/src/app/groups/groups-routing.module.ts
@@ -1,3 +1,4 @@
+/** Angular Imports */
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
@@ -7,11 +8,12 @@ import { Route } from '../core/route/route.service';
/** Translation Imports */
import { extract } from '../core/i18n/i18n.service';
+/** Custom Imports */
import { GroupsComponent } from './groups.component';
+/** Groups Routes */
const routes: Routes = [
Route.withShell([
-
{
path: 'groups',
component: GroupsComponent,
@@ -20,6 +22,11 @@ const routes: Routes = [
])
];
+/**
+ * Groups Routing Module
+ *
+ * Configures the groups routes.
+ */
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
diff --git a/src/app/groups/groups.component.html b/src/app/groups/groups.component.html
index 38023c258..39f69fc76 100644
--- a/src/app/groups/groups.component.html
+++ b/src/app/groups/groups.component.html
@@ -1,51 +1,55 @@
-
+
+
+
+
+
+
+ Show Closed Groups
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- | Name |
- {{row?.name}} |
-
-
-
-
- Account # |
- {{row?.accountNo}} |
-
-
-
-
- ExternalID |
- {{row?.externalId}} |
-
-
-
-
- Status |
-
-
- |
-
-
-
-
-
- Office |
- {{row?.officeName}} |
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+ | Name |
+ {{ group.name }} |
+
+
+
+ Account # |
+ {{ group.accountNo }} |
+
+
+
+ ExternalID |
+ {{ group.externalId }} |
+
+
+
+ Status |
+
+
+
+
+ |
+
+
+
+ Office Name |
+ {{ group.officeName }} |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/groups/groups.component.scss b/src/app/groups/groups.component.scss
index 73124c9c0..b917b27e6 100644
--- a/src/app/groups/groups.component.scss
+++ b/src/app/groups/groups.component.scss
@@ -1,27 +1,10 @@
+.container {
+ .action-button{
+ margin-left: auto;
+ }
- table {
- width: 100%;
+ .search-button{
+ min-width: 30px;
+ margin: 4px;
}
-
- .mat-form-field {
- font-size: 14px;
- width: 100%;
- }
-
- td, th {
- width: 15%;
- }
-
- .filter{
- width: 50%;
- }
-
- .inactive {
- color: red;
- }
-
- .active {
- color: green;
- }
-
-
\ No newline at end of file
+}
diff --git a/src/app/groups/groups.component.ts b/src/app/groups/groups.component.ts
index 795acbff2..75869763b 100644
--- a/src/app/groups/groups.component.ts
+++ b/src/app/groups/groups.component.ts
@@ -1,44 +1,113 @@
-import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
-import {MatPaginator, MatSort, MatTableDataSource} from '@angular/material';
+/** Angular Imports */
+import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
+import { MatPaginator, MatSort, MatCheckbox } from '@angular/material';
+import { FormControl } from '@angular/forms';
+import { Router, ActivatedRoute } from '@angular/router';
+
+/** rxjs Imports */
+import { merge } from 'rxjs';
+import { tap, startWith, map, distinctUntilChanged, debounceTime} from 'rxjs/operators';
+
+/** Custom Services */
import { GroupsService } from './groups.service';
-import {DataSource} from '@angular/cdk/collections';
-import { Observable } from 'rxjs';
+
+/** Custom Data Source */
+import { GroupsDataSource } from './groups.datasource';
+
+/**
+ * Groups component.
+ */
@Component({
selector: 'mifosx-app-groups',
templateUrl: './groups.component.html',
styleUrls: ['./groups.component.scss']
})
-export class GroupsComponent implements OnInit {
+export class GroupsComponent implements OnInit, AfterViewInit {
+ @ViewChild('showClosedGroups') showClosedGroups: MatCheckbox;
- private ELEMENT_DATA: any = undefined;
- displayedColumns = ['name', 'accountno', 'externalid', 'status', 'office'];
- dataSource = new MatTableDataSource();
+ /** Name form control. */
+ name = new FormControl();
+ /** Columns to be displayed in groups table. */
+ displayedColumns = ['name', 'accountNo', 'externalId', 'status', 'officeName'];
+ /** Data source for groups table. */
+ dataSource: GroupsDataSource;
+ /** Groups filter. */
+ filterGroupsBy = [
+ {
+ type: 'name',
+ value: ''
+ }
+ ];
+ /** Paginator for groups table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
+ /** Sorter for groups table. */
@ViewChild(MatSort) sort: MatSort;
- constructor(private groupService: GroupsService) { }
+
+ constructor(private groupsService: GroupsService) { }
ngOnInit() {
- this.groupService.getGroups()
- .subscribe(
- (res => {
- console.log(res);
- // console.log(res.active);
- res.active = !!res.active;
- this.dataSource = new MatTableDataSource(res);
- this.dataSource.paginator = this.paginator;
- this.dataSource.sort = this.sort;
+ this.getGroups();
+ }
+
+ /**
+ * Subscribes to all search filters:
+ * Name
+ * sort change and page change.
+ */
+ ngAfterViewInit() {
+
+ this.name.valueChanges
+ .pipe(
+ debounceTime(500),
+ distinctUntilChanged(),
+ tap((filterValue) => {
+ this.applyFilter(filterValue, 'name');
})
- );
+ )
+ .subscribe();
+
+ this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
+
+ merge(this.sort.sortChange, this.paginator.page)
+ .pipe(
+ tap(() => this.loadGroupsPage())
+ )
+ .subscribe();
}
+ changeShowClosedGroups() {
+ this.loadGroupsPage();
+ }
- applyFilter(filterValue: string) {
- filterValue = filterValue.trim(); // Remove whitespace
- filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
- this.dataSource.filter = filterValue;
- if (this.dataSource.paginator) {
- this.dataSource.paginator.firstPage();
+ /**
+ * Loads a page of groups.
+ */
+ loadGroupsPage() {
+ if (!this.sort.direction) {
+ delete this.sort.active;
}
+ this.dataSource.getGroups(this.filterGroupsBy, this.sort.active, this.sort.direction, this.paginator.pageIndex, this.paginator.pageSize, !this.showClosedGroups.checked);
}
+
+ /**
+ * Filters data in groups table based on passed value and poperty.
+ * @param {string} filterValue Value to filter data.
+ * @param {string} property Property to filter data by.
+ */
+ applyFilter(filterValue: string, property: string) {
+ this.paginator.pageIndex = 0;
+ const findIndex = this.filterGroupsBy.findIndex(filter => filter.type === property);
+ this.filterGroupsBy[findIndex].value = filterValue;
+ this.loadGroupsPage();
+ }
+
+ /**
+ * Initializes the data source for groups table and loads the first page.
+ */
+ getGroups() {
+ this.dataSource = new GroupsDataSource(this.groupsService);
+ this.dataSource.getGroups(this.filterGroupsBy, this.sort.active, this.sort.direction, this.paginator.pageIndex, this.paginator.pageSize);
+ }
+
}
diff --git a/src/app/groups/groups.datasource.ts b/src/app/groups/groups.datasource.ts
new file mode 100644
index 000000000..16e06d455
--- /dev/null
+++ b/src/app/groups/groups.datasource.ts
@@ -0,0 +1,61 @@
+/** Angular Imports */
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+
+/** rxjs Imports */
+import { Observable, BehaviorSubject } from 'rxjs';
+
+/** Custom Services */
+import { GroupsService } from './groups.service';
+
+/**
+ * Groups custom data source to implement server side filtering, pagination and sorting.
+ */
+export class GroupsDataSource implements DataSource
{
+
+ /** groups behavior subject to represent loaded groups page. */
+ private groupsSubject = new BehaviorSubject([]);
+ /** Records subject to represent total number of filtered groups records. */
+ private recordsSubject = new BehaviorSubject(0);
+ /** Records observable which can be subscribed to get the value of total number of filtered groups records. */
+ public records$ = this.recordsSubject.asObservable();
+
+ /**
+ * @param {GroupsService} groupsService Groups Service
+ */
+ constructor(private groupsService: GroupsService) { }
+
+ /**
+ * Gets groups on the basis of provided parameters and emits the value.
+ * @param {any} filterBy Properties by which entries should be filtered.
+ * @param {string} orderBy Property by which entries should be sorted.
+ * @param {string} sortOrder Sort order: ascending or descending.
+ * @param {number} pageIndex Page number.
+ * @param {number} limit Number of entries within the page.
+ * @param {boolean} groupActive Specify whether to only filter active groups.
+ */
+ getGroups(filterBy: any, orderBy: string = '', sortOrder: string = '', pageIndex: number = 0, limit: number = 10, groupActive: boolean = true) {
+ this.groupsSubject.next([]);
+ this.groupsService.getGroups(filterBy, orderBy, sortOrder, pageIndex * limit, limit)
+ .subscribe((groups: any) => {
+ groups.pageItems = (groupActive) ? (groups.pageItems.filter((group: any) => group.active)) : groups.pageItems;
+ this.recordsSubject.next(groups.totalFilteredRecords);
+ this.groupsSubject.next(groups.pageItems);
+ });
+ }
+
+ /**
+ * @param {CollectionViewer} collectionViewer
+ */
+ connect(collectionViewer: CollectionViewer): Observable {
+ return this.groupsSubject.asObservable();
+ }
+
+ /**
+ * @param {CollectionViewer} collectionViewer
+ */
+ disconnect(collectionViewer: CollectionViewer): void {
+ this.groupsSubject.complete();
+ this.recordsSubject.complete();
+ }
+
+}
diff --git a/src/app/groups/groups.module.ts b/src/app/groups/groups.module.ts
index 6c2a9d0b3..c191dd9ce 100644
--- a/src/app/groups/groups.module.ts
+++ b/src/app/groups/groups.module.ts
@@ -1,23 +1,29 @@
-import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { CoreModule } from '../core/core.module';
-import { MatTableModule } from '@angular/material/table';
-import { FlexLayoutModule } from '@angular/flex-layout';
+/** Angular Imports */
+import { NgModule } from '@angular/core';
+import { DatePipe } from '@angular/common';
+/** Custom Modules */
+import { GroupsRoutingModule } from './groups-routing.module';
+import { SharedModule } from 'app/shared/shared.module';
+import { PipesModule } from '../pipes/pipes.module';
+
+/** Custom Components */
import { GroupsComponent } from './groups.component';
-import { GroupsRoutingModule } from 'app/groups/groups-routing.module';
-import { GroupsService } from './groups.service';
+
+/**
+ * Groups Module
+ *
+ * All components related to Groups should be declared here.
+ */
@NgModule({
imports: [
- CommonModule,
+ SharedModule,
GroupsRoutingModule,
- CoreModule,
- MatTableModule,
- FlexLayoutModule
+ PipesModule
],
- declarations: [GroupsComponent],
- schemas: [
- CUSTOM_ELEMENTS_SCHEMA
- ]
+ declarations: [
+ GroupsComponent
+ ],
+ providers: [DatePipe]
})
export class GroupsModule { }
diff --git a/src/app/groups/groups.service.ts b/src/app/groups/groups.service.ts
index 6d777eeae..d671d84bc 100644
--- a/src/app/groups/groups.service.ts
+++ b/src/app/groups/groups.service.ts
@@ -1,17 +1,45 @@
+/** Angular Imports */
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
+
+/** rxjs Imports */
import { Observable } from 'rxjs';
+/**
+ * Groups service.
+ */
@Injectable({
providedIn: 'root'
- })
-
-
+})
export class GroupsService {
- constructor(private http: HttpClient) { }
+ /**
+ * @param {HttpClient} http Http Client to send requests.
+ */
+ constructor(private http: HttpClient) { }
- getGroups(): Observable {
- return this.http.get('/groups');
- }
+ /**
+ * @param {any} filterBy Properties by which entries should be filtered.
+ * @param {string} orderBy Property by which entries should be sorted.
+ * @param {string} sortOrder Sort order: ascending or descending.
+ * @param {number} offset Page offset.
+ * @param {number} limit Number of entries within the page.
+ * @returns {Observable} Groups.
+ */
+ getGroups(filterBy: any, orderBy: string, sortOrder: string, offset: number, limit: number): Observable {
+ let httpParams = new HttpParams()
+ .set('offset', offset.toString())
+ .set('limit', limit.toString())
+ .set('sortOrder', sortOrder)
+ .set('orderBy', orderBy)
+ .set('paged', 'true');
+ // filterBy: name
+ filterBy.forEach(function (filter: any) {
+ if (filter.value) {
+ console.log(filter.value);
+ httpParams = httpParams.set(filter.type, filter.value);
+ }
+ });
+ return this.http.get('/groups', { params: httpParams });
+ }
}