From 3fe5a05feda23fe35508985a53f06ab7dae2163a Mon Sep 17 00:00:00 2001 From: Karan Takalkar Date: Wed, 20 May 2020 15:13:50 +0530 Subject: [PATCH] feat: add groups view page (general-tab) (#784) Fixes: #217 --- .../group-account.resolver.ts | 32 ++ .../group-client-members.resolver.ts | 32 ++ .../group-summary.resolver.ts | 32 ++ .../common-resolvers/group-view.resolver.ts | 32 ++ src/app/groups/groups-routing.module.ts | 43 ++- .../general-tab/general-tab.component.html | 289 ++++++++++++++++++ .../general-tab/general-tab.component.scss | 33 ++ .../general-tab/general-tab.component.spec.ts | 25 ++ .../general-tab/general-tab.component.ts | 68 +++++ .../groups-view.component-theme.scss | 12 + .../groups-view/groups-view.component.html | 109 +++++++ .../groups-view/groups-view.component.scss | 51 ++++ .../groups-view/groups-view.component.spec.ts | 25 ++ .../groups-view/groups-view.component.ts | 28 ++ src/app/groups/groups.component.html | 2 +- src/app/groups/groups.component.scss | 7 +- src/app/groups/groups.module.ts | 12 +- src/app/groups/groups.service.ts | 38 +++ src/assets/images/group_placeholder.png | Bin 0 -> 8170 bytes src/theme/custom/denim-yellowgreen.scss | 3 + src/theme/custom/pictonblue-yellowgreen.scss | 5 +- 21 files changed, 869 insertions(+), 9 deletions(-) create mode 100644 src/app/groups/common-resolvers/group-account.resolver.ts create mode 100644 src/app/groups/common-resolvers/group-client-members.resolver.ts create mode 100644 src/app/groups/common-resolvers/group-summary.resolver.ts create mode 100644 src/app/groups/common-resolvers/group-view.resolver.ts create mode 100644 src/app/groups/groups-view/general-tab/general-tab.component.html create mode 100644 src/app/groups/groups-view/general-tab/general-tab.component.scss create mode 100644 src/app/groups/groups-view/general-tab/general-tab.component.spec.ts create mode 100644 src/app/groups/groups-view/general-tab/general-tab.component.ts create mode 100644 src/app/groups/groups-view/groups-view.component-theme.scss create mode 100644 src/app/groups/groups-view/groups-view.component.html create mode 100644 src/app/groups/groups-view/groups-view.component.scss create mode 100644 src/app/groups/groups-view/groups-view.component.spec.ts create mode 100644 src/app/groups/groups-view/groups-view.component.ts create mode 100644 src/assets/images/group_placeholder.png diff --git a/src/app/groups/common-resolvers/group-account.resolver.ts b/src/app/groups/common-resolvers/group-account.resolver.ts new file mode 100644 index 000000000..d7951bf2a --- /dev/null +++ b/src/app/groups/common-resolvers/group-account.resolver.ts @@ -0,0 +1,32 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; + +/** + * Group Accounts data resolver. + */ +@Injectable() +export class GroupAccountsResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Group's Acccounts data. + * @param {ActivatedRouteSnapshot} route Route Snapshot. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const groupId = route.parent.paramMap.get('groupId'); + return this.groupsService.getGroupAccountsData(groupId); + } + +} diff --git a/src/app/groups/common-resolvers/group-client-members.resolver.ts b/src/app/groups/common-resolvers/group-client-members.resolver.ts new file mode 100644 index 000000000..a0b4e5717 --- /dev/null +++ b/src/app/groups/common-resolvers/group-client-members.resolver.ts @@ -0,0 +1,32 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; + +/** + * Groups Client Members data resolver. + */ +@Injectable() +export class GroupClientMembersResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Group's Client Members data. + * @param {ActivatedRouteSnapshot} route Route Snapshot. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const groupId = route.parent.paramMap.get('groupId'); + return this.groupsService.getGroupClientMembers(groupId); + } + +} diff --git a/src/app/groups/common-resolvers/group-summary.resolver.ts b/src/app/groups/common-resolvers/group-summary.resolver.ts new file mode 100644 index 000000000..fd58f5516 --- /dev/null +++ b/src/app/groups/common-resolvers/group-summary.resolver.ts @@ -0,0 +1,32 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; + +/** + * Group Summary resolver. + */ +@Injectable() +export class GroupSummaryResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Group Summary data. + * @param {ActivatedRouteSnapshot} route Route Snapshot. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const groupId = route.parent.paramMap.get('groupId'); + return this.groupsService.getGroupSummary(groupId); + } + +} diff --git a/src/app/groups/common-resolvers/group-view.resolver.ts b/src/app/groups/common-resolvers/group-view.resolver.ts new file mode 100644 index 000000000..cc2a049ad --- /dev/null +++ b/src/app/groups/common-resolvers/group-view.resolver.ts @@ -0,0 +1,32 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { GroupsService } from '../groups.service'; + +/** + * Groups data resolver. + */ +@Injectable() +export class GroupViewResolver implements Resolve { + + /** + * @param {GroupsService} GroupsService Groups service. + */ + constructor(private groupsService: GroupsService) { } + + /** + * Returns the Groups data. + * @param {ActivatedRouteSnapshot} route Route Snapshot + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const groupId = route.paramMap.get('groupId'); + return this.groupsService.getGroupData(groupId); + } + +} diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts index cb6a40976..52c88b383 100644 --- a/src/app/groups/groups-routing.module.ts +++ b/src/app/groups/groups-routing.module.ts @@ -10,14 +10,48 @@ import { extract } from '../core/i18n/i18n.service'; /** Custom Imports */ import { GroupsComponent } from './groups.component'; +import { GroupsViewComponent } from './groups-view/groups-view.component'; +import { GeneralTabComponent } from './groups-view/general-tab/general-tab.component'; + +/** Custom Resolvers */ +import { GroupViewResolver } from './common-resolvers/group-view.resolver'; +import { GroupAccountsResolver } from './common-resolvers/group-account.resolver'; +import { GroupSummaryResolver } from './common-resolvers/group-summary.resolver'; +import { GroupClientMembersResolver } from './common-resolvers/group-client-members.resolver'; /** Groups Routes */ const routes: Routes = [ Route.withShell([ { path: 'groups', - component: GroupsComponent, - data: { title: extract('Groups'), breadcrumb: 'Groups' } + data: { title: extract('Groups'), breadcrumb: 'Groups', routeParamBreadcrumb: false }, + children: [ + { + path: '', + component: GroupsComponent, + }, + { + path: ':groupId', + component: GroupsViewComponent, + data: { title: extract('View Group'), routeParamBreadcrumb: 'groupId' }, + resolve: { + groupViewData: GroupViewResolver, + + }, + children: [ + { + path: 'general', + component: GeneralTabComponent, + data: { title: extract('General'), breadcrumb: 'General', routeParamBreadcrumb: false }, + resolve: { + groupAccountsData: GroupAccountsResolver, + groupClientMembers: GroupClientMembersResolver, + groupSummary: GroupSummaryResolver + } + } + ] + } + ] } ]) ]; @@ -30,6 +64,9 @@ const routes: Routes = [ @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], - providers: [] + providers: [GroupViewResolver, + GroupAccountsResolver, + GroupSummaryResolver, + GroupClientMembersResolver] }) export class GroupsRoutingModule { } diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.html b/src/app/groups/groups-view/general-tab/general-tab.component.html new file mode 100644 index 000000000..a97716937 --- /dev/null +++ b/src/app/groups/groups-view/general-tab/general-tab.component.html @@ -0,0 +1,289 @@ +
+ +

Group Details

+ +
+

+ Active Client Loans: {{groupSummary?.activeClientLoans}}
+ Active Client Borrowers: {{groupSummary?.activeClientBorrowers}}
+ Active Overdue Client Loans: {{groupSummary?.overdueClientLoans}}
+

+

+ Active Group Loans: {{groupSummary?.activeGroupLoans}}
+ Active Group Borrowers: {{groupSummary?.activeGroupBorrowers}}
+ Active Overdue Group Loans: {{groupSummary?.overdueGroupLoans}}
+

+

+ Active Clients: {{groupSummary?.activeClients}}
+

+
+ + +
+ +

Client Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Name + + {{element.displayName}} + Account No. {{element.accountNo}} Office {{element.officeName}} JLG Loan Application +
+ +
+
+ +
+ +
+ +
+
+

Loan Accounts

+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Account No. + {{element.accountNo}} + Loan Account {{element.productName}} Original Loan {{element.originalLoan}} Loan Balance {{element.loanBalance}} Amount Paid {{element.amountPaid}} Type + + Actions + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Account No. + {{element.accountNo}} + Loan Account {{element.productName}} Original Loan {{element.lastActiveTransactionDate | date}} Loan Balance {{element.loanBalance}} Amount Paid {{element.accountBalance}} Type + + Closed Date {{element.timeline.closedOnDate | date}}
+ +
+ +
+ +
+
+

Saving Accounts

+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Account No. + {{element.accountNo}} Saving Account {{element.productName}} Last Active {{element.lastActiveTransactionDate | date}} Balance {{element.accountBalance}} Actions + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
Account No. + {{element.accountNo}} Saving Account {{element.productName}} Closed Date {{element.timeline.closedOnDate | date}}
+ +
+ +
diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.scss b/src/app/groups/groups-view/general-tab/general-tab.component.scss new file mode 100644 index 000000000..8bb6e3775 --- /dev/null +++ b/src/app/groups/groups-view/general-tab/general-tab.component.scss @@ -0,0 +1,33 @@ +.tab-container { + padding: 1%; + margin: 1%; + h3 { + margin:1% auto; + } + .group-details-container { + border: 1px solid; + padding: 1%; + margin-bottom: 30px; + } + .table-header { + .action-button{ + margin-left: auto; + } + } + table { + width: 100%; + .account-action-button{ + min-width: 26px; + padding: 0 6px; + margin: 4px; + line-height: 25px; + } + tr.select-row:hover { + cursor: pointer; + } + margin-bottom: 30px; + } + i:hover { + cursor: pointer; + } +} diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.spec.ts b/src/app/groups/groups-view/general-tab/general-tab.component.spec.ts new file mode 100644 index 000000000..68ff6503e --- /dev/null +++ b/src/app/groups/groups-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/groups/groups-view/general-tab/general-tab.component.ts b/src/app/groups/groups-view/general-tab/general-tab.component.ts new file mode 100644 index 000000000..eff250e82 --- /dev/null +++ b/src/app/groups/groups-view/general-tab/general-tab.component.ts @@ -0,0 +1,68 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Groups View General Tab Component. + */ +@Component({ + selector: 'mifosx-general-tab', + templateUrl: './general-tab.component.html', + styleUrls: ['./general-tab.component.scss'] +}) +export class GeneralTabComponent { + + /** Group's all accounts data */ + groupAccountData: any; + /** Group's loan accounts data */ + loanAccounts: any; + /** Group's savings accounts data */ + savingAccounts: any; + /** Group Summary */ + groupSummary: any; + /** Group's Client Members */ + groupClientMembers: any; + /** Columns to be Displayed for client members table */ + clientMemberColumns: string[] = ['Name', 'Account No', 'Office', 'JLG Loan Application']; + /** Columns to be displayed for open loan accounts table */ + openLoansColumns: string[] = ['Account No', 'Loan Account', 'Original Loan', 'Loan Balance', 'Amount Paid', 'Type', 'Actions']; + /** Columns to be displayed for closed loan accounts table */ + closedLoansColumns: string[] = ['Account No', 'Loan Account', 'Original Loan', 'Loan Balance', 'Amount Paid', 'Type', 'Closed Date']; + /** Columns to be displayed for open savings accounts table */ + openSavingsColumns: string[] = ['Account No', 'Saving Account', 'Last Active', 'Balance', 'Actions']; + /** Columns to be displayed for closed accounts table */ + closedSavingsColumns: string[] = ['Account No', 'Saving Account', 'Closed Date']; + /** Boolean for toggling loan accounts table */ + showClosedLoanAccounts = false; + /** Boolean for toggling savings accounts table */ + showClosedSavingAccounts = false; + + /** + * Fetches group's related data from `resolve` + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { groupAccountsData: any, groupClientMembers: any, groupSummary: any }) => { + this.groupAccountData = data.groupAccountsData; + this.savingAccounts = data.groupAccountsData.savingsAccounts; + this.loanAccounts = data.groupAccountsData.loanAccounts; + this.groupSummary = data.groupSummary[0]; + this.groupClientMembers = data.groupClientMembers; + }); + } + + /** + * Toggles loan accounts table. + */ + toggleLoanAccountsOverview() { + this.showClosedLoanAccounts = !this.showClosedLoanAccounts; + } + + /** + * Toggles savings account table. + */ + toggleSavingAccountsOverview() { + this.showClosedSavingAccounts = !this.showClosedSavingAccounts; + } + +} diff --git a/src/app/groups/groups-view/groups-view.component-theme.scss b/src/app/groups/groups-view/groups-view.component-theme.scss new file mode 100644 index 000000000..676d5bc09 --- /dev/null +++ b/src/app/groups/groups-view/groups-view.component-theme.scss @@ -0,0 +1,12 @@ +@import "~@angular/material/theming"; + +@mixin groups-view-component-theme($theme) { + $primary: map-get($theme, primary); + mifosx-groups-view { + .group-card { + .header { + background-color: mat-color($primary, 500); + } + } + } +} diff --git a/src/app/groups/groups-view/groups-view.component.html b/src/app/groups/groups-view/groups-view.component.html new file mode 100644 index 000000000..625635bf3 --- /dev/null +++ b/src/app/groups/groups-view/groups-view.component.html @@ -0,0 +1,109 @@ + + + + + + +
+
+ +
+
+ +
+ +

+ + Group Name : {{groupViewData.name}} +

+
+ +

+ Group #: {{groupViewData.id}} | Center Name: {{groupViewData.centerName}} | Staff: {{groupViewData.staffName}}
+ Office Name: {{groupViewData.officeName}}
+ Activation Date : {{(groupViewData.activationDate)?(groupViewData.activationDate|date) :'Not Activated'}}
+ + Closure Date: {{groupViewData.timeline.closedOnDate | date}} + +

+
+
+ +
+
+

+ Next Meeting on: {{groupViewData.collectionMeetingCalendar?.recentEligibleMeetingDate | date}} +
+ Meeting Frequency: {{groupViewData.collectionMeetingCalendar?.frequency.value | lowercase}} +

+
+ +
+

+ Next Meeting on: Unassigned +
+ Meeting Frequency: N/A +

+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
diff --git a/src/app/groups/groups-view/groups-view.component.scss b/src/app/groups/groups-view/groups-view.component.scss new file mode 100644 index 000000000..b3bd5c5cb --- /dev/null +++ b/src/app/groups/groups-view/groups-view.component.scss @@ -0,0 +1,51 @@ +.group-card { + margin: 0 auto; + max-width: 80rem; + width: 90%; + padding: 0; + .header { + padding: 1%; + .header-title-group { + .group-card-title { + color: white; + width: 90%; + p { + color: white; + } + } + } + .profile-image-container { + margin: 1%; + .profile-image { + object-fit: cover; + border-radius: 20px; + } + } + .group-meeting { + align-self: flex-end; + width: 300px; + height: 140px; + div, ng-template > div { + background-color: #0a6aac; + p { + color: white; + padding-inline: 10px; + } + } + } + .group-actions { + align-self: flex-end; + margin: 0 1%; + i { + margin-bottom: 2px; + margin-right: 4px; + } + } + } + .navigation-tabs { + overflow: auto; + } + i:hover { + cursor: pointer; + } +} diff --git a/src/app/groups/groups-view/groups-view.component.spec.ts b/src/app/groups/groups-view/groups-view.component.spec.ts new file mode 100644 index 000000000..9d47bb4b8 --- /dev/null +++ b/src/app/groups/groups-view/groups-view.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { GroupsViewComponent } from './groups-view.component'; + +describe('GroupsViewComponent', () => { + let component: GroupsViewComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ GroupsViewComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GroupsViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/groups/groups-view/groups-view.component.ts b/src/app/groups/groups-view/groups-view.component.ts new file mode 100644 index 000000000..00d0555b7 --- /dev/null +++ b/src/app/groups/groups-view/groups-view.component.ts @@ -0,0 +1,28 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Groups View Component. + */ +@Component({ + selector: 'mifosx-groups-view', + templateUrl: './groups-view.component.html', + styleUrls: ['./groups-view.component.scss'] +}) +export class GroupsViewComponent { + + /** Group view data */ + groupViewData: any; + + /** + * Fetches group data from `resolve` + * @param {ActivatedRoute} route Activated Route + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { groupViewData: any }) => { + this.groupViewData = data.groupViewData; + }); + } + +} diff --git a/src/app/groups/groups.component.html b/src/app/groups/groups.component.html index 39f69fc76..ad044b7fc 100644 --- a/src/app/groups/groups.component.html +++ b/src/app/groups/groups.component.html @@ -45,7 +45,7 @@ - + diff --git a/src/app/groups/groups.component.scss b/src/app/groups/groups.component.scss index b917b27e6..f738e24d4 100644 --- a/src/app/groups/groups.component.scss +++ b/src/app/groups/groups.component.scss @@ -2,9 +2,14 @@ .action-button{ margin-left: auto; } - .search-button{ min-width: 30px; margin: 4px; } } + +table { + tr.select-row:hover { + cursor: pointer; + } +} diff --git a/src/app/groups/groups.module.ts b/src/app/groups/groups.module.ts index c191dd9ce..799648f06 100644 --- a/src/app/groups/groups.module.ts +++ b/src/app/groups/groups.module.ts @@ -6,9 +6,12 @@ import { DatePipe } from '@angular/common'; import { GroupsRoutingModule } from './groups-routing.module'; import { SharedModule } from 'app/shared/shared.module'; import { PipesModule } from '../pipes/pipes.module'; +import { DirectivesModule } from '../directives/directives.module'; /** Custom Components */ import { GroupsComponent } from './groups.component'; +import { GroupsViewComponent } from './groups-view/groups-view.component'; +import { GeneralTabComponent } from './groups-view/general-tab/general-tab.component'; /** * Groups Module @@ -18,11 +21,14 @@ import { GroupsComponent } from './groups.component'; @NgModule({ imports: [ SharedModule, - GroupsRoutingModule, - PipesModule + PipesModule, + DirectivesModule, + GroupsRoutingModule ], declarations: [ - GroupsComponent + GroupsComponent, + GroupsViewComponent, + GeneralTabComponent ], providers: [DatePipe] }) diff --git a/src/app/groups/groups.service.ts b/src/app/groups/groups.service.ts index 2705c9f69..8dfa71bcb 100644 --- a/src/app/groups/groups.service.ts +++ b/src/app/groups/groups.service.ts @@ -4,6 +4,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; /** rxjs Imports */ import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; /** * Groups service. @@ -51,4 +52,41 @@ export class GroupsService { return this.http.get('/groups', { params: httpParams } ); } + /** + * @param groupId Group Id of group to get data for. + * @returns {Observable} Group data. + */ + getGroupData(groupId: string): Observable { + const httpParams = new HttpParams().set('associations', 'all'); + return this.http.get(`/groups/${groupId}`, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get data for. + * @returns {Observable} Group Summary data. + */ + getGroupSummary(groupId: string): Observable { + const httpParams = new HttpParams().set('R_groupId', groupId) + .set('genericResultSet', 'false'); + return this.http.get(`/runreports/GroupSummaryCounts`, { params: httpParams }); + } + + /** + * @param groupId Group Id of group to get data for. + * @returns {Observable} Group Client Members data. + */ + getGroupClientMembers(groupId: string): Observable { + const httpParams = new HttpParams().set('associations', 'clientMembers'); + return this.http.get(`/groups/${groupId}`, { params: httpParams }) + .pipe(map((group: any) => group.clientMembers)); + } + + /** + * @param groupId Group Id of group to get data for. + * @returns {Observable} Group Accounts data. + */ + getGroupAccountsData(groupId: string): Observable { + return this.http.get(`/groups/${groupId}/accounts`); + } + } diff --git a/src/assets/images/group_placeholder.png b/src/assets/images/group_placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..2e053cba8c7eb44043c1e0a9ee4e8ce5998fce00 GIT binary patch literal 8170 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 JA9TO`e*osJz!3ld literal 0 HcmV?d00001 diff --git a/src/theme/custom/denim-yellowgreen.scss b/src/theme/custom/denim-yellowgreen.scss index bef500396..e6b71cfd9 100644 --- a/src/theme/custom/denim-yellowgreen.scss +++ b/src/theme/custom/denim-yellowgreen.scss @@ -1,6 +1,8 @@ @import '~@angular/material/theming'; // 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'; + // Custom material palette $mat-denim: ( 100: #5ba2ec, @@ -46,3 +48,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif // that you are using. @include angular-material-theme($mifosx-app-theme); @include clients-view-component-theme($mifosx-app-theme); +@include groups-view-component-theme($mifosx-app-theme); diff --git a/src/theme/custom/pictonblue-yellowgreen.scss b/src/theme/custom/pictonblue-yellowgreen.scss index 9e36753e9..88e1ffe65 100644 --- a/src/theme/custom/pictonblue-yellowgreen.scss +++ b/src/theme/custom/pictonblue-yellowgreen.scss @@ -1,6 +1,8 @@ @import '~@angular/material/theming'; // 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'; + // Custom material palette $mat-picton-blue: ( 100: #6ce0ff, @@ -45,4 +47,5 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif // Alternatively, you can import and @include the theme mixins for each component // that you are using. @include angular-material-theme($mifosx-app-theme); -@include clients-view-component-theme($mifosx-app-theme); \ No newline at end of file +@include clients-view-component-theme($mifosx-app-theme); +@include groups-view-component-theme($mifosx-app-theme);