diff --git a/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.html b/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.html index 658146ba7b..c966f16a2e 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.html +++ b/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.html @@ -3,8 +3,14 @@
-

- {{ tag }} +

+ {{ tag }} + |

diff --git a/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.scss b/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.scss index 8ac6ca8456..62ec360539 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.scss +++ b/src/app/main/component/eco-news/components/news-list/news-list-list-view/news-list-list-view.component.scss @@ -19,13 +19,24 @@ div { display: none; } +.tag-divider { + color: var(--primary-light-green); + height: 100%; + padding: 0 4px; + margin: 0 4px; +} + +.divider-small { + margin: 0 2px; + padding: 0; +} + .eco-news_list-tag { font-family: var(--primary-font); font-size: 12px; line-height: 16px; text-transform: uppercase; color: var(--primary-green); - margin-right: 5px; } .eco-news_list-content { diff --git a/src/app/main/component/eco-news/components/news-list/news-list.component.html b/src/app/main/component/eco-news/components/news-list/news-list.component.html index 78c542a296..bb1fce2049 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list.component.html +++ b/src/app/main/component/eco-news/components/news-list/news-list.component.html @@ -3,6 +3,27 @@

{{ 'homepage.eco-news.title' | translate }}

+
+
+ + cancel search +
+
+ +
+
+ +
+
+ my-event +
+
{{ 'homepage.eco-news.create' | translate }} @@ -34,9 +55,17 @@

{{ 'homepage.eco-news.title' | translate }}

}" *ngFor="let data of elements" > -
+ + +
+ +
diff --git a/src/app/main/component/eco-news/components/news-list/news-list.component.scss b/src/app/main/component/eco-news/components/news-list/news-list.component.scss index f593de22f8..da2dde03a0 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list.component.scss +++ b/src/app/main/component/eco-news/components/news-list/news-list.component.scss @@ -48,6 +48,140 @@ div hr { } } +.create-container { + height: 40px; + display: flex; + flex-direction: row; + align-items: center; + gap: 24px; + flex: 1; + justify-content: flex-end; + margin-right: 30px; + + @include responsivePCFirst(sm) { + flex-direction: row; + gap: 18px; + } +} + +.container-img { + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--primary-white); + border-radius: 4px; + box-shadow: 0 0 1px 0 var(--primary-grey); + cursor: pointer; + + span { + transition: all 0.3s; + } + + .search-img { + min-width: 20px; + min-height: 20px; + background: url('/assets/events-icons/search.png'); + display: inline-block; + + &:hover { + background: url('/assets/events-icons/search-hover.png'); + } + } + + .search-img-active { + min-width: 20px; + min-height: 20px; + background: url('/assets/events-icons/search-active.png'); + } + + .bookmark-img { + width: 12px; + height: 17px; + background: url('/assets/events-icons/bookmark-grey.png'); + } + + .bookmark-img-active { + width: 12px; + height: 17px; + background: url('/assets/events-icons/bookmark-active.png'); + } +} + +.container-input { + position: relative; + margin-left: 15px; + flex: 1; + + .cross-position { + position: absolute; + top: 14px; + right: 10px; + cursor: pointer; + } + + .place-input { + border: none; + border-radius: 4px; + width: 100%; + box-shadow: 0 0 1px 0 var(--primary-grey); + height: 40px; + padding: 0 14px; + + &:active, + &:focus, + &:hover { + border: 1px solid var(--primary-grey); + outline: none; + } + } +} + +.link { + position: relative; +} + +.news-flags { + width: 40px; + height: 40px; + background-color: rgba(255 255 255/ 80%); + position: absolute; + top: 8px; + right: 8px; + border-radius: 5px; + display: flex; + flex-direction: row; + gap: 10px; + padding: 8px; + justify-content: center; + align-items: center; + box-shadow: 0 0 1px 0 var(--primary-grey); + cursor: pointer; + + span { + display: inline-block; + width: 12px; + height: 16.5px; + transition: all 0.3s; + } + + .flag { + background: url('/assets/img/places/bookmark-default.svg') no-repeat center; + background-size: contain; + } + + .flag-active { + background: url('/assets/img/places/bookmark-set.svg') no-repeat center; + background-size: contain; + } +} + +.my-events-img { + width: 17px; + height: 17px; +} + .gallery-view-active { display: grid; grid-template-columns: repeat(3, 359px); diff --git a/src/app/main/component/eco-news/components/news-list/news-list.component.spec.ts b/src/app/main/component/eco-news/components/news-list/news-list.component.spec.ts index 9790b9fb74..c8818f6255 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list.component.spec.ts +++ b/src/app/main/component/eco-news/components/news-list/news-list.component.spec.ts @@ -18,17 +18,15 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { Store } from '@ngrx/store'; import { Language } from '../../../../i18n/Language'; +import { MatDialog } from '@angular/material/dialog'; +import { ChangeEcoNewsFavoriteStatusAction } from 'src/app/store/actions/ecoNews.actions'; describe('NewsListComponent', () => { let component: NewsListComponent; let fixture: ComponentFixture; - const ecoNewsServiceMock: EcoNewsService = jasmine.createSpyObj('EcoNewsService', [ - 'getAllPresentTags', - 'getNewsListByTags', - 'getEcoNewsListByPage' - ]); - ecoNewsServiceMock.getNewsListByTags = () => new Observable(); + const ecoNewsServiceMock: EcoNewsService = jasmine.createSpyObj('EcoNewsService', ['getAllPresentTags', 'getEcoNewsListByPage']); + ecoNewsServiceMock.getEcoNewsListByPage = () => new Observable(); const localStorageServiceMock: LocalStorageService = jasmine.createSpyObj('LocalStorageService', [ @@ -46,6 +44,31 @@ describe('NewsListComponent', () => { userOwnAuthServiceMock.credentialDataSubject = new Subject(); userOwnAuthServiceMock.isLoginUserSubject = new BehaviorSubject(true); + const newsMock = { + countComments: 5, + id: 13578, + imagePath: null, + title: '', + text: '', + content: '', + shortInfo: '', + tags: ['News', 'Events'], + tagsEn: ['News'], + tagsUa: ['Новини'], + creationDate: '2021-11-25T22:32:30.555088+02:00', + likes: 0, + source: '', + author: { id: 312, name: 'taqcTestName' } + }; + + const matDialogRefMock = { + afterClosed: jasmine.createSpy('afterClosed').and.returnValue(of(true)) + }; + + const matDialogMock = { + open: jasmine.createSpy('open').and.returnValue(matDialogRefMock) + }; + const storeMock = jasmine.createSpyObj('store', ['select', 'dispatch']); storeMock.select = () => of({ ecoNews: {}, pages: [], pageNumber: 1, error: 'error' }); @@ -70,7 +93,8 @@ describe('NewsListComponent', () => { { provide: LocalStorageService, useValue: localStorageServiceMock }, { provide: EcoNewsService, useValue: ecoNewsServiceMock }, { provide: UserOwnAuthService, useValue: userOwnAuthServiceMock }, - { provide: Store, useValue: storeMock } + { provide: Store, useValue: storeMock }, + { provide: MatDialog, useValue: matDialogMock } ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }).compileComponents(); @@ -80,6 +104,7 @@ describe('NewsListComponent', () => { fixture = TestBed.createComponent(NewsListComponent); component = fixture.componentInstance; fixture.detectChanges(); + storeMock.dispatch.calls.reset(); }); it('should create', () => { @@ -89,6 +114,15 @@ describe('NewsListComponent', () => { it('should add elements to current list if scroll', () => { spyOn(component, 'dispatchStore'); component.onScroll(); + expect(component.dispatchStore).toHaveBeenCalledTimes(0); + }); + + it('should dispatch store action on scroll when elements are present', () => { + component.elements = [newsMock, { ...newsMock, id: 2 }]; + + spyOn(component, 'dispatchStore'); + component.onScroll(); + expect(component.dispatchStore).toHaveBeenCalledWith(false); expect(component.dispatchStore).toHaveBeenCalledTimes(1); }); @@ -109,4 +143,39 @@ describe('NewsListComponent', () => { component.getFilterData(['News']); expect(component.getFilterData).toHaveBeenCalledWith(['News']); }); + + it('should cancel search correctly', () => { + component.searchNewsControl.setValue('test'); + component.cancelSearch(); + expect(component.searchNewsControl.value).toBe(''); + }); + + it('should toggle search state', () => { + component.isSearchVisible = false; + component.toggleSearch(); + expect(component.isSearchVisible).toBeTrue(); + }); + + it('should change favorite status when user is logged in', () => { + const event = new MouseEvent('click'); + const data = { ...newsMock, favorite: false }; + component.userId = 1; + + component.changeFavoriteStatus(event, data); + + const expectedAction = ChangeEcoNewsFavoriteStatusAction({ + id: data.id, + favorite: true, + isFavoritesPage: component.bookmarkSelected + }); + + expect(storeMock.dispatch).toHaveBeenCalledWith(expectedAction); + }); + + it('should toggle bookmarked news display', () => { + component.userId = 1; + component.bookmarkSelected = false; + component.showSelectedNews(); + expect(component.bookmarkSelected).toBeTrue(); + }); }); diff --git a/src/app/main/component/eco-news/components/news-list/news-list.component.ts b/src/app/main/component/eco-news/components/news-list/news-list.component.ts index 3296a5d065..81f86fda66 100644 --- a/src/app/main/component/eco-news/components/news-list/news-list.component.ts +++ b/src/app/main/component/eco-news/components/news-list/news-list.component.ts @@ -1,19 +1,21 @@ import { Breakpoints } from '../../../../config/breakpoints.constants'; import { Component, OnInit, OnDestroy } from '@angular/core'; -import { ReplaySubject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { EcoNewsService } from '@eco-news-service/eco-news.service'; +import { Observable, of, ReplaySubject } from 'rxjs'; +import { map, take, takeUntil } from 'rxjs/operators'; import { EcoNewsModel } from '@eco-news-models/eco-news-model'; import { FilterModel } from '@shared/components/tag-filter/tag-filter.model'; import { UserOwnAuthService } from '@auth-service/user-own-auth.service'; -import { MatSnackBarComponent } from '@global-errors/mat-snack-bar/mat-snack-bar.component'; import { LocalStorageService } from '@global-service/localstorage/local-storage.service'; import { Store } from '@ngrx/store'; import { IAppState } from 'src/app/store/state/app.state'; import { IEcoNewsState } from 'src/app/store/state/ecoNews.state'; -import { GetEcoNewsByTagsAction, GetEcoNewsByPageAction } from 'src/app/store/actions/ecoNews.actions'; -import { Router } from '@angular/router'; +import { GetEcoNewsAction, ChangeEcoNewsFavoriteStatusAction } from 'src/app/store/actions/ecoNews.actions'; import { tagsListEcoNewsData } from '@eco-news-models/eco-news-consts'; +import { FormControl, Validators } from '@angular/forms'; +import { Patterns } from '@assets/patterns/patterns'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { AuthModalComponent } from '@global-auth/auth-modal/auth-modal.component'; +import { EcoNewsService } from '@eco-news-service/eco-news.service'; @Component({ selector: 'app-news-list', @@ -28,24 +30,31 @@ export class NewsListComponent implements OnInit, OnDestroy { remaining = 0; windowSize: number; isLoggedIn: boolean; - private currentPage: number; + userId: number; scroll: boolean; numberOfNews: number; + newsTotal: number; elementsArePresent = true; tagList: FilterModel[] = tagsListEcoNewsData; private destroyed$: ReplaySubject = new ReplaySubject(1); - + bookmarkSelected = false; hasNext = true; - + loading = false; + private page = 0; + noNewsMatch = false; + isSearchVisible = false; + searchNewsControl = new FormControl('', [Validators.maxLength(30), Validators.pattern(Patterns.NameInfoPattern)]); econews$ = this.store.select((state: IAppState): IEcoNewsState => state.ecoNewsState); + searchQuery = ''; + + private dialogRef: MatDialogRef; constructor( - private ecoNewsService: EcoNewsService, private userOwnAuthService: UserOwnAuthService, - private snackBar: MatSnackBarComponent, private localStorageService: LocalStorageService, private store: Store, - private router: Router + private readonly dialog: MatDialog, + private readonly ecoNewsService: EcoNewsService ) {} ngOnInit() { @@ -55,11 +64,10 @@ export class NewsListComponent implements OnInit, OnDestroy { this.userOwnAuthService.getDataFromLocalStorage(); this.scroll = false; this.setLocalizedTags(); - - this.dispatchStore(false); + this.localStorageService.setCurentPage('previousPage', '/news'); this.econews$.subscribe((value: IEcoNewsState) => { - this.currentPage = value.pageNumber; + this.page = value.pageNumber; if (value.ecoNews) { this.elements = [...value.pages]; const data = value.ecoNews; @@ -68,8 +76,13 @@ export class NewsListComponent implements OnInit, OnDestroy { Math.abs(data.totalElements - value.countOfEcoNews) > 0 && value.countOfEcoNews !== 0 ? value.countOfEcoNews : data.totalElements; this.elementsArePresent = this.elements.length < data.totalElements; } + this.loading = false; + }); + + this.searchNewsControl.valueChanges.subscribe((value) => { + this.searchQuery = value.trim(); + this.dispatchStore(true); }); - this.localStorageService.setCurentPage('previousPage', '/news'); } private setLocalizedTags(): void { @@ -91,7 +104,9 @@ export class NewsListComponent implements OnInit, OnDestroy { } onScroll(): void { - this.scroll = true; + if (!this.elements.length) { + return; + } this.dispatchStore(false); } @@ -103,25 +118,91 @@ export class NewsListComponent implements OnInit, OnDestroy { if (this.tagsList !== value) { this.tagsList = value; } - this.hasNext = true; - this.currentPage = 0; + this.dispatchStore(true); + } + + cancelSearch(): void { + if (!this.searchNewsControl.value.trim()) { + this.isSearchVisible = false; + } else { + this.searchNewsControl.setValue(''); + } + } + + toggleSearch(): void { + this.isSearchVisible = !this.isSearchVisible; + } + + private checkAuthentication(): Observable { + if (!this.userId) { + this.openAuthModalWindow('sign-in'); + return this.dialogRef.afterClosed().pipe( + take(1), + map((result) => !!result) + ); + } + return of(true); + } + + changeFavoriteStatus(event: Event, data: EcoNewsModel) { + event.preventDefault(); + event.stopPropagation(); + + this.checkAuthentication(); + + const action = ChangeEcoNewsFavoriteStatusAction({ id: data.id, favorite: !data.favorite, isFavoritesPage: this.bookmarkSelected }); + this.store.dispatch(action); + } + + openAuthModalWindow(page: string): void { + this.dialogRef = this.dialog.open(AuthModalComponent, { + hasBackdrop: true, + closeOnNavigation: true, + panelClass: ['custom-dialog-container'], + data: { + popUpName: page + } + }); + } + + showSelectedNews(): void { + this.checkAuthentication(); + this.bookmarkSelected = !this.bookmarkSelected; this.dispatchStore(true); } dispatchStore(res: boolean): void { - if (!this.hasNext || this.currentPage === undefined) { + if (res) { + this.hasNext = true; + this.page = 0; + this.elements = []; + this.noNewsMatch = false; + this.newsTotal = 0; + } + + if (!this.hasNext || this.loading) { return; } - const action = this.tagsList.length - ? GetEcoNewsByTagsAction({ currentPage: this.currentPage, numberOfNews: this.numberOfNews, tagsList: this.tagsList, reset: res }) - : GetEcoNewsByPageAction({ currentPage: this.currentPage, numberOfNews: this.numberOfNews, reset: res }); + this.loading = true; + const params = this.ecoNewsService.getNewsHttpParams({ + page: this.page, + size: this.numberOfNews, + title: this.searchQuery, + favorite: this.bookmarkSelected, + userId: this.userId, + tags: this.tagsList + }); + const action = GetEcoNewsAction({ params, reset: res }); this.store.dispatch(action); } private checkUserSingIn(): void { - this.userOwnAuthService.credentialDataSubject.subscribe((data) => (this.isLoggedIn = data?.userId)); + this.userOwnAuthService.credentialDataSubject.subscribe((data) => { + this.isLoggedIn = data?.userId; + this.userId = data.userId; + }); } private setDefaultNumberOfNews(quantity: number): void { diff --git a/src/app/main/component/eco-news/models/eco-news-model.ts b/src/app/main/component/eco-news/models/eco-news-model.ts index f28ee61ee1..bd31f19518 100644 --- a/src/app/main/component/eco-news/models/eco-news-model.ts +++ b/src/app/main/component/eco-news/models/eco-news-model.ts @@ -16,4 +16,5 @@ export interface EcoNewsModel { tagsUa: Array; title: string; countOfEcoNews?: number; + favorite?: boolean; } diff --git a/src/app/main/component/eco-news/services/eco-news.service.spec.ts b/src/app/main/component/eco-news/services/eco-news.service.spec.ts index 9c6a885b51..9bbafa3da6 100644 --- a/src/app/main/component/eco-news/services/eco-news.service.spec.ts +++ b/src/app/main/component/eco-news/services/eco-news.service.spec.ts @@ -4,6 +4,7 @@ import { LocalStorageService } from '@global-service/localstorage/local-storage. import { BehaviorSubject } from 'rxjs'; import { environment } from '@environment/environment'; import { EcoNewsService } from './eco-news.service'; +import { HttpParams } from '@angular/common/http'; describe('EcoNewsService', () => { let service: EcoNewsService; @@ -14,12 +15,25 @@ describe('EcoNewsService', () => { imagePath: null, title: '', text: '', - author: { id: 312, name: 'taqcTestName' }, + content: '', + shortInfo: '', tags: ['News', 'Events'], + tagsEn: ['News'], + tagsUa: ['Новини'], creationDate: '2021-11-25T22:32:30.555088+02:00', likes: 0, - source: '' + source: '', + author: { id: 312, name: 'taqcTestName' } }; + + const newsDtoMock = { + page: [newsMock], + totalElements: 5, + currentPage: 0, + totalPages: 1, + hasNext: true + }; + const localStorageServiceMock: LocalStorageService = jasmine.createSpyObj('LocalStorageService', ['languageBehaviourSubject']); localStorageServiceMock.languageBehaviourSubject = new BehaviorSubject('en'); @@ -41,34 +55,12 @@ describe('EcoNewsService', () => { it('should return eco news list by current page', () => { service.getEcoNewsListByPage(0, 5).subscribe((data) => { - expect(data).toBe(newsMock); + expect(data).toEqual(newsDtoMock); }); const req = httpTestingController.expectOne(`${environment.backendLink}eco-news?page=0&size=5`); expect(req.request.method).toEqual('GET'); - req.flush(newsMock); - }); - - it('should return eco news list by current tags', () => { - const tagMock = ['News']; - service.getNewsListByTags(0, 5, tagMock).subscribe((data) => { - expect(data).toBe(newsMock); - }); - - const req = httpTestingController.expectOne(`${environment.backendLink}eco-news?tags=${tagMock}&page=0&size=5`); - expect(req.request.method).toEqual('GET'); - req.flush(newsMock); - }); - - it('should return news list', () => { - const arr = [newsMock]; - service.getNewsList().subscribe((data) => { - expect(data).toBe(arr); - }); - - const req = httpTestingController.expectOne(`${environment.backendLink}eco-news`); - expect(req.request.method).toEqual('GET'); - req.flush(arr); + req.flush(newsDtoMock); }); it('should return news list by id', () => { @@ -111,4 +103,58 @@ describe('EcoNewsService', () => { expect(req.request.method).toEqual('GET'); req.flush(isLikedByUser); }); + + it('should get eco news list with custom parameters', () => { + const params = new HttpParams().set('page', '0').set('size', '5'); + service.getEcoNewsList(params).subscribe((data) => { + expect(data).toEqual(newsDtoMock); + }); + + const req = httpTestingController.expectOne(`${environment.backendLink}eco-news?page=0&size=5`); + expect(req.request.method).toEqual('GET'); + req.flush(newsDtoMock); + }); + + it('should get eco news list by author ID', () => { + const authorId = 123; + service.getEcoNewsListByAuthorId(authorId, 0, 5).subscribe((data) => { + expect(data).toBeDefined(); + }); + + const req = httpTestingController.expectOne(`${environment.backendLink}eco-news?author-id=${authorId}&page=0&size=5`); + expect(req.request.method).toEqual('GET'); + }); + + it('should delete a news item', () => { + const newsId = 13578; + service.deleteNews(newsId).subscribe((data) => { + expect(data).toBeDefined(); + }); + + const req = httpTestingController.expectOne(`${environment.backendLink}eco-news/${newsId}`); + expect(req.request.method).toEqual('DELETE'); + req.flush({}); + }); + + it('should add news to favorites', () => { + const newsId = 13578; + service.addNewsToFavorites(newsId).subscribe((data) => { + expect(data).toBeDefined(); + }); + + const req = httpTestingController.expectOne(`${environment.backendLink}eco-news/${newsId}/favorites`); + expect(req.request.method).toEqual('POST'); + req.flush({}); + }); + + it('should remove news from favorites', () => { + const newsId = 13578; + service.removeNewsFromFavorites(newsId).subscribe((data) => { + expect(data).toBeDefined(); + }); + + const req = httpTestingController.expectOne(`${environment.backendLink}eco-news/${newsId}/favorites`); + expect(req.request.method).toEqual('DELETE'); + req.flush({}); + }); }); diff --git a/src/app/main/component/eco-news/services/eco-news.service.ts b/src/app/main/component/eco-news/services/eco-news.service.ts index 6f04e382cd..7919eea8e7 100644 --- a/src/app/main/component/eco-news/services/eco-news.service.ts +++ b/src/app/main/component/eco-news/services/eco-news.service.ts @@ -1,7 +1,7 @@ import { Injectable, OnDestroy } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Observable, Observer, ReplaySubject } from 'rxjs'; -import { take, takeUntil } from 'rxjs/operators'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, ReplaySubject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { EcoNewsModel } from '../models/eco-news-model'; import { environment } from '@environment/environment'; import { EcoNewsDto } from '../models/eco-news-dto'; @@ -22,29 +22,16 @@ export class EcoNewsService implements OnDestroy { this.localStorageService.languageBehaviourSubject.pipe(takeUntil(this.destroyed$)).subscribe((language) => (this.language = language)); } - getEcoNewsListByPage(page: number, quantity: number) { - return this.http.get(`${this.backEnd}eco-news?page=${page}&size=${quantity}`); + getEcoNewsListByPage(page: number, quantity: number): Observable { + return this.http.get(`${this.backEnd}eco-news?page=${page}&size=${quantity}`); } - getEcoNewsListByAutorId(authorId: number, page: number, quantity: number) { - return this.http.get(`${this.backEnd}eco-news?author-id=${authorId}&page=${page}&size=${quantity}`); + getEcoNewsList(params: HttpParams): Observable { + return this.http.get(`${this.backEnd}eco-news`, { params }); } - getNewsListByTags(page: number, quantity: number, tags: Array) { - return this.http.get(`${this.backEnd}eco-news?tags=${tags}&page=${page}&size=${quantity}`); - } - - getNewsList(): Observable { - const headers = new HttpHeaders(); - headers.set('Content-type', 'application/json'); - return new Observable((observer: Observer) => { - this.http - .get(`${this.backEnd}eco-news`) - .pipe(take(1)) - .subscribe((newsDto: EcoNewsDto) => { - observer.next(newsDto); - }); - }); + getEcoNewsListByAuthorId(authorId: number, page: number, quantity: number): Observable { + return this.http.get(`${this.backEnd}eco-news?author-id=${authorId}&page=${page}&size=${quantity}`); } getEcoNewsById(id: number): Observable { @@ -67,6 +54,48 @@ export class EcoNewsService implements OnDestroy { return this.http.delete(`${this.backEnd}eco-news/${id}`); } + addNewsToFavorites(id: number) { + return this.http.post(`${this.backEnd}eco-news/${id}/favorites`, {}); + } + + removeNewsFromFavorites(id: number) { + return this.http.delete(`${this.backEnd}eco-news/${id}/favorites`, {}); + } + + getNewsHttpParams(parameters: { + page: number; + size: number; + title?: string; + favorite: boolean; + userId: number; + authorId?: number; + tags: string[]; + }): HttpParams { + let params = new HttpParams().set('page', parameters.page.toString()).set('size', parameters.size.toString()); + + const optionalParams = [ + parameters.favorite && this.appendIfNotEmpty('user-id', parameters.userId.toString()), + !parameters.favorite && this.appendIfNotEmpty('author-id', parameters.authorId ? parameters?.authorId.toString() : null), + this.appendIfNotEmpty('title', parameters.title), + this.appendIfNotEmpty('tags', parameters.tags), + parameters.favorite && { key: 'favorite', value: parameters.favorite } + ]; + + optionalParams.forEach((param) => { + if (param) { + params = params.append(param.key, param.value); + } + }); + + const serializedParams = params.toString(); + return new HttpParams({ fromString: serializedParams }); + } + + private appendIfNotEmpty(key: string, value: string | string[]): { key: string; value: string } | null { + const formattedValue = Array.isArray(value) ? value.join(',') : value; + return formattedValue?.trim() ? { key, value: formattedValue.toUpperCase() } : null; + } + ngOnDestroy(): void { this.destroyed$.next(true); this.destroyed$.complete(); diff --git a/src/app/main/component/events/components/events-list/events-list.component.scss b/src/app/main/component/events/components/events-list/events-list.component.scss index 0395ed28b3..8002b582ef 100644 --- a/src/app/main/component/events/components/events-list/events-list.component.scss +++ b/src/app/main/component/events/components/events-list/events-list.component.scss @@ -108,7 +108,14 @@ width: 100%; box-shadow: 0 0 1px 0 var(--primary-grey); height: 40px; - padding-right: 25px; + padding: 0 14px; + + &:active, + &:focus, + &:hover { + border: 1px solid var(--primary-grey); + outline: none; + } } } diff --git a/src/app/main/component/shared/components/events-list-item/events-list-item.component.scss b/src/app/main/component/shared/components/events-list-item/events-list-item.component.scss index 06f5849e32..a46c8a80f9 100644 --- a/src/app/main/component/shared/components/events-list-item/events-list-item.component.scss +++ b/src/app/main/component/shared/components/events-list-item/events-list-item.component.scss @@ -146,17 +146,19 @@ span { display: inline-block; - width: 25px; - height: 25px; + width: 12px; + height: 16.5px; transition: all 0.3s; } .flag { background: url('/assets/img/places/bookmark-default.svg') no-repeat center; + background-size: contain; } .flag-active { background: url('/assets/img/places/bookmark-set.svg') no-repeat center; + background-size: contain; } } diff --git a/src/app/main/component/shared/components/tag-filter/tag-filter.component.html b/src/app/main/component/shared/components/tag-filter/tag-filter.component.html index 6e085e522b..5c8bbb774f 100644 --- a/src/app/main/component/shared/components/tag-filter/tag-filter.component.html +++ b/src/app/main/component/shared/components/tag-filter/tag-filter.component.html @@ -1,5 +1,5 @@
- {{ header | translate }} + {{ header | translate }}