diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 8b019b05f..4969c5c90 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -29,6 +29,7 @@ import { RouteReusableStrategy } from './route/route-reusable-strategy';
/** Custom Modules */
import { SharedModule } from '../shared/shared.module';
import { NotificationsModule } from '../notifications/notifications.module';
+import { SearchModule } from 'app/search/search.module';
/** Custom Components */
import { ShellComponent } from './shell/shell.component';
@@ -45,6 +46,7 @@ import { ContentComponent } from './shell/content/content.component';
@NgModule({
imports: [
SharedModule,
+ SearchModule,
NotificationsModule,
HttpClientModule,
TranslateModule,
diff --git a/src/app/core/shell/toolbar/toolbar.component.html b/src/app/core/shell/toolbar/toolbar.component.html
index 32e1e470c..39e584f33 100644
--- a/src/app/core/shell/toolbar/toolbar.component.html
+++ b/src/app/core/shell/toolbar/toolbar.component.html
@@ -41,21 +41,7 @@
-
-
-
- Search
-
-
-
-
-
+
diff --git a/src/app/core/shell/toolbar/toolbar.component.ts b/src/app/core/shell/toolbar/toolbar.component.ts
index 120394fcb..5f5266716 100644
--- a/src/app/core/shell/toolbar/toolbar.component.ts
+++ b/src/app/core/shell/toolbar/toolbar.component.ts
@@ -2,7 +2,6 @@
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
import { MatSidenav } from '@angular/material';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
-import { style, animate, transition, trigger } from '@angular/animations';
import { Router } from '@angular/router';
/** rxjs Imports */
@@ -18,18 +17,7 @@ import { AuthenticationService } from '../../authentication/authentication.servi
@Component({
selector: 'mifosx-toolbar',
templateUrl: './toolbar.component.html',
- styleUrls: ['./toolbar.component.scss'],
- animations: [
- trigger('fadeInOut', [
- transition(':enter', [
- style({ opacity: 0 }),
- animate(500, style({ opacity: 1 }))
- ]),
- transition(':leave', [
- animate(500, style({ opacity: 0 }))
- ])
- ])
- ]
+ styleUrls: ['./toolbar.component.scss']
})
export class ToolbarComponent implements OnInit {
@@ -39,8 +27,6 @@ export class ToolbarComponent implements OnInit {
map(result => result.matches)
);
- /** Sets the initial visibility of search input as hidden. Visible if true. */
- searchVisible = false;
/** Sets the initial state of sidenav as collapsed. Not collapsed if false. */
sidenavCollapsed = true;
@@ -84,13 +70,6 @@ export class ToolbarComponent implements OnInit {
this.collapse.emit(this.sidenavCollapsed);
}
- /**
- * Toggles the visibility of search input with fadeInOut animation.
- */
- toggleSearchVisibility() {
- this.searchVisible = !this.searchVisible;
- }
-
/**
* Logs out the authenticated user and redirects to login page.
*/
diff --git a/src/app/notifications/notifications-routing.module.ts b/src/app/notifications/notifications-routing.module.ts
index 927a7cacc..4f42e651d 100644
--- a/src/app/notifications/notifications-routing.module.ts
+++ b/src/app/notifications/notifications-routing.module.ts
@@ -2,7 +2,6 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
-
/** Routing Imports */
import { Route } from '../core/route/route.service';
diff --git a/src/app/search/search-page/search-page.component.html b/src/app/search/search-page/search-page.component.html
new file mode 100644
index 000000000..94d5da6c5
--- /dev/null
+++ b/src/app/search/search-page/search-page.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+ Searched query resulted more than 200 records, showing first 200 records.
+
+
+
+
+ {{ entity.entityName }} | #{{ entity.entityAccountNo }}
+
+ Entity: {{ entity.entityType }}
+ | {{ ['CLIENT','GROUP', 'CENTER'].includes(entity.entityType) ? 'Office' : 'Client' }}: {{ entity.parentName }}
+
+
+
+
+
+
+
+
+
diff --git a/src/app/search/search-page/search-page.component.scss b/src/app/search/search-page/search-page.component.scss
new file mode 100644
index 000000000..36433b509
--- /dev/null
+++ b/src/app/search/search-page/search-page.component.scss
@@ -0,0 +1,18 @@
+mat-list {
+ padding-top: 0px;
+}
+
+mat-list-item {
+ .link {
+ color: blue;
+ text-decoration: underline;
+ width: fit-content;
+ &:hover{
+ cursor: pointer;
+ }
+ }
+ margin-block: 20px;
+ &:hover{
+ background-color: #f5f5f5;
+ }
+}
diff --git a/src/app/search/search-page/search-page.component.spec.ts b/src/app/search/search-page/search-page.component.spec.ts
new file mode 100644
index 000000000..c39a155f0
--- /dev/null
+++ b/src/app/search/search-page/search-page.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SearchPageComponent } from './search-page.component';
+
+describe('SearchPageComponent', () => {
+ let component: SearchPageComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SearchPageComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SearchPageComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/search/search-page/search-page.component.ts b/src/app/search/search-page/search-page.component.ts
new file mode 100644
index 000000000..f4b4d2b66
--- /dev/null
+++ b/src/app/search/search-page/search-page.component.ts
@@ -0,0 +1,62 @@
+/** Angular Imports */
+import { Component } from '@angular/core';
+import { Router, ActivatedRoute } from '@angular/router';
+
+/**
+ * Search Page Component
+ */
+@Component({
+ selector: 'mifosx-search-page',
+ templateUrl: './search-page.component.html',
+ styleUrls: ['./search-page.component.scss']
+})
+export class SearchPageComponent {
+
+ /** Search Results */
+ searchResults: any;
+ /** Flags if number of search results exceed 200 */
+ overload: boolean;
+
+ /**
+ * @param {ActivatedRoute} route Activated Route
+ * @param {Router} router Router
+ */
+ constructor(private route: ActivatedRoute,
+ private router: Router) {
+ this.route.data.subscribe(( data: { searchResults: any }) => {
+ this.searchResults = data.searchResults;
+ this.overload = this.searchResults.length > 200 ? true : false;
+ if (this.overload) {
+ this.searchResults = this.searchResults.slice(0, 200);
+ }
+ });
+ }
+
+ /**
+ * Returns link to entity view page.
+ * @param {any} entity Entity
+ */
+ navigate(entity: any) {
+ switch (entity.entityType) {
+ case 'CLIENT':
+ this.router.navigate(['clients', entity.entityId]);
+ break;
+ case 'CENTER':
+ this.router.navigate(['centers', entity.entityId]);
+ break;
+ case 'GROUP':
+ this.router.navigate(['groups', entity.entityId]);
+ break;
+ case 'SHARE':
+ this.router.navigate(['clients', entity.parentId, 'sharesaccounts', entity.entityId]);
+ break;
+ case 'SAVING':
+ this.router.navigate(['clients', entity.parentId, 'savingsaccounts', entity.entityId]);
+ break;
+ case 'LOAN':
+ this.router.navigate(['clients', entity.parentId, 'loans', entity.entityId]);
+ break;
+ }
+ }
+
+}
diff --git a/src/app/search/search-routing.module.ts b/src/app/search/search-routing.module.ts
new file mode 100644
index 000000000..6308eda8e
--- /dev/null
+++ b/src/app/search/search-routing.module.ts
@@ -0,0 +1,37 @@
+/** Angular Imports */
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+/** Routing Imports */
+import { Route } from '../core/route/route.service';
+
+/** Translation Imports */
+import { extract } from '../core/i18n/i18n.service';
+
+/** Custom Components */
+import { SearchPageComponent } from './search-page/search-page.component';
+
+/** Custom Resolvers */
+import { SearchResolver } from './search.resolver';
+
+/** Search Routes */
+const routes: Routes = [
+ Route.withShell([
+ {
+ path: 'search',
+ component: SearchPageComponent,
+ data: { title: extract('Search'), breadcrumb: 'Search' },
+ runGuardsAndResolvers: 'paramsOrQueryParamsChange',
+ resolve: {
+ searchResults: SearchResolver
+ }
+ }
+ ])
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ providers: [SearchResolver],
+ exports: [RouterModule]
+})
+export class SearchRoutingModule { }
diff --git a/src/app/search/search-tool/search-tool.component.html b/src/app/search/search-tool/search-tool.component.html
new file mode 100644
index 000000000..e8011428f
--- /dev/null
+++ b/src/app/search/search-tool/search-tool.component.html
@@ -0,0 +1,23 @@
+
+
+
+ Search
+
+
+
+
+ Resource
+
+
+ {{ option.name }}
+
+
+
+
+
+
+
+
+
diff --git a/src/app/search/search-tool/search-tool.component.scss b/src/app/search/search-tool/search-tool.component.scss
new file mode 100644
index 000000000..430ae07dc
--- /dev/null
+++ b/src/app/search/search-tool/search-tool.component.scss
@@ -0,0 +1,18 @@
+.search-bar {
+ .search {
+ max-width: 400px;
+ width: 100%;
+ font-size: 1rem;
+ }
+ .resource {
+ max-width: 90px;
+ width: 100%;
+ font-size: 1rem;
+ }
+}
+
+.search-icon {
+ margin-left: 1rem;
+ display: flex;
+ align-items: center;
+}
diff --git a/src/app/search/search-tool/search-tool.component.spec.ts b/src/app/search/search-tool/search-tool.component.spec.ts
new file mode 100644
index 000000000..1359ef779
--- /dev/null
+++ b/src/app/search/search-tool/search-tool.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SearchToolComponent } from './search-tool.component';
+
+describe('SearchToolComponent', () => {
+ let component: SearchToolComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SearchToolComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SearchToolComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/search/search-tool/search-tool.component.ts b/src/app/search/search-tool/search-tool.component.ts
new file mode 100644
index 000000000..227fe1d45
--- /dev/null
+++ b/src/app/search/search-tool/search-tool.component.ts
@@ -0,0 +1,88 @@
+/** Angular Imports */
+import { Component } from '@angular/core';
+import { style, animate, transition, trigger } from '@angular/animations';
+import { Router } from '@angular/router';
+import { FormControl } from '@angular/forms';
+
+/**
+ * Search Tool Component
+ */
+@Component({
+ selector: 'mifosx-search-tool',
+ templateUrl: './search-tool.component.html',
+ styleUrls: ['./search-tool.component.scss'],
+ animations: [
+ trigger('fadeInOut', [
+ transition(':enter', [
+ style({ opacity: 0 }),
+ animate(500, style({ opacity: 1 }))
+ ]),
+ transition(':leave', [
+ animate(500, style({ opacity: 0 }))
+ ])
+ ])
+ ]
+})
+export class SearchToolComponent {
+
+ /** Query Form Control */
+ query = new FormControl('');
+ /** Resource Form Control */
+ resource = new FormControl('');
+
+ /** Sets the initial visibility of search input as hidden. Visible if true. */
+ searchVisible = false;
+ /** Resource Options */
+ resourceOptions: any[] = [
+ {
+ name: 'All',
+ value: 'clients,clientIdentifiers,groups,savings,shares,loans'
+ },
+ {
+ name: 'Clients',
+ value: 'clients,clientIdentifiers'
+ },
+ {
+ name: 'Groups',
+ value: 'groups'
+ },
+ {
+ name: 'Savings',
+ value: 'savings'
+ },
+ {
+ name: 'Shares',
+ value: 'shares'
+ },
+ {
+ name: 'Loans',
+ value: 'loans'
+ },
+ ];
+
+ /**
+ * @param {Router} router Router
+ */
+ constructor(private router: Router) {
+ this.resource.patchValue('clients,clientIdentifiers,groups,savings,shares,loans');
+ }
+
+ /**
+ * Toggles the visibility of search input with fadeInOut animation.
+ */
+ toggleSearchVisibility() {
+ this.searchVisible = !this.searchVisible;
+ }
+
+ /**
+ * Searches server for query and resource.
+ */
+ search() {
+ const queryParams: any = {
+ query: this.query.value,
+ resource: this.resource.value
+ };
+ this.router.navigate(['/search'], { queryParams: queryParams });
+ }
+
+}
diff --git a/src/app/search/search.module.ts b/src/app/search/search.module.ts
new file mode 100644
index 000000000..a13eaf117
--- /dev/null
+++ b/src/app/search/search.module.ts
@@ -0,0 +1,25 @@
+/** Angular Imports */
+import { NgModule } from '@angular/core';
+
+/** Custom Modules */
+import { SharedModule } from '../shared/shared.module';
+import { SearchRoutingModule } from './search-routing.module';
+
+/** Custom Components */
+import { SearchToolComponent } from './search-tool/search-tool.component';
+import { SearchPageComponent } from './search-page/search-page.component';
+
+/**
+ * Search Module
+ */
+@NgModule({
+ declarations: [SearchToolComponent, SearchPageComponent],
+ imports: [
+ SharedModule,
+ SearchRoutingModule
+ ],
+ exports: [
+ SearchToolComponent
+ ]
+})
+export class SearchModule { }
diff --git a/src/app/search/search.resolver.ts b/src/app/search/search.resolver.ts
new file mode 100644
index 000000000..5ec9518cc
--- /dev/null
+++ b/src/app/search/search.resolver.ts
@@ -0,0 +1,33 @@
+/** Angular Imports */
+import { Injectable } from '@angular/core';
+import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
+
+/** rxjs Imports */
+import { Observable } from 'rxjs';
+
+/** Custom Services */
+import { SearchService } from './search.service';
+
+/**
+ * Search Results data resolver.
+ */
+@Injectable()
+export class SearchResolver implements Resolve