From 810f526fa9a3005e844a9705242f21d97231f81b Mon Sep 17 00:00:00 2001 From: Bozhen Date: Wed, 6 Nov 2024 18:36:20 +0200 Subject: [PATCH] feat: Show total in front of each section header in search results When using search, show not only a total number of results, but also total number for each section separately. Resolves: #7745 --- src/app/main/model/search/search.model.ts | 15 +------ src/app/main/service/search/search.service.ts | 7 ++-- .../search-popup/search-popup.component.html | 18 +++++--- .../search-popup/search-popup.component.scss | 4 ++ .../search-popup.component.spec.ts | 41 +++++-------------- .../search-popup/search-popup.component.ts | 30 ++++++++------ 6 files changed, 52 insertions(+), 63 deletions(-) diff --git a/src/app/main/model/search/search.model.ts b/src/app/main/model/search/search.model.ts index ae64286a46..8fe72c8e6e 100644 --- a/src/app/main/model/search/search.model.ts +++ b/src/app/main/model/search/search.model.ts @@ -1,17 +1,6 @@ -import { NewsSearchModel } from './newsSearch.model'; -import { TipsSearchModel } from './tipsSearch.model'; -import { EventsSearchModel } from './eventsSearch.model'; - -export interface SearchModel { - countOfResults: number; - ecoNews: Array; - events: Array; - tipsAndTricks: Array; -} - -export interface SearchDataModel { +export interface SearchDataModel { currentPage: number; - page: Array; + page: Array; totalElements: number; totalPages: number; } diff --git a/src/app/main/service/search/search.service.ts b/src/app/main/service/search/search.service.ts index 81a011c20c..7a6b81087d 100644 --- a/src/app/main/service/search/search.service.ts +++ b/src/app/main/service/search/search.service.ts @@ -2,8 +2,9 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment } from '@environment/environment'; import { Observable, Subject } from 'rxjs'; -import { SearchDataModel, SearchModel } from '../../model/search/search.model'; +import { SearchDataModel } from '../../model/search/search.model'; import { SearchDto } from 'src/app/main/component/layout/components/models/search-dto'; +import { SearchCategory } from 'src/app/shared/search-popup/search-consts'; @Injectable({ providedIn: 'root' @@ -15,8 +16,8 @@ export class SearchService { allSearchSubject = new Subject(); allElements: SearchDto; - getAllResults(searchQuery: string, category, lang: string): Observable { - return this.http.get(`${this.backEndLink}search/${category}?lang=${lang}&searchQuery=${encodeURI(searchQuery)}`); + getAllResults(searchQuery: string, category: SearchCategory, lang: string): Observable { + return this.http.get(`${this.backEndLink}search/${category}?lang=${lang}&searchQuery=${encodeURI(searchQuery)}`); } getAllResultsByCat( diff --git a/src/app/shared/search-popup/search-popup.component.html b/src/app/shared/search-popup/search-popup.component.html index ca99cc05e8..7eaa1cabf4 100644 --- a/src/app/shared/search-popup/search-popup.component.html +++ b/src/app/shared/search-popup/search-popup.component.html @@ -23,11 +23,13 @@
- {{ itemsFound }} {{ 'search.search-popup.items-found' | translate }} + {{ resultsCounters.total }} {{ 'search.search-popup.items-found' | translate }}
-

{{ 'search.search-popup.news' | translate }}

+

+ {{ 'search.search-popup.news' | translate }} ({{ resultsCounters.news }}) +

{{ 'search.search-popup.news' | translate }}
- diff --git a/src/app/shared/search-popup/search-popup.component.scss b/src/app/shared/search-popup/search-popup.component.scss index 1fffc7dc3c..2e6f5cd044 100644 --- a/src/app/shared/search-popup/search-popup.component.scss +++ b/src/app/shared/search-popup/search-popup.component.scss @@ -136,6 +136,10 @@ div.search-content-wrapper { display: block; } +span.counter { + opacity: 0.5; +} + @media (min-width: 576px) { .list-search-items { grid-template-columns: repeat(2, 254px); diff --git a/src/app/shared/search-popup/search-popup.component.spec.ts b/src/app/shared/search-popup/search-popup.component.spec.ts index bb0d3c7bf4..34d0ced308 100644 --- a/src/app/shared/search-popup/search-popup.component.spec.ts +++ b/src/app/shared/search-popup/search-popup.component.spec.ts @@ -18,6 +18,9 @@ import { LocalStorageService } from '@global-service/localstorage/local-storage. import { SharedModule } from 'src/app/shared/shared.module'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { EventsSearchModel } from '@global-models/search/eventsSearch.model'; +import { SearchDataModel } from '@global-models/search/search.model'; +import { SearchCategory } from './search-consts'; describe('SearchPopupComponent', () => { let component: SearchPopupComponent; @@ -26,28 +29,6 @@ describe('SearchPopupComponent', () => { const localStorageServiceMock: LocalStorageService = jasmine.createSpyObj('LocalStorageService', ['getCurrentLanguage']); localStorageServiceMock.getCurrentLanguage = () => 'ua' as Language; - const mockTipData = { - id: 1, - title: 'test', - author: { - id: 1, - name: 'test' - }, - creationDate: '0101', - tags: ['test'] - }; - - const mockNewsData = { - id: 1, - title: 'test', - author: { - id: 1, - name: 'test' - }, - creationDate: '0101', - tags: ['test'] - }; - const mockEventsData = { id: 1, title: 'test', @@ -55,16 +36,16 @@ describe('SearchPopupComponent', () => { tags: ['test'] }; - const searchModelMock = { - countOfResults: 2, - ecoNews: [mockNewsData], - events: [mockEventsData], - tipsAndTricks: [mockTipData] + const eventsSearchModelMock: SearchDataModel = { + currentPage: 1, + page: [mockEventsData], + totalElements: 1, + totalPages: 1 }; const searchMock: SearchService = jasmine.createSpyObj('SearchService', ['getAllResults']); searchMock.searchSubject = new Subject(); - searchMock.getAllResults = () => of(searchModelMock); + searchMock.getAllResults = () => of(eventsSearchModelMock); searchMock.closeSearchSignal = () => true; beforeEach(waitForAsync(() => { @@ -113,12 +94,12 @@ describe('SearchPopupComponent', () => { describe('Testing services:', () => { it('should handle search value changes', fakeAsync(() => { - const getSearchSpy = spyOn(component.searchService, 'getAllResults').and.returnValue(of(searchModelMock)); + const getSearchSpy = spyOn(component.searchService, 'getAllResults').and.returnValue(of(eventsSearchModelMock)); component.ngOnInit(); component.searchInput.setValue('test'); tick(300); - expect(getSearchSpy).toHaveBeenCalledWith('test', 'econews', 'ua'); + expect(getSearchSpy).toHaveBeenCalledWith('test', SearchCategory.EVENTS, 'ua'); })); it('closeSearch should open SearchService/closeSearchSignal', () => { diff --git a/src/app/shared/search-popup/search-popup.component.ts b/src/app/shared/search-popup/search-popup.component.ts index 224c4cd950..187755fe79 100644 --- a/src/app/shared/search-popup/search-popup.component.ts +++ b/src/app/shared/search-popup/search-popup.component.ts @@ -20,10 +20,14 @@ import { SearchCategory } from './search-consts'; styleUrls: ['./search-popup.component.scss'] }) export class SearchPopupComponent implements OnInit, OnDestroy { + resultsCounters: { + news: number; + events: number; + total: number; + } = { events: null, news: null, total: null }; newsElements: NewsSearchModel[] = []; eventsElements: EventsSearchModel[] = []; isSearchClicked = false; - itemsFound: number = null; searchModalSubscription: Subscription; searchInput = new FormControl(''); isLoading = false; @@ -53,15 +57,15 @@ export class SearchPopupComponent implements OnInit, OnDestroy { this.resetData(); this.isLoading = true; }), - switchMap((val: string) => { + switchMap((query: string) => { this.currentLanguage = this.localStorageService.getCurrentLanguage(); - return forkJoin([ - this.searchService.getAllResults(val, SearchCategory.NEWS, this.currentLanguage), - this.searchService.getAllResults(val, SearchCategory.EVENTS, this.currentLanguage) - ]); + return forkJoin({ + news: this.searchService.getAllResults(query, SearchCategory.NEWS, this.currentLanguage), + events: this.searchService.getAllResults(query, SearchCategory.EVENTS, this.currentLanguage) + }); }) ) - .subscribe((data: SearchDataModel[]) => { + .subscribe((data: { news: SearchDataModel; events: SearchDataModel }) => { this.setData(data); }); @@ -80,12 +84,14 @@ export class SearchPopupComponent implements OnInit, OnDestroy { this.snackBar.openSnackBar('error'); } - private setData(data: SearchDataModel[]): void { + private setData(data: { news: SearchDataModel; events: SearchDataModel }): void { this.isLoading = false; - this.newsElements = data[0].page; - this.eventsElements = data[1].page; - this.itemsFound = data[0].totalElements + data[1].totalElements; + this.newsElements = data.news.page; + this.eventsElements = data.events.page; + this.resultsCounters.events = data.events.totalElements; + this.resultsCounters.news = data.news.totalElements; + this.resultsCounters.total = data.events.totalElements + data.news.totalElements; } private subscribeToSignal(signal: boolean): void { @@ -104,7 +110,7 @@ export class SearchPopupComponent implements OnInit, OnDestroy { private resetData(): void { this.newsElements = []; this.eventsElements = []; - this.itemsFound = null; + this.resultsCounters = { events: null, news: null, total: null }; } ngOnDestroy() {