diff --git a/src/app/core/services/form/form.service.ts b/src/app/core/services/form/form.service.ts index 9a3a76c0..693d2353 100644 --- a/src/app/core/services/form/form.service.ts +++ b/src/app/core/services/form/form.service.ts @@ -84,4 +84,18 @@ export class FormService { }) return existingData } + + async filterList(obj){ + const config = { + url: urlConstants.API_URLS.FILTER_LIST + '&type=' + obj, + payload: {}, + }; + try { + const data: any = await this.http.get(config); + return data.result + } + catch (error) { + return null; + } + } } diff --git a/src/app/core/services/permission/permission.service.ts b/src/app/core/services/permission/permission.service.ts index a715744e..dac34b2a 100644 --- a/src/app/core/services/permission/permission.service.ts +++ b/src/app/core/services/permission/permission.service.ts @@ -54,6 +54,7 @@ export class PermissionService { try { const data: any = await this.httpService.get(config); this.setConfigInLocal(data.result) + return data } catch (error) { return null; diff --git a/src/app/core/services/profile/profile.service.ts b/src/app/core/services/profile/profile.service.ts index 13dcce19..629c6763 100644 --- a/src/app/core/services/profile/profile.service.ts +++ b/src/app/core/services/profile/profile.service.ts @@ -218,4 +218,20 @@ export class ProfileService { modal.present(); } + async getMentors(showLoader = true, obj){ + showLoader ? await this.loaderService.startLoader() : ''; + const config = { + url: urlConstants.API_URLS.MENTORS_DIRECTORY_LIST + obj?.page + '&limit=' + obj.pageSize + '&search=' + btoa(obj.searchText) + '&directory=false'+ '&search_on=' + (obj?.selectedChip? obj?.selectedChip : '') + '&' + (obj?.urlQueryData ? obj?.urlQueryData: ''), + payload: {} + }; + try { + let data: any = await this.httpService.get(config); + showLoader ? await this.loaderService.stopLoader() : ''; + return data; + } + catch (error) { + showLoader ? await this.loaderService.stopLoader() : ''; + } + } + } diff --git a/src/app/core/services/session/session.service.ts b/src/app/core/services/session/session.service.ts index eea4c9d1..bb46bd00 100644 --- a/src/app/core/services/session/session.service.ts +++ b/src/app/core/services/session/session.service.ts @@ -62,7 +62,7 @@ export class SessionService { async getSessionsList(obj) { const config = { - url: urlConstants.API_URLS.GET_SESSIONS_LIST + obj?.type + '&page=' + obj?.page + '&limit=' + obj?.limit + '&search=' + btoa(obj?.searchText), + url: urlConstants.API_URLS.GET_SESSIONS_LIST + obj?.page + '&limit=' + obj?.limit + '&search=' + btoa(obj?.searchText) + '&search_on=' + (obj?.selectedChip ? obj?.selectedChip : '') + '&' + obj?.filterData, }; try { let data: any = await this.httpService.get(config); @@ -252,4 +252,16 @@ export class SessionService { catch (error) { } } + + async getSessions(obj) { + const config = { + url: urlConstants.API_URLS.HOME_SESSION + obj.page + '&limit=' + obj.limit, + }; + try { + let data: any = await this.httpService.get(config); + return data + } + catch (error) { + } + } } diff --git a/src/app/modules/private/private-routing.module.ts b/src/app/modules/private/private-routing.module.ts index ef4487a7..ef844270 100644 --- a/src/app/modules/private/private-routing.module.ts +++ b/src/app/modules/private/private-routing.module.ts @@ -100,6 +100,11 @@ const routes: Routes = [ loadChildren: () => import('../../pages/login-activity/login-activity.module').then(m => m.LoginActivityPageModule), canActivate: [PrivateGuard] }, + { + path: CommonRoutes.MENTOR_SEARCH_DIRECTORY, + loadChildren: () => import('../../pages/mentor-search-directory/mentor-search-directory.module').then(m => m.MentorSearchDirectoryPageModule), + canActivate: [PrivateGuard] + }, { path: '', redirectTo: '', diff --git a/src/app/pages/home-search/home-search.module.ts b/src/app/pages/home-search/home-search.module.ts index c379ee10..85fba492 100644 --- a/src/app/pages/home-search/home-search.module.ts +++ b/src/app/pages/home-search/home-search.module.ts @@ -9,6 +9,8 @@ import { HomeSearchPageRoutingModule } from './home-search-routing.module'; import { HomeSearchPage } from './home-search.page'; import { CoreModule } from 'src/app/core/core.module'; import { SharedModule } from 'src/app/shared/shared.module'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { OverlayModule } from '@angular/cdk/overlay'; @NgModule({ imports: [ @@ -17,7 +19,9 @@ import { SharedModule } from 'src/app/shared/shared.module'; CoreModule, SharedModule, IonicModule, - HomeSearchPageRoutingModule + HomeSearchPageRoutingModule, + MatPaginatorModule, + OverlayModule ], declarations: [HomeSearchPage] }) diff --git a/src/app/pages/home-search/home-search.page.html b/src/app/pages/home-search/home-search.page.html index 90b8c8db..cb423235 100644 --- a/src/app/pages/home-search/home-search.page.html +++ b/src/app/pages/home-search/home-search.page.html @@ -1,51 +1,70 @@ - - - - - - - - {{ "SESSIONS" | translate }} - - - {{ "MENTORS" | translate }} - - -
-
- - - - -
- - -
-
-
-
-
- -
- - - - - - + +
+ + +
+
+ + + +
+ + + + {{ chip.label }} + - -
-
-
-
- -
+ + + + + +
+ + + {{criteriaChip.label}} + +
+
+ +

+
+ + +
+ + + {{ chip.label }} + +
+
+
+ +
+
+

{{"FILTER" | translate}}

+
+ +
+
+
+
+
+
+ + + - - - {{"SEARCH" | translate}} - - \ No newline at end of file diff --git a/src/app/pages/home-search/home-search.page.scss b/src/app/pages/home-search/home-search.page.scss index 1d18ed7b..802dfea7 100644 --- a/src/app/pages/home-search/home-search.page.scss +++ b/src/app/pages/home-search/home-search.page.scss @@ -1,3 +1,98 @@ .segment-label{ text-transform: none; -} \ No newline at end of file +} +.search-bar{ + --border-radius:25px; + --icon-color:var(--ion-color-primary); + font-size:16px; + height: 36px; + max-width: 600px; + min-width: 350px; +} +ion-content { + --padding: 0; +} + +.ion-funnel-icon { + font-size: 12px; + color: var(--white); +} + +.search-navigation{ + display: flex; + justify-content: space-between; +} + +.search-result-label{ + display: flex; + align-items: center; +} + +.verticalLine { + border-left: thin solid #807e7e; + height: 32px; +} +.search-result-count{ + display: flex; + padding-left: 24%; +} + +.selected-chip{ + --background:var(--ion-color-primary); + --color:var(--white); +} +.filter{ + display: flex; + flex-direction: row; + gap: 5px; + justify-content: end; + padding: 0 2%; +} +.chip { + background-color: var(--ion-color-primary); + font-size: 14px; + color: var(--white); + align-items: center; + display: inline-block; + text-decoration: none; +} +.circle-container { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: #832215; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + color: var(--white); +} +.chip-container { + display: flex; + white-space: nowrap; + width: calc(100% - 100px); + overflow-y: auto; + scrollbar-width: none; +} + +.overlay-container { + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 16px; + max-width: 100%; + z-index: 1000; +} +.overlay-chip { + font-size: 14px; + align-items: center; + display: inline-block; + text-decoration: none; + ion-icon { + color: white; + } + &.selected-chip { + background-color: var(--ion-color-primary); + color: white; + } +} \ No newline at end of file diff --git a/src/app/pages/home-search/home-search.page.ts b/src/app/pages/home-search/home-search.page.ts index b5698dea..932a53bd 100644 --- a/src/app/pages/home-search/home-search.page.ts +++ b/src/app/pages/home-search/home-search.page.ts @@ -1,9 +1,18 @@ -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { urlConstants } from 'src/app/core/constants/urlConstants'; -import { HttpService, LoaderService, ToastService } from 'src/app/core/services'; +import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ModalController } from '@ionic/angular'; +import { HttpService, LoaderService, LocalStorageService, ToastService } from 'src/app/core/services'; +import { AdminWorkapceService } from 'src/app/core/services/admin-workspace/admin-workapce.service'; import { SessionService } from 'src/app/core/services/session/session.service'; +import { FilterPopupComponent } from 'src/app/shared/components/filter-popup/filter-popup.component'; import { CommonRoutes } from 'src/global.routes'; +import { MatPaginator } from '@angular/material/paginator'; +import { paginatorConstants } from 'src/app/core/constants/paginatorConstants'; +import { localKeys } from 'src/app/core/constants/localStorage.keys'; +import { ProfileService } from 'src/app/core/services/profile/profile.service'; +import { Location } from '@angular/common'; +import { PermissionService } from 'src/app/core/services/permission/permission.service'; +import { FormService } from 'src/app/core/services/form/form.service'; @Component({ selector: 'app-home-search', @@ -11,111 +20,228 @@ import { CommonRoutes } from 'src/global.routes'; styleUrls: ['./home-search.page.scss'], }) export class HomeSearchPage implements OnInit { + + @ViewChild(MatPaginator) paginator!: MatPaginator; + @Output() toggleOverlayEvent = new EventEmitter(); + public headerConfig: any = { - backButton: true, - label: "SEARCH", + menu: true, + notification: true, + headerColor: 'primary', + // label:'MENU' }; - noResults : boolean = false; - searchText:string=""; + searchText:string; results=[]; type:any; - searching=true; - constructor(private sessionService:SessionService, private loaderService: LoaderService,private httpService: HttpService, private router: Router, private toast: ToastService) { } - - ngOnInit() { - this.type='all-sessions'; - } - async getMentorList() { - const config = { - url: urlConstants.API_URLS.MENTORS_DIRECTORY_LIST+'&search=' + btoa(this.searchText)+ '&directory=true', - payload: {} - }; - try { - let data: any = await this.httpService.get(config); - this.results = data?.result?.data; - this.noResults = (this.results.length)?false:true; - this.searching = false; - } - catch (error) { - } + filterData: any; + filteredDatas = [] + page = 1; + setPaginatorToFirstpage:any = false; + limit = 5; + totalCount: any; + noDataMessage: any; + createdSessions: any; + user: any; + criteriaChip: any; + chips =[] + criteriaChipValue: string; + params: any; + overlayChips: any; + isOpen = false; + urlQueryData: string; + pageSize: any; + + constructor(private modalCtrl: ModalController, private adminWorkapceService: AdminWorkapceService,private httpService: HttpService, private router: Router, private toast: ToastService, + private sessionService: SessionService, + private localStorage: LocalStorageService, + private profileService: ProfileService, + private location: Location, + private activatedRoute: ActivatedRoute, + private permissionService: PermissionService, + private formService: FormService + ) { + this.activatedRoute.queryParamMap.subscribe(async (params) => { + this.params = params; + this.criteriaChip = JSON.parse(params.get('criteriaChip')); + this.searchText = this.params.get('searchString') + }) } - async getSessionsList() { - let obj={ - page: "", - limit: "", - type: "", - searchText : this.searchText, - } - let data = await this.sessionService.getSessionsList(obj); - this.results = data?.result?.data; - this.noResults = (this.results.length)?false:true; - this.searching = false; + async ngOnInit() { + this.criteriaChipValue = this.params.get('chipName'); + this.user = this.localStorage.getLocalData(localKeys.USER_DETAILS) + this.fetchSessionList() + this.permissionService.getPlatformConfig().then((config)=>{ + this.overlayChips = config?.result?.search_config?.search?.session?.fields; + }) } - checkInput(event: any){ - if(event.keyCode == 13){ - this.search(); - } + async ionViewWillEnter() { + let data = await this.formService.filterList('session'); + this.filterData = this.transformData(data); + } + + search(event) { + this.searchText = event; + this.isOpen = false; + this.fetchSessionList() + } + + async onClickFilter() { + let modal = await this.modalCtrl.create({ + component: FilterPopupComponent, + cssClass: 'filter-modal', + componentProps: { filterData: this.filterData } + }); + + modal.onDidDismiss().then(async (dataReturned) => { + this.filteredDatas = [] + if (dataReturned !== null) { + if (dataReturned.data.data.selectedFilters) { + for (let key in dataReturned.data.data.selectedFilters) { + this.filteredDatas[key] = dataReturned.data.data.selectedFilters[key].slice(0, dataReturned.data.data.selectedFilters[key].length).map(obj => obj.value).join(',').toString() + } + } + this.extractLabels(dataReturned.data.data.selectedFilters); + this.getUrlQueryData(); + } + this.page = 1; + this.setPaginatorToFirstpage = true; + this.fetchSessionList() + }); + modal.present() } - cancelSearch(event: any){ - this.searching = true - this.results = [] + + async fetchSessionList() { + var obj={page: this.page, limit: this.limit, type: this.type, searchText : this.searchText, selectedChip : this.criteriaChipValue, filterData : this.urlQueryData} + var response = await this.sessionService.getSessionsList(obj); + this.results = response?.result?.data; + this.totalCount = response.result.count; + this.noDataMessage = obj.searchText ? "SEARCH_RESULT_NOT_FOUND" : "THIS_SPACE_LOOKS_EMPTY" } - trimLeft(inputString: string): string { - return this.searchText = inputString.replace(/^\s+/, ''); + + onPageChange(event){ + this.page = event.page, + this.pageSize = event.pageSize; + this.fetchSessionList() } - search(){ - if(this.searchText!=""){ - switch(this.type) { - case 'all-sessions': - this.getSessionsList(); + async eventAction(event) { + this.user = await this.localStorage.getLocalData(localKeys.USER_DETAILS) + if (this.user.about) { + switch (event.type) { + case 'cardSelect': + this.router.navigate([`/${CommonRoutes.SESSIONS_DETAILS}/${event.data.id}`]); break; - case 'mentor-profile': - this.getMentorList(); + + case 'joinAction': + await this.sessionService.joinSession(event.data) + this.fetchSessionList() + break; + + case 'enrollAction': + let enrollResult = await this.sessionService.enrollSession(event.data.id); + if (enrollResult.result) { + this.toast.showToast(enrollResult.message, "success") + this.fetchSessionList() + } + break; + + case 'startAction': + this.sessionService.startSession(event.data.id).then(async () => { + var obj = { page: this.page, limit: this.limit, searchText: "" }; + if(this.profileService.isMentor){ + this.createdSessions = await this.sessionService.getAllSessionsAPI(obj); + } + }) break; } } else { - this.toast.showToast("Please provide a valid text for search","danger") + this.profileService.upDateProfilePopup() } } - segmentChanged(event){ - this.results=[] - this.type = event.target.value; - if(this.searchText !== "") - this.search(); + locationBack(){ + this.location.back() } - async onSessionAction(event){ - switch (event.type) { - case 'cardSelect': - this.router.navigate([`/${CommonRoutes.SESSIONS_DETAILS}/${event.data.id}`]) - break; + extractLabels(data) { + this.chips = []; + for (const key in data) { + if (data.hasOwnProperty(key)) { + this.chips.push(...data[key]); + } + } + } - case 'joinAction': - this.sessionService.joinSession(event.data) - this.search(); - break; + removeChip(chip: string, index: number) { + this.chips.splice(index, 1); + this.removeFilteredData(chip); + this.getUrlQueryData(); + this.fetchSessionList() + } - case 'enrollAction': - let enrollResult = await this.sessionService.enrollSession(event.data.id); - if(enrollResult.result){ - this.toast.showToast(enrollResult.message, "success") - this.search(); - } - break; + closeCriteriaChip(){ + this.criteriaChip.name = this.criteriaChip.label = ""; + this.searchText = this.params.get('searchString') + this.router.navigate(['/' + CommonRoutes.HOME_SEARCH], { queryParams: {searchText : this.searchText, selectedChip : ''} }); + this.fetchSessionList() + } - case 'startAction': - this.sessionService.startSession(event.data._id); - this.search(); - break; - } + transformData(responseData) { + const entityTypes = responseData.entity_types; + + const filterData = Object.keys(entityTypes).map(type => { + const entityType = entityTypes[type][0]; + return { + title: entityType.label, + name: entityType.value, + options: entityType.entities.map(entity => ({ + label: entity.label, + value: entity.value + })), + type: "checkbox" + }; + }); + + return filterData; } - eventAction(event){ - this.router.navigate([`/${CommonRoutes.MENTOR_DETAILS}/${event.data.id}`]) + selectChip(chip) { + this.criteriaChip = chip.label; + this.criteriaChipValue = chip.name; + this.fetchSessionList() + this.isOpen = false; } + getUrlQueryData() { + const queryString = Object.keys(this.filteredDatas) + .map(key => `${key}=${this.filteredDatas[key]}`) + .join('&'); + + this.urlQueryData = queryString; + } + + removeFilteredData(chip){ + for (let key in this.filteredDatas) { + if (this.filteredDatas.hasOwnProperty(key)) { + + let values = this.filteredDatas[key].split(','); + + let chipIndex = values.indexOf(chip); + + if (chipIndex > -1) { + values.splice(chipIndex, 1); + + let newValue = values.join(','); + + if (newValue === '') { + delete this.filteredDatas[key]; + } else { + this.filteredDatas[key] = newValue; + } + } + } + } + } } diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory-routing.module.ts b/src/app/pages/mentor-search-directory/mentor-search-directory-routing.module.ts new file mode 100644 index 00000000..ddb07a64 --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { MentorSearchDirectoryPage } from './mentor-search-directory.page'; + +const routes: Routes = [ + { + path: '', + component: MentorSearchDirectoryPage + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class MentorSearchDirectoryPageRoutingModule {} diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory.module.ts b/src/app/pages/mentor-search-directory/mentor-search-directory.module.ts new file mode 100644 index 00000000..ef1ede49 --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { IonicModule } from '@ionic/angular'; + +import { MentorSearchDirectoryPageRoutingModule } from './mentor-search-directory-routing.module'; + +import { MentorSearchDirectoryPage } from './mentor-search-directory.page'; +import { SharedModule } from 'src/app/shared/shared.module'; +import { OverlayModule } from '@angular/cdk/overlay'; +import {MatPaginatorModule} from '@angular/material/paginator'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + IonicModule, + MentorSearchDirectoryPageRoutingModule, + SharedModule, + OverlayModule, + MatPaginatorModule + ], + declarations: [MentorSearchDirectoryPage] +}) +export class MentorSearchDirectoryPageModule {} diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory.page.html b/src/app/pages/mentor-search-directory/mentor-search-directory.page.html new file mode 100644 index 00000000..46760f60 --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory.page.html @@ -0,0 +1,96 @@ + +
+ +
+
+ + +
+ + + + {{ chip.label }} + + +
+
+
+ + + + +
+ + + {{selectedChipLabel}} + +
+
+ +

+
+ + +
+ + + {{ chip.label }} + +
+
+
+ +
+
+

{{"FILTER" | translate}}

+
+ +
+
+
+
+
+
+
+ +
+
+
+ + + + {{"MENTOR_SEARCH_RESULT" | translate}} "{{searchText}}" +
+
+ {{totalCount}} {{"SEARCH_RESULT" | translate}} +
+
+
+ +
+
+ + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory.page.scss b/src/app/pages/mentor-search-directory/mentor-search-directory.page.scss new file mode 100644 index 00000000..08ff662c --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory.page.scss @@ -0,0 +1,104 @@ +.index-label{ + border-top: 1px solid var(--gray); + padding: 10px 15px; + margin: 20px 15px 15px 10px; + border-bottom: 1px solid var(--gray); + font-weight: 600; +} +.search-style{ + --border-radius: 20px; + padding: 5px 35px !important; + max-width: 600px; + } + +.mentor-card{ + cursor: pointer; +} + +.selected-chip{ + --background:var(--ion-color-primary); + --color:var(--white); +} +.filter{ + display: flex; + flex-direction: row; + gap: 5px; + justify-content: end; + padding: 0 2%; +} +.verticalLine { + border-left: thin solid #807e7e; + height: 32px; +} +.chip { + background-color: var(--ion-color-primary); + font-size: 14px; + color: var(--white); + align-items: center; + display: inline-block; + text-decoration: none; +} +.circle-container { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--ion-color-primary); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + color: var(--white); +} + +.chip-container { + display: flex; + white-space: nowrap; + width: calc(100% - 100px); /* Adjust width as necessary */ + overflow-y: auto; + scrollbar-width: none; +} + + +.ion-funnel-icon { + font-size: 12px; + color: var(--white); +} + +.overlay-container { + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 16px; + max-width: 100%; + z-index: 1000; +} +.overlay-chip { + font-size: 14px; + align-items: center; + display: inline-block; + text-decoration: none; + ion-icon { + color: white; + } + &.selected-chip { + background-color: var(--ion-color-primary); + color: white; + } +} + +.search-navigation{ + display: flex; + justify-content: space-between; +} +.search-result-count{ + display: flex; + padding-left: 24%; +} +.search-result-label{ + display: flex; + align-items: center; +} +.search-result-count{ + display: flex; + padding-left: 24%; +} \ No newline at end of file diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory.page.spec.ts b/src/app/pages/mentor-search-directory/mentor-search-directory.page.spec.ts new file mode 100644 index 00000000..9a7adbcd --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory.page.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { IonicModule } from '@ionic/angular'; + +import { MentorSearchDirectoryPage } from './mentor-search-directory.page'; + +describe('MentorSearchDirectoryPage', () => { + let component: MentorSearchDirectoryPage; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ MentorSearchDirectoryPage ], + imports: [IonicModule.forRoot()] + }).compileComponents(); + + fixture = TestBed.createComponent(MentorSearchDirectoryPage); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/pages/mentor-search-directory/mentor-search-directory.page.ts b/src/app/pages/mentor-search-directory/mentor-search-directory.page.ts new file mode 100644 index 00000000..505e0edc --- /dev/null +++ b/src/app/pages/mentor-search-directory/mentor-search-directory.page.ts @@ -0,0 +1,194 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator } from '@angular/material/paginator'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ModalController } from '@ionic/angular'; +import { paginatorConstants } from 'src/app/core/constants/paginatorConstants'; +import { urlConstants } from 'src/app/core/constants/urlConstants'; +import { HttpService, LoaderService } from 'src/app/core/services'; +import { FormService } from 'src/app/core/services/form/form.service'; +import { PermissionService } from 'src/app/core/services/permission/permission.service'; +import { ProfileService } from 'src/app/core/services/profile/profile.service'; +import { FilterPopupComponent } from 'src/app/shared/components/filter-popup/filter-popup.component'; +import { CommonRoutes } from 'src/global.routes'; + +@Component({ + selector: 'app-mentor-search-directory', + templateUrl: './mentor-search-directory.page.html', + styleUrls: ['./mentor-search-directory.page.scss'], +}) +export class MentorSearchDirectoryPage implements OnInit { + @ViewChild(MatPaginator) paginator!: MatPaginator; + pageSize = paginatorConstants.defaultPageSize; + pageSizeOptions = paginatorConstants.pageSizeOptions; + + public headerConfig: any = { + menu: true, + notification: true, + headerColor: 'primary', + // label:'MENU' + }; + searchText: string = ''; + isOpen = false; + overlayChips = []; + selectedChipLabel: any; + selectedChipName: any; + filterData: any; + filteredDatas: any[]; + selectedChips: boolean; + urlQueryData: string; + setPaginatorToFirstpage: boolean; + page: any = 1; + data: any; + isLoaded: boolean; + totalCount: any; + limit: any; + chips = []; + + constructor( + private router: Router, + private profileService: ProfileService, + private modalCtrl: ModalController, + private permissionService: PermissionService, + private formService: FormService + ) { } + + async ngOnInit() { + this.getMentors(); + this.permissionService.getPlatformConfig().then((config)=>{ + this.overlayChips = config?.result?.search_config?.search?.mentor?.fields; + }) + let data = await this.formService.filterList('profile') + this.filterData = this.transformData(data) + } + + onSearch(){ + this.getMentors() + } + + selectChip(chip) { + this.selectedChipLabel = chip.label; + this.selectedChipName = chip.name; + this.isOpen = false; + this.getMentors() + } + + closeCriteriaChip(){ + this.selectedChipLabel = ""; + this.selectedChipName = ""; + this.getMentors() + } + + removeChip(chip: string,index: number) { + this.chips.splice(index, 1); + this.removeFilteredData(chip) + this.getUrlQueryData(); + this.getMentors() + } + + async onClickFilter() { + let modal = await this.modalCtrl.create({ + component: FilterPopupComponent, + cssClass: 'filter-modal', + componentProps: { filterData: this.filterData } + }); + + modal.onDidDismiss().then(async (dataReturned) => { + this.filteredDatas = [] + if (dataReturned !== null) { + if (dataReturned?.data?.data?.selectedFilters) { + for (let key in dataReturned?.data?.data?.selectedFilters) { + this.filteredDatas[key] = dataReturned?.data?.data?.selectedFilters[key].slice(0, dataReturned?.data?.data?.selectedFilters[key].length).map(obj => obj.value).join(',').toString() + } + this.selectedChips = true; + } + this.extractLabels(dataReturned?.data?.data?.selectedFilters); + this.getUrlQueryData(); + } + this.page = 1; + this.setPaginatorToFirstpage = true; + this.getMentors() + }); + modal.present(); + } + + transformData(responseData) { + const entityTypes = responseData.entity_types; + + const filterData = Object.keys(entityTypes).map(type => { + const entityType = entityTypes[type][0]; + return { + title: entityType.label, + name: entityType.value, + options: entityType.entities.map(entity => ({ + label: entity.label, + value: entity.value + })), + type: "checkbox" + }; + }); + + return filterData; + } + + extractLabels(data) { + this.chips = []; + for (const key in data) { + if (data.hasOwnProperty(key)) { + this.chips.push(...data[key]); + } + } + } + + getUrlQueryData() { + const queryString = Object.keys(this.filteredDatas) + .map(key => `${key}=${this.filteredDatas[key]}`) + .join('&'); + + this.urlQueryData = queryString; + } + + eventAction(event){ + switch (event.type) { + case 'cardSelect': + this.router.navigate([CommonRoutes.MENTOR_DETAILS, event?.data?.id]); + break; + } + } + + onPageChange(event){ + this.page = event.pageIndex + 1, + this.pageSize = this.paginator.pageSize; + this.getMentors() + } + + removeFilteredData(chip){ + for (let key in this.filteredDatas) { + if (this.filteredDatas.hasOwnProperty(key)) { + + let values = this.filteredDatas[key].split(','); + + let chipIndex = values.indexOf(chip); + + if (chipIndex > -1) { + values.splice(chipIndex, 1); + + let newValue = values.join(','); + + if (newValue === '') { + delete this.filteredDatas[key]; + } else { + this.filteredDatas[key] = newValue; + } + } + } + } + } + + async getMentors(){ + var obj = {page: this.page, pageSize: this.pageSize, searchText: this.searchText, selectedChip: this.selectedChipName, urlQueryData: this.urlQueryData}; + let data = await this.profileService.getMentors(true,obj); + this.data = data.result.data; + this.totalCount = data.result.count; + } + +} diff --git a/src/app/pages/tabs/home/home.module.ts b/src/app/pages/tabs/home/home.module.ts index 891c3b05..3bf70e13 100644 --- a/src/app/pages/tabs/home/home.module.ts +++ b/src/app/pages/tabs/home/home.module.ts @@ -8,6 +8,7 @@ import { HomePageRoutingModule } from './home-routing.module'; import { SharedModule } from 'src/app/shared/shared.module'; import { HttpClientModule } from '@angular/common/http'; import { CoreModule } from 'src/app/core/core.module'; +import {OverlayModule} from '@angular/cdk/overlay' @NgModule({ imports: [ @@ -18,6 +19,7 @@ import { CoreModule } from 'src/app/core/core.module'; SharedModule, CoreModule, HttpClientModule, + OverlayModule ], declarations: [HomePage], }) diff --git a/src/app/pages/tabs/home/home.page.html b/src/app/pages/tabs/home/home.page.html index dce3fea1..aaa1bf82 100644 --- a/src/app/pages/tabs/home/home.page.html +++ b/src/app/pages/tabs/home/home.page.html @@ -7,12 +7,38 @@

-->
- +
+ + +
+ + + + {{ chip.label }} + + +
+
+
{{"CONNECT_SHARE_&_INSPIRE"|translate}} diff --git a/src/app/pages/tabs/home/home.page.scss b/src/app/pages/tabs/home/home.page.scss index 3fa25dbb..29f4f901 100644 --- a/src/app/pages/tabs/home/home.page.scss +++ b/src/app/pages/tabs/home/home.page.scss @@ -115,4 +115,34 @@ img { .mentor-card-button { min-width: 100%; --border-radius:8px; +} + + + +.overlay-container { + background-color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 16px; + max-width: 100%; + z-index: 1000; +} +.chip { + font-size: 14px; + align-items: center; + display: inline-block; + text-decoration: none; + ion-icon { + color: white; + } + &.selected-chip { + background-color: var(--ion-color-primary); + color: white; + } +} +.chip-container { + display: flex; + white-space: nowrap; + width: calc(100% - 100px); + scrollbar-width: none; } \ No newline at end of file diff --git a/src/app/pages/tabs/home/home.page.ts b/src/app/pages/tabs/home/home.page.ts index 269b093e..45b45ea9 100644 --- a/src/app/pages/tabs/home/home.page.ts +++ b/src/app/pages/tabs/home/home.page.ts @@ -13,6 +13,7 @@ import { SessionService } from 'src/app/core/services/session/session.service'; import { TermsAndConditionsPage } from '../../terms-and-conditions/terms-and-conditions.page'; import { App, AppState } from '@capacitor/app'; import { Capacitor } from '@capacitor/core'; +import { PermissionService } from 'src/app/core/services/permission/permission.service'; @Component({ @@ -46,6 +47,10 @@ export class HomePage implements OnInit { createdSessions: any; isMentor: boolean; userEventSubscription: any; + isOpen = false; + + chips= []; + criteriaChip: any; constructor( private http: HttpClient, private router: Router, @@ -57,7 +62,8 @@ export class HomePage implements OnInit { private modalController: ModalController, private userService: UserService, private localStorage: LocalStorageService, - private toast: ToastService) { } + private toast: ToastService, + private permissionService: PermissionService) { } ngOnInit() { this.isMentor = this.profileService.isMentor @@ -85,6 +91,9 @@ export class HomePage implements OnInit { } }) this.user = this.localStorage.getLocalData(localKeys.USER_DETAILS) + this.permissionService.getPlatformConfig().then((config)=>{ + this.chips = config.result.search_config.search.session.fields; + }) } gotToTop() { this.content.scrollToTop(1000); @@ -137,8 +146,12 @@ export class HomePage implements OnInit { this.router.navigate([`/${CommonRoutes.SESSIONS}`], { queryParams: { type: data } }); } - search() { - this.router.navigate([`/${CommonRoutes.HOME_SEARCH}`]); + search(q: string) { + this.isOpen = false; + if(q){ + this.router.navigate([`/${CommonRoutes.HOME_SEARCH}`], {queryParams: { criteriaChip: JSON.stringify(this.criteriaChip), searchString: q}}); + } + this.criteriaChip = null; } getUser() { this.profileService.profileDetails().then(data => { @@ -151,16 +164,10 @@ export class HomePage implements OnInit { } async getSessions() { - const config = { - url: urlConstants.API_URLS.HOME_SESSION + this.page + '&limit=' + this.limit, - }; - try { - let data: any = await this.httpService.get(config); - this.sessions = data.result; - this.sessionsCount = data.result.count; - } - catch (error) { - } + var obj = {page: this.page, limit: this.limit} + let data = await this.sessionService.getSessions(obj); + this.sessions = data.result; + this.sessionsCount = data.result.count; } async openModal() { const modal = await this.modalController.create({ @@ -208,4 +215,8 @@ export class HomePage implements OnInit { this.userEventSubscription.unsubscribe(); } } + + selectChip(chip: any) { + this.criteriaChip = chip; + } } diff --git a/src/app/pages/tabs/mentor-directory/mentor-directory.module.ts b/src/app/pages/tabs/mentor-directory/mentor-directory.module.ts index a178c6ab..f760003d 100644 --- a/src/app/pages/tabs/mentor-directory/mentor-directory.module.ts +++ b/src/app/pages/tabs/mentor-directory/mentor-directory.module.ts @@ -10,6 +10,7 @@ import { MentorDirectoryPage } from './mentor-directory.page'; import { TranslateModule } from '@ngx-translate/core'; import { CoreModule } from 'src/app/core/core.module'; import { SharedModule } from 'src/app/shared/shared.module'; +import {OverlayModule} from '@angular/cdk/overlay' @NgModule({ imports: [ @@ -19,7 +20,8 @@ import { SharedModule } from 'src/app/shared/shared.module'; IonicModule, SharedModule, TranslateModule, - MentorDirectoryPageRoutingModule + MentorDirectoryPageRoutingModule, + OverlayModule ], declarations: [MentorDirectoryPage] }) diff --git a/src/app/pages/tabs/mentor-directory/mentor-directory.page.html b/src/app/pages/tabs/mentor-directory/mentor-directory.page.html index 36029700..0b643a32 100644 --- a/src/app/pages/tabs/mentor-directory/mentor-directory.page.html +++ b/src/app/pages/tabs/mentor-directory/mentor-directory.page.html @@ -1,27 +1,24 @@ - -
- +
-
+
-
-
- {{mentor.key}} +
+
+ {{mentor.key}} +
+ + + + + + + +
- - - - - - - -
-
diff --git a/src/app/pages/tabs/mentor-directory/mentor-directory.page.ts b/src/app/pages/tabs/mentor-directory/mentor-directory.page.ts index 7f947fe1..14aa0e62 100644 --- a/src/app/pages/tabs/mentor-directory/mentor-directory.page.ts +++ b/src/app/pages/tabs/mentor-directory/mentor-directory.page.ts @@ -1,11 +1,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { IonContent, IonInfiniteScroll } from '@ionic/angular'; import { urlConstants } from 'src/app/core/constants/urlConstants'; import { HttpService, - LoaderService, - ToastService + LoaderService } from 'src/app/core/services'; import { CommonRoutes } from 'src/global.routes'; @@ -23,7 +22,7 @@ export class MentorDirectoryPage implements OnInit { searchText: string = ''; public headerConfig: any = { menu: true, - label: 'MENTORS_DIRECTORY', + // label: 'MENTORS_DIRECTORY', headerColor: 'primary', notification: false, }; @@ -31,26 +30,32 @@ export class MentorDirectoryPage implements OnInit { mentors = []; mentorsCount; isLoaded: boolean = false; + filterData : any; + filteredDatas = [] + chips =[] + setPaginatorToFirstpage: boolean; + criteriaData = [] + isOpen = false; + selectedChipLabel: any; + overlayChips = []; + selectedChipName: any; + urlFilterData: string; + directory: boolean = true; + selectedChips: boolean = false; + data: any; constructor( private router: Router, private loaderService: LoaderService, - private httpService: HttpService, - private route: ActivatedRoute + private httpService: HttpService ) { } - ngOnInit() { - this.route.queryParamMap.subscribe((queryParams) => { - this.searchText = queryParams.get('search'); - this.searchText = this.searchText === null ? '' : this.searchText; - }); - } + ngOnInit() {} - ionViewWillEnter() { + async ionViewWillEnter() { this.page = 1; this.mentors = []; - this.searchText = ''; this.getMentors(); this.gotToTop(); } @@ -62,11 +67,12 @@ export class MentorDirectoryPage implements OnInit { async getMentors(showLoader = true) { showLoader ? await this.loaderService.startLoader() : ''; const config = { - url: urlConstants.API_URLS.MENTORS_DIRECTORY_LIST + this.page + '&limit=' + this.limit + '&search=' + btoa(this.searchText) + '&directory=true', + url: urlConstants.API_URLS.MENTORS_DIRECTORY_LIST + this.page + '&limit=' + this.limit + '&search=' + btoa(this.searchText) + '&directory=' + this.directory + '&search_on=' + (this.selectedChipName? this.selectedChipName : '') + '&' + (this.urlFilterData ? this.urlFilterData: ''), payload: {} }; try { let data: any = await this.httpService.get(config); + this.data = data.result.data; this.isLoaded = true showLoader ? await this.loaderService.stopLoader() : ''; if (this.mentors.length && this.mentors[this.mentors.length - 1].key == data.result.data[0]?.key) { @@ -93,17 +99,14 @@ export class MentorDirectoryPage implements OnInit { } } async loadMore(event) { - this.page = this.page + 1; - await this.getMentors(false); + if(this.data){ + this.page = this.directory ? this.page + 1 : this.page; + await this.getMentors(false); + } event.target.complete(); } onSearch(){ - this.isLoaded = false; - this.page = 1; - if (this.searchText) { - this.router.navigate([CommonRoutes.TABS + '/' + CommonRoutes.MENTOR_DIRECTORY], { queryParams: { search: this.searchText } }); - } - this.getMentors(); - this.mentors = []; + this.router.navigate(['/' + CommonRoutes.MENTOR_SEARCH_DIRECTORY], { queryParams: { search: this.searchText } }); } + } diff --git a/src/app/shared/components/filter-popup/filter-popup.component.html b/src/app/shared/components/filter-popup/filter-popup.component.html index 46ae2409..10c190ae 100644 --- a/src/app/shared/components/filter-popup/filter-popup.component.html +++ b/src/app/shared/components/filter-popup/filter-popup.component.html @@ -5,7 +5,7 @@
- + {{"APPLY"|translate}} diff --git a/src/app/shared/components/filter-tree/filter-tree.component.html b/src/app/shared/components/filter-tree/filter-tree.component.html index 702eded5..9d7edc34 100644 --- a/src/app/shared/components/filter-tree/filter-tree.component.html +++ b/src/app/shared/components/filter-tree/filter-tree.component.html @@ -1,6 +1,5 @@ -
- {{"FILTER"|translate}} +
{{"CLEAR_ALL"|translate}}
diff --git a/src/app/shared/components/filter-tree/filter-tree.component.scss b/src/app/shared/components/filter-tree/filter-tree.component.scss index 8e7ccef4..ea578937 100644 --- a/src/app/shared/components/filter-tree/filter-tree.component.scss +++ b/src/app/shared/components/filter-tree/filter-tree.component.scss @@ -5,17 +5,16 @@ } .wrapper-class { display: flex; - justify-content: space-between; + justify-content: end; + padding: 5px 5px; } .underline { - border-bottom: 1px solid black; cursor: pointer; + font-weight: bold; } .sub-header { font-weight: bold; font-size: 16px; - padding-bottom: 16px; - // letter-spacing: 1px; } ion-checkbox { --border-color: var(--ion-color-primary) diff --git a/src/app/shared/components/generic-search/generic-search.component.html b/src/app/shared/components/generic-search/generic-search.component.html new file mode 100644 index 00000000..40960d66 --- /dev/null +++ b/src/app/shared/components/generic-search/generic-search.component.html @@ -0,0 +1,33 @@ +
+
+
+ + + + {{"SESSSION_SEARCH_RESULT" | translate}} "{{searchValue}}" +
+
+ {{totalCount}} {{"SEARCH_RESULT" | translate}} +
+
+
+ +
+
+
+ + + +
+ + +
+
+ + + +
+
+
\ No newline at end of file diff --git a/src/app/shared/components/generic-search/generic-search.component.scss b/src/app/shared/components/generic-search/generic-search.component.scss new file mode 100644 index 00000000..eae6bd73 --- /dev/null +++ b/src/app/shared/components/generic-search/generic-search.component.scss @@ -0,0 +1,16 @@ +.search-navigation{ + display: flex; + justify-content: space-between; +} +.search-result-count{ + display: flex; + padding-left: 24%; +} +.search-result-label{ + display: flex; + align-items: center; +} +.search-result-count{ + display: flex; + padding-left: 24%; +} \ No newline at end of file diff --git a/src/app/shared/components/generic-search/generic-search.component.spec.ts b/src/app/shared/components/generic-search/generic-search.component.spec.ts new file mode 100644 index 00000000..f3fe712c --- /dev/null +++ b/src/app/shared/components/generic-search/generic-search.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { IonicModule } from '@ionic/angular'; + +import { GenericSearchComponent } from './generic-search.component'; + +describe('GenericSearchComponent', () => { + let component: GenericSearchComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ GenericSearchComponent ], + imports: [IonicModule.forRoot()] + }).compileComponents(); + + fixture = TestBed.createComponent(GenericSearchComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/generic-search/generic-search.component.ts b/src/app/shared/components/generic-search/generic-search.component.ts new file mode 100644 index 00000000..0400b86c --- /dev/null +++ b/src/app/shared/components/generic-search/generic-search.component.ts @@ -0,0 +1,49 @@ +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { MatPaginator } from '@angular/material/paginator'; +import { paginatorConstants } from 'src/app/core/constants/paginatorConstants'; + +@Component({ + selector: 'app-generic-search', + templateUrl: './generic-search.component.html', + styleUrls: ['./generic-search.component.scss'], +}) +export class GenericSearchComponent implements OnInit { + + @Input() results: any; + @Input() totalCount: any; + @Input() searchValue: any; + @Output() onPageChangeEvent = new EventEmitter(); + @ViewChild(MatPaginator) paginator!: MatPaginator; + @Output() onClickEvent = new EventEmitter(); + pageSize = paginatorConstants.defaultPageSize; + pageSizeOptions = paginatorConstants.pageSizeOptions; + createdSessions: any; + user: any; + sessions: any; + page = 1; + limit = 5; + + constructor() { } + + async ngOnInit() { } + + async onPageChange(event) { + this.page = event.pageIndex + 1, + this.pageSize = this.paginator.pageSize; + let value = { + page: this.page, + pageSize: this.pageSize, + pageOption: this.pageSizeOptions + } + this.onPageChangeEvent.emit(value) + } + async eventAction(event) { + let value = { + data: event.data, + type: event.type, + } + this.onClickEvent.emit(value); + } + + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 0bf8668c..42e2c677 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -43,6 +43,7 @@ import { MenteeListPopupComponent } from './components/mentee-list-popup/mentee- import { BulkUploadComponent } from './components/bulk-upload/bulk-upload.component'; import { UserListModalComponent } from './components/user-list-modal/user-list-modal.component'; import { snakeCaseToUpperCasePipe } from '../core/pipes/snake-case-to-normal-case.pipe'; +import { GenericSearchComponent } from './components/generic-search/generic-search.component'; @NgModule({ declarations: [ @@ -76,7 +77,8 @@ import { snakeCaseToUpperCasePipe } from '../core/pipes/snake-case-to-normal-cas MenteeListPopupComponent, BulkUploadComponent, UserListModalComponent, - snakeCaseToUpperCasePipe + snakeCaseToUpperCasePipe, + GenericSearchComponent ], imports: [ CommonModule, @@ -124,7 +126,8 @@ import { snakeCaseToUpperCasePipe } from '../core/pipes/snake-case-to-normal-cas MenteeListPopupComponent, BulkUploadComponent, UserListModalComponent, - snakeCaseToUpperCasePipe + snakeCaseToUpperCasePipe, + GenericSearchComponent ], }) export class SharedModule {} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 69754025..72d683ad 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -269,5 +269,9 @@ "VALIDATE_OTP": "Validate OTP", "CREATE_SESSIONS": "Create sessions", "VIEW_ROLES": "View roles", - "ROLES": "Roles" + "ROLES": "Roles", + "NO_SESSIONS_AVAILABLE":"No sessions available", + "SESSSION_SEARCH_RESULT": "Session search result for", + "SEARCH_RESULT": "Search results found", + "MENTOR_SEARCH_RESULT": "Mentors search result for" } \ No newline at end of file diff --git a/src/global.routes.ts b/src/global.routes.ts index b59731c2..e19b46b5 100644 --- a/src/global.routes.ts +++ b/src/global.routes.ts @@ -34,4 +34,5 @@ export class CommonRoutes { public static MANAGERS_SESSION_DETAILS = 'managers-session-details' public static CHANGE_PASSWORD = 'change-password' public static LOGIN_ACTIVITY = 'login-activity' + public static MENTOR_SEARCH_DIRECTORY = 'mentor-search-directory' } \ No newline at end of file