From 9a3241c42ab59e15c0084178f76dc4a2450a2bb8 Mon Sep 17 00:00:00 2001 From: Andy Bastian Date: Thu, 27 Jan 2022 14:11:35 +0000 Subject: [PATCH] feat: add HeBIS HDS search --- package-lock.json | 112 +++++++++-- src/app/_helpers/data/sample-things.ts | 2 +- src/app/app.module.ts | 2 + src/app/modules/data/data.module.ts | 3 + .../data/detail/data-detail.component.ts | 8 +- .../favorites/favorites-page.component.ts | 79 +++++++- .../daia-availability.component.spec.ts | 138 +++++++++++++ .../daia-availability.component.ts | 85 ++++++++ .../daia-availability/daia-availability.html | 63 ++++++ .../daia-availability/daia-availability.scss | 38 ++++ src/app/modules/hebis/daia-data.provider.ts | 121 ++++++++++++ src/app/modules/hebis/hebis-data.provider.ts | 104 ++++++++++ .../hebis-detail-content.component.ts | 31 +++ .../hebis-detail/hebis-detail-content.html | 36 ++++ .../hebis-detail/hebis-detail-content.scss | 28 +++ .../hebis-detail.component.spec.ts | 135 +++++++++++++ .../hebis-detail/hebis-detail.component.ts | 83 ++++++++ .../hebis/hebis-detail/hebis-detail.html | 51 +++++ .../hebis/hebis-detail/hebis-detail.scss | 5 + src/app/modules/hebis/hebis-routing.module.ts | 32 +++ src/app/modules/hebis/hebis.module.ts | 100 ++++++++++ .../hebis/list/hebis-search-page.component.ts | 186 ++++++++++++++++++ .../modules/hebis/list/hebis-search-page.html | 39 ++++ src/app/modules/hebis/protocol/request.ts | 20 ++ src/app/modules/hebis/protocol/response.ts | 58 ++++++ src/app/modules/hebis/protocol/route.ts | 54 +++++ .../book/book-detail-content.component.ts | 30 +++ .../hebis/types/book/book-detail-content.html | 82 ++++++++ .../types/book/book-list-item.component.ts | 31 +++ .../hebis/types/book/book-list-item.html | 16 ++ .../hebis-article-content.component.ts | 30 +++ .../hebis-article/hebis-article-content.html | 76 +++++++ .../hebis-article-item.component.ts | 31 +++ .../hebis-article/hebis-article-item.html | 16 ++ .../periodical-detail-content.component.ts | 30 +++ .../periodical/periodical-detail-content.html | 82 ++++++++ .../periodical-list-item.component.ts | 31 +++ .../periodical/periodical-list-item.html | 16 ++ .../menu/navigation/navigation.component.ts | 1 + src/assets/i18n/de.json | 23 +++ src/assets/i18n/en.json | 23 +++ src/environments/environment.ts | 1 + 42 files changed, 2109 insertions(+), 23 deletions(-) create mode 100644 src/app/modules/hebis/daia-availability/daia-availability.component.spec.ts create mode 100644 src/app/modules/hebis/daia-availability/daia-availability.component.ts create mode 100644 src/app/modules/hebis/daia-availability/daia-availability.html create mode 100644 src/app/modules/hebis/daia-availability/daia-availability.scss create mode 100644 src/app/modules/hebis/daia-data.provider.ts create mode 100644 src/app/modules/hebis/hebis-data.provider.ts create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail-content.component.ts create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail-content.html create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail-content.scss create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail.component.ts create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail.html create mode 100644 src/app/modules/hebis/hebis-detail/hebis-detail.scss create mode 100644 src/app/modules/hebis/hebis-routing.module.ts create mode 100644 src/app/modules/hebis/hebis.module.ts create mode 100644 src/app/modules/hebis/list/hebis-search-page.component.ts create mode 100644 src/app/modules/hebis/list/hebis-search-page.html create mode 100644 src/app/modules/hebis/protocol/request.ts create mode 100644 src/app/modules/hebis/protocol/response.ts create mode 100644 src/app/modules/hebis/protocol/route.ts create mode 100644 src/app/modules/hebis/types/book/book-detail-content.component.ts create mode 100644 src/app/modules/hebis/types/book/book-detail-content.html create mode 100644 src/app/modules/hebis/types/book/book-list-item.component.ts create mode 100644 src/app/modules/hebis/types/book/book-list-item.html create mode 100644 src/app/modules/hebis/types/hebis-article/hebis-article-content.component.ts create mode 100644 src/app/modules/hebis/types/hebis-article/hebis-article-content.html create mode 100644 src/app/modules/hebis/types/hebis-article/hebis-article-item.component.ts create mode 100644 src/app/modules/hebis/types/hebis-article/hebis-article-item.html create mode 100644 src/app/modules/hebis/types/periodical/periodical-detail-content.component.ts create mode 100644 src/app/modules/hebis/types/periodical/periodical-detail-content.html create mode 100644 src/app/modules/hebis/types/periodical/periodical-list-item.component.ts create mode 100644 src/app/modules/hebis/types/periodical/periodical-list-item.html diff --git a/package-lock.json b/package-lock.json index f4d3b6d6..6a08ce32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2282,6 +2282,16 @@ "serve-index": "^1.9.1" }, "dependencies": { + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2328,6 +2338,12 @@ "is-wsl": "^2.2.0" } }, + "proxy-middleware": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz", + "integrity": "sha1-o/3xvvtzD5UZZYcqwvYHTGFHelY=", + "dev": true + }, "send": { "version": "0.17.2", "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", @@ -2576,6 +2592,13 @@ "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } } }, "@ionic-native/diagnostic": { @@ -2584,6 +2607,13 @@ "integrity": "sha512-ovzydKPNNK3zu1A0e9Z+cc8oSKaVmuV6DxCE82+KSyPddZzHuzZq/56us39WjlqQ07KDDKLwlGmIib9VGB1Y/A==", "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } } }, "@ionic-native/dialogs": { @@ -2592,6 +2622,13 @@ "integrity": "sha512-cCvwbD/duIL1CVVpgSwwgvyGYuUzL83jFAjPye7WX0ZzqZrh5ifvLjCAw0B+7YFv7Hd3FXZn+04cqvYcZLFcEQ==", "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } } }, "@ionic-native/geolocation": { @@ -2600,6 +2637,13 @@ "integrity": "sha512-Fk7YXBn9/dOBGqtySSQgoCg7OLlmS8M6Y1Xa3hjgZBzFU0NPb9nnhVuMWI5Wp2qH/7cuzWRB7kEp4oN2tZ6fbw==", "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } } }, "@ionic-native/http": { @@ -2609,6 +2653,14 @@ "optional": true, "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=", + "optional": true + } } }, "@ionic-native/in-app-browser": { @@ -2618,6 +2670,14 @@ "optional": true, "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=", + "optional": true + } } }, "@ionic-native/network": { @@ -2626,6 +2686,13 @@ "integrity": "sha512-gpa7cJqodEK+zmmViYJCqEpXoKSXcaYLaaRKdv5gn5M++bpmiw2pKM9JH8VoqYWaYDcUwD3S0yYeBBkG5DE0Kg==", "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } } }, "@ionic-native/safari-view-controller": { @@ -2635,6 +2702,14 @@ "optional": true, "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=", + "optional": true + } } }, "@ionic-native/secure-storage": { @@ -2644,6 +2719,14 @@ "optional": true, "requires": { "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=", + "optional": true + } } }, "@ionic/angular": { @@ -3884,11 +3967,6 @@ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", "dev": true }, - "@types/cordova": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", - "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" - }, "@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -5481,6 +5559,16 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -9377,6 +9465,13 @@ "flat-cache": "^3.0.4" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "filelist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", @@ -15863,12 +15958,6 @@ "ipaddr.js": "1.9.1" } }, - "proxy-middleware": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz", - "integrity": "sha1-o/3xvvtzD5UZZYcqwvYHTGFHelY=", - "dev": true - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -19505,6 +19594,7 @@ "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1" } }, diff --git a/src/app/_helpers/data/sample-things.ts b/src/app/_helpers/data/sample-things.ts index 68606f42..7e6e3ad5 100644 --- a/src/app/_helpers/data/sample-things.ts +++ b/src/app/_helpers/data/sample-things.ts @@ -204,7 +204,7 @@ const sampleBooks: SCBook[] = [ type: SCThingOriginType.Remote, }, type: SCThingType.Book, - uid: 'book-123', + uid: 'HEB290615194', }, { authors: [], diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7be38a04..071899b9 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -41,6 +41,7 @@ import {CatalogModule} from './modules/catalog/catalog.module'; import {ConfigModule} from './modules/config/config.module'; import {ConfigProvider} from './modules/config/config.provider'; import {DataModule} from './modules/data/data.module'; +import {HebisModule} from './modules/hebis/hebis.module'; import {MapModule} from './modules/map/map.module'; import {MenuModule} from './modules/menu/menu.module'; import {NewsModule} from './modules/news/news.module'; @@ -153,6 +154,7 @@ const providers: Provider[] = [ CommonModule, ConfigModule, DataModule, + HebisModule, EndSessionPageModule, IonicModule.forRoot(), FavoritesModule, diff --git a/src/app/modules/data/data.module.ts b/src/app/modules/data/data.module.ts index 901caaeb..30ba6138 100644 --- a/src/app/modules/data/data.module.ts +++ b/src/app/modules/data/data.module.ts @@ -182,6 +182,9 @@ import {TitleCardComponent} from './elements/title-card.component'; SkeletonSimpleCardComponent, SearchPageComponent, SimpleDataListComponent, + ArticleDetailContentComponent, + OriginDetailComponent, + FavoriteButtonComponent, ], }) export class DataModule {} diff --git a/src/app/modules/data/detail/data-detail.component.ts b/src/app/modules/data/detail/data-detail.component.ts index ec9e5ed3..b3c21849 100644 --- a/src/app/modules/data/detail/data-detail.component.ts +++ b/src/app/modules/data/detail/data-detail.component.ts @@ -66,9 +66,9 @@ export class DataDetailComponent { * @param translateService he translate provider */ constructor( - private readonly route: ActivatedRoute, + protected readonly route: ActivatedRoute, private readonly dataProvider: DataProvider, - private readonly network: Network, + protected readonly network: Network, private readonly favoritesService: FavoritesService, translateService: TranslateService, ) { @@ -125,9 +125,7 @@ export class DataDetailComponent { * @param refresher Refresher component that triggers the update */ async refresh(refresher: IonRefresher) { - await this.getItem( - this.item?.uid ?? this.route.snapshot.paramMap.get('uid') ?? '', - ); + await this.getItem(this.route.snapshot.paramMap.get('uid') ?? ''); await refresher.complete(); } } diff --git a/src/app/modules/favorites/favorites-page.component.ts b/src/app/modules/favorites/favorites-page.component.ts index 739a4199..670fd4f0 100644 --- a/src/app/modules/favorites/favorites-page.component.ts +++ b/src/app/modules/favorites/favorites-page.component.ts @@ -13,17 +13,24 @@ * this program. If not, see . */ import {Component, OnInit} from '@angular/core'; +import {AlertController} from '@ionic/angular'; +import {Router} from '@angular/router'; +import {NGXLogger} from 'ngx-logger'; +import { + debounceTime, + distinctUntilChanged, + startWith, + take, +} from 'rxjs/operators'; +import {combineLatest} from 'rxjs'; +import {SCThingType} from '@openstapps/core'; import {FavoritesService} from './favorites.service'; import {DataRoutingService} from '../data/data-routing.service'; -import {Router} from '@angular/router'; import {ContextMenuService} from '../menu/context/context-menu.service'; import {SearchPageComponent} from '../data/list/search-page.component'; -import {AlertController} from '@ionic/angular'; import {DataProvider} from '../data/data.provider'; import {SettingsProvider} from '../settings/settings.provider'; -import {NGXLogger} from 'ngx-logger'; import {PositionService} from '../map/position.service'; -import {take} from 'rxjs/operators'; /** * The page for showing favorites @@ -62,9 +69,69 @@ export class FavoritesPageComponent ngOnInit() { super.ngOnInit(); + for (const subscription of this.subscriptions) { + subscription.unsubscribe(); + } + + // Recreate subscriptions to handle different routing this.subscriptions.push( - this.favoritesService.favoritesChanged$.subscribe(_favoritesMap => { - this.fetchAndUpdateItems(); + combineLatest([ + this.queryTextChanged.pipe( + debounceTime(this.searchQueryDueTime), + distinctUntilChanged(), + startWith(this.queryText), + ), + this.contextMenuService.filterQueryChanged$.pipe( + startWith(this.filterQuery), + ), + this.contextMenuService.sortQueryChanged$.pipe( + startWith(this.sortQuery), + ), + this.favoritesService.favoritesChanged$, + ]).subscribe(async query => { + this.queryText = query[0]; + this.filterQuery = query[1]; + this.sortQuery = query[2]; + this.from = 0; + if ( + typeof this.filterQuery !== 'undefined' || + this.queryText?.length > 0 || + this.showDefaultData + ) { + await this.fetchAndUpdateItems(); + this.queryChanged.next(); + } + }), + this.settingsProvider.settingsActionChanged$.subscribe( + ({type, payload}) => { + if (type === 'stapps.settings.changed') { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const {category, name, value} = payload!; + this.logger.log(`received event "settings.changed" with category: + ${category}, name: ${name}, value: ${JSON.stringify(value)}`); + } + }, + ), + this.dataRoutingService.itemSelectListener().subscribe(item => { + if (this.itemRouting) { + if ( + [ + SCThingType.Book, + SCThingType.Periodical, + SCThingType.Article, + ].includes(item.type) + ) { + void this.router.navigate([ + 'hebis-detail', + (item.origin && + 'originalId' in item.origin && + item.origin['originalId']) || + '', + ]); + } else { + void this.router.navigate(['data-detail', item.uid]); + } + } }), ); } diff --git a/src/app/modules/hebis/daia-availability/daia-availability.component.spec.ts b/src/app/modules/hebis/daia-availability/daia-availability.component.spec.ts new file mode 100644 index 00000000..0c304dec --- /dev/null +++ b/src/app/modules/hebis/daia-availability/daia-availability.component.spec.ts @@ -0,0 +1,138 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */ +/* + * Copyright (C) 2018, 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {ActivatedRoute, RouterModule} from '@angular/router'; +import {IonRefresher} from '@ionic/angular'; +import { + TranslateLoader, + TranslateModule, + TranslateService, +} from '@ngx-translate/core'; +import {sampleThingsMap} from '../../../_helpers/data/sample-things'; +import {HebisRoutingModule} from '../hebis-routing.module'; +import {HebisModule} from '../hebis.module'; +import {DaiaAvailabilityComponent} from './daia-availability.component'; +import {Observable, of} from 'rxjs'; +import {StorageProvider} from '../../storage/storage.provider'; +import {DaiaDataProvider} from '../daia-data.provider'; + +const translations: any = {data: {detail: {TITLE: 'Foo'}}}; + +class TranslateFakeLoader implements TranslateLoader { + getTranslation(_lang: string): Observable { + return of(translations); + } +} + +describe('DaiaAvailabilityComponent', () => { + let comp: DaiaAvailabilityComponent; + let fixture: ComponentFixture; + let dataProvider: DaiaDataProvider; + let refresher: IonRefresher; + const sampleThing = sampleThingsMap.book[0]; + let translateService: TranslateService; + + // @Component({ selector: 'stapps-data-list-item', template: '' }) + // class DataListItemComponent { + // @Input() item; + // } + + const fakeActivatedRoute = { + snapshot: { + paramMap: { + get: () => { + return sampleThing.uid; + }, + }, + }, + }; + + const storageProviderSpy = jasmine.createSpyObj('StorageProvider', [ + 'init', + 'get', + 'has', + 'put', + 'search', + ]); + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + RouterModule.forRoot([], {relativeLinkResolution: 'legacy'}), + HebisRoutingModule, + HebisModule, + TranslateModule.forRoot({ + loader: {provide: TranslateLoader, useClass: TranslateFakeLoader}, + }), + ], + providers: [ + { + provide: ActivatedRoute, + useValue: fakeActivatedRoute, + }, + { + provide: StorageProvider, + useValue: storageProviderSpy, + }, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + }), + ); + + beforeEach(async () => { + dataProvider = TestBed.get(DaiaDataProvider); + translateService = TestBed.get(TranslateService); + refresher = jasmine.createSpyObj('refresher', ['complete']); + spyOn(dataProvider, 'get' as any).and.returnValue( + Promise.resolve(sampleThing), + ); + spyOn( + DaiaAvailabilityComponent.prototype, + 'getAvailability', + ).and.callThrough(); + fixture = await TestBed.createComponent(DaiaAvailabilityComponent); + comp = fixture.componentInstance; + translateService.use('foo'); + fixture.detectChanges(); + }); + + it('should create component', () => expect(comp).toBeDefined()); + + it('should get the availability of an item', () => { + comp.getAvailability(sampleThing.uid); + expect( + DaiaAvailabilityComponent.prototype.getAvailability, + ).toHaveBeenCalledWith(sampleThing.uid); + }); + + it('should get the availability of an item when the view is entered', () => { + comp.ngOnInit(); + expect( + DaiaAvailabilityComponent.prototype.getAvailability, + ).toHaveBeenCalledWith(sampleThing.uid); + }); + + it('should update the data item when refresh is called', async () => { + await comp.refresh(refresher); + expect( + DaiaAvailabilityComponent.prototype.getAvailability, + ).toHaveBeenCalledWith(sampleThing.uid); + expect(refresher.complete).toHaveBeenCalled(); + }); +}); diff --git a/src/app/modules/hebis/daia-availability/daia-availability.component.ts b/src/app/modules/hebis/daia-availability/daia-availability.component.ts new file mode 100644 index 00000000..6f8861b9 --- /dev/null +++ b/src/app/modules/hebis/daia-availability/daia-availability.component.ts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018, 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {Network} from '@ionic-native/network/ngx'; +import {TranslateService} from '@ngx-translate/core'; +import {SCUuid} from '@openstapps/core'; +import {FavoritesService} from '../../favorites/favorites.service'; +import {DataProvider} from '../../data/data.provider'; +import {DataDetailComponent} from '../../data/detail/data-detail.component'; +import {DaiaDataProvider} from '../daia-data.provider'; +import {SCDaiaHoldings} from '../protocol/response'; + +/** + * A Component to display an SCThing detailed + */ +@Component({ + selector: 'stapps-daia-availability', + styleUrls: ['daia-availability.scss'], + templateUrl: 'daia-availability.html', +}) +export class DaiaAvailabilityComponent + extends DataDetailComponent + implements OnInit +{ + holdings: SCDaiaHoldings[]; + + /** + * + * @param route the route the page was accessed from + * @param dataProvider the data provider + * @param network the network provider + * @param favoritesService the favorites provider + * @param translateService he translate provider + * @param daiaDataProvider DaiaDataProvider + */ + constructor( + route: ActivatedRoute, + dataProvider: DataProvider, + network: Network, + favoritesService: FavoritesService, + translateService: TranslateService, + private daiaDataProvider: DaiaDataProvider, + ) { + super(route, dataProvider, network, favoritesService, translateService); + } + + /** + * Check if we have internet + */ + isDisconnected(): boolean { + return this.network.type === this.network.Connection.NONE; + } + + /** + * Initialize + */ + async ngOnInit() { + const uid = this.route.snapshot.paramMap.get('uid') || ''; + await this.getAvailability(uid ?? ''); + } + + /** + * Provides data item with given UID + * + * @param uid Unique identifier of a thing + */ + async getAvailability(uid: SCUuid) { + this.daiaDataProvider.getAvailability(uid).then(holdings => { + this.holdings = holdings; + }); + } +} diff --git a/src/app/modules/hebis/daia-availability/daia-availability.html b/src/app/modules/hebis/daia-availability/daia-availability.html new file mode 100644 index 00000000..9e16a025 --- /dev/null +++ b/src/app/modules/hebis/daia-availability/daia-availability.html @@ -0,0 +1,63 @@ + + {{ + 'hebisSearch.daia.availability' | translate + }} + + + {{ + holding.label + }} + + + {{ + 'hebisSearch.daia.signature' | translate + }} + {{ holding.signature }} + + {{ + 'hebisSearch.daia.ejournal' | translate + }} + + + + {{ + 'hebisSearch.daia.location' | translate + }} + + + + {{ + 'hebisSearch.daia.comment' | translate + }} + {{ holding.about }} + + + {{ + 'hebisSearch.daia.status' | translate + }} + {{ 'hebisSearch.daia.available' | translate }} + {{ 'hebisSearch.daia.order' | translate }} + + + + + diff --git a/src/app/modules/hebis/daia-availability/daia-availability.scss b/src/app/modules/hebis/daia-availability/daia-availability.scss new file mode 100644 index 00000000..2b8cc024 --- /dev/null +++ b/src/app/modules/hebis/daia-availability/daia-availability.scss @@ -0,0 +1,38 @@ +ion-card { + margin: 0; + box-shadow: none; + ion-card-content { + h1 { + margin: 0; + } + padding-bottom: 8px; + } + ion-card-header { + color: var(--ion-color-dark); + padding-top: 8px; + padding-bottom: 4px; + font-weight: bold; + } + ion-card-content { + ion-label a { + display: block; + text-decoration: none; + font-weight: 700; + color: var(--ion-color-primary); + margin: 20px 0 5px; + } + ion-grid { + padding: 0; + + ion-row { + background-color: var(--ion-color-light); + color: var(--ion-color-light-contrast); + border-bottom: 1px solid #fff; + + ion-col:first-child { + font-weight: 700; + } + } + } + } +} diff --git a/src/app/modules/hebis/daia-data.provider.ts b/src/app/modules/hebis/daia-data.provider.ts new file mode 100644 index 00000000..cced212c --- /dev/null +++ b/src/app/modules/hebis/daia-data.provider.ts @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018-2021 StApps + * 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, version 3. + * + * 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 . + */ +import {Injectable} from '@angular/core'; +import {Client} from '@openstapps/api/lib/client'; +import {SCDaiaAvailabilityResponse, SCDaiaHoldings} from './protocol/response'; +import {StorageProvider} from '../storage/storage.provider'; +import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; +import {HttpClient} from '@angular/common/http'; +import {DataProvider} from '../data/data.provider'; +import {environment} from '../../../environments/environment'; + +/** + * Generated class for the DataProvider provider. + * + * See https://angular.io/guide/dependency-injection for more info on providers + * and Angular DI. + */ +@Injectable({ + providedIn: 'root', +}) +export class DaiaDataProvider extends DataProvider { + /** + * TODO + */ + storageProvider: StorageProvider; + + httpClient: HttpClient; + + backendUrl = environment.daia_url; + + /** + * TODO + * + * @param stAppsWebHttpClient TODO + * @param storageProvider TODO + * @param httpClient TODO + */ + constructor( + stAppsWebHttpClient: StAppsWebHttpClient, + storageProvider: StorageProvider, + httpClient: HttpClient, + ) { + super(stAppsWebHttpClient, storageProvider); + this.storageProvider = storageProvider; + this.httpClient = httpClient; + this.client = new Client( + stAppsWebHttpClient, + this.backendUrl, + this.appVersion, + ); + } + + async getAvailability(id: string): Promise { + return new Promise(resolve => + this.httpClient + .get(this.backendUrl, {params: {id}}) + .subscribe((response: SCDaiaAvailabilityResponse) => { + console.error(response); + const holdings: SCDaiaHoldings[] = []; + if (response && Array.isArray(response.document)) { + response.document.map(document => { + Array.isArray(document.item) && + document.item.map(element => { + try { + const { + department: { + id: departmentId, + content: departmentLabel, + href: departmentLink, + } = {id: 'noDep', content: '', href: ''}, + label, + about, + available, + storage, + } = element; + const holdingIndex = holdings.findIndex( + holding => holding.id === departmentId, + ); + + if (holdingIndex === -1) { + holdings.push({ + id: departmentId, + label: departmentLabel, + href: departmentLink, + signature: label, + available: + (Array.isArray(available) && + (available.find( + item => item.service === 'openaccess', + ) || + available.find( + item => item.service === 'loan', + ))) || + undefined, + storage, + about, + }); + } + } catch { + // No element available + } + }); + }); + } + resolve(holdings); + }), + ); + } +} diff --git a/src/app/modules/hebis/hebis-data.provider.ts b/src/app/modules/hebis/hebis-data.provider.ts new file mode 100644 index 00000000..b922add9 --- /dev/null +++ b/src/app/modules/hebis/hebis-data.provider.ts @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018-2021 StApps + * 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, version 3. + * + * 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 . + */ +import {Injectable} from '@angular/core'; +import {Client} from '@openstapps/api/lib/client'; +import {SCHebisSearchRequest} from './protocol/request'; +import {SCHebisSearchResponse} from './protocol/response'; +import {StorageProvider} from '../storage/storage.provider'; +import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; +import {HttpClient} from '@angular/common/http'; +import {DataProvider} from '../data/data.provider'; +import {SCHebisSearchRoute} from './protocol/route'; + +/** + * Generated class for the DataProvider provider. + * + * See https://angular.io/guide/dependency-injection for more info on providers + * and Angular DI. + */ +@Injectable({ + providedIn: 'root', +}) +export class HebisDataProvider extends DataProvider { + /** + * TODO + */ + storageProvider: StorageProvider; + + httpClient: HttpClient; + + /** + * Instance of hebis search request route + */ + private readonly hebisSearchRoute = new SCHebisSearchRoute(); + + /** + * TODO + * + * @param stAppsWebHttpClient TODO + * @param storageProvider TODO + * @param httpClient TODO + */ + constructor( + stAppsWebHttpClient: StAppsWebHttpClient, + storageProvider: StorageProvider, + httpClient: HttpClient, + ) { + super(stAppsWebHttpClient, storageProvider); + this.storageProvider = storageProvider; + this.httpClient = httpClient; + this.client = new Client( + stAppsWebHttpClient, + this.backendUrl, + this.appVersion, + ); + } + + /** + * Send a search request to the backend + * + * All results will be returned if no size is set in the request. + * + * @param searchRequest Search request + */ + async hebisSearch( + searchRequest: SCHebisSearchRequest, + ): Promise { + let page: number | undefined = searchRequest.page; + + if (typeof page === 'undefined') { + const preFlightResponse = + await this.client.invokeRoute( + this.hebisSearchRoute, + undefined, + { + ...searchRequest, + page: 0, + }, + ); + + page = preFlightResponse.pagination.total; + } + + return this.client.invokeRoute( + this.hebisSearchRoute, + undefined, + { + ...searchRequest, + page, + }, + ); + } +} diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail-content.component.ts b/src/app/modules/hebis/hebis-detail/hebis-detail-content.component.ts new file mode 100644 index 00000000..291b3957 --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail-content.component.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCThings} from '@openstapps/core'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-hebis-detail-content', + styleUrls: ['hebis-detail-content.scss'], + templateUrl: 'hebis-detail-content.html', +}) +export class HebisDetailContentComponent { + /** + * TODO + */ + @Input() item: SCThings; +} diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail-content.html b/src/app/modules/hebis/hebis-detail/hebis-detail-content.html new file mode 100644 index 00000000..5d1287a1 --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail-content.html @@ -0,0 +1,36 @@ +
+ + + + + + + + + + + +
+

{{ item.name }}

+ {{ item.type }} +
+
+
+
+
+ +
+
diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail-content.scss b/src/app/modules/hebis/hebis-detail/hebis-detail-content.scss new file mode 100644 index 00000000..480a391e --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail-content.scss @@ -0,0 +1,28 @@ +:host ::ng-deep { + ion-card { + margin: 0; + box-shadow: none; + ion-card-content { + h1 { + margin: 0; + } + padding-bottom: 8px; + } + ion-card-header { + color: var(--ion-color-dark); + padding-top: 8px; + padding-bottom: 4px; + font-weight: bold; + } + ion-grid, ion-col { + padding-inline-start: 0; + padding-top: 0; + padding-bottom: 0; + } + } + ion-grid, ion-col { + padding-inline-start: 0; + padding-top: 0; + padding-bottom: 0; + } +} diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts b/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts new file mode 100644 index 00000000..cbce65b0 --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts @@ -0,0 +1,135 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */ +/* + * Copyright (C) 2018, 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {ActivatedRoute, RouterModule} from '@angular/router'; +import {IonRefresher} from '@ionic/angular'; +import { + TranslateLoader, + TranslateModule, + TranslateService, +} from '@ngx-translate/core'; +import {sampleThingsMap} from '../../../_helpers/data/sample-things'; +import {HebisRoutingModule} from '../hebis-routing.module'; +import {HebisModule} from '../hebis.module'; +import {HebisDataProvider} from '../hebis-data.provider'; +import {HebisDetailComponent} from './hebis-detail.component'; +import {Observable, of} from 'rxjs'; +import {StorageProvider} from '../../storage/storage.provider'; + +const translations: any = {data: {detail: {TITLE: 'Foo'}}}; + +class TranslateFakeLoader implements TranslateLoader { + getTranslation(_lang: string): Observable { + return of(translations); + } +} + +describe('HebisDetailComponent', () => { + let comp: HebisDetailComponent; + let fixture: ComponentFixture; + let dataProvider: HebisDataProvider; + let refresher: IonRefresher; + const sampleThing = sampleThingsMap.book[0]; + let translateService: TranslateService; + + // @Component({ selector: 'stapps-data-list-item', template: '' }) + // class DataListItemComponent { + // @Input() item; + // } + + const fakeActivatedRoute = { + snapshot: { + paramMap: { + get: () => { + return sampleThing.uid; + }, + }, + }, + }; + + const storageProviderSpy = jasmine.createSpyObj('StorageProvider', [ + 'init', + 'get', + 'has', + 'put', + 'search', + ]); + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + RouterModule.forRoot([], {relativeLinkResolution: 'legacy'}), + HebisRoutingModule, + HebisModule, + TranslateModule.forRoot({ + loader: {provide: TranslateLoader, useClass: TranslateFakeLoader}, + }), + ], + providers: [ + { + provide: ActivatedRoute, + useValue: fakeActivatedRoute, + }, + { + provide: StorageProvider, + useValue: storageProviderSpy, + }, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + }), + ); + + beforeEach(async () => { + dataProvider = TestBed.get(HebisDataProvider); + translateService = TestBed.get(TranslateService); + refresher = jasmine.createSpyObj('refresher', ['complete']); + spyOn(dataProvider, 'get' as any).and.returnValue( + Promise.resolve(sampleThing), + ); + spyOn(HebisDetailComponent.prototype, 'getItem').and.callThrough(); + fixture = await TestBed.createComponent(HebisDetailComponent); + comp = fixture.componentInstance; + translateService.use('foo'); + fixture.detectChanges(); + }); + + it('should create component', () => expect(comp).toBeDefined()); + + it('should get a data item', () => { + comp.getItem(sampleThing.uid); + expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith( + sampleThing.uid, + ); + }); + + it('should get a data item when the view is entered', () => { + comp.ionViewWillEnter(); + expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith( + sampleThing.uid, + ); + }); + + it('should update the data item when refresh is called', async () => { + await comp.refresh(refresher); + expect(HebisDetailComponent.prototype.getItem).toHaveBeenCalledWith( + sampleThing.uid, + ); + expect(refresher.complete).toHaveBeenCalled(); + }); +}); diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts b/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts new file mode 100644 index 00000000..cfb0a721 --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail.component.ts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018, 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {Network} from '@ionic-native/network/ngx'; +import {TranslateService} from '@ngx-translate/core'; +import {SCUuid} from '@openstapps/core'; +import {HebisDataProvider} from '../hebis-data.provider'; +import {FavoritesService} from '../../favorites/favorites.service'; +import {DataProvider} from '../../data/data.provider'; +import {DataDetailComponent} from '../../data/detail/data-detail.component'; +import {SCDaiaHoldings} from '../protocol/response'; + +/** + * A Component to display an SCThing detailed + */ +@Component({ + selector: 'stapps-hebis-detail', + styleUrls: ['hebis-detail.scss'], + templateUrl: 'hebis-detail.html', +}) +export class HebisDetailComponent extends DataDetailComponent { + holdings: SCDaiaHoldings[]; + + /** + * + * @param route the route the page was accessed from + * @param dataProvider the data provider + * @param network the network provider + * @param favoritesService the favorites provider + * @param translateService he translate provider + * @param hebisDataProvider HebisDataProvider + */ + constructor( + route: ActivatedRoute, + dataProvider: DataProvider, + network: Network, + favoritesService: FavoritesService, + translateService: TranslateService, + private hebisDataProvider: HebisDataProvider, + ) { + super(route, dataProvider, network, favoritesService, translateService); + } + + /** + * Check if we have internet + */ + isDisconnected(): boolean { + return this.network.type === this.network.Connection.NONE; + } + + /** + * Initialize + */ + async ionViewWillEnter() { + const uid = this.route.snapshot.paramMap.get('uid') || ''; + await this.getItem(uid ?? ''); + } + + /** + * Provides data item with given UID + * + * @param uid Unique identifier of a thing + */ + async getItem(uid: SCUuid) { + this.hebisDataProvider.hebisSearch({query: uid, page: 0}).then(result => { + // eslint-disable-next-line unicorn/no-null + this.item = (result.data && result.data[0]) || null; + }); + } +} diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.html b/src/app/modules/hebis/hebis-detail/hebis-detail.html new file mode 100644 index 00000000..d76e3b1e --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail.html @@ -0,0 +1,51 @@ + + + + + + + {{ 'data.detail.TITLE' | translate }} + + + + + + + + + + +
+ +
+ + + {{ 'data.detail.COULD_NOT_CONNECT' | translate }} + +
+
+ +
+ + + {{ 'data.detail.NOT_FOUND' | translate }} + +
+
+ + + + + + + + +
+
diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.scss b/src/app/modules/hebis/hebis-detail/hebis-detail.scss new file mode 100644 index 00000000..2a8df22b --- /dev/null +++ b/src/app/modules/hebis/hebis-detail/hebis-detail.scss @@ -0,0 +1,5 @@ +::ng-deep { + ion-card-header { + font-weight: bold; + } +} diff --git a/src/app/modules/hebis/hebis-routing.module.ts b/src/app/modules/hebis/hebis-routing.module.ts new file mode 100644 index 00000000..338e7d47 --- /dev/null +++ b/src/app/modules/hebis/hebis-routing.module.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018-2021 StApps + * 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, version 3. + * + * 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 . + */ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {HebisDetailComponent} from './hebis-detail/hebis-detail.component'; +import {HebisSearchPageComponent} from './list/hebis-search-page.component'; + +const hebisRoutes: Routes = [ + {path: 'hebis-search', component: HebisSearchPageComponent}, + {path: 'hebis-detail/:uid', component: HebisDetailComponent}, +]; + +/** + * Module defining routes for data module + */ +@NgModule({ + exports: [RouterModule], + imports: [RouterModule.forChild(hebisRoutes)], +}) +export class HebisRoutingModule {} diff --git a/src/app/modules/hebis/hebis.module.ts b/src/app/modules/hebis/hebis.module.ts new file mode 100644 index 00000000..90004997 --- /dev/null +++ b/src/app/modules/hebis/hebis.module.ts @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018-2021 StApps + * 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, version 3. + * + * 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 . + */ +import {ScrollingModule} from '@angular/cdk/scrolling'; +import {CommonModule} from '@angular/common'; +import {HttpClientModule} from '@angular/common/http'; +import {NgModule} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {Network} from '@ionic-native/network/ngx'; +import {IonicModule} from '@ionic/angular'; +import {TranslateModule} from '@ngx-translate/core'; +import {MarkdownModule} from 'ngx-markdown'; +import {MomentModule} from 'ngx-moment'; +import {ThingTranslateModule} from '../../translation/thing-translate.module'; +import {MenuModule} from '../menu/menu.module'; +import {StorageModule} from '../storage/storage.module'; +import {HebisDetailComponent} from './hebis-detail/hebis-detail.component'; +import {HebisDetailContentComponent} from './hebis-detail/hebis-detail-content.component'; +import {HebisSearchPageComponent} from './list/hebis-search-page.component'; +import {HebisDataProvider} from './hebis-data.provider'; +import {DaiaDataProvider} from './daia-data.provider'; +import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; +import {HebisRoutingModule} from './hebis-routing.module'; +import {DataModule} from '../data/data.module'; + +import {BookDetailContentComponent} from './types/book/book-detail-content.component'; +import {BookListItemComponent} from './types/book/book-list-item.component'; + +import {PeriodicalListItemComponent} from './types/periodical/periodical-list-item.component'; +import {PeriodicalDetailContentComponent} from './types/periodical/periodical-detail-content.component'; +import {HebisArticleListItemComponent} from './types/hebis-article/hebis-article-item.component'; +import {HebisArticleContentComponent} from './types/hebis-article/hebis-article-content.component'; +import {DataListComponent} from '../data/list/data-list.component'; +import {DaiaAvailabilityComponent} from './daia-availability/daia-availability.component'; + +/** + * Module for handling data + */ +@NgModule({ + declarations: [ + HebisSearchPageComponent, + HebisDetailComponent, + HebisDetailContentComponent, + DaiaAvailabilityComponent, + BookDetailContentComponent, + BookListItemComponent, + PeriodicalDetailContentComponent, + PeriodicalListItemComponent, + HebisArticleListItemComponent, + HebisArticleContentComponent, + ], + entryComponents: [DataListComponent], + imports: [ + CommonModule, + DataModule, + FormsModule, + HebisRoutingModule, + HttpClientModule, + IonicModule.forRoot(), + MarkdownModule.forRoot(), + MenuModule, + MomentModule.forRoot({ + relativeTimeThresholdOptions: { + m: 59, + }, + }), + ScrollingModule, + StorageModule, + TranslateModule.forChild(), + ThingTranslateModule.forChild(), + ], + providers: [ + HebisDataProvider, + DaiaDataProvider, + Network, + StAppsWebHttpClient, + ], + exports: [ + HebisSearchPageComponent, + HebisDetailComponent, + HebisDetailContentComponent, + DaiaAvailabilityComponent, + PeriodicalDetailContentComponent, + BookDetailContentComponent, + HebisArticleListItemComponent, + HebisArticleContentComponent, + ], +}) +export class HebisModule {} diff --git a/src/app/modules/hebis/list/hebis-search-page.component.ts b/src/app/modules/hebis/list/hebis-search-page.component.ts new file mode 100644 index 00000000..054d4e9b --- /dev/null +++ b/src/app/modules/hebis/list/hebis-search-page.component.ts @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2018-2021 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input, OnInit, OnDestroy} from '@angular/core'; +import {Router} from '@angular/router'; +import {AlertController} from '@ionic/angular'; +import {NGXLogger} from 'ngx-logger'; +import {combineLatest} from 'rxjs'; +import {debounceTime, distinctUntilChanged, startWith} from 'rxjs/operators'; +import {ContextMenuService} from '../../menu/context/context-menu.service'; +import {SettingsProvider} from '../../settings/settings.provider'; +import {DataRoutingService} from '../../data/data-routing.service'; +import {SearchPageComponent} from '../../data/list/search-page.component'; +import {HebisDataProvider} from '../hebis-data.provider'; +import {PositionService} from '../../map/position.service'; + +/** + * HebisSearchPageComponent queries things and shows list of things as search results and filter as context menu + */ +@Component({ + selector: 'stapps-hebissearch-page', + templateUrl: 'hebis-search-page.html', +}) +export class HebisSearchPageComponent + extends SearchPageComponent + implements OnInit, OnDestroy +{ + /** + * If routing should be done if the user clicks on an item + */ + @Input() itemRouting? = true; + + /** + * Current page to start query + */ + page = 0; + + /** + * Injects the providers and creates subscriptions + * + * @param alertController AlertController + * @param dataProvider HebisProvider + * @param contextMenuService ContextMenuService + * @param settingsProvider SettingsProvider + * @param logger An angular logger + * @param dataRoutingService DataRoutingService + * @param router Router + * @param positionService PositionService + */ + constructor( + protected readonly alertController: AlertController, + protected dataProvider: HebisDataProvider, + protected readonly contextMenuService: ContextMenuService, + protected readonly settingsProvider: SettingsProvider, + protected readonly logger: NGXLogger, + protected dataRoutingService: DataRoutingService, + protected router: Router, + protected positionService: PositionService, + ) { + super( + alertController, + dataProvider, + contextMenuService, + settingsProvider, + logger, + dataRoutingService, + router, + positionService, + ); + } + + /** + * Fetches items with set query configuration + * + * @param append If true fetched data gets appended to existing, override otherwise (default false) + */ + protected async fetchAndUpdateItems(append = false): Promise { + // build query search options + const searchOptions: {page: number; query: string} = { + page: this.page, + query: '', + }; + + if (this.queryText && this.queryText.length > 0) { + // add query string + searchOptions.query = this.queryText; + } + + return this.dataProvider.hebisSearch(searchOptions).then( + async result => { + /*this.singleTypeResponse = + result.facets.find(facet => facet.field === 'type')?.buckets + .length === 1;*/ + if (append) { + let items = await this.items; + // append results + items = [...items, ...result.data]; + this.items = (async () => items)(); + } else { + // override items with results + this.items = (async () => { + return result.data; + })(); + } + }, + async error => { + const alert: HTMLIonAlertElement = await this.alertController.create({ + buttons: ['Dismiss'], + header: 'Error', + subHeader: error.message, + }); + + await alert.present(); + }, + ); + } + + /** + * Loads next page of things + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async loadMore(): Promise { + this.page += 1; + await this.fetchAndUpdateItems(true); + } + + ngOnInit() { + //this.fetchAndUpdateItems(); + this.initialize(); + + this.subscriptions.push( + combineLatest([ + this.queryTextChanged.pipe( + debounceTime(this.searchQueryDueTime), + distinctUntilChanged(), + startWith(this.queryText), + ), + ]).subscribe(async query => { + this.queryText = query[0]; + this.page = 0; + if (this.queryText?.length > 0 || this.showDefaultData) { + await this.fetchAndUpdateItems(); + this.queryChanged.next(); + } + }), + this.settingsProvider.settingsActionChanged$.subscribe( + ({type, payload}) => { + if (type === 'stapps.settings.changed') { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const {category, name, value} = payload!; + this.logger.log(`received event "settings.changed" with category: + ${category}, name: ${name}, value: ${JSON.stringify(value)}`); + } + }, + ), + this.dataRoutingService.itemSelectListener().subscribe(async item => { + if (this.itemRouting) { + void this.router.navigate([ + 'hebis-detail', + (item.origin && + 'originalId' in item.origin && + item.origin['originalId']) || + '', + ]); + } + }), + ); + } + + ngOnDestroy() { + for (const subscription of this.subscriptions) { + subscription.unsubscribe(); + } + } +} diff --git a/src/app/modules/hebis/list/hebis-search-page.html b/src/app/modules/hebis/list/hebis-search-page.html new file mode 100644 index 00000000..b92e1b7f --- /dev/null +++ b/src/app/modules/hebis/list/hebis-search-page.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + +
+ + {{ 'hebisSearch.instruction' | translate }} + +
+ +
diff --git a/src/app/modules/hebis/protocol/request.ts b/src/app/modules/hebis/protocol/request.ts new file mode 100644 index 00000000..0a03c761 --- /dev/null +++ b/src/app/modules/hebis/protocol/request.ts @@ -0,0 +1,20 @@ +import {SCLicensePlate} from '@openstapps/core'; + +export interface SCHebisSearchRequest { + /** + * HDS2 will supply results for the speficied insitute / university if available (Defaults to f-u) + */ + institute?: SCLicensePlate; + /** + * Simple pagination support (Defaults to 0) + */ + page?: number; + /** + * Search query for HDS + */ + query: string; +} + +export interface SCDaiaAvailabilityRequest { + id: string; +} diff --git a/src/app/modules/hebis/protocol/response.ts b/src/app/modules/hebis/protocol/response.ts new file mode 100644 index 00000000..f7bbff91 --- /dev/null +++ b/src/app/modules/hebis/protocol/response.ts @@ -0,0 +1,58 @@ +import { + SCArticle, + SCBook, + SCPeriodical, + SCSearchResultPagination, +} from '@openstapps/core'; + +export interface SCHebisSearchResponse { + /** + * Response Array of SCBook type or Object + */ + data: Array; + + /** + * Pagination information + */ + pagination: SCSearchResultPagination; +} + +export interface SCDaiaAvailabilityResponse { + document: Array<{ + item: Array<{ + id: string; + label: string; + department: SCDaiaSimpleContent; + available: SCDaiaService[]; + unavailable: SCDaiaService[]; + debugInfo: string; + about?: string; + storage?: SCDaiaSimpleContent; + }>; + }>; + institution: SCDaiaSimpleContent; + timestamp: string; +} + +export interface SCDaiaSimpleContent { + id: string; + content: string; + href?: string; +} + +export interface SCDaiaService { + delay?: string; + href?: string; + service: string; + limitations?: SCDaiaSimpleContent[]; +} + +export interface SCDaiaHoldings { + id: string; + label: string; + href?: string; + signature: string; + storage?: SCDaiaSimpleContent; + available?: SCDaiaService; + about?: string; +} diff --git a/src/app/modules/hebis/protocol/route.ts b/src/app/modules/hebis/protocol/route.ts new file mode 100644 index 00000000..25e1be87 --- /dev/null +++ b/src/app/modules/hebis/protocol/route.ts @@ -0,0 +1,54 @@ +import { + SCAbstractRoute, + SCRouteHttpVerbs, + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, +} from '@openstapps/core'; + +/** + * Route for searching things + */ +export class SCHebisSearchRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.POST; + this.requestBodyName = 'SCHebisSearchRequest'; + this.responseBodyName = 'SCHebisSearchResponse'; + this.statusCodeSuccess = 200; + this.urlPath = '/hebissearch'; + } +} + +/** + * Route for availability + */ +export class SCDaiaRoute extends SCAbstractRoute { + constructor() { + super(); + this.errorNames = [ + SCInternalServerErrorResponse, + SCMethodNotAllowedErrorResponse, + SCRequestBodyTooLargeErrorResponse, + SCSyntaxErrorResponse, + SCUnsupportedMediaTypeErrorResponse, + SCValidationErrorResponse, + ]; + this.method = SCRouteHttpVerbs.GET; + this.requestBodyName = 'SCDaiaAvailabilityRequest'; + this.responseBodyName = 'SCDaiaAvailabilityResponse'; + this.statusCodeSuccess = 200; + this.urlPath = '/UB_Frankfurt'; + } +} diff --git a/src/app/modules/hebis/types/book/book-detail-content.component.ts b/src/app/modules/hebis/types/book/book-detail-content.component.ts new file mode 100644 index 00000000..64d0ffbe --- /dev/null +++ b/src/app/modules/hebis/types/book/book-detail-content.component.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCBook} from '@openstapps/core'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-book-detail-content', + templateUrl: 'book-detail-content.html', +}) +export class BookDetailContentComponent { + /** + * TODO + */ + @Input() item: SCBook; +} diff --git a/src/app/modules/hebis/types/book/book-detail-content.html b/src/app/modules/hebis/types/book/book-detail-content.html new file mode 100644 index 00000000..2fcb5f18 --- /dev/null +++ b/src/app/modules/hebis/types/book/book-detail-content.html @@ -0,0 +1,82 @@ + + {{ + 'hebisSearch.detail.title' | translate + }} + + {{ + 'name' | thingTranslate: item | titlecase + }} + + + + + + + + + + + + {{ + 'authors' | propertyNameTranslate: item | titlecase + }} + + {{ + 'name' | thingTranslate: author + }} + + + + + + + + + + + {{ + 'publications' | propertyNameTranslate: item | titlecase + }} + +

+ {{ publication.locations | join: ', ' }} + {{ publication.locations && publication.publisher ? ':' : '' }} + {{ publication.publisher }} +

+
+
+ + {{ + 'categories' | propertyNameTranslate: item | titlecase + }} + + + + {{ 'categories' | thingTranslate: item }} + + + diff --git a/src/app/modules/hebis/types/book/book-list-item.component.ts b/src/app/modules/hebis/types/book/book-list-item.component.ts new file mode 100644 index 00000000..35abb0bb --- /dev/null +++ b/src/app/modules/hebis/types/book/book-list-item.component.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCBook} from '@openstapps/core'; +import {DataListItemComponent} from '../../../data/list/data-list-item.component'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-book-list-item', + templateUrl: 'book-list-item.html', +}) +export class BookListItemComponent extends DataListItemComponent { + /** + * TODO + */ + @Input() item: SCBook; +} diff --git a/src/app/modules/hebis/types/book/book-list-item.html b/src/app/modules/hebis/types/book/book-list-item.html new file mode 100644 index 00000000..180d8694 --- /dev/null +++ b/src/app/modules/hebis/types/book/book-list-item.html @@ -0,0 +1,16 @@ + + + +

{{ 'name' | thingTranslate: item }}

+

+ +

+ + {{ 'type' | thingTranslate: item }} + +
+
+
diff --git a/src/app/modules/hebis/types/hebis-article/hebis-article-content.component.ts b/src/app/modules/hebis/types/hebis-article/hebis-article-content.component.ts new file mode 100644 index 00000000..485594ae --- /dev/null +++ b/src/app/modules/hebis/types/hebis-article/hebis-article-content.component.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCArticle} from '@openstapps/core'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-hebis-article-content', + templateUrl: 'hebis-article-content.html', +}) +export class HebisArticleContentComponent { + /** + * TODO + */ + @Input() item: SCArticle; +} diff --git a/src/app/modules/hebis/types/hebis-article/hebis-article-content.html b/src/app/modules/hebis/types/hebis-article/hebis-article-content.html new file mode 100644 index 00000000..26611b37 --- /dev/null +++ b/src/app/modules/hebis/types/hebis-article/hebis-article-content.html @@ -0,0 +1,76 @@ + + {{ + 'hebisSearch.detail.title' | translate + }} + + {{ + 'name' | thingTranslate: item | titlecase + }} + + + + + + + + + + + + {{ + 'authors' | propertyNameTranslate: item | titlecase + }} + + {{ + 'name' | thingTranslate: author + }} + + + + + + + + + {{ + 'publications' | propertyNameTranslate: item | titlecase + }} + +

+ {{ publication.locations | join: ', ' }} + {{ publication.locations && publication.publisher ? ':' : '' }} + {{ publication.publisher }} +

+
+
+ + {{ + 'categories' | propertyNameTranslate: item | titlecase + }} + + + + {{ 'categories' | thingTranslate: item }} + + + diff --git a/src/app/modules/hebis/types/hebis-article/hebis-article-item.component.ts b/src/app/modules/hebis/types/hebis-article/hebis-article-item.component.ts new file mode 100644 index 00000000..1f86495b --- /dev/null +++ b/src/app/modules/hebis/types/hebis-article/hebis-article-item.component.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCArticle} from '@openstapps/core'; +import {DataListItemComponent} from '../../../data/list/data-list-item.component'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-hebis-article-item', + templateUrl: 'hebis-article-item.html', +}) +export class HebisArticleListItemComponent extends DataListItemComponent { + /** + * TODO + */ + @Input() item: SCArticle; +} diff --git a/src/app/modules/hebis/types/hebis-article/hebis-article-item.html b/src/app/modules/hebis/types/hebis-article/hebis-article-item.html new file mode 100644 index 00000000..180d8694 --- /dev/null +++ b/src/app/modules/hebis/types/hebis-article/hebis-article-item.html @@ -0,0 +1,16 @@ + + + +

{{ 'name' | thingTranslate: item }}

+

+ +

+ + {{ 'type' | thingTranslate: item }} + +
+
+
diff --git a/src/app/modules/hebis/types/periodical/periodical-detail-content.component.ts b/src/app/modules/hebis/types/periodical/periodical-detail-content.component.ts new file mode 100644 index 00000000..908e5d67 --- /dev/null +++ b/src/app/modules/hebis/types/periodical/periodical-detail-content.component.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCPeriodical} from '@openstapps/core'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-periodical-detail-content', + templateUrl: 'periodical-detail-content.html', +}) +export class PeriodicalDetailContentComponent { + /** + * TODO + */ + @Input() item: SCPeriodical; +} diff --git a/src/app/modules/hebis/types/periodical/periodical-detail-content.html b/src/app/modules/hebis/types/periodical/periodical-detail-content.html new file mode 100644 index 00000000..dd2f57b5 --- /dev/null +++ b/src/app/modules/hebis/types/periodical/periodical-detail-content.html @@ -0,0 +1,82 @@ + + {{ + 'hebisSearch.detail.title' | translate + }} + + {{ + 'name' | thingTranslate: item | titlecase + }} + + + + + + + + + + + + {{ + 'authors' | propertyNameTranslate: item | titlecase + }} + + {{ + 'name' | thingTranslate: author + }} + + + + + + + + + {{ + 'publications' | propertyNameTranslate: item | titlecase + }} + +

+ {{ publication.locations | join: ', ' }} + {{ publication.locations && publication.publisher ? ':' : '' }} + {{ publication.publisher }} +

+
+
+ + {{ + 'categories' | propertyNameTranslate: item | titlecase + }} + + + + {{ 'categories' | thingTranslate: item }} + + + + + diff --git a/src/app/modules/hebis/types/periodical/periodical-list-item.component.ts b/src/app/modules/hebis/types/periodical/periodical-list-item.component.ts new file mode 100644 index 00000000..f727c009 --- /dev/null +++ b/src/app/modules/hebis/types/periodical/periodical-list-item.component.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 StApps + * 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, version 3. + * + * 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 . + */ +import {Component, Input} from '@angular/core'; +import {SCPeriodical} from '@openstapps/core'; +import {DataListItemComponent} from '../../../data/list/data-list-item.component'; + +/** + * TODO + */ +@Component({ + selector: 'stapps-periodical-list-item', + templateUrl: 'periodical-list-item.html', +}) +export class PeriodicalListItemComponent extends DataListItemComponent { + /** + * TODO + */ + @Input() item: SCPeriodical; +} diff --git a/src/app/modules/hebis/types/periodical/periodical-list-item.html b/src/app/modules/hebis/types/periodical/periodical-list-item.html new file mode 100644 index 00000000..180d8694 --- /dev/null +++ b/src/app/modules/hebis/types/periodical/periodical-list-item.html @@ -0,0 +1,16 @@ + + + +

{{ 'name' | thingTranslate: item }}

+

+ +

+ + {{ 'type' | thingTranslate: item }} + +
+
+
diff --git a/src/app/modules/menu/navigation/navigation.component.ts b/src/app/modules/menu/navigation/navigation.component.ts index d959d1ee..26345fbc 100644 --- a/src/app/modules/menu/navigation/navigation.component.ts +++ b/src/app/modules/menu/navigation/navigation.component.ts @@ -49,6 +49,7 @@ export class NavigationComponent implements OnInit { */ public pages = [ {title: 'Search', url: '/search', icon: 'search'}, + {title: 'Hebis Search', url: '/hebis-search', icon: 'search'}, {title: 'Schedule', url: '/schedule', icon: 'calendar'}, {title: 'Settings', url: '/settings', icon: 'settings'}, ]; diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 429d8411..ff9ce41c 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -197,6 +197,29 @@ "instruction": "Starte oben zu tippen, um Veranstaltungen, Veranstaltungstermine, Personen, Orte, Essen und mehr zu finden ...", "nothing_found": "Keine Ergebnisse" }, + "hebisSearch": { + "search_bar": { + "placeholder": "Suche ..." + }, + "instruction": "Starte oben zu tippen, um Bücher, mehrteilige Werke, Zeitschriften, E-Books und mehr zu finden ...", + "nothing_found": "Keine Ergebnisse", + "detail": { + "title": "Titel", + "description": "Umfang", + "firstPublished": "Erscheinungsjahr" + }, + "daia": { + "availability": "Verfügbarkeit", + "available": "ausleihbar", + "status": "Status", + "location": "Standort", + "signature": "Signatur", + "comment": "Kommentar", + "order": "Bestellen", + "issn": "ISSN", + "ejournal": "ejournal" + } + }, "schedule": { "recurring": "Stundenplan", "calendar": "Kalender", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 952c7dc5..441051a0 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -197,6 +197,29 @@ "instruction": "Start typing above to find events, persons, places, food and more ...", "nothing_found": "No results" }, + "hebisSearch": { + "search_bar": { + "placeholder": "Search ..." + }, + "instruction": "Start typing above to find books, journals, multipart items, e-books and more ...", + "nothing_found": "No results", + "detail": { + "title": "Title", + "description": "Scope", + "firstPublished": "Year of publication" + }, + "daia": { + "availability": "Availability", + "available": "available", + "status": "Status", + "location": "Location", + "signature": "Shelfmark", + "comment": "Remark", + "order": "Request", + "issn": "ISSN", + "ejournal": "ejournal" + } + }, "schedule": { "recurring": "Recurring", "calendar": "Calendar", diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 341ed618..2586c10d 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -24,6 +24,7 @@ const appDomain = 'mobile.app.uni-frankfurt.de'; export const environment = { backend_url: 'https://mobile.server.uni-frankfurt.de', + daia_url: 'https://daia.hebis.de/DAIA2/UB_Frankfurt', appDomain: 'mobile.app.uni-frankfurt.de', backend_version: '2.0.0', use_fake_backend: false,