This is the codeAbility Sharing Platform! Learn more about the codeAbility Sharing Platform.

Skip to content
Snippets Groups Projects
bookmarks.component.ts 9.5 KiB
Newer Older
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpHeaders, HttpResponse } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { EventManager } from 'app/core/util/event-manager.service';
import { ParseLinks } from 'app/core/util/parse-links.service';

import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

import { IUserWatchList } from 'app/shared/model/user-watch-list.model';
import { Exercise, searchResultToExercise } from 'app/shared/model/exercise.model';
import { ITEMS_PER_PAGE } from 'app/config/pagination.constants';
import { UserWatchListService } from 'app/entities/user-watch-list/user-watch-list.service';
Michael Breu's avatar
Michael Breu committed
import { BookmarksDeleteDialogComponent } from './bookmarks-delete-dialog.component';
import { SearchResultsDTO } from 'app/shared/model/search/search-results-dto.model';
import { SearchResultDTO, PluginActionInfo, equalPluginActionInfo } from 'app/shared/model/search/search-result-dto.model';
import { WatchlistManager } from 'app/shared/watchlist/watchlist-manager';
import { ShoppingBasketInfo, ShoppingBasketRedirectInfoDTO } from 'app/shared/model/basket/shopping-basket-info.model';
import { PluginService } from 'app/shared/service/plugin-service';
import * as lodash from 'lodash';
  selector: 'jhi-bookmarks',
  styleUrls: ['./bookmarks.component.scss'],
  templateUrl: './bookmarks.component.html',
})
export class BookmarkComponent implements OnInit, OnDestroy {
  userWatchLists: IUserWatchList[];

  selectedWatchList?: IUserWatchList;

  eventSubscriber?: Subscription;
  itemsPerPage: number;
  links: any;
  page: number;
  allLoaded = false;
  predicate: string;
  ascending: boolean;
  currentSearch: string;

  results: Exercise[] = [];
  selectedResult?: Exercise;
  hitCount = 0;

  constructor(
    protected userWatchListService: UserWatchListService,
    protected eventManager: EventManager,
    protected modalService: NgbModal,
    protected parseLinks: ParseLinks,
    protected activatedRoute: ActivatedRoute,
    protected watchlistManager: WatchlistManager,
    protected pluginService: PluginService
  ) {
    this.userWatchLists = [];
    this.itemsPerPage = ITEMS_PER_PAGE;
    this.page = 0;
    this.allLoaded = false;
    this.links = {
      last: 0,
    };
    this.predicate = 'id';
    this.ascending = true;
    this.currentSearch =
      this.activatedRoute.snapshot && this.activatedRoute.snapshot.queryParams['search']
        ? this.activatedRoute.snapshot.queryParams['search']
        : '';
  }

  loadAll(): void {
    if (this.currentSearch) {
      this.userWatchListService
        .searchForCurrentUser({
          query: this.currentSearch,
          page: this.page,
          size: this.itemsPerPage,
          sort: this.sort(),
        })
        .subscribe((res: HttpResponse<IUserWatchList[]>) => {
          this.paginateUserWatchLists(res.body, res.headers);
    this.userWatchListService
      .findMyWatchlists({
        page: this.page,
        size: this.itemsPerPage,
        sort: this.sort(),
      })
      .subscribe((res: HttpResponse<IUserWatchList[]>) => {
        this.paginateUserWatchLists(res.body, res.headers);
        if (!this.loadCurrent()) {
          // should reset also current watchlist
      });
  }

  private loadCurrent(): boolean {
    let found = false;
    if (this.watchlistManager.getCurrentWatchList()) {
      this.userWatchLists.every(uwl => {
        if (this.isSelected(uwl)) {
          this.view(uwl);
          found = true;
          return false;
        return true;
      });
    } else {
      // currently no default yet selected
      if (this.userWatchLists && this.userWatchLists.length > 0) {
        this.watchlistManager.setCurrentWatchList(this.userWatchLists[0].name!);
        this.view(this.userWatchLists[0]);
        found = true;
        return false;
      }
    return found;
  }

  reset(): void {
    this.page = 0;
    this.allLoaded = false;
    this.userWatchLists = [];
    this.loadAll();
  }

  loadPage(page: number): void {
    this.page = page;
    this.loadAll();
  }

  selectExercise(exercise: Exercise): void {
    this.selectedResult = exercise;
  }

  search(query: string): void {
    this.userWatchLists = [];
    this.links = {
      last: 0,
    };
    this.page = 0;
    if (query) {
      this.predicate = '_score';
      this.ascending = false;
    } else {
      this.predicate = 'id';
      this.ascending = true;
    this.currentSearch = query;
    this.loadAll();
  }

  ngOnInit(): void {
    this.loadAll();
    this.registerChangeInUserWatchLists();
  }

  ngOnDestroy(): void {
    if (this.eventSubscriber) {
      this.eventManager.destroy(this.eventSubscriber);
  }

  trackId(index: number, item: IUserWatchList): number {
    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
    return item.id!;
  }

  registerChangeInUserWatchLists(): void {
    this.eventSubscriber = this.eventManager.subscribe('userWatchListListModification', () => this.reset());
  }

  private parseSearchResultsDTO(searchResultsDTO: SearchResultsDTO): Exercise[] {
    this.hitCount = searchResultsDTO.hitCount;
    // fix string to date conversion: unfortunatelly dates are not converted correctly :-()
    searchResultsDTO.searchResult.forEach(hit => {
      hit.project.last_activity_at = new Date(hit.project.last_activity_at);
      hit.file.indexing_date = new Date(hit.file.indexing_date);
    });
    return searchResultsDTO.searchResult.map(searchResultToExercise);
  }

  delete(userWatchList: IUserWatchList): void {
    const modalRef = this.modalService.open(BookmarksDeleteDialogComponent, { size: 'lg', backdrop: 'static' });
    modalRef.componentInstance.userWatchList = userWatchList;
  }

  sort(): string[] {
    const result = [this.predicate + ',' + (this.ascending ? 'asc' : 'desc')];
    if (this.predicate !== 'id') {
      result.push('id');
    return result;
  }

  view(userWatchList: IUserWatchList): void {
    this.hitCount = 0;
    this.page = 0;
    this.allLoaded = false;
    this.results = [];
    this.selectedWatchList = userWatchList;
    this.watchlistManager.setCurrentWatchList(userWatchList.name!);
    this.onScroll();
  }

  onScroll(): void {
    if (this.selectedWatchList) {
      if (!this.allLoaded) {
        this.userWatchListService.findExercises(this.selectedWatchList, this.page).subscribe(
          (data: SearchResultsDTO) => {
            const searchResults = this.parseSearchResultsDTO(data);
            if (data.pageStartIndex + searchResults.length < this.results.length) {
              // we are replacing already existing results inside the array
              for (let i = 0; i < searchResults.length; i++) {
                this.results[data.pageStartIndex + i] = searchResults[i];
              }
            } else {
              const diff = data.pageStartIndex - this.results.length;
              if (diff > 0) {
                // overlap with current results, throw away current result
                this.results = this.results.slice(0, data.pageStartIndex - 1);
              } else if (diff < 0) {
                alert('reload of exercises failed!');
                // fill up results
                for (let i = 0; i < -diff; i++) {
                  // fill up array with empty content
                }
              }
              this.results = this.results.concat(searchResults);
              if (data.hitCount <= this.results.length) {
                this.allLoaded = true;
              }
            }
            ++this.page; // TODO this may result in a race condition, if requests are not returned in sequence :-()
          },
          () => alert('Search failed')
  isSelected(userWatchList: IUserWatchList): boolean {
    if (this.watchlistManager.getCurrentWatchList())
      return userWatchList.id === this.watchlistManager.getCurrentWatchList()!.userWatchList.id;
    else return false;
  }

  protected paginateUserWatchLists(data: IUserWatchList[] | null, headers: HttpHeaders): void {
    const headersLink = headers.get('link');
    this.links = this.parseLinks.parse(headersLink ? headersLink : '');
    if (data) {
      for (let i = 0; i < data.length; i++) {
        this.userWatchLists.push(data[i]);
      }
    }
  }

  getCommonActions(): PluginActionInfo[] {
    const result = lodash
      .chain(this.results)
      .map(function (ex: Exercise): PluginActionInfo[] {
        return ex.originalResult.supportedActions;
      })
      .flatten()
      .uniqWith(equalPluginActionInfo);

    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
    return result.value();
  }

  startAction(action: PluginActionInfo): void {
    const selectedExercises = lodash
      .chain(this.results)
      .map(function (ex: Exercise): SearchResultDTO {
        return ex.originalResult;
      })
      .filter((sr: SearchResultDTO) =>
        sr.supportedActions.some(function (a: PluginActionInfo): boolean {
          return equalPluginActionInfo(a, action);
        })
      );
    const basketInfo: ShoppingBasketInfo = {
      plugin: action.plugin,
      action: action.action,
      itemInfos: selectedExercises.value(),
    };

    this.pluginService.getRedirectLink(basketInfo).subscribe(
      (redirectInfo: ShoppingBasketRedirectInfoDTO) => {
        // alert('redirecting to ' + redirectInfo.redirectURL);
        // location.href = redirectInfo.redirectURL;
        window.open(redirectInfo.redirectURL, action.action);
      },
      () => alert('Search failed')
    );
  }