diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 2fe798bc4..cd3e0c9fd 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -36,6 +36,7 @@ import { ProductsModule } from './products/products.module';
import { OrganizationModule } from './organization/organization.module';
import { TemplatesModule } from './templates/templates.module';
import { UsersModule } from './users/users.module';
+import { ReportsModule } from './reports/reports.module';
@@ -61,6 +62,7 @@ import { AppRoutingModule } from './app-routing.module';
SettingsModule,
NavigationModule,
ClientsModule,
+ ReportsModule,
GroupsModule,
CentersModule,
AccountingModule,
diff --git a/src/app/core/shell/toolbar/toolbar.component.html b/src/app/core/shell/toolbar/toolbar.component.html
index 1366df12c..1075713ad 100644
--- a/src/app/core/shell/toolbar/toolbar.component.html
+++ b/src/app/core/shell/toolbar/toolbar.component.html
@@ -90,12 +90,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/app/reports/reports-routing.module.ts b/src/app/reports/reports-routing.module.ts
new file mode 100644
index 000000000..e88e69c72
--- /dev/null
+++ b/src/app/reports/reports-routing.module.ts
@@ -0,0 +1,53 @@
+/** Angular Imports */
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+/** Routing Imports */
+import { Route } from '../core/route/route.service';
+
+/** Translation Imports */
+import { extract } from '../core/i18n/i18n.service';
+
+/** Custom Components */
+import { ReportsComponent } from './reports.component';
+
+/** Custom Resolvers */
+import { ReportsResolver } from './reports.resolver';
+
+/** Reports Routes */
+const routes: Routes = [
+ Route.withShell([
+ {
+ path: 'reports',
+ data: { title: extract('Reports'), breadcrumb: 'Reports' },
+ resolve: {
+ reports: ReportsResolver
+ },
+ children: [
+ {
+ path: '',
+ component: ReportsComponent,
+ },
+ {
+ path: ':filter',
+ data: { routeParamBreadcrumb: 'filter' },
+ component: ReportsComponent,
+ }
+ ]
+ }
+ ])
+];
+
+/**
+ * Reports Routing Module
+ *
+ * Configures the reports routes.
+ */
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: [
+ ReportsResolver
+ ]
+})
+export class ReportsRoutingModule { }
diff --git a/src/app/reports/reports.component.html b/src/app/reports/reports.component.html
new file mode 100644
index 000000000..616b2e6ef
--- /dev/null
+++ b/src/app/reports/reports.component.html
@@ -0,0 +1,39 @@
+
+
+
+
+ Filter
+
+
+
+
+
+
+
+
+
+ | Name |
+ {{ report.reportName }} |
+
+
+
+ Type |
+ {{ report.reportType }} |
+
+
+
+ Category |
+ {{ report.reportCategory }} |
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/reports/reports.component.scss b/src/app/reports/reports.component.scss
new file mode 100644
index 000000000..24edb63bb
--- /dev/null
+++ b/src/app/reports/reports.component.scss
@@ -0,0 +1,7 @@
+table {
+ width: 100%;
+
+ .select-row:hover {
+ cursor: pointer;
+ }
+}
diff --git a/src/app/reports/reports.component.ts b/src/app/reports/reports.component.ts
new file mode 100644
index 000000000..dc5653f20
--- /dev/null
+++ b/src/app/reports/reports.component.ts
@@ -0,0 +1,108 @@
+/** Angular Imports */
+import { Component, OnInit, ViewChild } from '@angular/core';
+import {MatPaginator, MatSort, MatTableDataSource} from '@angular/material';
+import { ActivatedRoute, Router } from '@angular/router';
+
+/**
+ * Reports component.
+ */
+@Component({
+ selector: 'mifosx-reports',
+ templateUrl: './reports.component.html',
+ styleUrls: ['./reports.component.scss']
+})
+export class ReportsComponent implements OnInit {
+
+ /** Reports data. */
+ reportsData: any;
+ /** Report category filter. */
+ filter: string;
+ /** Columns to be displayed in reports table. */
+ displayedColumns: string[] = ['reportName', 'reportType', 'reportCategory'];
+ /** Data source for reports table. */
+ dataSource = new MatTableDataSource();
+
+ /** Paginator for reports table. */
+ @ViewChild(MatPaginator) paginator: MatPaginator;
+ /** Sorter for reports table. */
+ @ViewChild(MatSort) sort: MatSort;
+
+ /**
+ * Retrieves the reports data from `resolve`.
+ * @param {ActivatedRoute} route Activated Route.
+ * Prevents reuse of route parameter `filter`.
+ * @param {Router} router: Router.
+ */
+ constructor(private route: ActivatedRoute,
+ private router: Router) {
+ this.router.routeReuseStrategy.shouldReuseRoute = () => false;
+ this.route.data.subscribe(( data: { reports: any }) => {
+ this.reportsData = data.reports;
+ });
+ this.filter = this.route.snapshot.params['filter'];
+ }
+
+ /*
+ *Sets and filters the reports table by category.
+ */
+ ngOnInit() {
+ this.setReports();
+ this.filterReportsByCategory();
+ }
+
+ /**
+ * Switches filterPredicate if filterValue is not null.
+ * @param {string} filterValue filter string for mat-table.
+ */
+ applyFilter(filterValue: string) {
+ if (filterValue.length) {
+ this.setCustomFilterPredicate();
+ this.dataSource.filter = filterValue.trim().toLowerCase();
+ } else {
+ this.filterReportsByCategory();
+ }
+ }
+
+ /**
+ * Initializes the data source, paginator and sorter for reports table.
+ */
+ setReports() {
+ this.dataSource = new MatTableDataSource(this.reportsData);
+ this.dataSource.paginator = this.paginator;
+ this.dataSource.sort = this.sort;
+ }
+
+ /**
+ * Filters the data source only for report category passed in route params.
+ */
+ filterReportsByCategory() {
+ this.dataSource.filterPredicate = (data: any, filter: string) => {
+ return data.reportCategory === filter;
+ };
+ this.dataSource.filter = this.filter;
+ }
+
+ /**
+ * Filters Reports for filter value string and report category.
+ */
+ setCustomFilterPredicate() {
+ this.dataSource.filterPredicate = (data: any, filter: string) => {
+ /** Transform the data into a lowercase string of all property values. */
+ const dataStr = Object.keys(data).reduce(function (currentTerm: string, key: string) {
+ /** Use an obscure Unicode character to delimit the words in the concatenated string.
+ * This avoids matches where the values of two columns combined will match the user's query
+ */
+ return currentTerm + ((/** @type {any} */ (data)))[key] + '◬';
+ }, '').toLowerCase();
+ /** Transform the filter by converting it to lowercase and removing whitespace. */
+ const transformedFilter = filter.trim().toLowerCase();
+ /* Seperates filter for All reports page.*/
+ if (this.filter) {
+ return dataStr.indexOf(transformedFilter) !== -1 && data.reportCategory === this.filter;
+ } else {
+ return dataStr.indexOf(transformedFilter) !== -1;
+ }
+ };
+ }
+
+}
diff --git a/src/app/reports/reports.module.ts b/src/app/reports/reports.module.ts
new file mode 100644
index 000000000..d4a27bc81
--- /dev/null
+++ b/src/app/reports/reports.module.ts
@@ -0,0 +1,23 @@
+/** Angular Imports */
+import { NgModule } from '@angular/core';
+
+/** Custom Modules */
+import { SharedModule } from '../shared/shared.module';
+import { ReportsRoutingModule } from 'app/reports/reports-routing.module';
+
+/** Custom Components */
+import { ReportsComponent } from './reports.component';
+
+/**
+ * Reports Module
+ *
+ * Reports components should be declared here.
+ */
+@NgModule({
+ imports: [
+ SharedModule,
+ ReportsRoutingModule
+ ],
+ declarations: [ReportsComponent],
+})
+export class ReportsModule { }
diff --git a/src/app/reports/reports.resolver.ts b/src/app/reports/reports.resolver.ts
new file mode 100644
index 000000000..05cf70c27
--- /dev/null
+++ b/src/app/reports/reports.resolver.ts
@@ -0,0 +1,30 @@
+/** Angular Imports */
+import { Injectable } from '@angular/core';
+import { Resolve } from '@angular/router';
+
+/** rxjs Imports */
+import { Observable } from 'rxjs';
+
+/** Custom Services */
+import { ReportsService } from './reports.service';
+
+/**
+ * Reports data resolver.
+ */
+@Injectable()
+export class ReportsResolver implements Resolve