-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #300 from geonetwork/datahub-show-favorites
Datahub / Add the possibility to set records as favorites
- Loading branch information
Showing
29 changed files
with
772 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
13 changes: 13 additions & 0 deletions
13
libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<div> | ||
<span class="align-text-top mr-1.5 favorite-count" *ngIf="hasFavoriteCount">{{ | ||
favoriteCount | ||
}}</span> | ||
<gn-ui-star-toggle | ||
[toggled]="isFavorite$ | async" | ||
(newValue)="toggleFavorite($event)" | ||
[disabled]="loading || (isAnonymous$ | async)" | ||
[attr.title]=" | ||
(isAnonymous$ | async) ? ('favorite.not.authenticated' | translate) : null | ||
" | ||
></gn-ui-star-toggle> | ||
</div> |
197 changes: 197 additions & 0 deletions
197
libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
import { ComponentFixture, TestBed } from '@angular/core/testing' | ||
import { FavoriteStarComponent } from './favorite-star.component' | ||
import { BehaviorSubject, of, throwError } from 'rxjs' | ||
import { AuthService } from '@geonetwork-ui/feature/auth' | ||
import { FavoritesService } from '../favorites.service' | ||
import { StarToggleComponent } from '@geonetwork-ui/ui/inputs' | ||
import { RECORDS_SUMMARY_FIXTURE } from '@geonetwork-ui/util/shared' | ||
import { By } from '@angular/platform-browser' | ||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core' | ||
import { TranslateModule } from '@ngx-translate/core' | ||
|
||
class AuthServiceMock { | ||
authReady = jest.fn(() => this._authSubject) | ||
_authSubject = new BehaviorSubject({ | ||
id: '1234', | ||
name: 'fakeuser', | ||
}) | ||
} | ||
|
||
class FavoritesServiceMock { | ||
myFavoritesUuid$ = new BehaviorSubject<string[]>([]) | ||
removeFromFavorites = jest.fn(() => of(true)) | ||
addToFavorites = jest.fn(() => of(true)) | ||
} | ||
|
||
describe('FavoriteStarComponent', () => { | ||
let component: FavoriteStarComponent | ||
let fixture: ComponentFixture<FavoriteStarComponent> | ||
let authService: AuthService | ||
let favoritesService: FavoritesService | ||
let favoriteCountEl: HTMLElement | ||
let starToggle: StarToggleComponent | ||
|
||
beforeEach(async () => { | ||
await TestBed.configureTestingModule({ | ||
declarations: [FavoriteStarComponent, StarToggleComponent], | ||
imports: [TranslateModule.forRoot()], | ||
providers: [ | ||
{ | ||
provide: AuthService, | ||
useClass: AuthServiceMock, | ||
}, | ||
{ | ||
provide: FavoritesService, | ||
useClass: FavoritesServiceMock, | ||
}, | ||
], | ||
schemas: [NO_ERRORS_SCHEMA], | ||
}) | ||
.overrideComponent(FavoriteStarComponent, { | ||
set: { | ||
changeDetection: ChangeDetectionStrategy.Default, | ||
}, | ||
}) | ||
.compileComponents() | ||
|
||
authService = TestBed.inject(AuthService) | ||
favoritesService = TestBed.inject(FavoritesService) | ||
fixture = TestBed.createComponent(FavoriteStarComponent) | ||
component = fixture.componentInstance | ||
component.record = { ...RECORDS_SUMMARY_FIXTURE[0], favoriteCount: 42 } | ||
fixture.detectChanges() | ||
starToggle = fixture.debugElement.query( | ||
By.directive(StarToggleComponent) | ||
).componentInstance | ||
}) | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy() | ||
}) | ||
|
||
describe('when a record has a favorite count', () => { | ||
beforeEach(() => { | ||
favoriteCountEl = fixture.debugElement.query( | ||
By.css('.favorite-count') | ||
).nativeElement | ||
}) | ||
it('shows the amount of favorites on the record', () => { | ||
expect(favoriteCountEl).toBeTruthy() | ||
expect(favoriteCountEl.textContent).toEqual( | ||
component.record.favoriteCount.toString() | ||
) | ||
}) | ||
}) | ||
describe('when a record does not have a favorite count', () => { | ||
beforeEach(() => { | ||
component.record = { ...RECORDS_SUMMARY_FIXTURE[0] } | ||
delete component.record.favoriteCount | ||
fixture.detectChanges() | ||
}) | ||
it('does not show the amount of favorites on the record', () => { | ||
expect(fixture.debugElement.query(By.css('.favorite-count'))).toBeFalsy() | ||
}) | ||
}) | ||
describe('when not authenticated', () => { | ||
beforeEach(() => { | ||
;(authService as any)._authSubject.next(null) | ||
fixture.detectChanges() | ||
}) | ||
it('star toggle is disabled', () => { | ||
expect(starToggle.disabled).toBe(true) | ||
}) | ||
}) | ||
describe('when authenticated', () => { | ||
it('star toggle is enabled', () => { | ||
expect(starToggle.disabled).toBe(false) | ||
}) | ||
describe('on toggle state change', () => { | ||
beforeEach(() => { | ||
favoriteCountEl = fixture.debugElement.query( | ||
By.css('.favorite-count') | ||
).nativeElement | ||
}) | ||
describe('if record is not part of favorite', () => { | ||
beforeEach(() => { | ||
;(favoritesService as any).myFavoritesUuid$.next([ | ||
'aaa', | ||
'bbb', | ||
'ccc', | ||
]) | ||
starToggle.newValue.emit(true) | ||
fixture.detectChanges() | ||
}) | ||
it('adds record to favorites', () => { | ||
expect(favoritesService.addToFavorites).toHaveBeenCalledWith([ | ||
component.record.uuid, | ||
]) | ||
expect(favoritesService.removeFromFavorites).not.toHaveBeenCalled() | ||
}) | ||
it('increase record favorite count by one', () => { | ||
expect(favoriteCountEl.textContent).toEqual( | ||
(component.record.favoriteCount + 1).toString() | ||
) | ||
}) | ||
}) | ||
describe('if record is part of favorite', () => { | ||
beforeEach(() => { | ||
;(favoritesService as any).myFavoritesUuid$.next([ | ||
'aaa', | ||
'bbb', | ||
component.record.uuid, | ||
]) | ||
starToggle.newValue.emit(false) | ||
fixture.detectChanges() | ||
}) | ||
it('removes record from favorites', () => { | ||
expect(favoritesService.removeFromFavorites).toHaveBeenCalledWith([ | ||
component.record.uuid, | ||
]) | ||
expect(favoritesService.addToFavorites).not.toHaveBeenCalled() | ||
}) | ||
it('decrease record favorite count by one', () => { | ||
expect(favoriteCountEl.textContent).toEqual( | ||
(component.record.favoriteCount - 1).toString() | ||
) | ||
}) | ||
}) | ||
describe('two subsequent changes', () => { | ||
beforeEach(() => { | ||
;(favoritesService as any).myFavoritesUuid$.next([ | ||
'aaa', | ||
'bbb', | ||
component.record.uuid, | ||
]) | ||
starToggle.newValue.emit(false) | ||
starToggle.newValue.emit(true) | ||
fixture.detectChanges() | ||
}) | ||
it('removes and adds record to favorites', () => { | ||
expect(favoritesService.removeFromFavorites).toHaveBeenCalledWith([ | ||
component.record.uuid, | ||
]) | ||
expect(favoritesService.addToFavorites).toHaveBeenCalledWith([ | ||
component.record.uuid, | ||
]) | ||
}) | ||
it('record favorite count stays the same', () => { | ||
expect(favoriteCountEl.textContent).toEqual( | ||
component.record.favoriteCount.toString() | ||
) | ||
}) | ||
}) | ||
describe('if favorite modification fails', () => { | ||
beforeEach(() => { | ||
favoritesService.addToFavorites = () => throwError('blargz') | ||
starToggle.newValue.emit(true) | ||
fixture.detectChanges() | ||
}) | ||
it('does not change record favorite count', () => { | ||
expect(favoriteCountEl.textContent).toEqual( | ||
component.record.favoriteCount.toString() | ||
) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) |
58 changes: 58 additions & 0 deletions
58
libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core' | ||
import { FavoritesService } from '../favorites.service' | ||
import { MetadataRecord } from '@geonetwork-ui/util/shared' | ||
import { map } from 'rxjs/operators' | ||
import { AuthService } from '@geonetwork-ui/feature/auth' | ||
|
||
@Component({ | ||
selector: 'gn-ui-favorite-star', | ||
templateUrl: './favorite-star.component.html', | ||
styleUrls: ['./favorite-star.component.css'], | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
}) | ||
export class FavoriteStarComponent { | ||
@Input() set record(value) { | ||
this.record_ = value | ||
this.favoriteCount = | ||
'favoriteCount' in this.record_ ? this.record_.favoriteCount : null | ||
} | ||
get record() { | ||
return this.record_ | ||
} | ||
isFavorite$ = this.favoritesService.myFavoritesUuid$.pipe( | ||
map((favorites) => favorites.indexOf(this.record.uuid) > -1) | ||
) | ||
isAnonymous$ = this.authService | ||
.authReady() | ||
.pipe(map((user) => !user || !('id' in user))) | ||
record_: MetadataRecord | ||
favoriteCount: number | null | ||
loading = false | ||
|
||
get hasFavoriteCount() { | ||
return this.favoriteCount !== null | ||
} | ||
|
||
constructor( | ||
private favoritesService: FavoritesService, | ||
private authService: AuthService | ||
) {} | ||
|
||
toggleFavorite(isFavorite) { | ||
this.loading = true | ||
;(isFavorite | ||
? this.favoritesService.addToFavorites([this.record.uuid]) | ||
: this.favoritesService.removeFromFavorites([this.record.uuid]) | ||
).subscribe({ | ||
complete: () => { | ||
if (this.hasFavoriteCount) { | ||
this.favoriteCount += isFavorite ? 1 : -1 | ||
} | ||
this.loading = false | ||
}, | ||
error: () => { | ||
this.loading = false | ||
}, | ||
}) | ||
} | ||
} |
Oops, something went wrong.