From 165d10c4d52a281e8dfd3dc372e5b7e65298bd6d Mon Sep 17 00:00:00 2001 From: Simon Grimme <9295182+grimsi@users.noreply.github.com> Date: Tue, 16 Aug 2022 00:32:04 +0200 Subject: [PATCH] Chips in game detail view are now clickable Filters are now expanded if they are active at page load Fixed bug where filters would be loaded twice, resulting in the user not being able to navigate back --- .../game-detail-view.component.html | 4 +- .../game-detail-view.component.ts | 12 +++-- .../library-overview.component.html | 8 ++-- .../library-overview.component.ts | 47 ++++++++++--------- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.html b/frontend/src/app/components/game-detail-view/game-detail-view.component.html index 27dff99..b35200e 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.html +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.html @@ -28,14 +28,14 @@

Genres

- {{genre.name}} + {{genre.name}}

Themes

- {{theme.name}} + {{theme.name}}
diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts index c641e4c..c7a92c8 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts @@ -1,9 +1,7 @@ -import { Component, OnInit } from '@angular/core'; -import {ActivatedRoute, Router} from "@angular/router"; +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute, Params, Router} from "@angular/router"; import {DetectedGameDto} from "../../models/dtos/DetectedGameDto"; import {GamesService} from "../../services/games.service"; -import {HttpErrorResponse} from "@angular/common/http"; -import {takeWhile} from "rxjs"; @Component({ selector: 'app-game-detail-view', @@ -58,4 +56,10 @@ export class GameDetailViewComponent implements OnInit { return bytes.toFixed(dp) + ' ' + units[u]; } + goToLibraryWithFilter(field: string, value: string) { + let params: Params = {}; + params[field] = value; + this.router.navigate(['/library'], {queryParams: params}); + } + } diff --git a/frontend/src/app/components/library-overview/library-overview.component.html b/frontend/src/app/components/library-overview/library-overview.component.html index 0fd6599..7501b07 100644 --- a/frontend/src/app/components/library-overview/library-overview.component.html +++ b/frontend/src/app/components/library-overview/library-overview.component.html @@ -54,7 +54,7 @@ - +

Gamemodes

@@ -75,7 +75,7 @@
- +

Genres

@@ -87,7 +87,7 @@
- +

Themes

@@ -99,7 +99,7 @@
- +

Player Perspectives

diff --git a/frontend/src/app/components/library-overview/library-overview.component.ts b/frontend/src/app/components/library-overview/library-overview.component.ts index c40b4f7..c7a556a 100644 --- a/frontend/src/app/components/library-overview/library-overview.component.ts +++ b/frontend/src/app/components/library-overview/library-overview.component.ts @@ -6,9 +6,8 @@ import {ThemeDto} from "../../models/dtos/ThemeDto"; import {firstValueFrom, forkJoin, Observable} from "rxjs"; import {SortDirection} from "@angular/material/sort"; import {PlayerPerspectiveDto} from "../../models/dtos/PlayerPerspectiveDto"; -import {ActivatedRoute, Params, Router} from "@angular/router"; +import {ActivatedRoute, ActivatedRouteSnapshot, Params, Router} from "@angular/router"; import {Location} from "@angular/common"; -import {HttpParams} from "@angular/common/http"; class SortOption { title: string; @@ -61,6 +60,7 @@ export class LibraryOverviewComponent implements AfterContentInit { loading: boolean = true; gameLibraryIsEmpty: boolean = false; + private previousStateParams: Params = {}; constructor(private gameServerService: GamesService, private route: ActivatedRoute, @@ -88,16 +88,15 @@ export class LibraryOverviewComponent implements AfterContentInit { this.availableThemes = result[1]; this.availablePlayerPerspectives = result[2]; - this.route.queryParams.subscribe(params => { - if (params['search'] !== undefined) this.searchTerm = params['search']; - if (params['sort'] !== undefined) this.selectedSortOption = this.matchSelectedSortOptionFromParam(params['sort']); - if (params['gamemodes'] !== undefined) this.setSelectedGamemodesFromParam(params['gamemodes']); - if (params['genres'] !== undefined) this.activeGenreFilters = this.matchSelectedFilters(this.availableGenres, params['genres']); - if (params['themes'] !== undefined) this.activeThemeFilters = this.matchSelectedFilters(this.availableThemes, params['themes']); - if (params['playerPerspectives'] !== undefined) this.activePlayerPerspectiveFilters = this.matchSelectedFilters(this.availablePlayerPerspectives, params['playerPerspectives']); + this.previousStateParams = this.route.snapshot.queryParams; + if (this.previousStateParams['search'] !== undefined) this.searchTerm = this.previousStateParams['search']; + if (this.previousStateParams['sort'] !== undefined) this.selectedSortOption = this.matchSelectedSortOptionFromParam(this.previousStateParams['sort']); + if (this.previousStateParams['gamemodes'] !== undefined) this.setSelectedGamemodesFromParam(this.previousStateParams['gamemodes']); + if (this.previousStateParams['genres'] !== undefined) this.activeGenreFilters = this.matchSelectedFilters(this.availableGenres, this.previousStateParams['genres']); + if (this.previousStateParams['themes'] !== undefined) this.activeThemeFilters = this.matchSelectedFilters(this.availableThemes, this.previousStateParams['themes']); + if (this.previousStateParams['playerPerspectives'] !== undefined) this.activePlayerPerspectiveFilters = this.matchSelectedFilters(this.availablePlayerPerspectives, this.previousStateParams['playerPerspectives']); - this.refreshLibraryView().then(() => this.loading = false); - }); + this.refreshLibraryView().then(() => this.loading = false); }); } ); @@ -199,25 +198,29 @@ export class LibraryOverviewComponent implements AfterContentInit { } private saveStateToRoute(): void { - let stateParams: Params = {}; + let newStateParams: Params = {}; - if (this.searchTerm.trim().length > 0) stateParams['search'] = this.searchTerm; - if (this.selectedSortOption !== this.defaultSortOption) stateParams['sort'] = this.toParam(this.selectedSortOption); - if (this.getActiveGameModesFilters().length > 0) stateParams['gamemodes'] = this.getActiveGameModesFilters().join(','); - if (this.activeGenreFilters.length > 0) stateParams['genres'] = this.activeGenreFilters.join(','); - if (this.activeThemeFilters.length > 0) stateParams['themes'] = this.activeThemeFilters.join(','); - if (this.activePlayerPerspectiveFilters.length > 0) stateParams['playerPerspectives'] = this.activePlayerPerspectiveFilters.join(','); + if (this.searchTerm.trim().length > 0) newStateParams['search'] = this.searchTerm; + if (this.selectedSortOption !== this.defaultSortOption) newStateParams['sort'] = LibraryOverviewComponent.toParam(this.selectedSortOption); + if (this.getActiveGameModesFilters().length > 0) newStateParams['gamemodes'] = this.getActiveGameModesFilters().join(','); + if (this.activeGenreFilters.length > 0) newStateParams['genres'] = this.activeGenreFilters.join(','); + if (this.activeThemeFilters.length > 0) newStateParams['themes'] = this.activeThemeFilters.join(','); + if (this.activePlayerPerspectiveFilters.length > 0) newStateParams['playerPerspectives'] = this.activePlayerPerspectiveFilters.join(','); - const url = this.router.createUrlTree([], {relativeTo: this.route, queryParams: stateParams}).toString(); - this.location.go(url); + // only update the route if it changed + if (JSON.stringify(this.previousStateParams) !== JSON.stringify(newStateParams)) { + const url = this.router.createUrlTree([], {relativeTo: this.route, queryParams: newStateParams}).toString(); + this.previousStateParams = newStateParams; + this.location.go(url); + } } - private toParam(sortOption: SortOption): string { + private static toParam(sortOption: SortOption): string { return `${sortOption.field}_${sortOption.direction}`; } private matchSelectedSortOptionFromParam(sortParam: string): SortOption { - return this.sortOptions.find(s => sortParam === this.toParam(s)) ?? this.defaultSortOption; + return this.sortOptions.find(s => sortParam === LibraryOverviewComponent.toParam(s)) ?? this.defaultSortOption; } private matchSelectedFilters(options: any[], paramString: string): string[] {