Updating the search page

This commit is contained in:
Zoe Roux 2020-08-04 20:46:34 +02:00
parent cee5b62469
commit cf2196b153
29 changed files with 169 additions and 628 deletions

View File

@ -1,7 +1,7 @@
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {ItemsGridComponent} from './components/items-grid/items-grid.component';
import {NotFoundComponent} from './not-found/not-found.component';
import {NotFoundComponent} from './pages/not-found/not-found.component';
import {PageResolver} from './services/resolvers/page-resolver.service';
import {ShowDetailsComponent} from './pages/show-details/show-details.component';
import {AuthGuard} from "./auth/misc/authenticated-guard.service";
@ -18,7 +18,8 @@ import {Show} from "../models/show";
import {ItemResolver} from "./services/resolvers/item-resolver.service";
import {CollectionComponent} from "./pages/collection/collection.component";
import {Collection} from "../models/collection";
import {People} from "../models/people";
import {SearchComponent} from "./pages/search/search.component";
import {SearchResult} from "../models/search-result";
const routes: Routes = [
{path: "browse", component: ItemsGridComponent, pathMatch: "full",
@ -55,8 +56,14 @@ const routes: Routes = [
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
},
{path: "search/:query", component: SearchComponent,
resolve: { items: ItemResolver.forResource<SearchResult>("search/:query") },
canLoad: [AuthGuard.forPermissions("read")],
canActivate: [AuthGuard.forPermissions("read")]
},
// {path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService }, canLoad: [AuthGuard.forPermissions("play")], canActivate: [AuthGuard.forPermissions("play")]},
// {path: "search/:query", component: SearchComponent, resolve: { items: SearchResolverService }, canLoad: [AuthGuard.forPermissions("read")], canActivate: [AuthGuard.forPermissions("read")]},
// TODO implement missing pages: /genre, /studio & an home page.
{path: "**", component: NotFoundComponent}
];

View File

@ -17,12 +17,11 @@ import { AppComponent } from './app.component';
import {ItemsGridComponent} from './components/items-grid/items-grid.component';
import {CollectionComponent} from './pages/collection/collection.component';
import {EpisodesListComponent} from './components/episodes-list/episodes-list.component';
import { NotFoundComponent } from './not-found/not-found.component';
import {NotFoundComponent} from './pages/not-found/not-found.component';
import {PeopleListComponent} from './components/people-list/people-list.component';
import {PlayerComponent} from './pages/player/player.component';
import {SearchComponent} from './pages/search/search.component';
import {ShowDetailsComponent} from './pages/show-details/show-details.component';
import { ShowsListComponent } from './components/shows-list/shows-list.component';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {MatInputModule} from "@angular/material/input";
import {MatFormFieldModule} from "@angular/material/form-field";
@ -34,12 +33,11 @@ import {FallbackDirective} from "./misc/fallback.directive";
import {AuthModule} from "./auth/auth.module";
import {AuthRoutingModule} from "./auth/auth-routing.module";
import {TrailerDialogComponent} from './pages/trailer-dialog/trailer-dialog.component';
import {CollectionsListComponent} from "./collection-list/collections-list.component";
import {ItemsListComponent} from "./components/items-list/items-list.component";
import {MetadataEditComponent} from './pages/metadata-edit/metadata-edit.component';
import {MatChipsModule} from "@angular/material/chips";
import {MatAutocompleteModule} from "@angular/material/autocomplete";
import {MatExpansionModule} from "@angular/material/expansion";
import {ShowGridComponent} from './components/show-grid/show-grid.component';
import {InfiniteScrollModule} from "ngx-infinite-scroll";
@ -54,13 +52,11 @@ import {InfiniteScrollModule} from "ngx-infinite-scroll";
CollectionComponent,
SearchComponent,
PeopleListComponent,
ShowsListComponent,
PasswordValidator,
FallbackDirective,
TrailerDialogComponent,
CollectionsListComponent,
ItemsListComponent,
MetadataEditComponent,
ShowGridComponent
],
imports: [
BrowserModule,

View File

@ -1,10 +0,0 @@
<div class="scroll-row mb-5">
<div class="collections-container" #scrollView (scroll)="onScroll()">
<a class="collection" *ngFor="let collection of this.collections" routerLink="/collection/{{collection.slug}}" href="/collection/{{collection.slug}}">
<div matRipple [style.background-image]="getThumb(collection.slug)"> </div>
<p class="title">{{collection.name}}</p>
</a>
</div>
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -1,142 +0,0 @@
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.collections-container
{
display: flex;
padding-left: 15px;
padding-right: 15px;
overflow-x: auto;
min-width: 100%;
flex-shrink: 0;
flex-direction: row;
&::-webkit-scrollbar
{
height: 4px;
background: transparent;
}
&::-webkit-scrollbar-thumb
{
background-color: #999;
border-radius: 90px;
&:host-context(.hoverEnabled) &:hover
{
background-color: rgb(134, 127, 127);
}
}
}
.collection
{
width: 33%;
min-width: 120px;
max-width: 200px;
list-style: none;
padding: .5em;
text-decoration: none;
color: inherit;
outline: none;
flex-shrink: 0;
flex-grow: 0;
@include media-breakpoint-up(sm)
{
width: 25%;
}
@include media-breakpoint-up(md)
{
width: 20%;
padding: 1em;
}
@include media-breakpoint-up(lg)
{
width: 18%;
}
@include media-breakpoint-up(xl)
{
width: 15%;
}
&:focus, &:hover
{
> div
{
outline: solid var(--accentColor);
}
> .title
{
text-decoration: underline;
}
}
> div
{
width: 100%;
height: 0;
padding-top: 147.0588%;
background-size: cover;
background-color: #333333;
}
> p
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0px;
opacity: 1;
}
&:host-context(.hoverEnabled) &:hover
{
cursor: pointer;
}
}
.scroll-row
{
position: relative;
&:host-context(.hoverEnabled) &:hover
{
.scrollBtn
{
display: block;
}
}
}
.scrollBtn
{
padding: 0;
outline: none;
min-width: 0;
position: absolute;
top: 30%;
bottom: 40%;
display: none;
&.leftBtn
{
left: 0;
padding-left: 10px;
padding-right: 2px;
}
&.rightBtn
{
right: 0;
padding-right: 10px;
padding-left: 2px;
}
}

View File

@ -1,50 +0,0 @@
import {Component, ElementRef, Input, ViewChild} from "@angular/core";
import {Collection} from "../../models/collection";
import {MatButton} from "@angular/material/button";
import {DomSanitizer} from "@angular/platform-browser";
@Component({
selector: 'app-collections-list',
templateUrl: './collections-list.component.html',
styleUrls: ['./collections-list.component.scss']
})
export class CollectionsListComponent
{
@Input() collections: Collection[];
@ViewChild("scrollView", {static: true}) private scrollView: ElementRef;
@ViewChild("leftBtn", {static: false}) private leftBtn: MatButton;
@ViewChild("rightBtn", {static: false}) private rightBtn: MatButton;
constructor(private sanitizer: DomSanitizer)
{
}
scrollLeft()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({top: 0, left: -scroll, behavior: "smooth"});
}
scrollRight()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({top: 0, left: scroll, behavior: "smooth"});
}
onScroll()
{
if (this.scrollView.nativeElement.scrollLeft <= 0)
this.leftBtn._elementRef.nativeElement.classList.add("d-none");
else
this.leftBtn._elementRef.nativeElement.classList.remove("d-none");
if (this.scrollView.nativeElement.scrollLeft >= this.scrollView.nativeElement.scrollWidth - this.scrollView.nativeElement.clientWidth)
this.rightBtn._elementRef.nativeElement.classList.add("d-none");
else
this.rightBtn._elementRef.nativeElement.classList.remove("d-none");
}
getThumb(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
}

View File

@ -27,7 +27,7 @@
<div class="container-fluid justify-content-center" infinite-scroll (scrolled)="this.page?.loadNext(this.client)">
<a class="show" *ngFor="let item of this.page?.items" [href]="getLink(item)" [routerLink]="getLink(item)">
<div matRipple [style.background-image]="getThumb(item.slug)" > </div>
<p class="title">{{item.title}}</p>
<p class="title">{{item.title ? item.title : item.name}}</p>
<p class="date">{{getDate(item)}}</p>
</a>
</div>

View File

@ -79,7 +79,7 @@ button
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0px;
margin-bottom: 0;
opacity: 1;
&.date

View File

@ -1,10 +1,12 @@
import {Component, Input} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {DomSanitizer} from '@angular/platform-browser';
import {ItemType, LibraryItem} from "../../../models/library-item";
import {LibraryItem} from "../../../models/library-item";
import {Page} from "../../../models/page";
import {HttpClient} from "@angular/common/http";
import {Show, ShowRole} from "../../../models/show";
import {Collection} from "../../../models/collection";
import {ItemsUtils} from "../../misc/items-utils";
@Component({
selector: 'app-items',
@ -13,7 +15,7 @@ import {Show, ShowRole} from "../../../models/show";
})
export class ItemsGridComponent
{
@Input() page: Page<LibraryItem | Show | ShowRole>;
@Input() page: Page<LibraryItem | Show | ShowRole | Collection>;
@Input() sortEnabled: boolean = true;
sortType: string = "title";
sortKeys: string[] = ["title", "start year", "end year"]
@ -34,12 +36,14 @@ export class ItemsGridComponent
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
getLink(item: LibraryItem | Show | ShowRole)
getDate(item: LibraryItem | Show | ShowRole | Collection)
{
if ("type" in item && item.type == ItemType.Collection)
return "/collection/" + item.slug;
else
return "/show/" + item.slug;
return ItemsUtils.getDate(item);
}
getLink(item: LibraryItem | Show | ShowRole | Collection)
{
return ItemsUtils.getLink(item);
}
sort(type: string, order: boolean)
@ -52,20 +56,4 @@ export class ItemsGridComponent
this.client.get<Page<LibraryItem | Show>>(url.toString())
.subscribe(x => this.page = Object.assign(new Page<LibraryItem | Show>(), x));
}
getDate(item: LibraryItem | Show | ShowRole): string
{
if ("role" in item && item.role)
{
if ("type" in item && item.type)
return `as ${item.role} (${item.type})`;
return `as ${item.role}`;
}
if ("type" in item && item.type && typeof item.type == "string")
return item.type;
if (item.endYear && item.startYear != item.endYear)
return `${item.startYear} - ${item.endYear}`
return item.startYear?.toString();
}
}

View File

@ -0,0 +1,11 @@
<div class="scroll-row mb-5">
<div class="container" #scrollView (scroll)="onScroll()" infinite-scroll (scrolled)="this.items?.loadNext(this.client)" [horizontal]="true" [scrollWindow]="false">
<a class="item" *ngFor="let item of this.items?.items" [routerLink]="getLink(item)" [href]="getLink(item)" #itemsDom>
<div matRipple [style.background-image]="getThumb(item.slug)"> </div>
<p class="title">{{item.title ? item.title : item.name}}</p>
<p class="date">{{getDate(item)}}</p>
</a>
</div>
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -2,7 +2,7 @@
@import "../../../../node_modules/bootstrap/scss/variables";
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
.shows-container
.container
{
display: flex;
padding-left: 15px;
@ -11,6 +11,8 @@
min-width: 100%;
flex-shrink: 0;
flex-direction: row;
scrollbar-width: thin;
scrollbar-color: #999 transparent;
&::-webkit-scrollbar
{
@ -30,7 +32,7 @@
}
}
.show
.item
{
width: 33%;
min-width: 120px;
@ -93,7 +95,7 @@
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0px;
margin-bottom: 0;
opacity: 1;
&.date

View File

@ -0,0 +1,39 @@
import {Component, Input} from "@angular/core";
import {Collection} from "../../../models/collection";
import {DomSanitizer} from "@angular/platform-browser";
import {HorizontalScroller} from "../../misc/horizontal-scroller";
import {Page} from "../../../models/page";
import {HttpClient} from "@angular/common/http";
import {Show, ShowRole} from "../../../models/show";
import {LibraryItem} from "../../../models/library-item";
import {ItemsUtils} from "../../misc/items-utils";
@Component({
selector: 'app-items-list',
templateUrl: './items-list.component.html',
styleUrls: ['./items-list.component.scss']
})
export class ItemsListComponent extends HorizontalScroller
{
@Input() items: Page<Collection | Show | LibraryItem | ShowRole>;
constructor(private sanitizer: DomSanitizer, public client: HttpClient)
{
super();
}
getThumb(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
getDate(item: LibraryItem | Show | ShowRole | Collection)
{
return ItemsUtils.getDate(item);
}
getLink(item: LibraryItem | Show | ShowRole | Collection)
{
return ItemsUtils.getLink(item);
}
}

View File

@ -1,22 +0,0 @@
<div class="container-fluid">
<div *ngFor="let show of this.shows" class="show-container">
<mat-card class="show">
<a [href]="getLink(show)" [routerLink]="getLink(show)" class="d-flex" (click)="this.clickCallback.emit(show)">
<div class="thumb">
<div [style.background-image]="getThumb(show)"> </div>
</div>
<div class="data">
<p class="title">{{show.title}}</p>
<p class="date" *ngIf="show.endYear && show.startYear != show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
<p class="overview">{{show.overview}}</p>
<ul>
<li class="provider" *ngFor="let id of this.show.externalIDs">
<a [href]="id.link"><img [src]="id.provider.logo" [alt]="id.provider.name"/></a>
</li>
</ul>
</div>
</a>
</mat-card>
</div>
</div>

View File

@ -1,144 +0,0 @@
@import "../../../../node_modules/bootstrap/scss/functions";
@import "../../../../node_modules/bootstrap/scss/variables";
@import "../../../../node_modules/bootstrap/scss/mixins/breakpoints";
button
{
outline: none;
}
.arrow
{
font-size: 12px;
}
.container-fluid
{
display: flex;
flex-wrap: wrap;
}
.show-container
{
width: 100%;
min-width: 300px;
list-style: none;
padding: .5em;
@include media-breakpoint-up(lg)
{
width: 50%;
}
@include media-breakpoint-up(xl)
{
width: 33%;
}
}
.show
{
padding: 0;
> a
{
text-decoration: none;
color: inherit;
outline: none;
position: relative;
&:focus, &:hover
{
> .data > .title
{
text-decoration: underline;
}
}
> .thumb
{
width: 33%;
> div
{
width: 100%;
height: 0;
padding-top: 147.0588%;
background-size: cover;
background-color: #333333;
}
}
> .data
{
width: 67%;
padding: .5rem;
position: absolute;
top: 0;
bottom: 0;
right: 0;
> p:not(.overview)
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0;
opacity: 1;
display: inline-block;
&.date
{
opacity: 0.8;
font-size: 0.8em;
padding-left: 1rem;
}
}
> .overview
{
overflow-y: auto;
height: calc(100% - 4rem);
text-align: justify;
padding-right: .5rem;
margin-bottom: 0;
}
&:host-context(.hoverEnabled) &:hover
{
cursor: pointer;
}
}
}
}
.provider
{
display: inline-block;
width: 2.5rem;
height: 2.5rem;
margin: .25rem;
> a
{
width: 2.5rem;
height: 2.5rem;
position: relative;
display: inline-block;
> img
{
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
max-width: 2.5rem;
max-height: 2.5rem;
}
}
}

View File

@ -1,29 +0,0 @@
import {AfterViewInit, Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Show} from "../../../models/show";
import {DomSanitizer} from "@angular/platform-browser";
@Component({
selector: 'app-show-grid',
templateUrl: './show-grid.component.html',
styleUrls: ['./show-grid.component.scss']
})
export class ShowGridComponent
{
@Input() shows: Show[]
@Input() externalShows: boolean = false;
@Output() clickCallback: EventEmitter<Show> = new EventEmitter();
constructor(private sanitizer: DomSanitizer) { }
getThumb(show: Show)
{
return this.sanitizer.bypassSecurityTrustStyle(`url(${show.poster})`);
}
getLink(show: Show)
{
if (this.externalShows)
return null;
return `/show/${show.slug}`;
}
}

View File

@ -1,12 +0,0 @@
<div class="scroll-row mb-5">
<div class="shows-container" #scrollView (scroll)="onScroll()">
<a class="show" *ngFor="let show of this.shows" routerLink="/show/{{show.slug}}" href="/show/{{show.slug}}">
<div matRipple [style.background-image]="getThumb(show.slug)"> </div>
<p class="title">{{show.title}}</p>
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
</a>
</div>
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -1,48 +0,0 @@
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
import { MatButton } from "@angular/material/button";
import { DomSanitizer } from "@angular/platform-browser";
import { Show } from "../../../models/show";
@Component({
selector: 'app-shows-list',
templateUrl: './shows-list.component.html',
styleUrls: ['./shows-list.component.scss']
})
export class ShowsListComponent
{
@Input() shows: Show[];
@ViewChild("scrollView", { static: true }) private scrollView: ElementRef;
@ViewChild("leftBtn", { static: false }) private leftBtn: MatButton;
@ViewChild("rightBtn", { static: false }) private rightBtn: MatButton;
constructor(private sanitizer: DomSanitizer) { }
scrollLeft()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({ top: 0, left: -scroll, behavior: "smooth" });
}
scrollRight()
{
let scroll: number = this.scrollView.nativeElement.offsetWidth * 0.80;
this.scrollView.nativeElement.scrollBy({ top: 0, left: scroll, behavior: "smooth" });
}
onScroll()
{
if (this.scrollView.nativeElement.scrollLeft <= 0)
this.leftBtn._elementRef.nativeElement.classList.add("d-none");
else
this.leftBtn._elementRef.nativeElement.classList.remove("d-none");
if (this.scrollView.nativeElement.scrollLeft >= this.scrollView.nativeElement.scrollWidth - this.scrollView.nativeElement.clientWidth)
this.rightBtn._elementRef.nativeElement.classList.add("d-none");
else
this.rightBtn._elementRef.nativeElement.classList.remove("d-none");
}
getThumb(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
}

View File

@ -6,7 +6,7 @@ export class HorizontalScroller
@ViewChild("scrollView", { static: true }) private scrollView: ElementRef;
@ViewChild("leftBtn", { static: false }) private leftBtn: MatButton;
@ViewChild("rightBtn", { static: false }) private rightBtn: MatButton;
@ViewChild("itemsDom", { static: false }) private items: ElementRef;
@ViewChild("itemsDom", { static: false }) private itemsDom: ElementRef;
scrollLeft()
{
@ -22,7 +22,7 @@ export class HorizontalScroller
roundScroll(offset: number): number
{
let itemSize: number = this.items.nativeElement.scrollWidth;
let itemSize: number = this.itemsDom.nativeElement.scrollWidth;
offset = Math.round(offset / itemSize) * itemSize;
if (offset == 0)

View File

@ -0,0 +1,30 @@
import {ItemType, LibraryItem} from "../../models/library-item";
import {Show, ShowRole} from "../../models/show";
import {Collection} from "../../models/collection";
export class ItemsUtils
{
static getLink(item: LibraryItem | Show | ShowRole | Collection): string
{
if ("type" in item && item.type == ItemType.Collection)
return "/collection/" + item.slug;
else
return "/show/" + item.slug;
}
static getDate(item: LibraryItem | Show | ShowRole | Collection): string
{
if ("role" in item && item.role)
{
if ("type" in item && item.type)
return `as ${item.role} (${item.type})`;
return `as ${item.role}`;
}
if ("type" in item && item.type && typeof item.type == "string")
return item.type;
if (item.endYear && item.startYear != item.endYear)
return `${item.startYear} - ${item.endYear}`
return item.startYear?.toString();
}
}

View File

@ -1,16 +1,16 @@
<div *ngIf="items.collections.length > 0" class="container-fluid mt-3">
<h3>Collections</h3>
</div>
<app-collections-list [collections]="items.collections"></app-collections-list>
<app-items-list [items]="AsPage(items.collections)"></app-items-list>
<div *ngIf="items.shows.length > 0" class="container-fluid mt-3">
<h3>Shows</h3>
</div>
<app-shows-list [shows]="items.shows"></app-shows-list>
<app-items-list [items]="AsPage(items.shows)"></app-items-list>
<div *ngIf="items.episodes.length > 0" class="container-fluid mt-5">
<h3>Episodes</h3>
</div>
<app-episodes-list displayShowTitle="true" [episodes]="items.episodes"></app-episodes-list>
<app-episodes-list displayShowTitle="true" [episodes]="AsPage(items.episodes)"></app-episodes-list>
<div *ngIf="items.people.length > 0" class="container-fluid mt-5">
<h3>People</h3>
</div>
<app-people-list [people]="items.people"></app-people-list>
<app-people-list [people]="AsPage(items.people)"></app-people-list>

View File

@ -2,6 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from "@angular/router";
import { SearchResult } from "../../../models/search-result";
import { Title } from "@angular/platform-browser";
import {Page} from "../../../models/page";
@Component({
selector: 'app-search',
@ -36,4 +37,9 @@ export class SearchComponent implements OnInit, OnDestroy
searchBar.classList.remove("searching");
searchBar.value = "";
}
AsPage<T>(collection: T[]): Page<T>
{
return new Page<T>({this: "", items: collection, next: null, count: collection.length});
}
}

View File

@ -1,33 +0,0 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators'
import { Collection } from "../../../models/collection";
@Injectable({
providedIn: 'root'
})
export class CollectionResolverService implements Resolve<Collection>
{
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
resolve(route: ActivatedRouteSnapshot): Collection | Observable<Collection> | Promise<Collection>
{
let collection: string = route.paramMap.get("collection-slug");
return this.http.get<Collection>("api/collection/" + collection).pipe(catchError((error: HttpErrorResponse) =>
{
console.log(error.status + " - " + error.message);
if (error.status == 404)
{
this.snackBar.open("Collection \"" + collection + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
else
{
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
return EMPTY;
}));
}
}

View File

@ -4,14 +4,13 @@ import {MatSnackBar} from '@angular/material/snack-bar';
import {ActivatedRouteSnapshot, Resolve} from '@angular/router';
import {Observable, EMPTY} from 'rxjs';
import {catchError} from 'rxjs/operators';
import {IResource} from "../../../models/resources/resource";
@Injectable()
export class ItemResolver
{
public static resolvers: any[] = [];
static forResource<T extends IResource>(resource: string)
static forResource<T>(resource: string)
{
@Injectable()
class Resolver implements Resolve<T>
@ -27,6 +26,16 @@ export class ItemResolver
return this.http.get<T>(`api/${res}`)
.pipe(
catchError((error: HttpErrorResponse) =>
{
if (error.status == 404)
{
this.snackBar.open(`Item not found.`, null, {
horizontalPosition: "left",
panelClass: ['snackError'],
duration: 2500
});
}
else
{
console.log(error.status + " - " + error.message);
this.snackBar.open(`An unknown error occurred: ${error.message}.`, null, {
@ -34,6 +43,7 @@ export class ItemResolver
panelClass: ['snackError'],
duration: 2500
});
}
return EMPTY;
}));
}

View File

@ -1,34 +0,0 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Collection } from "../../../models/collection";
import { People } from "../../../models/people";
@Injectable({
providedIn: 'root'
})
export class PeopleResolverService implements Resolve<Collection>
{
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
resolve(route: ActivatedRouteSnapshot): Collection | Observable<Collection> | Promise<Collection>
{
let people: string = route.paramMap.get("people-slug");
return this.http.get<Collection>("api/people/" + people).pipe(catchError((error: HttpErrorResponse) =>
{
console.log(error.status + " - " + error.message);
if (error.status == 404)
{
this.snackBar.open("People \"" + people + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
else
{
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
return EMPTY;
}));
}
}

View File

@ -1,27 +0,0 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Show } from "../../../models/show";
@Injectable()
export class ShowResolverService implements Resolve<Show>
{
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
resolve(route: ActivatedRouteSnapshot): Show | Observable<Show> | Promise<Show>
{
let slug: string = route.paramMap.get("show-slug");
return this.http.get<Show>("api/shows/" + slug).pipe(catchError((error: HttpErrorResponse) =>
{
console.log(error.status + " - " + error.message);
if (error.status == 404)
this.snackBar.open("Show \"" + slug + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
else
this.snackBar.open("An unknown error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
return EMPTY;
}));
}
}

View File

@ -8,7 +8,10 @@ export class Page<T>
count: number
items: T[]
constructor() {}
constructor(init?:Partial<Page<T>>)
{
Object.assign(this, init);
}
loadNext(client: HttpClient)
{

View File

@ -12,6 +12,6 @@ export interface SearchResult
shows: Show[];
episodes: Episode[];
people: People[];
genrwes: Genre[];
genres: Genre[];
studios: Studio[];
}