feat: add navigation component (#590)

Fixes: #256
This commit is contained in:
punwai
2020-05-24 22:28:47 +05:30
committed by GitHub
parent 7a5069e590
commit e2707a1d0a
43 changed files with 1713 additions and 9 deletions
@@ -0,0 +1,121 @@
<mat-card-header fxLayout="row" fxLayoutGap="5%" class="header">
<fa-icon class="main-icon" icon="building" size="3x"></fa-icon>
<mat-card-title-group>
<div class="mat-typography">
<mat-card-title>
<h2>
{{ centerData.name }}
<span [className]="centerData.status.code | statusLookup">
<fa-icon matTooltip="{{ centerData.status.value }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
</span>
</h2>
</mat-card-title>
<mat-card-subtitle>
<p>
Account No: {{ centerData.accountNo }} | {{ centerData.externalId ? '| External ID: ' + centerData.externalId : '' }}
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab label="Details">
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong">
Activation Date
</div>
<div fxFlex="50%">
{{ centerData.activationDate | date }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Associated Officer
</div>
<div fxFlex="50%">
{{ centerData.staffName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerSummaryData">
Number of Active Clients
</div>
<div fxFlex="50%" *ngIf="centerSummaryData">
{{ centerSummaryData.activeClients }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerSummaryData">
Number of Active Client Loans
</div>
<div fxFlex="50%" *ngIf="centerSummaryData">
{{ centerSummaryData.activeClientLoans }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerSummaryData">
Number of Active Client Borrowers
</div>
<div fxFlex="50%" *ngIf="centerSummaryData">
{{ centerSummaryData.activeClientBorrowers }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerSummaryData">
Number of Active Overdue Group Loans
</div>
<div fxFlex="50%" *ngIf="centerSummaryData">
{{ centerSummaryData.overdueGroupLoans }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerSummaryData">
Number of Active Overdue Client Loans
</div>
<div fxFlex="50%" *ngIf="centerSummaryData">
{{ centerSummaryData.overdueClientLoans }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerData.collectionMeetingCalendar && centerData.collectionMeetingCalendar.nextTenRecurringDates[0]">
Next Meeting Date
</div>
<div fxFlex="50%" *ngIf="centerData.collectionMeetingCalendar && centerData.collectionMeetingCalendar.nextTenRecurringDates[0]">
{{ centerSummaryData.collectionMeetingCalendar.nextTenRecurringDates[0] | date }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="centerData.collectionMeetingCalendar && centerData.collectionMeetingCalendar.humanReadable">
Meeting Frequency
</div>
<div fxFlex="50%" *ngIf="centerData.collectionMeetingCalendar && centerData.collectionMeetingCalendar.humanReadable">
{{ centerSummaryData.collectionMeetingCalendar.humanReadable }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Number of Groups
</div>
<div fxFlex="50%">
{{ groupData ? groupData.length : '' }}
</div>
</div>
</mat-tab>
<mat-tab label="Loan Accounts" *ngIf="centerAccountsData && centerAccountsData.loanAccounts">
<mifosx-loan-account-table [loanAccountData]="centerAccountsData.loanAccounts"></mifosx-loan-account-table>
</mat-tab>
<mat-tab label="Savings Accounts" *ngIf="centerAccountsData && centerAccountsData.savingsAccounts">
<mifosx-savings-account-table [savingsAccountData]="centerAccountsData.savingsAccounts"></mifosx-savings-account-table>
</mat-tab>
</mat-tab-group>
</mat-card-content>
@@ -0,0 +1,14 @@
.main-icon {
margin: 7px 0 0 0;
}
h2 {
font-weight: 500;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CenterNavigationComponent } from './center-navigation.component';
describe('CenterNavigationComponent', () => {
let component: CenterNavigationComponent;
let fixture: ComponentFixture<CenterNavigationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CenterNavigationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CenterNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,29 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
/** Custom Components */
import { LoanAccountTableComponent } from '../loan-account-table/loan-account-table.component';
import { SavingsAccountTableComponent } from '../savings-account-table/savings-account-table.component';
@Component({
selector: 'mifosx-center-navigation',
templateUrl: './center-navigation.component.html',
styleUrls: ['./center-navigation.component.scss']
})
export class CenterNavigationComponent implements OnInit {
@ViewChild(LoanAccountTableComponent) loanAccountTableComponent: LoanAccountTableComponent;
@ViewChild(SavingsAccountTableComponent) savingsAccountTableComponent: SavingsAccountTableComponent;
@Input() centerData: any;
@Input() centerAccountsData: any;
@Input() centerSummaryData: any;
@Input() groupData: any;
constructor() { }
ngOnInit() {
}
}
@@ -0,0 +1,115 @@
<mat-card-header fxLayout="row" fxLayoutGap="5%">
<fa-icon class="main-icon" icon="user" size="3x"></fa-icon>
<mat-card-title-group>
<div class="mat-typography">
<mat-card-title>
<h2>
{{ clientData.displayName }}
<span [className]="clientData.status.code | statusLookup">
<fa-icon matTooltip="{{ clientData.status.value }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
</span>
</h2>
</mat-card-title>
<mat-card-subtitle>
<p>
Account No: {{ clientData.accountNo }} {{ clientData.externalId ? '| External ID: ' + clientData.externalId : '' }}
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab label="Details">
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.firstName">
First Name
</div>
<div fxFlex="50%" *ngIf="clientData.firstName">
{{ clientData.firstName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.middleName">
Middle Name
</div>
<div fxFlex="50%" *ngIf="clientData.middleName">
{{ clientData.middleName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.lastName">
Last Name
</div>
<div fxFlex="50%" *ngIf="clientData.lastName">
{{ clientData.lastName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.dateOfBirth">
Date of Birth
</div>
<div fxFlex="50%" *ngIf="clientData.dateOfBirth">
{{ clientData.dateOfBirth | date }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.mobileNo">
Mobile Number
</div>
<div fxFlex="50%" *ngIf="clientData.mobileNo">
{{ clientData.mobileNo }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Activation Date
</div>
<div fxFlex="50%">
{{ clientData.activationDate | date }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.officeName">
Associated Office
</div>
<div fxFlex="50%" *ngIf="clientData.officeName">
{{ clientData.officeName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="clientData.staffName">
Associated Staff
</div>
<div fxFlex="50%" *ngIf="clientData.staffName">
{{ clientData.staffName }}
</div>
</div>
</mat-tab>
<mat-tab label="Loan Accounts" *ngIf="clientAccountsData && clientAccountsData.loanAccounts">
<mifosx-loan-account-table [loanAccountData]="clientAccountsData.loanAccounts"></mifosx-loan-account-table>
</mat-tab>
<mat-tab label="Savings Accounts" *ngIf="clientAccountsData && clientAccountsData.savingsAccounts">
<mifosx-savings-account-table [savingsAccountData]="clientAccountsData.savingsAccounts"></mifosx-savings-account-table>
</mat-tab>
<mat-tab label="Share Accounts" *ngIf="clientAccountsData && clientAccountsData.shareAccounts">
<mifosx-share-account-table [shareAccountData]="clientAccountsData.shareAccounts"></mifosx-share-account-table>
</mat-tab>
<mat-tab label="Group Members" *ngIf="clientData.groups && clientData.groups.length !== 0">
<mifosx-member-groups [memberGroupData]="clientData.groups"></mifosx-member-groups>
</mat-tab>
</mat-tab-group>
</mat-card-content>
@@ -0,0 +1,14 @@
.main-icon {
margin: 7px 0 0 0;
}
h2 {
font-weight: 500;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ClientNavigationComponent } from './client-navigation.component';
describe('ClientNavigationComponent', () => {
let component: ClientNavigationComponent;
let fixture: ComponentFixture<ClientNavigationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ClientNavigationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ClientNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,30 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
/** Custom Components */
import { LoanAccountTableComponent } from '../loan-account-table/loan-account-table.component';
import { SavingsAccountTableComponent } from '../savings-account-table/savings-account-table.component';
import { ShareAccountTableComponent } from '../share-account-table/share-account-table.component';
import { MemberGroupsComponent } from '../member-groups/member-groups.component';
@Component({
selector: 'mifosx-client-navigation',
templateUrl: './client-navigation.component.html',
styleUrls: ['./client-navigation.component.scss']
})
export class ClientNavigationComponent implements OnInit {
@ViewChild(LoanAccountTableComponent) loanAccountTableComponent: LoanAccountTableComponent;
@ViewChild(SavingsAccountTableComponent) savingsAccountTableComponent: SavingsAccountTableComponent;
@ViewChild(ShareAccountTableComponent) shareAccountTableComponent: ShareAccountTableComponent;
@ViewChild(MemberGroupsComponent) memberGroupsComponent: MemberGroupsComponent;
@Input() clientData: any;
@Input() clientAccountsData: any;
constructor() { }
ngOnInit() {
}
}
@@ -0,0 +1,87 @@
<mat-card-header fxLayout="row" fxLayoutGap="5%">
<fa-icon class="main-icon" icon="users" size="3x"></fa-icon>
<mat-card-title-group>
<div class="mat-typography">
<mat-card-title>
<h2>
{{ groupData.name }}
<span [className]="groupData.status.code | statusLookup">
<fa-icon matTooltip="{{ groupData.status.value }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
</span>
</h2>
</mat-card-title>
<mat-card-subtitle>
<p>
Account No: {{ groupData.accountNo }} {{ groupData.externalId ? '| External ID: ' + groupData.externalId : '' }}
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab label="Details">
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong">
Activation Date
</div>
<div fxFlex="50%">
{{ groupData.activationDate | date }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Associated Officer
</div>
<div fxFlex="50%">
{{ groupData.staffName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="groupData.centerName">
Associated Center
</div>
<div fxFlex="50%" *ngIf="groupData.centerName">
{{ groupData.centerName }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="groupData.collectionMeetingCalendar && groupData.collectionMeetingCalendar.nextTenRecurringDates[0]">
Next Meeting Date
</div>
<div fxFlex="50%" *ngIf="groupData.collectionMeetingCalendar && groupData.collectionMeetingCalendar.nextTenRecurringDates[0]">
{{ groupData.collectionMeetingCalendar.nextTenRecurringDates[0] | date }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="groupData.collectionMeetingCalendar && groupData.collectionMeetingCalendar.humanReadable">
Meeting Frequency
</div>
<div fxFlex="50%" *ngIf="groupData.collectionMeetingCalendar && groupData.collectionMeetingCalendar.humanReadable">
{{ groupData.collectionMeetingCalendar.humanReadable }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Number of Clients
</div>
<div fxFlex="50%">
{{ clientData ? clientData.length : '' }}
</div>
</div>
</mat-tab>
<mat-tab label="Loan Accounts" *ngIf="groupAccountsData && groupAccountsData.loanAccounts">
<mifosx-loan-account-table [loanAccountData]="groupAccountsData.loanAccounts"></mifosx-loan-account-table>
</mat-tab>
<mat-tab label="Savings Accounts" *ngIf="groupAccountsData && groupAccountsData.savingsAccounts">
<mifosx-savings-account-table [savingsAccountData]="groupAccountsData.savingsAccounts"></mifosx-savings-account-table>
</mat-tab>
</mat-tab-group>
</mat-card-content>
@@ -0,0 +1,14 @@
.main-icon {
margin: 7px 0 0 0;
}
h2 {
font-weight: 500;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GroupNavigationComponent } from './group-navigation.component';
describe('GroupNavigationComponent', () => {
let component: GroupNavigationComponent;
let fixture: ComponentFixture<GroupNavigationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupNavigationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GroupNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,28 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
/** Custom Components */
import { LoanAccountTableComponent } from '../loan-account-table/loan-account-table.component';
import { SavingsAccountTableComponent } from '../savings-account-table/savings-account-table.component';
@Component({
selector: 'mifosx-group-navigation',
templateUrl: './group-navigation.component.html',
styleUrls: ['./group-navigation.component.scss']
})
export class GroupNavigationComponent implements OnInit {
@ViewChild(LoanAccountTableComponent) loanAccountTableComponent: LoanAccountTableComponent;
@ViewChild(SavingsAccountTableComponent) savingsAccountTableComponent: SavingsAccountTableComponent;
@Input() groupData: any;
@Input() groupAccountsData: any;
@Input() clientData: any;
constructor() { }
ngOnInit() {
}
}
@@ -0,0 +1,44 @@
<div fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxFlex="50%">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
<button mat-raised-button color="primary" (click)="toggleClosed()">
{{ showClosed ? 'View Active' : 'View Closed' }}
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="accountNo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Account Number </th>
<td mat-cell *matCellDef="let loanAccount">{{ loanAccount.accountNo }}</td>
</ng-container>
<ng-container matColumnDef="productName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Loan Account </th>
<td mat-cell *matCellDef="let loanAccount">{{ loanAccount.productName }}</td>
</ng-container>
<ng-container matColumnDef="Type">
<th mat-header-cell *matHeaderCellDef> Type </th>
<td mat-cell *matCellDef="let loanAccount">
<fa-icon matTooltip="{{ loanAccount.loanType.value }}" matTooltipPosition="right" [icon]="(loanAccount.loanType.code === 'accountType.individual') ? 'user' : 'users'" size="lg"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="Status">
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let loanAccount">
<span [className]="loanAccount.inArrears?'status-active-overdue' : (loanAccount.status.code | statusLookup)">
<fa-icon matTooltip="{{ loanAccount.status.value }}" matTooltipPosition="right" icon="circle" size="md"></fa-icon>
</span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25]" showFirstLastButtons></mat-paginator>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoanAccountTableComponent } from './loan-account-table.component';
describe('LoanAccountTableComponent', () => {
let component: LoanAccountTableComponent;
let fixture: ComponentFixture<LoanAccountTableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoanAccountTableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoanAccountTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,65 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/** Custom Pipes */
import { AccountsFilterPipe } from '../../pipes/accounts-filter.pipe';
@Component({
selector: 'mifosx-loan-account-table',
templateUrl: './loan-account-table.component.html',
styleUrls: ['./loan-account-table.component.scss']
})
export class LoanAccountTableComponent implements OnInit {
/** Columns to be displayed in the loan accounts table. */
displayedColumns: string[] = ['accountNo', 'productName', 'Type', 'Status'];
/** Show closed loan accounts */
showClosed = false;
/** Data source for loan account table. */
dataSource: MatTableDataSource<any>;
/** Loan Account Data */
accountData: any;
/** Paginator for loan accounts table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for loan accounts table. */
@ViewChild(MatSort) sort: MatSort;
/** Loan Account Setter */
@Input() set loanAccountData(data: any) {
this.accountData = data;
const filteredAccountData = this.accountsFilterPipe.transform(data, 'loan', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* @param {AccountsFilterPipe} accountsFilterPipe Accounts Filter Pipe.
*/
constructor(private accountsFilterPipe: AccountsFilterPipe) { }
/**
* Filters data in users table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit() {
}
/**
* Toggles the loan status
*/
toggleClosed() {
this.showClosed = !this.showClosed;
const filteredAccountData = this.accountsFilterPipe.transform(this.accountData, 'loan', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
@@ -0,0 +1,25 @@
<div fxLayout="row">
<mat-form-field fxFlex="50%">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="accountNo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Account Number </th>
<td mat-cell *matCellDef="let memberGroup"> {{ memberGroup.accountNo }} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Group Name </th>
<td mat-cell *matCellDef="let memberGroup"> {{ memberGroup.name }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25]" showFirstLastButtons></mat-paginator>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MemberGroupsComponent } from './member-groups.component';
describe('MemberGroupsComponent', () => {
let component: MemberGroupsComponent;
let fixture: ComponentFixture<MemberGroupsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MemberGroupsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MemberGroupsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,41 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
@Component({
selector: 'mifosx-member-groups',
templateUrl: './member-groups.component.html',
styleUrls: ['./member-groups.component.scss']
})
export class MemberGroupsComponent implements OnInit {
/** Columns to be displayed in the member groups table. */
displayedColumns: string[] = ['accountNo', 'name'];
/** Data source for member groups table. */
dataSource: MatTableDataSource<any>;
/** Paginator for member groups table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for member groups table. */
@ViewChild(MatSort) sort: MatSort;
/** Member Group Data Setter */
@Input() set memberGroupData(data: any) {
this.dataSource = new MatTableDataSource(data);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
constructor() { }
/**
* Filters data in member groups table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit() { }
}
@@ -11,13 +11,19 @@ import { extract } from '../core/i18n/i18n.service';
/** Custom Components */
import { NavigationComponent } from './navigation.component';
/** Custom Resolvers */
import { OfficesResolver } from './offices.resolver';
/** Navigation Routes */
const routes: Routes = [
Route.withShell([
{
path: 'navigation',
component: NavigationComponent,
data: { title: extract('Navigation'), breadcrumb: 'Navigation' }
data: { title: extract('Navigation'), breadcrumb: 'Navigation' },
resolve: {
offices: OfficesResolver
}
}
])
];
@@ -30,6 +36,8 @@ const routes: Routes = [
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: []
providers: [
OfficesResolver
]
})
export class NavigationRoutingModule { }
+88 -3
View File
@@ -1,7 +1,92 @@
<div class="container">
<p>
TODO: navigation component.
</p>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="2%">
<div fxFlex="48%">
<mat-card fxLayout="column">
<mat-card-content fxLayout="column">
<mat-form-field *ngIf="!(officeData === undefined || officeData === null)">
<mat-label>Office</mat-label>
<mat-select [formControl]="officeSelector">
<mat-option *ngFor="let office of officeData" [value]="office.id">
{{ office.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="!(employeeData === undefined || employeeData === null)">
<mat-label>{{ employeeData.length ? 'Officer' : 'No Associated Officers' }}</mat-label>
<mat-select [formControl]="employeeSelector">
<mat-option *ngFor="let employee of employeeData" [value]="employee.id">
{{ employee.displayName }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="!(centerData === undefined || centerData === null)">
<mat-label>{{ centerData.length ? 'Center' : 'No Associated Centers' }}</mat-label>
<mat-select [formControl]="centerSelector">
<mat-option *ngFor="let center of centerData" [value]="center.id">
{{ center.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="!(groupData === undefined || groupData === null)">
<mat-label>{{ groupData.length ? 'Group' : 'No Associated Groups' }}</mat-label>
<mat-select [formControl]="groupSelector">
<mat-option *ngFor="let group of groupData" [value]="group.id">
{{ group.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="!(clientData === undefined || clientData === null)">
<mat-label>{{ clientData.length ? 'Client' : 'No Associated Clients' }}</mat-label>
<mat-select [formControl]="clientSelector">
<mat-option *ngFor="let client of clientData" [value]="client.id">
{{ client.displayName }}
</mat-option>
</mat-select>
</mat-form-field>
</mat-card-content>
</mat-card>
</div>
<div fxFlex="48%">
<mat-card fxLayout="column" *ngIf="selectedItem">
<ng-container *ngIf="selectedItem.itemType === 'office'">
<mifosx-office-navigation [officeData]="selectedItem" [employeeData]="employeeData"></mifosx-office-navigation>
</ng-container>
<ng-container *ngIf="selectedItem.itemType === 'employee'">
<mifosx-staff-navigation [employeeData]="selectedItem" [centerData]="centerData"></mifosx-staff-navigation>
</ng-container>
<ng-container *ngIf="selectedItem.itemType === 'center'">
<mifosx-center-navigation [centerData]="selectedItem" [groupData]="groupData" [centerAccountsData]='selectedItemAccounts' [centerSummaryData]='selectedItemSummary'></mifosx-center-navigation>
</ng-container>
<ng-container *ngIf="selectedItem.itemType === 'group'">
<mifosx-group-navigation [groupData]="selectedItem" [clientData]="clientData" [groupAccountsData]='selectedItemAccounts'></mifosx-group-navigation>
</ng-container>
<ng-container *ngIf="selectedItem.itemType === 'client'">
<mifosx-client-navigation [clientData]="selectedItem" [clientAccountsData]='selectedItemAccounts'></mifosx-client-navigation>
</ng-container>
</mat-card>
</div>
</div>
</div>
+200 -3
View File
@@ -1,8 +1,20 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormControl } from '@angular/forms';
/** Custom Services */
import { NavigationService } from './navigation.service';
/** Custom Components */
import { OfficeNavigationComponent } from './office-navigation/office-navigation.component';
import { StaffNavigationComponent } from './staff-navigation/staff-navigation.component';
import { CenterNavigationComponent } from './center-navigation/center-navigation.component';
import { GroupNavigationComponent } from './group-navigation/group-navigation.component';
import { ClientNavigationComponent } from './client-navigation/client-navigation.component';
/**
* Navigation component. (by office)
* Navigation component.
*/
@Component({
selector: 'mifosx-navigation',
@@ -11,9 +23,194 @@ import { Component, OnInit } from '@angular/core';
})
export class NavigationComponent implements OnInit {
constructor() { }
/** Navigation Components */
@ViewChild(OfficeNavigationComponent) officeNavigationComponent: OfficeNavigationComponent;
@ViewChild(StaffNavigationComponent) staffNavigationComponent: StaffNavigationComponent;
@ViewChild(CenterNavigationComponent) centerNavigationComponent: CenterNavigationComponent;
@ViewChild(GroupNavigationComponent) groupNavigationComponent: GroupNavigationComponent;
@ViewChild(ClientNavigationComponent) clientNavigationComponent: ClientNavigationComponent;
/** Office data */
officeData: any;
/** Employee data */
employeeData: any;
/** Center data */
centerData: any;
/** Group data */
groupData: any;
/** Client data */
clientData: any;
/** Office selector */
officeSelector = new FormControl();
/** Employee selector */
employeeSelector = new FormControl();
/** Center selector */
centerSelector = new FormControl();
/** Group selector */
groupSelector = new FormControl();
/** Client selector */
clientSelector = new FormControl();
/** Selected Item */
selectedItem: any;
/** Selected Item Accounts */
selectedItemAccounts: any;
/** Selected Item Summary */
selectedItemSummary: any;
/**
* Retrieves the offices data from `resolve`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {NavigationService} navigationService Navigation Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
*/
constructor(private navigationService: NavigationService,
private route: ActivatedRoute,
private router: Router) {
this.route.data.subscribe((data: { offices: any }) => {
this.officeData = data.offices;
});
}
/**
* Sets all selectors
*/
ngOnInit() {
this.setOfficeSelector();
this.setEmployeeSelector();
this.setCenterSelector();
this.setGroupSelector();
this.setClientSelector();
}
/**
* Sets the office selector
*/
setOfficeSelector() {
this.officeSelector.valueChanges.subscribe(officeId => {
this.employeeSelector.reset(null, { emitEvent: false });
this.centerSelector.reset(null, { emitEvent: false });
this.groupSelector.reset(null, { emitEvent: false });
this.clientSelector.reset(null, { emitEvent: false });
this.employeeData = null;
this.centerData = null;
this.groupData = null;
this.clientData = null;
this.selectedItem = this.officeData.find((office: any) => office.id === officeId);
this.selectedItem.itemType = 'office';
this.navigationService.getEmployees(officeId).subscribe((employees: any) => {
this.employeeData = employees;
if (this.employeeData.length) {
this.employeeSelector.enable();
} else {
this.employeeSelector.disable();
}
});
});
}
/**
* Sets the employee selector
*/
setEmployeeSelector() {
this.employeeSelector.valueChanges.subscribe(employeeId => {
if (employeeId) {
this.centerSelector.reset(null, { emitEvent: false });
this.groupSelector.reset(null, { emitEvent: false });
this.clientSelector.reset(null, { emitEvent: false });
this.centerData = null;
this.groupData = null;
this.clientData = null;
this.selectedItem = this.employeeData.find((employee: any) => employee.id === employeeId);
this.selectedItem.itemType = 'employee';
this.navigationService.getCentersFromStaffId(employeeId).subscribe((centers: any) => {
this.centerData = centers;
if (this.centerData.length) {
this.centerSelector.enable();
} else {
this.centerSelector.disable();
}
});
}
});
}
/**
* Sets the center selector
*/
setCenterSelector() {
this.centerSelector.valueChanges.subscribe(centerId => {
if (centerId) {
this.groupSelector.reset(null, { emitEvent: false });
this.clientSelector.reset(null, { emitEvent: false });
this.groupData = null;
this.clientData = null;
this.navigationService.getCenter(centerId).subscribe((center: any) => {
this.selectedItem = center;
this.selectedItem.itemType = 'center';
this.groupData = center.groupMembers ? center.groupMembers : [];
if (this.groupData.length) {
this.groupSelector.enable();
} else {
this.groupSelector.disable();
}
});
this.selectedItemAccounts = null;
this.navigationService.getCenterAccounts(centerId).subscribe((centerAccounts: any) => {
this.selectedItemAccounts = centerAccounts;
});
this.selectedItemSummary = null;
this.navigationService.getCenterSummary(centerId).subscribe((centerSummary: any) => {
this.selectedItemSummary = centerSummary[0];
});
}
});
}
/**
* Sets the group selector
*/
setGroupSelector() {
this.groupSelector.valueChanges.subscribe(groupId => {
if (groupId) {
this.clientSelector.reset(null, { emitEvent: false });
this.clientData = null;
this.navigationService.getGroup(groupId).subscribe((group: any) => {
this.selectedItem = group;
this.selectedItem.itemType = 'group';
this.clientData = group.clientMembers ? group.clientMembers : [];
if (this.clientData.length) {
this.clientSelector.enable();
} else {
this.clientSelector.disable();
}
});
this.selectedItemAccounts = null;
this.navigationService.getGroupAccounts(groupId).subscribe((groupAccounts: any) => {
this.selectedItemAccounts = groupAccounts;
});
}
});
}
/**
* Sets the client selector
*/
setClientSelector() {
this.clientSelector.valueChanges.subscribe(clientId => {
if (clientId) {
this.selectedItemAccounts = null;
this.navigationService.getClient(clientId).subscribe((client: any) => {
this.selectedItem = client;
this.selectedItem.itemType = 'client';
});
this.navigationService.getClientAccounts(clientId).subscribe((clientAccounts: any) => {
this.selectedItemAccounts = clientAccounts;
});
}
});
}
}
+21 -1
View File
@@ -3,10 +3,20 @@ import { NgModule } from '@angular/core';
/** Custom Modules */
import { SharedModule } from '../shared/shared.module';
import { PipesModule } from '../pipes/pipes.module';
import { NavigationRoutingModule } from './navigation-routing.module';
/** Custom Components */
import { NavigationComponent } from './navigation.component';
import { OfficeNavigationComponent } from './office-navigation/office-navigation.component';
import { StaffNavigationComponent } from './staff-navigation/staff-navigation.component';
import { CenterNavigationComponent } from './center-navigation/center-navigation.component';
import { GroupNavigationComponent } from './group-navigation/group-navigation.component';
import { ClientNavigationComponent } from './client-navigation/client-navigation.component';
import { LoanAccountTableComponent } from './loan-account-table/loan-account-table.component';
import { ShareAccountTableComponent } from './share-account-table/share-account-table.component';
import { SavingsAccountTableComponent } from './savings-account-table/savings-account-table.component';
import { MemberGroupsComponent } from './member-groups/member-groups.component';
/**
* Navigation Module
@@ -16,10 +26,20 @@ import { NavigationComponent } from './navigation.component';
@NgModule({
imports: [
SharedModule,
PipesModule,
NavigationRoutingModule
],
declarations: [
NavigationComponent
NavigationComponent,
OfficeNavigationComponent,
StaffNavigationComponent,
CenterNavigationComponent,
GroupNavigationComponent,
ClientNavigationComponent,
LoanAccountTableComponent,
ShareAccountTableComponent,
SavingsAccountTableComponent,
MemberGroupsComponent
]
})
export class NavigationModule { }
+112
View File
@@ -0,0 +1,112 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
/** rxjs Imports */
import { Observable } from 'rxjs';
/**
* Navigation service.
*/
@Injectable({
providedIn: 'root'
})
export class NavigationService {
/**
* @param {HttpClient} http Http Client to send requests.
*/
constructor(private http: HttpClient) { }
/**
* @returns {Observable<any>} Offices.
*/
getOffices(): Observable<any> {
return this.http.get('/offices');
}
/**
* @param {number} officeId Office Id to get employees from.
* @returns {Observable<any>} Employees
*/
getEmployees(officeId: number): Observable<any> {
const httpParams = new HttpParams()
.set('officeId', officeId.toString());
return this.http.get('/staff', { params: httpParams });
}
/**
* @param {number} staffId Staff Id to get centers from.
* @returns {Observable<any>} Centers
*/
getCentersFromStaffId(staffId: number): Observable<any> {
const httpParams = new HttpParams()
.set('R_staffId', staffId.toString())
.set('genericResultSet', false.toString());
return this.http.get('/runreports/GroupNamesByStaff', { params: httpParams });
}
/**
* @param {number} centerId Center ID of center
* @returns {Observable<any>} Center
*/
getCenter(centerId: number): Observable<any> {
const httpParams = new HttpParams()
.set('associations', 'groupMembers');
return this.http.get(`/centers/${centerId}`, { params: httpParams });
}
/**
* @param {number} centerId Center ID of center to retrieve accounts of
* @returns {Observable<any>} Center Accounts
*/
getCenterAccounts(centerId: number): Observable<any> {
return this.http.get(`/centers/${centerId}/accounts`);
}
/**
* @param {number} centerId Center ID of center to retrieve summary of
* @returns {Observable<any>} Center Accounts
*/
getCenterSummary(centerId: number): Observable<any> {
const httpParams = new HttpParams()
.set('R_groupId', centerId.toString())
.set('genericResultSet', false.toString());
return this.http.get('/runreports/GroupSummaryCounts', { params: httpParams });
}
/**
* @param {number} groupId Group ID of group
* @returns {Observable<any>} Group
*/
getGroup(groupId: number): Observable<any> {
const httpParams = new HttpParams()
.set('associations', 'all');
return this.http.get(`/groups/${groupId}`, { params: httpParams });
}
/**
* @param {number} groupId Group ID of group to retrieve accounts of
* @returns {Observable<any>} Group Accounts
*/
getGroupAccounts(groupId: number): Observable<any> {
return this.http.get(`/groups/${groupId}/accounts`);
}
/**
* @param {number} clientId Client ID of client
* @returns {Observable<any>} Client
*/
getClient(clientId: number): Observable<any> {
return this.http.get(`/clients/${clientId}`);
}
/**
* @param {number} clientId Client ID of client to retrieve accounts of
* @returns {Observable<any>} Client Accounts
*/
getClientAccounts(clientId: number): Observable<any> {
return this.http.get(`/clients/${clientId}/accounts`);
}
}
@@ -0,0 +1,47 @@
<mat-card-header fxLayout="row" fxLayoutGap="5%" class="header">
<fa-icon class="main-icon" icon="building" size="3x"></fa-icon>
<mat-card-title-group>
<div class="mat-typography">
<mat-card-title>
<h2>
{{ officeData.name }}
</h2>
</mat-card-title>
<mat-card-subtitle>
<p>
{{ officeData.externalId ? 'External ID: ' + officeData.externalId : '' }}
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
</mat-card-header>
<mat-card-content>
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong">
Opened On
</div>
<div fxFlex="50%">
{{ officeData.openingDate | date }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="officeData.parentName">
Parent officeData
</div>
<div fxFlex="50%" *ngIf="officeData.parentName">
{{ officeData.parentName }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Number of Staff
</div>
<div fxFlex="50%">
{{ employeeData ? employeeData.length : '' }}
</div>
</div>
</mat-card-content>
@@ -0,0 +1,14 @@
h2 {
font-weight: 500;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
.main-icon {
margin: 7px 0 0 0;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OfficeNavigationComponent } from './office-navigation.component';
describe('OfficeNavigationComponent', () => {
let component: OfficeNavigationComponent;
let fixture: ComponentFixture<OfficeNavigationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OfficeNavigationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OfficeNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,20 @@
/** Angular Imports */
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'mifosx-office-navigation',
templateUrl: './office-navigation.component.html',
styleUrls: ['./office-navigation.component.scss']
})
export class OfficeNavigationComponent implements OnInit {
@Input() officeData: any;
@Input() employeeData: any;
constructor() { }
ngOnInit() {
}
}
+30
View File
@@ -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 { NavigationService } from './navigation.service';
/**
* Offices data resolver.
*/
@Injectable()
export class OfficesResolver implements Resolve<Object> {
/**
* @param {NavigationService} navigationService Navigation service.
*/
constructor(private navigationService: NavigationService) {}
/**
* Returns the Offices data.
* @returns {Observable<any>}
*/
resolve(): Observable<any> {
return this.navigationService.getOffices();
}
}
@@ -0,0 +1,42 @@
<div fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxFlex="50%">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
<button mat-raised-button color="primary" (click)="toggleClosed()">
{{ showClosed ? 'View Active' : 'View Closed' }}
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="accountNo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Account Number </th>
<td mat-cell *matCellDef="let savingsAccount">{{ savingsAccount.accountNo }}</td>
</ng-container>
<ng-container matColumnDef="productName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Savings Account </th>
<td mat-cell *matCellDef="let savingsAccount">{{ savingsAccount.productName }}</td>
</ng-container>
<ng-container matColumnDef="accountBalance">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Balance </th>
<td mat-cell *matCellDef="let savingsAccount">{{ savingsAccount.accountBalance }}</td>
</ng-container>
<ng-container matColumnDef="Status">
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let savingsAccount">
<span [className]="savingsAccount.status.code | statusLookup">
<fa-icon matTooltip="{{ savingsAccount.status.value }}" matTooltipPosition="right" icon="circle" size="md"></fa-icon>
</span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25]" showFirstLastButtons></mat-paginator>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SavingsAccountTableComponent } from './savings-account-table.component';
describe('SavingsAccountTableComponent', () => {
let component: SavingsAccountTableComponent;
let fixture: ComponentFixture<SavingsAccountTableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SavingsAccountTableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SavingsAccountTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,65 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/** Custom Pipes */
import { AccountsFilterPipe } from '../../pipes/accounts-filter.pipe';
@Component({
selector: 'mifosx-savings-account-table',
templateUrl: './savings-account-table.component.html',
styleUrls: ['./savings-account-table.component.scss']
})
export class SavingsAccountTableComponent implements OnInit {
/** Columns to be displayed in the savings accounts table. */
displayedColumns: string[] = ['accountNo', 'productName', 'accountBalance', 'Status'];
/** Show closed saving accounts */
showClosed = false;
/** Data source for savings account table. */
dataSource: MatTableDataSource<any>;
/** Savings Account Data */
accountData: any;
/** Paginator for savings account table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for savings account table. */
@ViewChild(MatSort) sort: MatSort;
/** Savings Account Setter */
@Input() set savingsAccountData(data: any) {
this.accountData = data;
const filteredAccountData = this.accountsFilterPipe.transform(data, 'saving', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* @param {AccountsFilterPipe} accountsFilterPipe Accounts Filter Pipe.
*/
constructor(private accountsFilterPipe: AccountsFilterPipe) { }
/**
* Filters data in users table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit() {
}
/**
* Toggles the savings status
*/
toggleClosed() {
this.showClosed = !this.showClosed;
const filteredAccountData = this.accountsFilterPipe.transform(this.accountData, 'saving', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
@@ -0,0 +1,44 @@
<div fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxFlex="50%">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
<button mat-raised-button color="primary" (click)="toggleClosed()">
{{ showClosed ? 'View Active' : 'View Closed' }}
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="accountNo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Account Number </th>
<td mat-cell *matCellDef="let shareAccount">{{ shareAccount.accountNo }}</td>
</ng-container>
<ng-container matColumnDef="productName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Share Account </th>
<td mat-cell *matCellDef="let shareAccount">{{ shareAccount.productName }}</td>
</ng-container>
<ng-container matColumnDef="totalApprovedShares">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Approved Shares </th>
<td mat-cell *matCellDef="let savingsAccount">{{ savingsAccount.totalApprovedShares }}</td>
</ng-container>
<ng-container matColumnDef="Status">
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let shareAccount">
<span [className]="shareAccount.status.code | statusLookup">
<fa-icon matTooltip="{{ shareAccount.status.value }}" matTooltipPosition="right" icon="circle" size="md"></fa-icon>
</span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25]" showFirstLastButtons></mat-paginator>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ShareAccountTableComponent } from './share-account-table.component';
describe('ShareAccountTableComponent', () => {
let component: ShareAccountTableComponent;
let fixture: ComponentFixture<ShareAccountTableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ShareAccountTableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ShareAccountTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,65 @@
/** Angular Imports */
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/** Custom Pipes */
import { AccountsFilterPipe } from '../../pipes/accounts-filter.pipe';
@Component({
selector: 'mifosx-share-account-table',
templateUrl: './share-account-table.component.html',
styleUrls: ['./share-account-table.component.scss']
})
export class ShareAccountTableComponent implements OnInit {
/** Columns to be displayed in the share accounts table. */
displayedColumns: string[] = ['accountNo', 'productName', 'totalApprovedShares', 'Status'];
/** Show closed share accounts */
showClosed = false;
/** Data source for share account table. */
dataSource: MatTableDataSource<any>;
/** Share Account Data */
accountData: any;
/** Paginator for share account table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for share account table. */
@ViewChild(MatSort) sort: MatSort;
/** Share Account Setter */
@Input() set shareAccountData(data: any) {
this.accountData = data;
const filteredAccountData = this.accountsFilterPipe.transform(data, 'share', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* @param {AccountsFilterPipe} accountsFilterPipe Accounts Filter Pipe.
*/
constructor(private accountsFilterPipe: AccountsFilterPipe) { }
/**
* Filters data in users table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
ngOnInit() {
}
/**
* Toggles the share status
*/
toggleClosed() {
this.showClosed = !this.showClosed;
const filteredAccountData = this.accountsFilterPipe.transform(this.accountData, 'share', this.showClosed ? 'closed' : 'open');
this.dataSource = new MatTableDataSource(filteredAccountData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
@@ -0,0 +1,58 @@
<mat-card-header fxLayout="row" fxLayoutGap="5%" class="header">
<fa-icon class="main-icon" icon="user" size="3x"></fa-icon>
<mat-card-title-group>
<div class="mat-typography">
<mat-card-title>
<h2>
{{ employeeData.displayName }}
<span [className]="employeeData.isActive === true ? 'true' : 'false'">
<fa-icon matTooltip="{{ employeeData.isActive === true ? 'Active' : 'Inactive' }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
</span>
</h2>
</mat-card-title>
<mat-card-subtitle>
<p>
Associated Office: {{ employeeData.officeName }}
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
</mat-card-header>
<mat-card-content>
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong">
Joined On
</div>
<div fxFlex="50%">
{{ employeeData.joiningDate | date }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Loan Officer
</div>
<div fxFlex="50%">
{{ employeeData.isLoanOfficer ? 'Yes' : 'No' }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="employeeData.mobileNo">
Mobile Number
</div>
<div fxFlex="50%" *ngIf="employeeData.mobileNo">
{{ employeeData.mobileNo }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Number of Centers
</div>
<div fxFlex="50%">
{{ centerData ? centerData.length : '' }}
</div>
</div>
</mat-card-content>
@@ -0,0 +1,22 @@
.main-icon {
margin: 7px 0 0 0;
}
.true {
color: #32cd32;
}
.false {
color: #f44366;
}
h2 {
font-weight: 500;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StaffNavigationComponent } from './staff-navigation.component';
describe('StaffNavigationComponent', () => {
let component: StaffNavigationComponent;
let fixture: ComponentFixture<StaffNavigationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ StaffNavigationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StaffNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,19 @@
/** Angular Imports */
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'mifosx-staff-navigation',
templateUrl: './staff-navigation.component.html',
styleUrls: ['./staff-navigation.component.scss']
})
export class StaffNavigationComponent implements OnInit {
@Input() employeeData: any;
@Input() centerData: any;
constructor() { }
ngOnInit() {
}
}
+4
View File
@@ -36,6 +36,10 @@ export class StatusLookupPipe implements PipeTransform {
'clientStatusTYpe.approved': 'status-approved',
'clientStatusType.transfer.in.progress': 'status-transfer-progress', // write
'clientStatusType.transfer.on.hold': 'status-transfer-hold', // write
'groupingStatusType.active': 'status-active',
'groupingStatusType.pending': 'status-pending',
'groupingStatusType.submitted.and.pending.approval': 'status-pending',
'groupingStatusType.approved': 'status-approved',
'smsCampaignStatus.active': 'status-active',
'smsCampaignStatus.pending': 'status-pending',
'smsCampaignStatus.closed': 'status-closed',