feat: display availability and item data for library items

This commit is contained in:
Jovan Krunić
2022-09-08 13:02:19 +00:00
committed by Thea Schöbl
parent 605aa1b782
commit d571b1dbe5
25 changed files with 695 additions and 145 deletions

View File

@@ -90,6 +90,7 @@ import {TreeListComponent} from './list/tree-list.component';
import {TreeListFragmentComponent} from './list/tree-list-fragment.component';
import {SettingsProvider} from '../settings/settings.provider';
import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
import {ExternalLinkComponent} from './elements/external-link.component';
/**
* Module for handling data
@@ -150,6 +151,7 @@ import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
VideoListItemComponent,
SimpleDataListComponent,
TitleCardComponent,
ExternalLinkComponent,
],
entryComponents: [DataListComponent, SimpleDataListComponent],
imports: [
@@ -201,6 +203,7 @@ import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
OriginDetailComponent,
FavoriteButtonComponent,
TreeListComponent,
ExternalLinkComponent,
],
})
export class DataModule {}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
import {Component, Input} from '@angular/core';
import {Browser} from '../../../util/browser.factory';
@Component({
selector: 'stapps-external-link',
templateUrl: './external-link.html',
styleUrls: ['./external-link.scss'],
})
export class ExternalLinkComponent {
@Input() link: string;
@Input() text: string;
constructor(private browser: Browser) {}
onLinkClick(url: string) {
this.browser.open(url);
}
}

View File

@@ -0,0 +1,17 @@
<!--
~ Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
-->
<a (click)="onLinkClick(link)"
>{{ text }}<ion-icon name="open_in_browser"></ion-icon>
</a>

View File

@@ -0,0 +1,8 @@
:host a {
cursor: pointer;
ion-icon {
vertical-align: text-top;
font-size: 80%;
padding-left: 2px;
}
}

View File

@@ -1,16 +1,16 @@
<!--
~ Copyright (C) 2022 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 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.
~ 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 <https://www.gnu.org/licenses/>.
~ You should have received a copy of the GNU General Public License along with
~ this program. If not, see <https://www.gnu.org/licenses/>.
-->
<div *ngIf="!item.categories.includes('news'); else news">
@@ -59,9 +59,10 @@
{{ 'sameAs' | propertyNameTranslate: item | titlecase }}
</ion-card-header>
<ion-card-content>
<a (click)="onLinkClick(item.sameAs)"
>{{ item.name }}<ion-icon name="open_in_browser"></ion-icon>
</a>
<stapps-external-link
[link]="item.sameAs"
[text]="item.name"
></stapps-external-link>
</ion-card-content>
</ion-card>
</ng-template>

View File

@@ -21,14 +21,6 @@
display: block;
}
}
a {
cursor: pointer;
ion-icon {
vertical-align: text-top;
font-size: 80%;
padding-left: 2px;
}
}
// Show smaller image on a desktop
@media (min-width: 992px) {
ion-thumbnail {

View File

@@ -20,7 +20,7 @@ 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';
import {SCDaiaHolding} from '../protocol/response';
import {ModalController} from '@ionic/angular';
/**
@@ -35,7 +35,7 @@ export class DaiaAvailabilityComponent
extends DataDetailComponent
implements OnInit
{
holdings: SCDaiaHoldings[] | undefined;
holdings: SCDaiaHolding[] | undefined;
/**
*

View File

@@ -4,60 +4,7 @@
</ion-card-header>
<ion-card-content>
<ng-container *ngFor="let holding of holdings">
<ion-label>
<a [href]="holding.href" target="_blank">
{{ holding.label }}
</a>
</ion-label>
<ion-grid>
<ion-row *ngIf="holding.signature">
<ion-col size="3">{{
'hebisSearch.daia.signature' | translate
}}</ion-col>
<ion-col
size="9"
*ngIf="
!holding ||
!holding.available ||
holding.available.service !== 'openaccess'
"
>{{ holding.signature }}</ion-col
>
<ion-col size="9" *ngIf="holding.available?.service === 'openaccess'">
<a [href]="holding.available.href" target="_blank">{{
'hebisSearch.daia.ejournal' | translate
}}</a>
</ion-col>
</ion-row>
<ion-row *ngIf="holding.storage && holding.storage.content">
<ion-col size="3">{{
'hebisSearch.daia.location' | translate
}}</ion-col>
<ion-col size="9" [innerHTML]="holding.storage.content"></ion-col>
</ion-row>
<ion-row *ngIf="holding.about">
<ion-col size="3">{{
'hebisSearch.daia.comment' | translate
}}</ion-col>
<ion-col size="9" [innerHTML]="holding.about"></ion-col>
</ion-row>
<ion-row
*ngIf="holding.available && holding.available.service === 'loan'"
>
<ion-col size="3">{{
'hebisSearch.daia.status' | translate
}}</ion-col>
<ion-col size="9"
>{{ 'hebisSearch.daia.available' | translate }}
<a
[href]="holding.available.href"
*ngIf="holding.available.href"
target="_blank"
>{{ 'hebisSearch.daia.order' | translate }}</a
></ion-col
>
</ion-row>
</ion-grid>
<stapps-daia-holding [holding]="holding"></stapps-daia-holding>
</ng-container>
<ion-label *ngIf="!holdings">
{{ 'hebisSearch.daia.unavailableAvailability' | translate }}

View File

@@ -1,4 +1,19 @@
ion-card {
/*!
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
:host ion-card {
margin: 0;
box-shadow: none;
ion-card-content {
@@ -13,26 +28,4 @@ ion-card {
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;
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
import {Component, Input, OnInit} from '@angular/core';
import {SCDaiaHolding} from '../protocol/response';
import {DaiaDataProvider} from '../daia-data.provider';
@Component({
selector: 'stapps-daia-holding',
templateUrl: './daia-holding.html',
styleUrls: ['./daia-holding.scss'],
})
export class DaiaHoldingComponent implements OnInit {
@Input() holding: SCDaiaHolding;
constructor(private daiaDataProvider: DaiaDataProvider) {}
resourceLink?: string;
ngOnInit(): void {
console.log(this.holding);
this.resourceLink = this.daiaDataProvider.getHoldingLink(this.holding);
}
}

View File

@@ -0,0 +1,89 @@
<!--
~ Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
-->
<ion-label>
<stapps-external-link
*ngIf="holding.label"
[text]="holding.label"
[link]="holding.href"
>
</stapps-external-link>
</ion-label>
<ion-grid>
<ion-row *ngIf="holding.storage && holding.storage.content">
<ion-col size="3">{{ 'hebisSearch.daia.location' | translate }}</ion-col>
<ion-col size="9" [innerHTML]="holding.storage.content"></ion-col>
</ion-row>
<ion-row *ngIf="holding.signature && !holding.online">
<ion-col size="3">{{ 'hebisSearch.daia.signature' | translate }}</ion-col>
<ion-col size="9">{{ holding.signature }}</ion-col>
</ion-row>
<ion-row *ngIf="holding.about">
<ion-col size="3">{{ 'hebisSearch.daia.comment' | translate }}</ion-col>
<ion-col size="9" [innerHTML]="holding.about"></ion-col>
</ion-row>
<ion-row *ngIf="holding.available && holding.online && resourceLink">
<ion-col size="3">{{ 'Online' }}</ion-col>
<ion-col size="9">
<stapps-external-link
[link]="resourceLink"
[text]="'hebisSearch.daia.fulltext' | translate"
></stapps-external-link
></ion-col>
</ion-row>
<ion-row *ngIf="holding.status">
<ion-col size="3">{{ 'hebisSearch.daia.status' | translate }}</ion-col>
<ion-col size="9">
<ion-icon
*ngIf="holding.status === 'available'"
name="check_circle"
color="success"
></ion-icon>
<ion-icon
*ngIf="holding.status === 'library_only'"
name="check_circle"
color="warning"
></ion-icon>
<ion-icon
*ngIf="
['checked_out', 'not_yet_available', 'not_available'].indexOf(
holding.status
) > -1
"
name="cancel"
color="danger"
>
</ion-icon>
{{ 'hebisSearch.daia.status_states' + '.' + holding.status | translate }}
<stapps-external-link
*ngIf="holding.status === 'available' && holding.available.href"
[text]="'hebisSearch.daia.order' | translate"
[link]="holding.available.href"
>
</stapps-external-link>
<stapps-external-link
*ngIf="holding.status === 'checked_out' && holding.unavailable.href"
[text]="'hebisSearch.daia.reserve' | translate"
[link]="holding.unavailable.href"
>
</stapps-external-link>
</ion-col>
</ion-row>
<ion-row *ngIf="holding.dueDate">
<ion-col size="3">{{ 'hebisSearch.daia.dueDate' | translate }}</ion-col>
<ion-col size="9">{{ holding.dueDate | amDateFormat: 'll' }}</ion-col>
</ion-row>
</ion-grid>

View File

@@ -0,0 +1,38 @@
/*!
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
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;
}
}
}
ion-icon ::ng-deep stapps-icon {
--fill: 1;
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
*/
/* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-explicit-any, unicorn/no-thenable */
import {TestBed} from '@angular/core/testing';
import {DaiaDataProvider} from './daia-data.provider';
import {HebisModule} from './hebis.module';
import {ConfigProvider} from '../config/config.provider';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {StorageProvider} from '../storage/storage.provider';
import {LoggerConfig, LoggerModule, NGXLogger} from 'ngx-logger';
import {MapModule} from '../map/map.module';
import {HttpClientModule} from '@angular/common/http';
import {StorageModule} from '../storage/storage.module';
import {SCDaiaHolding, SCDaiaService} from './protocol/response';
import {Observable, of} from 'rxjs';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
const translations: any = {data: {detail: {TITLE: 'Foo'}}};
class TranslateFakeLoader implements TranslateLoader {
getTranslation(_lang: string): Observable<any> {
return of(translations);
}
}
describe('DaiaDataProvider', () => {
let daiaDataProvider: DaiaDataProvider;
let configProvider: ConfigProvider;
const proxyUrl = 'https://some-proxy.com?q=';
beforeEach(async () => {
configProvider = jasmine.createSpyObj('ConfigProvider', ['getValue']);
TestBed.configureTestingModule({
imports: [
HebisModule,
MapModule,
HttpClientModule,
StorageModule,
LoggerModule,
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
}),
],
providers: [
{
provide: ConfigProvider,
useValue: configProvider,
},
StAppsWebHttpClient,
StorageProvider,
NGXLogger,
LoggerConfig,
DaiaDataProvider,
],
});
daiaDataProvider = TestBed.inject(DaiaDataProvider);
daiaDataProvider.hebisProxyUrl = proxyUrl;
});
describe('getResourceLink', () => {
it('should return undefined when available not defined', () => {
const holding: SCDaiaHolding = {
id: '',
label: '',
online: false,
signature: '',
};
expect(daiaDataProvider.getHoldingLink(holding)).toEqual(undefined);
});
it('should return the resource link without proxy when service is openaccess', () => {
const available: SCDaiaService = {
delay: '',
expected: '',
href: 'https://some-url.com',
limitations: [],
service: 'openaccess',
};
const holding: SCDaiaHolding = {
id: '',
label: '',
online: false,
signature: '',
available: available,
};
expect(daiaDataProvider.getHoldingLink(holding)).toEqual(available.href);
});
it('should return the resource link with proxy when service is not openaccess', () => {
const available: SCDaiaService = {
delay: '',
expected: '',
href: 'https://some-url.com',
limitations: [],
service: 'other',
};
const holding: SCDaiaHolding = {
id: '',
label: '',
online: false,
signature: '',
available: available,
};
expect(daiaDataProvider.getHoldingLink(holding)).toEqual(
`${proxyUrl}${available.href}`,
);
});
});
describe('getResourceStatus', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// let available, unavalable: SCDaiaService[];
const checkedOut: SCDaiaService = {
expected: '2022-09-01',
limitations: [],
service: 'loan',
};
const notYetAvailableOnBuy: SCDaiaService = {
limitations: [{id: 'OnBuy', content: ''}],
service: 'loan',
};
const notYetAvailableJustReturned: SCDaiaService = {
limitations: [{id: 'JustReturned', content: ''}],
service: 'loan',
};
const notAvailableCopyIsMissing: SCDaiaService = {
limitations: [{id: 'CopyIsMissing', content: ''}],
service: 'loan',
};
const notAvailableCanceled: SCDaiaService = {
limitations: [{id: 'Canceled', content: ''}],
service: 'loan',
};
const libraryOnlyOnlyInHouse: SCDaiaService = {
limitations: [{id: 'OnlyInHouse', content: ''}],
service: 'loan',
};
const libraryOnlyExternalLoan: SCDaiaService = {
limitations: [{id: 'ExternalLoan', content: ''}],
service: 'loan',
};
const libraryOnlyNoLimitations: SCDaiaService = {
service: 'loan',
};
const availableLimitationsUndefined: SCDaiaService = {
service: 'loan',
};
const availableLimitationsEmpty: SCDaiaService = {
limitations: [],
service: 'loan',
};
it('should return check out', () => {
expect(daiaDataProvider.getHoldingStatus([], [checkedOut])).toEqual(
'checked_out',
);
});
it('should return not yet available', () => {
expect(
daiaDataProvider.getHoldingStatus([], [notYetAvailableOnBuy]),
).toEqual('not_yet_available');
expect(
daiaDataProvider.getHoldingStatus([], [notYetAvailableJustReturned]),
).toEqual('not_yet_available');
});
it('should return not available', () => {
expect(
daiaDataProvider.getHoldingStatus([], [notAvailableCopyIsMissing]),
).toEqual('not_available');
expect(
daiaDataProvider.getHoldingStatus([], [notAvailableCanceled]),
).toEqual('not_available');
});
it('should return library only', () => {
expect(
daiaDataProvider.getHoldingStatus([], [libraryOnlyOnlyInHouse]),
).toEqual('library_only');
expect(
daiaDataProvider.getHoldingStatus([libraryOnlyExternalLoan], []),
).toEqual('library_only');
expect(
daiaDataProvider.getHoldingStatus([], [libraryOnlyNoLimitations]),
).toEqual('library_only');
});
it('should return available', () => {
expect(
daiaDataProvider.getHoldingStatus([availableLimitationsUndefined], []),
).toEqual('available');
expect(
daiaDataProvider.getHoldingStatus([availableLimitationsEmpty], []),
).toEqual('available');
});
it('should return unknown otherwise', () => {
const withoutLoan: SCDaiaService = {
limitations: [],
service: 'anything else',
};
expect(daiaDataProvider.getHoldingStatus([withoutLoan], [])).toEqual(
'unknown',
);
expect(daiaDataProvider.getHoldingStatus([], [withoutLoan])).toEqual(
'unknown',
);
});
});
});

View File

@@ -13,12 +13,18 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Injectable} from '@angular/core';
import {SCDaiaAvailabilityResponse, SCDaiaHoldings} from './protocol/response';
import {
SCDaiaAvailabilityResponse,
SCDaiaHolding,
SCDaiaService,
SCDaiaSimpleContent,
} from './protocol/response';
import {StorageProvider} from '../storage/storage.provider';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {ConfigProvider} from '../config/config.provider';
import {SCFeatureConfiguration} from '@openstapps/core';
import {NGXLogger} from 'ngx-logger';
import {TranslateService} from '@ngx-translate/core';
/**
* Generated class for the DataProvider provider.
@@ -37,9 +43,9 @@ export class DaiaDataProvider {
httpClient: HttpClient;
configProvider: ConfigProvider;
daiaServiceUrl?: string;
daiaServiceUrl: string | undefined;
hebisProxyUrl?: string;
clientHeaders = new HttpHeaders();
@@ -50,23 +56,24 @@ export class DaiaDataProvider {
* @param httpClient TODO
* @param configProvider TODO
* @param logger TODO
* @param translateService TODO
*/
constructor(
storageProvider: StorageProvider,
httpClient: HttpClient,
configProvider: ConfigProvider,
private configProvider: ConfigProvider,
private readonly logger: NGXLogger,
private translateService: TranslateService,
) {
this.storageProvider = storageProvider;
this.httpClient = httpClient;
this.configProvider = configProvider;
this.clientHeaders = this.clientHeaders.set(
'Content-Type',
'application/json',
);
}
async getAvailability(id: string): Promise<SCDaiaHoldings[] | undefined> {
async getAvailability(id: string): Promise<SCDaiaHolding[] | undefined> {
if (typeof this.daiaServiceUrl === 'undefined') {
try {
const features = this.configProvider.getValue(
@@ -78,6 +85,12 @@ export class DaiaDataProvider {
this.logger.error('Daia service url undefined');
return undefined;
}
if (features.extern?.hebisProxy?.url) {
this.hebisProxyUrl = features.extern?.hebisProxy?.url;
} else {
this.logger.error('HeBIS proxy url undefined');
return undefined;
}
} catch (error) {
this.logger.error(error);
return undefined;
@@ -86,11 +99,12 @@ export class DaiaDataProvider {
return new Promise(resolve =>
this.httpClient
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
.get<SCDaiaAvailabilityResponse>(this.daiaServiceUrl!, {params: {id}})
.get<SCDaiaAvailabilityResponse>(this.daiaServiceUrl as string, {
params: {id, lang: this.translateService.currentLang},
})
.subscribe(
(response: SCDaiaAvailabilityResponse) => {
const holdings: SCDaiaHoldings[] = [];
const holdings: SCDaiaHolding[] = [];
if (response && Array.isArray(response.document)) {
response.document.map(document => {
Array.isArray(document.item) &&
@@ -106,17 +120,43 @@ export class DaiaDataProvider {
about,
available,
storage,
unavailable,
} = element;
const holdingIndex = holdings.findIndex(
holding => holding.id === departmentId,
);
if (holdingIndex === -1) {
const holdingStatus = this.holdingHasStatus(
available || [],
)
? this.getHoldingStatus(
available || [],
unavailable || [],
)
: undefined;
const dueDate =
holdingStatus === 'checked_out'
? (
unavailable.find(
item => item.service === 'loan',
) as SCDaiaService
).expected
: undefined;
holdings.push({
id: departmentId,
label: departmentLabel,
href: departmentLink,
signature: label,
status: holdingStatus,
dueDate: dueDate,
online:
Array.isArray(available) &&
typeof available.find(
item => item.service === 'remote',
) !== 'undefined',
available:
(Array.isArray(available) &&
(available.find(
@@ -126,6 +166,12 @@ export class DaiaDataProvider {
item => item.service === 'loan',
))) ||
undefined,
unavailable:
(Array.isArray(unavailable) &&
unavailable.find(
item => item.service === 'loan',
)) ||
undefined,
storage,
about,
});
@@ -139,11 +185,85 @@ export class DaiaDataProvider {
resolve(holdings);
},
error => {
this.logger.error(error);
// handle "availability info not found" separately from the problems with getting the info
if (error.status === 404) resolve([]);
// eslint-disable-next-line unicorn/no-useless-undefined
resolve(undefined);
},
),
);
}
getHoldingLink(holding: SCDaiaHolding) {
if (typeof this.hebisProxyUrl === 'undefined') {
this.logger.error('HeBIS proxy url undefined');
return;
}
const resourceLink = holding.available?.href;
if (
typeof resourceLink === 'undefined' ||
holding.available?.service === 'openaccess'
) {
return resourceLink;
}
return `${this.hebisProxyUrl}${resourceLink}`;
}
holdingHasStatus(available: SCDaiaService[]): boolean {
return !available.some(item => item.service === 'remote');
}
getHoldingStatus(
available: SCDaiaService[],
unavailable: SCDaiaService[],
): SCDaiaHolding['status'] {
const loan: {available: number; unavailable: number} = {
available: available.findIndex(item => item.service === 'loan'),
unavailable: unavailable.findIndex(item => item.service === 'loan'),
};
if (
loan.unavailable !== -1 &&
typeof unavailable[loan.unavailable].expected !== 'undefined'
) {
return 'checked_out';
}
if (
loan.unavailable !== -1 &&
unavailable[loan.unavailable].limitations?.some(limitation =>
['OnBuy', 'JustReturned'].includes(limitation.id),
)
)
return 'not_yet_available';
if (
loan.unavailable !== -1 &&
unavailable[loan.unavailable].limitations?.some(limitation =>
['CopyIsMissing', 'Canceled'].includes(limitation.id),
)
)
return 'not_available';
if (
(loan.unavailable !== -1 &&
(!Array.isArray(unavailable[loan.unavailable].limitations) ||
(unavailable[loan.unavailable].limitations as SCDaiaSimpleContent[])
.length === 0 ||
unavailable[loan.unavailable].limitations?.some(limitation =>
['OnlyInHouse'].includes(limitation.id),
))) ||
(loan.available !== -1 &&
available[loan.available].limitations?.some(limitation =>
['ExternalLoan'].includes(limitation.id),
))
)
return 'library_only';
if (loan.available !== -1) return 'available';
return 'unknown';
}
}

View File

@@ -20,7 +20,7 @@ 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';
import {SCDaiaHolding} from '../protocol/response';
import {ModalController} from '@ionic/angular';
/**
@@ -32,7 +32,7 @@ import {ModalController} from '@ionic/angular';
templateUrl: 'hebis-detail.html',
})
export class HebisDetailComponent extends DataDetailComponent {
holdings: SCDaiaHoldings[];
holdings: SCDaiaHolding[];
/**
*

View File

@@ -1,16 +1,16 @@
/*
* Copyright (C) 2022 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.
* Copyright (C) 2018-2022 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.
* 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 <https://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {ScrollingModule} from '@angular/cdk/scrolling';
import {CommonModule} from '@angular/common';
@@ -44,6 +44,7 @@ import {DataListComponent} from '../data/list/data-list.component';
import {DaiaAvailabilityComponent} from './daia-availability/daia-availability.component';
import {UtilModule} from '../../util/util.module';
import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
import {DaiaHoldingComponent} from './daia-availability/daia-holding.component';
/**
* Module for handling data
@@ -60,6 +61,7 @@ import {IonIconModule} from '../../util/ion-icon/ion-icon.module';
PeriodicalListItemComponent,
HebisArticleListItemComponent,
HebisArticleContentComponent,
DaiaHoldingComponent,
],
entryComponents: [DataListComponent],
imports: [

View File

@@ -44,15 +44,26 @@ export interface SCDaiaService {
delay?: string;
href?: string;
service: string;
expected?: string;
limitations?: SCDaiaSimpleContent[];
}
export interface SCDaiaHoldings {
export interface SCDaiaHolding {
id: string;
label: string;
href?: string;
signature: string;
storage?: SCDaiaSimpleContent;
available?: SCDaiaService;
unavailable?: SCDaiaService;
about?: string;
online: boolean;
dueDate?: string;
status?:
| 'checked_out'
| 'not_yet_available'
| 'not_available'
| 'library_only'
| 'available'
| 'unknown';
}

View File

@@ -18,9 +18,10 @@
'hebisSearch.detail.title' | translate | sentencecase
}}</ion-card-header>
<ion-card-content>
<a [href]="item.sameAs" target="_blank">{{
'name' | thingTranslate: item
}}</a>
<stapps-external-link
[text]="'name' | thingTranslate: item"
[link]="item.sameAs"
></stapps-external-link>
</ion-card-content>
</ion-card>

View File

@@ -18,9 +18,10 @@
'hebisSearch.detail.title' | translate | sentencecase
}}</ion-card-header>
<ion-card-content>
<a [href]="item.sameAs" target="_blank">{{
'name' | thingTranslate: item
}}</a>
<stapps-external-link
[text]="'name' | thingTranslate: item"
[link]="item.sameAs"
></stapps-external-link>
</ion-card-content>
</ion-card>

View File

@@ -18,9 +18,10 @@
'hebisSearch.detail.title' | translate | sentencecase
}}</ion-card-header>
<ion-card-content>
<a [href]="item.sameAs" target="_blank">{{
'name' | thingTranslate: item
}}</a>
<stapps-external-link
[text]="'name' | thingTranslate: item"
[link]="item.sameAs"
></stapps-external-link>
</ion-card-content>
</ion-card>

View File

@@ -14,7 +14,7 @@
*/
import {Component, Input} from '@angular/core';
import {SCMessage} from '@openstapps/core';
import {Browser} from '../../../util/browser.factory';
/**
* News page component
*/
@@ -24,14 +24,8 @@ import {Browser} from '../../../util/browser.factory';
styleUrls: ['news-item.scss'],
})
export class NewsItemComponent {
constructor(private browser: Browser) {}
/**
* News (message) to show
*/
@Input() item: SCMessage;
onLinkClick(url: string) {
this.browser.open(url);
}
}