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
This commit is contained in:
Simon Grimme
2022-08-16 00:32:04 +02:00
parent af74ee83d3
commit 165d10c4d5
4 changed files with 39 additions and 32 deletions
@@ -28,14 +28,14 @@
<div *ngIf="game.genres !== undefined && game.genres.length > 0">
<h2>Genres</h2>
<mat-chip-list>
<mat-chip *ngFor="let genre of game.genres">{{genre.name}}</mat-chip>
<mat-chip *ngFor="let genre of game.genres" (click)="goToLibraryWithFilter('genres', genre.slug)">{{genre.name}}</mat-chip>
</mat-chip-list>
</div>
<div *ngIf="game.themes !== undefined && game.themes.length > 0">
<h2>Themes</h2>
<mat-chip-list>
<mat-chip *ngFor="let theme of game.themes">{{theme.name}}</mat-chip>
<mat-chip *ngFor="let theme of game.themes" (click)="goToLibraryWithFilter('themes', theme.slug)">{{theme.name}}</mat-chip>
</mat-chip-list>
</div>
</div>
@@ -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});
}
}
@@ -54,7 +54,7 @@
</mat-select>
</mat-card>
<mat-expansion-panel>
<mat-expansion-panel [expanded]="offlineCoopFilterEnabled || onlineCoopFilterEnabled || lanSupportFilterEnabled">
<mat-expansion-panel-header>
<mat-panel-title fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="6px">
<h3 class="filter-category-title">Gamemodes</h3>
@@ -75,7 +75,7 @@
</div>
</mat-expansion-panel>
<mat-expansion-panel *ngIf="availableGenres.length > 0">
<mat-expansion-panel *ngIf="availableGenres.length > 0" [expanded]="activeGenreFilters.length > 0">
<mat-expansion-panel-header>
<h3 class="filter-category-title">Genres</h3>
</mat-expansion-panel-header>
@@ -87,7 +87,7 @@
</div>
</mat-expansion-panel>
<mat-expansion-panel *ngIf="availableThemes.length > 0">
<mat-expansion-panel *ngIf="availableThemes.length > 0" [expanded]="activeThemeFilters.length > 0">
<mat-expansion-panel-header>
<h3 class="filter-category-title">Themes</h3>
</mat-expansion-panel-header>
@@ -99,7 +99,7 @@
</div>
</mat-expansion-panel>
<mat-expansion-panel *ngIf="availablePlayerPerspectives.length > 0">
<mat-expansion-panel *ngIf="availablePlayerPerspectives.length > 0" [expanded]="activePlayerPerspectiveFilters.length > 0">
<mat-expansion-panel-header>
<h3 class="filter-category-title">Player Perspectives</h3>
</mat-expansion-panel-header>
@@ -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[] {