diff --git a/src/app/centers/centers-routing.module.ts b/src/app/centers/centers-routing.module.ts index c0a3c8b62..1ae65bc31 100644 --- a/src/app/centers/centers-routing.module.ts +++ b/src/app/centers/centers-routing.module.ts @@ -10,6 +10,12 @@ import { extract } from '../core/i18n/i18n.service'; import { CentersComponent } from './centers.component'; import { CreateCenterComponent } from './create-center/create-center.component'; import { OfficesResolver } from 'app/accounting/common-resolvers/offices.resolver'; +import { CentersViewComponent } from './centers-view/centers-view.component'; +import { GeneralTabComponent } from './centers-view/general-tab/general-tab.component'; +import { CenterViewResolver } from './common-resolvers/center-view.resolver'; +import { SavingsAccountResolver } from './common-resolvers/savings-account.resolver'; +import { CenterResourceResolver } from './common-resolvers/center-resource.resolver'; +import { CenterSummaryResolver } from './common-resolvers/center-summary.resolver'; const routes: Routes = [ Route.withShell([ @@ -29,6 +35,26 @@ const routes: Routes = [ resolve: { offices: OfficesResolver, } + }, + { + path: ':centerId', + component: CentersViewComponent, + data: { title: extract('Centers View'), routeParamBreadcrumb: 'centerId' }, + resolve: { + centerViewData: CenterViewResolver + }, + children: [ + { + path: 'general', + component: GeneralTabComponent, + data: { title: extract('General'), breadcrumb: 'General', routeParamBreadcrumb: false }, + resolve: { + centerSummaryData: CenterSummaryResolver, + centerViewData: CenterResourceResolver, + savingsAccountData: SavingsAccountResolver + } + } + ] } ] } @@ -38,6 +64,12 @@ const routes: Routes = [ @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], - providers: [OfficesResolver] + providers: [ + OfficesResolver, + CenterViewResolver, + SavingsAccountResolver, + CenterResourceResolver, + CenterSummaryResolver + ] }) export class CentersRoutingModule { } diff --git a/src/app/centers/centers-view/centers-view.component-theme.scss b/src/app/centers/centers-view/centers-view.component-theme.scss new file mode 100644 index 000000000..ea0a53818 --- /dev/null +++ b/src/app/centers/centers-view/centers-view.component-theme.scss @@ -0,0 +1,13 @@ +@import "~@angular/material/theming"; + +@mixin centers-view-component-theme($theme) { + $primary: map-get($theme, primary); + + mifosx-centers-view { + .center-card { + .header { + background-color: mat-color($primary, 500); + } + } + } +} diff --git a/src/app/centers/centers-view/centers-view.component.html b/src/app/centers/centers-view/centers-view.component.html new file mode 100644 index 000000000..7b442adfd --- /dev/null +++ b/src/app/centers/centers-view/centers-view.component.html @@ -0,0 +1,93 @@ + + + +
+
+ +
+
+
+ +

+ + Center Name : {{centerViewData.name}} +

+
+ +
+
+

+ Account #:{{centerViewData.accountNo}}
+ Office: {{centerViewData.officeName}}
+ + External Id: {{centerViewData.externalId}}
+
+ + Staff: {{centerViewData.staffName}}
+
+ Activation Date : + {{(centerViewData.activationDate)?(centerViewData.activationDate|date) :'Not Activated'}}
+

+
+
+

+ Next Meeting On: + + {{centerViewData.collectionMeetingCalendar.nextTenRecurringDates[0]|date}} + + +
+ Meeting Frequency: {{centerViewData.collectionMeetingCalendar.humanReadable}} +
+ Unassigned
+ Closed Date: {{centerViewData.timeline.closedOnDate|date}} +

+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
diff --git a/src/app/centers/centers-view/centers-view.component.scss b/src/app/centers/centers-view/centers-view.component.scss new file mode 100644 index 000000000..e67ff794c --- /dev/null +++ b/src/app/centers/centers-view/centers-view.component.scss @@ -0,0 +1,39 @@ +.center-card { + margin: 0 auto; + max-width: 80rem; + width: 90%; + padding: 0; + .header { + padding: 1%; + .header-title-group { + .center-card-title { + color: white; + width: 90%; + p { + color: white; + } + } + } + .profile-image-container { + margin: 1%; + .profile-image { + object-fit: cover; + border-radius: 20px; + } + } + .center-actions { + align-self: flex-end; + margin: 0 1%; + } + } + .navigation-tabs { + overflow: auto; + } +} + +.meetingDetails { + float:right; + margin-right: 10px; + border: 1px black solid; + padding: 10px; +} diff --git a/src/app/centers/centers-view/centers-view.component.spec.ts b/src/app/centers/centers-view/centers-view.component.spec.ts new file mode 100644 index 000000000..dad47f80c --- /dev/null +++ b/src/app/centers/centers-view/centers-view.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CentersViewComponent } from './centers-view.component'; + +describe('CentersViewComponent', () => { + let component: CentersViewComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CentersViewComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CentersViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/centers/centers-view/centers-view.component.ts b/src/app/centers/centers-view/centers-view.component.ts new file mode 100644 index 000000000..79bd80e1f --- /dev/null +++ b/src/app/centers/centers-view/centers-view.component.ts @@ -0,0 +1,37 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Create Center View + */ +@Component({ + selector: 'mifosx-centers-view', + templateUrl: './centers-view.component.html', + styleUrls: ['./centers-view.component.scss'] +}) +export class CentersViewComponent implements OnInit { + + /** Stores Center View Data */ + centerViewData: any; + meetingData: boolean; + + /** + * Retrieves the data for center + * @param route route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { + centerViewData: any, + }) => { + this.centerViewData = data.centerViewData; + }); + } + + ngOnInit() { + if (this.centerViewData.collectionMeetingCalendar) { + this.meetingData = true; + } else { this.meetingData = false; } + } + +} diff --git a/src/app/centers/centers-view/general-tab/general-tab.component.html b/src/app/centers/centers-view/general-tab/general-tab.component.html new file mode 100644 index 000000000..c1c4f06d3 --- /dev/null +++ b/src/app/centers/centers-view/general-tab/general-tab.component.html @@ -0,0 +1,140 @@ +
+
+

Center Closed

+
+

Summary Details

+
+

+ Active Clients: {{centerSummaryData.activeClients}}
+ Active Group Loans: {{centerSummaryData.activeGroupLoans}}
+ Active Client Loans: {{centerSummaryData.activeClientLoans}}
+ Active Overdue Group Loans: {{centerSummaryData.overdueGroupLoans}}
+

+

+ Active Group Borrowers: {{centerSummaryData.activeGroupBorrowers}}
+ Active Client Borrowers: {{centerSummaryData.activeClientBorrowers}}
+ Active Overdue Client Loans: {{centerSummaryData.overdueClientLoans}}
+

+
+ + + +

Groups

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Account Number + {{element.accountNo}} Group Name {{element.name}} Office Name {{element.officeName}} Submitted On {{element.timeline.submittedOnDate|date}}
+
+ + + + + + +

Savings Account Overview

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Account No + {{element.accountNo}} Products {{element.productName}} Balance {{element.accountBalance}} Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + +
diff --git a/src/app/centers/centers-view/general-tab/general-tab.component.scss b/src/app/centers/centers-view/general-tab/general-tab.component.scss new file mode 100644 index 000000000..ecbf73a5f --- /dev/null +++ b/src/app/centers/centers-view/general-tab/general-tab.component.scss @@ -0,0 +1,28 @@ +.tab-container { + padding: 1%; + margin: 1%; + + h3{ + margin:1% auto; + } + .summary-details-container { + border: 1px solid; + padding: 1%; + } + + table { + width: 100%; + .account-action-button{ + min-width: 26px; + padding: 0 6px; + margin: 4px; + line-height: 25px; + } + } +} + +.closedCenter { + text-align: center; + color: red; + font-size: 2rem; +} diff --git a/src/app/centers/centers-view/general-tab/general-tab.component.spec.ts b/src/app/centers/centers-view/general-tab/general-tab.component.spec.ts new file mode 100644 index 000000000..68ff6503e --- /dev/null +++ b/src/app/centers/centers-view/general-tab/general-tab.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GeneralTabComponent } from './general-tab.component'; + +describe('GeneralTabComponent', () => { + let component: GeneralTabComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ GeneralTabComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GeneralTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/centers/centers-view/general-tab/general-tab.component.ts b/src/app/centers/centers-view/general-tab/general-tab.component.ts new file mode 100644 index 000000000..77b24712c --- /dev/null +++ b/src/app/centers/centers-view/general-tab/general-tab.component.ts @@ -0,0 +1,48 @@ +/** Angular Imports */ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Create Center General Tab Component + */ +@Component({ + selector: 'mifosx-general-tab', + templateUrl: './general-tab.component.html', + styleUrls: ['./general-tab.component.scss'] +}) +export class GeneralTabComponent implements OnInit { + + /** Savings Account Table Columns */ + savingsAccountColumns: string[] = ['Account No', 'Products', 'Balance', 'Actions']; + /** Groups Table Columns */ + groupsColumns: string[] = ['Account No', 'Group Name', 'Office Name', 'Submitted On']; + /** Stores the summary of center */ + centerSummaryData: any; + /** Stores Center Data for particular center */ + centerViewData: any; + /** Stores Saving Account for particular center */ + savingsAccountData: any; + /** Stores Group Data */ + groupResourceData: any; + + /** + * Retrieves the data for centers + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { + centerSummaryData: any, + centerViewData: any, + savingsAccountData: any + }) => { + this.centerSummaryData = data.centerSummaryData[0]; + this.centerViewData = data.centerViewData; + this.savingsAccountData = data.savingsAccountData.savingsAccounts; + this.groupResourceData = data.centerViewData.groupMembers; + }); + } + + ngOnInit() { + } + +} diff --git a/src/app/centers/centers.component.html b/src/app/centers/centers.component.html index bad25b9d2..3a66a3f36 100644 --- a/src/app/centers/centers.component.html +++ b/src/app/centers/centers.component.html @@ -52,7 +52,7 @@ - + diff --git a/src/app/centers/centers.component.scss b/src/app/centers/centers.component.scss index 15e12ff37..28cb201c5 100644 --- a/src/app/centers/centers.component.scss +++ b/src/app/centers/centers.component.scss @@ -5,6 +5,13 @@ .search-button{ min-width: 30px; margin: 4px; - + } +} + +table { + width: 100%; + + .select-row:hover { + cursor: pointer; } } diff --git a/src/app/centers/centers.module.ts b/src/app/centers/centers.module.ts index 75839507e..8d20ee980 100644 --- a/src/app/centers/centers.module.ts +++ b/src/app/centers/centers.module.ts @@ -5,10 +5,13 @@ import { NgModule } from '@angular/core'; import { CentersRoutingModule } from './centers-routing.module'; import { SharedModule } from 'app/shared/shared.module'; import { PipesModule } from '../pipes/pipes.module'; +import { DirectivesModule } from '../directives/directives.module'; /** Custom Components */ import { CentersComponent } from './centers.component'; import { CreateCenterComponent } from './create-center/create-center.component'; +import { CentersViewComponent } from './centers-view/centers-view.component'; +import { GeneralTabComponent } from './centers-view/general-tab/general-tab.component'; /** * Centers Module @@ -19,11 +22,14 @@ import { CreateCenterComponent } from './create-center/create-center.component'; imports: [ SharedModule, CentersRoutingModule, - PipesModule + PipesModule, + DirectivesModule ], declarations: [ CentersComponent, - CreateCenterComponent + CreateCenterComponent, + CentersViewComponent, + GeneralTabComponent ] }) export class CentersModule { } diff --git a/src/app/centers/centers.service.ts b/src/app/centers/centers.service.ts index 9c2f5d078..17c884287 100644 --- a/src/app/centers/centers.service.ts +++ b/src/app/centers/centers.service.ts @@ -61,4 +61,31 @@ export class CentersService { return this.http.get('/centers/template', { params: httpParams }); } + /** + * @param centerId CenterID + * @returns {Observable} Group Data for Center + */ + getCenterData(centerId: string): Observable { + const httpParams = new HttpParams() + .set('associations', 'groupMembers,collectionMeetingCalendar'); + return this.http.get(`/centers/${centerId}`, { params: httpParams } ); + } + + /** + * @param centerId Center ID + * @returns {Observable} Returns the entire details of the Center ID + */ + getCenterSummary(centerId: string): Observable { + const httpParams = new HttpParams().set('R_groupId', centerId) + .set('genericResultSet', 'false'); + return this.http.get(`/runreports/GroupSummaryCounts`, { params: httpParams }); + } + + /** + * @param centerId Center ID + * @returns {Observable} Returns the saving account for that center + */ + getSavingsAccountDetails(centerId: string): Observable { + return this.http.get(`/centers/${centerId}/accounts`); + } } diff --git a/src/app/centers/common-resolvers/center-resource.resolver.ts b/src/app/centers/common-resolvers/center-resource.resolver.ts new file mode 100644 index 000000000..a8ccbf89d --- /dev/null +++ b/src/app/centers/common-resolvers/center-resource.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + +/** + * Centers data resolver. + */ +@Injectable() +export class CenterResourceResolver implements Resolve { + + /** + * @param {CentersService} CentersService Centers service. + */ + constructor(private centersService: CentersService) { } + + /** + * Returns the Centers data for General Tab. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const centerId = route.parent.paramMap.get('centerId'); + return this.centersService.getCenterData(centerId); + } + +} diff --git a/src/app/centers/common-resolvers/center-summary.resolver.ts b/src/app/centers/common-resolvers/center-summary.resolver.ts new file mode 100644 index 000000000..accf32410 --- /dev/null +++ b/src/app/centers/common-resolvers/center-summary.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + +/** + * Centers data resolver. + */ +@Injectable() +export class CenterSummaryResolver implements Resolve { + + /** + * @param {CentersService} CentersService Centers service. + */ + constructor(private centersService: CentersService) { } + + /** + * Returns the Centers Summary Data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const centerId = route.parent.paramMap.get('centerId'); + return this.centersService.getCenterSummary(centerId); + } + +} diff --git a/src/app/centers/common-resolvers/center-view.resolver.ts b/src/app/centers/common-resolvers/center-view.resolver.ts new file mode 100644 index 000000000..51acb9ca4 --- /dev/null +++ b/src/app/centers/common-resolvers/center-view.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + +/** + * Centers data resolver. + */ +@Injectable() +export class CenterViewResolver implements Resolve { + + /** + * @param {CentersService} CentersService Centers service. + */ + constructor(private centersService: CentersService) { } + + /** + * Returns the Centers data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const centerId = route.paramMap.get('centerId'); + return this.centersService.getCenterData(centerId); + } + +} diff --git a/src/app/centers/common-resolvers/savings-account.resolver.ts b/src/app/centers/common-resolvers/savings-account.resolver.ts new file mode 100644 index 000000000..ecf01865d --- /dev/null +++ b/src/app/centers/common-resolvers/savings-account.resolver.ts @@ -0,0 +1,31 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { CentersService } from '../centers.service'; + +/** + * Centers data resolver. + */ +@Injectable() +export class SavingsAccountResolver implements Resolve { + + /** + * @param {CentersService} CentersService Centers service. + */ + constructor(private centersService: CentersService) { } + + /** + * Returns the Center Savings Account data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const centerId = route.parent.paramMap.get('centerId'); + return this.centersService.getSavingsAccountDetails(centerId); + } + +} diff --git a/src/app/pipes/status-lookup.pipe.ts b/src/app/pipes/status-lookup.pipe.ts index 36a72b665..c5cee8cfb 100644 --- a/src/app/pipes/status-lookup.pipe.ts +++ b/src/app/pipes/status-lookup.pipe.ts @@ -39,6 +39,7 @@ export class StatusLookupPipe implements PipeTransform { 'smsCampaignStatus.active': 'status-active', 'smsCampaignStatus.pending': 'status-pending', 'smsCampaignStatus.closed': 'status-closed', + 'groupingStatusType.active': 'status-active' }; return cssClassNameLookup[status]; } diff --git a/src/assets/images/center_placeholder.png b/src/assets/images/center_placeholder.png new file mode 100644 index 000000000..04550482d Binary files /dev/null and b/src/assets/images/center_placeholder.png differ diff --git a/src/theme/custom/denim-yellowgreen.scss b/src/theme/custom/denim-yellowgreen.scss index e6b71cfd9..40d8fc15d 100644 --- a/src/theme/custom/denim-yellowgreen.scss +++ b/src/theme/custom/denim-yellowgreen.scss @@ -2,6 +2,7 @@ // Plus imports for other components in your app. @import '../../app/clients/clients-view/clients-view.component-theme.scss'; @import '../../app/groups/groups-view/groups-view.component-theme.scss'; +@import '../../app/centers/centers-view/centers-view.component-theme.scss'; // Custom material palette $mat-denim: ( @@ -49,3 +50,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif @include angular-material-theme($mifosx-app-theme); @include clients-view-component-theme($mifosx-app-theme); @include groups-view-component-theme($mifosx-app-theme); +@include centers-view-component-theme($mifosx-app-theme); diff --git a/src/theme/custom/pictonblue-yellowgreen.scss b/src/theme/custom/pictonblue-yellowgreen.scss index 88e1ffe65..8a637355a 100644 --- a/src/theme/custom/pictonblue-yellowgreen.scss +++ b/src/theme/custom/pictonblue-yellowgreen.scss @@ -2,6 +2,7 @@ // Plus imports for other components in your app. @import '../../app/clients/clients-view/clients-view.component-theme.scss'; @import '../../app/groups/groups-view/groups-view.component-theme.scss'; +@import '../../app/centers/centers-view/centers-view.component-theme.scss'; // Custom material palette $mat-picton-blue: ( @@ -49,3 +50,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif @include angular-material-theme($mifosx-app-theme); @include clients-view-component-theme($mifosx-app-theme); @include groups-view-component-theme($mifosx-app-theme); +@include centers-view-component-theme($mifosx-app-theme);