Skip to content

Commit

Permalink
[Issue comixed#49] Add the CollectionPage component and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
mcpierce committed Dec 2, 2019
1 parent 690a204 commit a11061e
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 2 deletions.
4 changes: 3 additions & 1 deletion comixed-frontend/src/app/library/library.module.ts
Expand Up @@ -90,6 +90,7 @@ import { CollectionService } from 'app/library/services/collection.service';
import { CollectionAdaptor } from 'app/library/adaptors/collection.adaptor';
import { CollectionEffects } from 'app/library/effects/collection.effects';
import { CollectionDetailsPageComponent } from './pages/collection-details-page/collection-details-page.component';
import { CollectionPageComponent } from './pages/collection-page/collection-page.component';

@NgModule({
imports: [
Expand Down Expand Up @@ -168,7 +169,8 @@ import { CollectionDetailsPageComponent } from './pages/collection-details-page/
DuplicatePageGridItemComponent,
DuplicatesPageToolbarComponent,
DuplicatePageListItemComponent,
CollectionDetailsPageComponent
CollectionDetailsPageComponent,
CollectionPageComponent
],
providers: [
LibraryService,
Expand Down
Expand Up @@ -17,7 +17,7 @@
*/

export enum CollectionType {
PUBLISHERS = 'publisher',
PUBLISHERS = 'publishers',
SERIES = 'series',
CHARACTERS = 'characters',
TEAMS = 'teams',
Expand Down
@@ -0,0 +1,24 @@
<h2>{{'collection-page.page-title'|translate:{collectionType: collectionType, count: collection.length} }}</h2>
<p-table [value]='collection'
paginator='true'
alwaysShowPaginator='true'
[rows]='rows'
paginatorPosition='both'>
<ng-template pTemplate='colgroup'>
<col>
<col class='cx-table-column-large'>
</ng-template>
<ng-template pTemplate='header'>
<tr>
<th>{{'collection-page.table.header.collection-name'|translate:{collectionType: collectionType.toString().toUpperCase()} }}</th>
<th>{{'collection-page.table.header.collection-count'|translate}}</th>
</tr>
</ng-template>
<ng-template pTemplate='body'
let-entry>
<tr>
<td><a [routerLink]='["/collections", collectionType, entry.name]'>{{entry.name}}</a></td>
<td class='cx-table-column-align-center'>{{'collection-page.table.value.collection-count'|translate:{count: entry.comicCount} }}</td>
</tr>
</ng-template>
</p-table>
Empty file.
@@ -0,0 +1,111 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2019, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { BreadcrumbAdaptor } from 'app/adaptors/breadcrumb.adaptor';
import { LibraryDisplayAdaptor } from 'app/library';
import { CollectionAdaptor } from 'app/library/adaptors/collection.adaptor';
import { CollectionEffects } from 'app/library/effects/collection.effects';
import {
COLLECTION_FEATURE_KEY,
reducer
} from 'app/library/reducers/collection.reducer';
import { AuthenticationAdaptor } from 'app/user';
import { MessageService } from 'primeng/api';
import { TableModule } from 'primeng/table';
import { BehaviorSubject } from 'rxjs';
import { CollectionPageComponent } from './collection-page.component';
import objectContaining = jasmine.objectContaining;

describe('CollectionPageComponent', () => {
let component: CollectionPageComponent;
let fixture: ComponentFixture<CollectionPageComponent>;
let activatedRoute: ActivatedRoute;
let router: Router;
let messageService: MessageService;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule,
TranslateModule.forRoot(),
StoreModule.forRoot({}),
StoreModule.forFeature(COLLECTION_FEATURE_KEY, reducer),
EffectsModule.forRoot([]),
EffectsModule.forFeature([CollectionEffects]),
TableModule
],
declarations: [CollectionPageComponent],
providers: [
CollectionAdaptor,
LibraryDisplayAdaptor,
AuthenticationAdaptor,
BreadcrumbAdaptor,
MessageService,
{
provide: ActivatedRoute,
useValue: {
params: new BehaviorSubject<{}>({}),
queryParams: new BehaviorSubject<{}>({})
}
}
]
}).compileComponents();

fixture = TestBed.createComponent(CollectionPageComponent);
component = fixture.componentInstance;
activatedRoute = TestBed.get(ActivatedRoute);
(activatedRoute.params as BehaviorSubject<{}>).next({
collectionType: 'publishers'
});
router = TestBed.get(Router);
spyOn(router, 'navigateByUrl');
messageService = TestBed.get(MessageService);
spyOn(messageService, 'add');
fixture.detectChanges();
}));

it('should create', () => {
expect(component).toBeTruthy();
});

describe('when the collection type is invalid', () => {
beforeEach(() => {
(activatedRoute.params as BehaviorSubject<{}>).next({
collectionType: 'farkle'
});
});

it('redirects the user to the root page', () => {
expect(router.navigateByUrl).toHaveBeenCalledWith('/home');
});

it('shows an error message', () => {
expect(messageService.add).toHaveBeenCalledWith(
objectContaining({ severity: 'error' })
);
});
});
});
@@ -0,0 +1,111 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2019, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { BreadcrumbAdaptor } from 'app/adaptors/breadcrumb.adaptor';
import { LibraryDisplayAdaptor } from 'app/library';
import { CollectionAdaptor } from 'app/library/adaptors/collection.adaptor';
import { CollectionEntry } from 'app/library/models/collection-entry';
import { CollectionType } from 'app/library/models/collection-type.enum';
import { MessageService } from 'primeng/api';
import { Subscription } from 'rxjs';

@Component({
selector: 'app-collection-page',
templateUrl: './collection-page.component.html',
styleUrls: ['./collection-page.component.scss']
})
export class CollectionPageComponent implements OnInit, OnDestroy {
activatedRouteSubscription: Subscription;
langChangeSubscription: Subscription;
collectionType: CollectionType;
collectionSubscription: Subscription;
collection: CollectionEntry[];
rowsSubscription: Subscription;
rows = 10;

constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title,
private breadcrumbAdaptor: BreadcrumbAdaptor,
private collectionAdaptor: CollectionAdaptor,
private displayAdaptor: LibraryDisplayAdaptor,
private translateService: TranslateService,
private messageService: MessageService
) {}

ngOnInit() {
this.activatedRouteSubscription = this.activatedRoute.params.subscribe(
params => {
const typeName = params['collectionType'].toString().toUpperCase();
this.collectionType = CollectionType[typeName] as CollectionType;
if (!!this.collectionType) {
this.collectionSubscription = this.collectionAdaptor.entries$.subscribe(
collection => (this.collection = collection)
);
this.collectionAdaptor.getCollection(this.collectionType);
} else {
this.messageService.add({
severity: 'error',
detail: this.translateService.instant(
'collections.error.invalid-collection-type',
{ name: typeName }
)
});
this.router.navigateByUrl('/home');
}
}
);
this.langChangeSubscription = this.translateService.onLangChange.subscribe(
() => this.loadTranslations()
);
this.loadTranslations();
this.rowsSubscription = this.displayAdaptor.rows$.subscribe(
rows => (this.rows = rows)
);
}

ngOnDestroy() {
this.activatedRouteSubscription.unsubscribe();
this.rowsSubscription.unsubscribe();
this.collectionSubscription.unsubscribe();
}

private loadTranslations() {
this.titleService.setTitle(
this.translateService.instant('collection-page.title', {
collectionType: this.collectionType.toString().toUpperCase()
})
);
this.breadcrumbAdaptor.loadEntries([
{
label: this.translateService.instant('breadcrumb.collections.root')
},
{
label: this.translateService.instant(
`breadcrumb.collections.${this.collectionType}`
),
routerLink: [`/collections/${this.collectionType}`]
}
]);
}
}
27 changes: 27 additions & 0 deletions comixed-frontend/src/assets/i18n/library-en.json
Expand Up @@ -289,5 +289,32 @@
"error": {
"invalid-collection-type": "No such collection type: {name}"
}
},
"collection-page": {
"page-title": "{collectionType} - {count, plural, =1{One Comic} other{# Comics}}",
"title": "{collectionType}",
"table": {
"header": {
"collection-name": "{collectionType} NAME",
"collection-count": "# OF COMICS"
},
"value": {
"collection-count": "{count, plural, =1{1 COMIC} other{# COMICS}}"
}
},
"error": {
"invalid-collection-type": "No such collection type: {name}"
}
},
"breadcrumb": {
"collections": {
"root": "Collections",
"publishers": "Publishers",
"series": "Series",
"characters": "Characters",
"teams": "Teams",
"locations": "Locations",
"stories": "Stories"
}
}
}

0 comments on commit a11061e

Please sign in to comment.