diff --git a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.html b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.html index 9f41aeb6b6fae38dc15e2892af798f82c1b5c8ac..abbb617576532141031ef048b2bbf19c926ecc55 100644 --- a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.html +++ b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.html @@ -23,7 +23,7 @@ <div style="margin-top: auto; width: 100%; padding-left: 30px; padding-right: 30px"> <!-- card rating--> <div style="margin-bottom: 20px"> - <!-- + <!-- <div style="float: left"> <p class="card-text" jhiTranslate="exercise.details.rating"></p> </div> --> @@ -39,21 +39,7 @@ <!-- card rating end--> <!-- card bookmark--> - <div style="float: left; width: 100%"> - <div style="float: left"> - <p class="card-text" jhiTranslate="exercise.details.bookmark"></p> - </div> - <div class="form-check" style="float: right; padding-right: 10px"> - <input - class="form-check-input" - type="checkbox" - [checked]="isOnCurrentWatchlist(exercise)" - id="card-defaultCheck1" - (change)="handleForCurrentWatchlist(exercise)" - /> - <label class="form-check-label" for="card-defaultCheck1"></label> - </div> - </div> + <jhi-bookmark-toggle [exercise]="exercise"></jhi-bookmark-toggle> <!-- card bookmark end--> <!-- Button to Open the Modal --> diff --git a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts index 04e291324f8a15dd6fcd8e1710d38924138dcfa5..6ebe754f0fbf13fde58de6fba138b7031c76c301 100644 --- a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts +++ b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts @@ -2,7 +2,6 @@ import { Component, Input, Output, EventEmitter, AfterViewChecked } from '@angul import { Exercise } from 'app/shared/model/exercise.model'; import { SearchService } from 'app/search/service/search-service'; import { WatchlistManager } from 'app/shared/watchlist/watchlist-manager'; -import { LikesService } from 'app/entities/likes/likes.service'; import { ExerciseService } from '../service/exercise.service'; @Component({ @@ -19,7 +18,6 @@ export class ExerciseCardComponent implements AfterViewChecked { constructor( protected searchService: SearchService, private watchlistManager: WatchlistManager, - private likesService: LikesService, private exerciseService: ExerciseService ) {} @@ -32,19 +30,12 @@ export class ExerciseCardComponent implements AfterViewChecked { } } } + selectExercise(): void { this.exercise = this.exerciseService.populateExerciseWithData(this.exercise!); this.exerciseSelectionEvent.emit(this.exercise); } - isOnCurrentWatchlist(e: Exercise): boolean { - return this.watchlistManager.isExerciseOnCurrentWatchlist(e); - } - - handleForCurrentWatchlist(e: Exercise): void { - this.watchlistManager.handleCheckForCurrentWatchlist(e); - } - /** * correct missing image urls */ diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts index 5c26b8d2b2cff36384ae9cf5d29e05aff8f69b41..785c71d2c8a6a0305ab80263db590da74af98b6b 100644 --- a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts +++ b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts @@ -26,6 +26,8 @@ export class ExerciseDetailsModalComponent { @Input() exercise: Exercise | undefined; @Output() exerciseChangedEvent = new EventEmitter<Exercise>(); + constructor(private watchlistManager: WatchlistManager) {} + handleExerciseChangedEvent(exercise: Exercise): void { this.exerciseChangedEvent.emit(exercise); } @@ -68,8 +70,9 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy { @Input() exercise: Exercise | undefined; @Output() exerciseChangedEvent = new EventEmitter<Exercise>(); - downloadWithChildren = false; + bookmarked = false; + downloadWithChildren = false; markDownExercise: Exercise | undefined; account: Account | null = null; authSubscription?: Subscription; @@ -177,13 +180,8 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy { }; } - handleForCurrentWatchlist(e: Exercise): void { - if (this.watchlistManager.isExerciseOnCurrentWatchlist(e)) { - e.numberOfWatchlistEntries = e.numberOfWatchlistEntries - 1; - } else { - e.numberOfWatchlistEntries = e.numberOfWatchlistEntries + 1; - } - this.watchlistManager.handleCheckForCurrentWatchlist(e); + isLoggedIn(): boolean { + return this.accountService.isAuthenticated(); } public isEditable(): boolean { @@ -223,10 +221,6 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy { return ''; } - isOnCurrentWatchlist(e: Exercise): boolean { - return this.watchlistManager.isExerciseOnCurrentWatchlist(e); - } - likeAction(): void { // to do call like service this.likesService.likeExercise(this.exercise!.originalResult.exerciseId).subscribe(() => @@ -236,23 +230,14 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy { this.exercise!.numberOfLikes = this.exercise!.numberOfLikes + 1; this.exercise!.userHasLiked = true; - - // eslint-disable-next-line no-console - console.log(`Reloaded number of likes is ${this.exercise!.numberOfLikes}`); } unlikeAction(): void { // to do call like service - this.likesService.unlikeExercise(this.exercise!.originalResult.exerciseId).subscribe(() => - // eslint-disable-next-line no-console - console.log('Unliked post ' + this.exercise!.originalResult.exerciseId) - ); + this.likesService.unlikeExercise(this.exercise!.originalResult.exerciseId); this.exercise!.numberOfLikes = this.exercise!.numberOfLikes - 1; this.exercise!.userHasLiked = false; - - // eslint-disable-next-line no-console - console.log(`Reloaded number of likes is ${this.exercise!.numberOfLikes}`); } public isAuthenticated(): boolean { @@ -260,6 +245,7 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy { } ngOnInit(): void { + this.bookmarked = this.watchlistManager.isExerciseOnCurrentWatchlist(this.exercise!); this.authSubscription = this.accountService.getAuthenticationState().subscribe(account => (this.account = account)); this.applicationInfoService.loadOerLink().subscribe( (res: string) => { diff --git a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html index 8cf8946bb66337076d554d82f5e220e5fd385676..ffd923bbe682e9ef250ef4a2a5d5385c627ea708 100644 --- a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html +++ b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html @@ -120,24 +120,7 @@ <ng-template #helpForWatchlists> {{ 'exercise.details.watchlists' | translate }}</ng-template> </div> - <!-- modal bookmark--> - <div style="float: left; width: 100%; padding-top: 15px; margin-bottom: 25px"> - <div style="float: left"> - <p class="card-text" jhiTranslate="exercise.details.bookmark"></p> - </div> - <div class="form-check" style="float: right; padding-right: 10px" placement="right"> - <input - class="form-check-input" - type="checkbox" - [checked]="isOnCurrentWatchlist(exercise)" - (change)="handleForCurrentWatchlist(exercise)" - value="" - id="modal-defaultCheck1" - /> - <label class="form-check-label" for="modal-defaultCheck1"></label> - </div> - </div> - <!-- modal bookmark end--> + <jhi-bookmark-toggle [exercise]="exercise"></jhi-bookmark-toggle> <div *ngIf="exercise.originalResult.file.parentId" style="float: left; width: 100%; padding-top: 15px; margin-bottom: 25px"> <ng-template #helpToParent data-container="body"> {{ 'exercise.help.toParent' | translate }} </ng-template> diff --git a/src/main/webapp/app/exercise/service/exercise.service.ts b/src/main/webapp/app/exercise/service/exercise.service.ts index 9a264eceb9689babfb86cb657462b345ed6f7a71..a98012523be79a6471638d33513b1e8c32504cc9 100644 --- a/src/main/webapp/app/exercise/service/exercise.service.ts +++ b/src/main/webapp/app/exercise/service/exercise.service.ts @@ -48,21 +48,21 @@ export class ExerciseService { (data: number) => { exercise.numberOfLikes = data; }, - () => alert('Could not load number of likes') + () => console.warn('Could not load number of likes') ); this.statisticsService.getNumberOfWatchListEntriesForExerciseID(exercise.originalResult.exerciseId).subscribe( (data: number) => { exercise.numberOfWatchlistEntries = data; }, - () => alert('Could not load number of likes') + () => console.warn('Could not load number of watchlists') ); this.likesService.hasLiked(exercise.originalResult.exerciseId).subscribe( (data: boolean) => { exercise.userHasLiked = data; }, - () => alert('Could not load if user has liked or not') + () => console.warn('Could not load if user has liked or not') ); this.searchService.getStatisticsForExercise(exercise.originalResult.exerciseId).subscribe( @@ -70,7 +70,7 @@ export class ExerciseService { exercise.views = data.views!; exercise.downloads = data.downloads!; }, - () => alert('Could not load exercise statistics') + () => console.warn('Could not load exercise statistics') ); } return exercise; diff --git a/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.html b/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f296f215a411436cfe83638064cc3f6b11bef3b7 --- /dev/null +++ b/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.html @@ -0,0 +1,26 @@ +<div style="float: left; width: 100%; padding-top: 15px; margin-bottom: 25px"> + <div style="float: left"> + <p class="card-text" jhiTranslate="exercise.details.bookmark"></p> + </div> + <div class="form-check" style="float: right; padding-right: 10px" placement="right" [ngbTooltip]="helpForBookmark"> + <input + class="form-check-input" + type="checkbox" + [checked]="this.isOnCurrentWatchlist(this.exercise)" + (change)="handleForCurrentWatchlist()" + value="" + [disabled]="!isLoggedIn() || isLoadingBookmark" + id="modal-defaultCheck1" + /> + <label class="form-check-label" for="modal-defaultCheck1"></label> + </div> + <ng-template #helpForBookmark> + <div *ngIf="isLoggedIn() && !this.isOnCurrentWatchlist(this.exercise)"> + {{ 'exercise.details.bookmarkLoggedIn' | translate }} + </div> + <div *ngIf="isLoggedIn() && this.isOnCurrentWatchlist(this.exercise)"> + {{ 'exercise.details.bookmarkedLoggedIn' | translate }} + </div> + <div *ngIf="!isLoggedIn()">{{ 'exercise.details.bookmarkLogin' | translate }}</div> + </ng-template> +</div> diff --git a/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.ts b/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f685968bacf29a1d9acefb952287a0852f9980b --- /dev/null +++ b/src/main/webapp/app/shared/bookmark/bookmark-toggle.component.ts @@ -0,0 +1,43 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Exercise } from '../model/exercise.model'; +import { AccountService } from '../../core/auth/account.service'; +import { WatchlistManager } from '../watchlist/watchlist-manager'; +import { AlertService } from '../../core/util/alert.service'; + +@Component({ + selector: 'jhi-bookmark-toggle', + templateUrl: './bookmark-toggle.component.html', +}) +export class BookmarkToggleComponent implements OnInit { + @Input() exercise: Exercise | undefined; + + isBookmarked = false; + isLoadingBookmark = false; + + constructor(private jhiAlertService: AlertService, private watchlistManager: WatchlistManager, private accountService: AccountService) {} + + ngOnInit(): void { + this.isBookmarked = this.watchlistManager.isExerciseOnCurrentWatchlist(this.exercise!); + } + + isOnCurrentWatchlist(e: Exercise | undefined): boolean { + return e ? this.watchlistManager.isExerciseOnCurrentWatchlist(e) : false; + } + + isLoggedIn(): boolean { + return this.accountService.isAuthenticated(); + } + + handleForCurrentWatchlist(): void { + if (!this.isLoadingBookmark) { + this.isLoadingBookmark = true; + this.watchlistManager.handleCheckForCurrentWatchlist(this.exercise!)?.then(() => { + this.isBookmarked = !this.isBookmarked; + this.exercise!.numberOfWatchlistEntries = !this.isBookmarked + ? this.exercise!.numberOfWatchlistEntries-- + : this.exercise!.numberOfWatchlistEntries++; + this.isLoadingBookmark = false; + }); + } + } +} diff --git a/src/main/webapp/app/shared/shared.module.ts b/src/main/webapp/app/shared/shared.module.ts index 22628929b1bb6e0abf03af4926b7482339745696..ea6021e91197d49f516fd7724d317196607d0221 100644 --- a/src/main/webapp/app/shared/shared.module.ts +++ b/src/main/webapp/app/shared/shared.module.ts @@ -12,6 +12,7 @@ import { FormatMediumDatePipe } from './date/format-medium-date.pipe'; import { SortByDirective } from './sort/sort-by.directive'; import { SortDirective } from './sort/sort.directive'; import { ItemCountComponent } from './pagination/item-count.component'; +import { BookmarkToggleComponent } from './bookmark/bookmark-toggle.component'; @NgModule({ imports: [SharedLibsModule], @@ -27,6 +28,7 @@ import { ItemCountComponent } from './pagination/item-count.component'; SortByDirective, SortDirective, ItemCountComponent, + BookmarkToggleComponent, ], exports: [ SharedLibsModule, @@ -41,6 +43,7 @@ import { ItemCountComponent } from './pagination/item-count.component'; SortByDirective, SortDirective, ItemCountComponent, + BookmarkToggleComponent, ], }) export class SharedModule {} diff --git a/src/main/webapp/app/shared/watchlist/watchlist-manager.ts b/src/main/webapp/app/shared/watchlist/watchlist-manager.ts index 071ca5701a30bb508d451b3b3f10d15d39b0ced2..7ee77ac6eb3c996af40802b4d9ed22fd7d10e789 100644 --- a/src/main/webapp/app/shared/watchlist/watchlist-manager.ts +++ b/src/main/webapp/app/shared/watchlist/watchlist-manager.ts @@ -111,28 +111,35 @@ export class WatchlistManager implements OnDestroy { return this.currentWatchlist; } - public handleCheckForCurrentWatchlist(e: Exercise): void { - if (this.currentWatchlist) { - if (!this.isExerciseOnCurrentWatchlist(e)) { - // add - const watchListEntry: IWatchListEntry = { - exerciseId: e.originalResult.exerciseId, - exerciseName: e.originalResult.metadata.title, - watchlistId: this.currentWatchlist.userWatchList.id, - }; - // reload watchlist - this.watchListEntryService.createForCurrentUser(watchListEntry).subscribe((/* wle: HttpResponse<IWatchListEntry> */) => { - if (this.currentWatchlist) this.loadCurrentWatchList(this.currentWatchlist.userWatchList); - }); - } else { - // delete - this.watchListEntryService - .deleteForCurrentUser(this.currentWatchlist.userWatchList.id!, e.originalResult.exerciseId) - .subscribe(() => { + public handleCheckForCurrentWatchlist(e: Exercise): Promise<void> { + return new Promise<void>((resolve, reject) => { + let handling; + + if (this.currentWatchlist) { + if (!this.isExerciseOnCurrentWatchlist(e)) { + // add + const watchListEntry: IWatchListEntry = { + exerciseId: e.originalResult.exerciseId, + exerciseName: e.originalResult.metadata.title, + watchlistId: this.currentWatchlist.userWatchList.id, + }; + // reload watchlist + handling = this.watchListEntryService.createForCurrentUser(watchListEntry); + } else { + // delete + handling = this.watchListEntryService.deleteForCurrentUser(this.currentWatchlist.userWatchList.id!, e.originalResult.exerciseId); + } + handling.subscribe({ + next: () => { if (this.currentWatchlist) this.loadCurrentWatchList(this.currentWatchlist.userWatchList); - }); + resolve(); + }, + error: err => { + reject(err); + }, + }); } - } + }); } public createForCurrentUser(userWatchList: IUserWatchList): Observable<EntityResponseType> { diff --git a/src/main/webapp/i18n/de/exercise.json b/src/main/webapp/i18n/de/exercise.json index e8e295c0ce10fdd69487c6eaf0e7105a0e2444a9..338be31884e6e17d4fc6c9d26d4934583667cc97 100644 --- a/src/main/webapp/i18n/de/exercise.json +++ b/src/main/webapp/i18n/de/exercise.json @@ -20,7 +20,10 @@ "toParent": "zum übergeordneten Objekt", "like": "Wenn Ihnen diese Aufgabe gefällt, dann klicken Sie auf das Herz!", "unlike": "Wenn Ihnen diese Aufgabe nicht mehr gefällt, dann klicken Sie auf das Herz!", - "likeLogin": "Melden Sie sich an, um dieser Aufgabe ein like zu geben" + "likeLogin": "Melden Sie sich an, um dieser Aufgabe ein like zu geben", + "bookmarkLogin": "Melden Sie sich an, um diese Aufgabe zu merken", + "bookmarkLoggedIn": "Klicken Sie hier um diese Aufgabe Ihrer Merkliste hinzuzufügen", + "bookmarkedLoggedIn": "Klicken Sie hier um diese Aufgabe von Ihrer Merkliste zu streichen" }, "metadata": { "metadata": "Metadaten", diff --git a/src/main/webapp/i18n/de/global.json b/src/main/webapp/i18n/de/global.json index d71d0c45482197a9345a1a85208ad227a573722c..82eea1723b01a6fd33cd4e5c77e6ec4bfbbb0650 100644 --- a/src/main/webapp/i18n/de/global.json +++ b/src/main/webapp/i18n/de/global.json @@ -17,7 +17,7 @@ "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)" }, "account": { - "main": "Zugang", + "main": "Account", "settings": "Einstellungen", "settingsDescription": "Ihre Nutzereinstellungen bearbeiten", "achievements": "Errungenschaften", diff --git a/src/main/webapp/i18n/en/exercise.json b/src/main/webapp/i18n/en/exercise.json index 2c635b7066889c396fb1db43babcb57f11f4ed63..b5142819cfb8a2775f679f35d8594444262da272 100644 --- a/src/main/webapp/i18n/en/exercise.json +++ b/src/main/webapp/i18n/en/exercise.json @@ -20,7 +20,10 @@ "toParent": "to parent object", "like": "If you like this exercise, you can click here!", "unlike": "If you don't like this exercise anymore, you can click here!", - "likeLogin": "Log-in to be able to click this heart" + "likeLogin": "Log-in to be able to click this heart", + "bookmarkLogin": "Log-in to be able to click this bookmark", + "bookmarkLoggedIn": "Click this bookmark to save this exercise in your watchlist", + "bookmarkedLoggedIn": "Click this bookmark to remove this exercise from your watchlist" }, "metadata": { "metadata": "Meta data",