diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 88a1e0f0..90a5a028 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,11 +1,11 @@ -import {NgModule} from '@angular/core'; -import {RouterModule, Routes} from '@angular/router'; -import {ItemsGridComponent} from './components/items-grid/items-grid.component'; -import {NotFoundComponent} from './pages/not-found/not-found.component'; -import {PageResolver} from './services/page-resolver.service'; -import {ShowDetailsComponent} from './pages/show-details/show-details.component'; -import {AuthGuard} from "./auth/misc/authenticated-guard.service"; -import {LibraryItem} from "../models/resources/library-item"; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ItemsGridComponent } from './components/items-grid/items-grid.component'; +import { NotFoundComponent } from './pages/not-found/not-found.component'; +import { PageResolver } from './services/page-resolver.service'; +import { ShowDetailsComponent } from './pages/show-details/show-details.component'; +import { AuthGuard } from "./auth/misc/authenticated-guard.service"; +import { LibraryItem } from "../models/resources/library-item"; import { EpisodeService, LibraryItemService, @@ -14,29 +14,29 @@ import { SeasonService, ShowService } from "./services/api.service"; -import {Show} from "../models/resources/show"; -import {ItemResolver} from "./services/item-resolver.service"; -import {CollectionComponent} from "./pages/collection/collection.component"; -import {Collection} from "../models/resources/collection"; -import {SearchComponent} from "./pages/search/search.component"; -import {SearchResult} from "../models/search-result"; -import {PlayerComponent} from "./pages/player/player.component"; -import {WatchItem} from "../models/watch-item"; +import { Show } from "../models/resources/show"; +import { ItemResolver } from "./services/item-resolver.service"; +import { CollectionComponent } from "./pages/collection/collection.component"; +import { Collection } from "../models/resources/collection"; +import { SearchComponent } from "./pages/search/search.component"; +import { SearchResult } from "../models/search-result"; +import { PlayerComponent } from "./pages/player/player.component"; +import { WatchItem } from "../models/watch-item"; const routes: Routes = [ {path: "browse", component: ItemsGridComponent, pathMatch: "full", - resolve: { items: PageResolver.forResource("items") }, + resolve: {items: PageResolver.forResource("items", ItemsGridComponent.routeMapper)}, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")] }, {path: "browse/:slug", component: ItemsGridComponent, - resolve: { items: PageResolver.forResource("library/:slug/items") }, + resolve: {items: PageResolver.forResource("library/:slug/items", ItemsGridComponent.routeMapper)}, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")] }, {path: "show/:slug", component: ShowDetailsComponent, - resolve: { show: ItemResolver.forResource("shows/:slug") }, + resolve: {show: ItemResolver.forResource("shows/:slug")}, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")] }, @@ -60,13 +60,13 @@ const routes: Routes = [ }, {path: "search/:query", component: SearchComponent, - resolve: { items: ItemResolver.forResource("search/:query") }, + resolve: {items: ItemResolver.forResource("search/:query")}, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")] }, {path: "watch/:item", component: PlayerComponent, - resolve: { item: ItemResolver.forResource("watch/:item") }, + resolve: {item: ItemResolver.forResource("watch/:item")}, canLoad: [AuthGuard.forPermissions("play")], canActivate: [AuthGuard.forPermissions("play")] }, diff --git a/src/app/components/items-grid/items-grid.component.ts b/src/app/components/items-grid/items-grid.component.ts index e8bf1acb..c7dfaa72 100644 --- a/src/app/components/items-grid/items-grid.component.ts +++ b/src/app/components/items-grid/items-grid.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; +import { ActivatedRoute, ActivatedRouteSnapshot, Router } from "@angular/router"; import { DomSanitizer } from '@angular/platform-browser'; import { Genre } from "../../../models/resources/genre"; import { LibraryItem } from "../../../models/resources/library-item"; @@ -36,7 +36,8 @@ export class ItemsGridComponent implements OnInit constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer, private loader: PreLoaderService, - public client: HttpClient) + public client: HttpClient, + private router: Router) { this.route.data.subscribe((data) => { @@ -45,13 +46,29 @@ export class ItemsGridComponent implements OnInit this.loader.load("/api/genres?limit=0").subscribe(data => { this.genres = data; + let selectedGenres: string[] = []; + if (this.route.snapshot.queryParams.genres?.startsWith("ctn:")) + selectedGenres = this.route.snapshot.queryParams.genres.substr(4).split(','); + this.filters.genres = this.genres.filter(x => selectedGenres.includes(x.slug)); }); this.loader.load("/api/studios?limit=0").subscribe(data => { this.studios = data; + this.filters.studio = this.studios.find(x => x.slug == this.route.params["studio"]); }); } + static routeMapper(route: ActivatedRouteSnapshot, endpoint: string): string + { + const filter: string[] = ["genres", "studio"]; + let queryParams: [string, string][] = Object.entries(route.queryParams).filter(x => filter.includes(x[0])); + if (queryParams.length > 0) + endpoint = "shows"; + + let params: string = '?' + queryParams.map(x => `${x[0]}=${x[1]}`).join('&'); + return `api/${endpoint}${params}` + } + ngOnInit() { this.defaultType = this.page.this.match(/\/(\w*)($|\?)/)[1]; @@ -107,12 +124,22 @@ export class ItemsGridComponent implements OnInit : new URL(this.page.changeType(this.defaultType)); } + let param: string; if (isArray && this.filters[category].length > 0) - url.searchParams.set(category, `ctn:${this.filters[category].map(x => x.slug).join(',')}`); + param = `ctn:${this.filters[category].map(x => x.slug).join(',')}`; else if (!isArray && this.filters[category] != null) - url.searchParams.set(category, filter.slug) + param = filter.slug; + + if (param != null) + url.searchParams.set(category, param); else url.searchParams.delete(category) + this.router.navigate([], { + relativeTo: this.route, + queryParams: { [category]: param }, + replaceUrl: true, + queryParamsHandling: "merge" + }); this.client.get>(url.toString()) .subscribe(x => this.page = Object.assign(new Page(), x)); } diff --git a/src/app/services/page-resolver.service.ts b/src/app/services/page-resolver.service.ts index a9bafbef..5720ac9c 100644 --- a/src/app/services/page-resolver.service.ts +++ b/src/app/services/page-resolver.service.ts @@ -7,12 +7,14 @@ import {catchError, map} from 'rxjs/operators'; import {Page} from "../../models/page"; import {IResource} from "../../models/resources/resource"; +type RouteMapper = (route: ActivatedRouteSnapshot, endpoint: string) => string; + @Injectable() export class PageResolver { public static resolvers: any[] = []; - static forResource(resource: string) + static forResource(resource: string, copyParams: boolean | string[] | RouteMapper = false) { @Injectable() class Resolver implements Resolve> @@ -24,8 +26,21 @@ export class PageResolver resolve(route: ActivatedRouteSnapshot): Page | Observable> | Promise> { let res: string = resource.replace(/:(.*?)(\/|$)/, (x, y) => `${route.paramMap.get(y)}/`); + let uri: string; + if (typeof copyParams == "function") + uri = copyParams(route, res); + else + { + let queryParams: [string, string][] = copyParams == true + ? Object.entries(route.queryParams) + : Object.entries(route.queryParams).filter(x => copyParams && copyParams.includes(x[0])); + let params: string = queryParams.length > 0 + ? '?' + queryParams.map(x => `${x[0]}=${x[1]}`).join('&') + : ""; + uri = `api/${res}${params}`; + } - return this.http.get>(`api/${res}`) + return this.http.get>(uri) .pipe( map(x => Object.assign(new Page(), x)), catchError((error: HttpErrorResponse) =>