fix: library account missing ready for pickup

Closes #330
This commit is contained in:
Jovan Krunić
2022-11-11 15:00:34 +00:00
committed by Rainer Killinger
parent 42b860e417
commit e504d8cf6d
12 changed files with 131 additions and 91 deletions

View File

@@ -35,7 +35,7 @@
<ion-icon name="account_circle" slot="start"></ion-icon <ion-icon name="account_circle" slot="start"></ion-icon
>{{ 'library.account.pages.profile.title' | translate | titlecase }} >{{ 'library.account.pages.profile.title' | translate | titlecase }}
</ion-item> </ion-item>
<ion-item [routerLink]="['holds-and-reservations']"> <ion-item [routerLink]="['holds']">
<ion-icon name="collections_bookmark" slot="start"></ion-icon <ion-icon name="collections_bookmark" slot="start"></ion-icon
>{{ 'library.account.pages.holds.title' | translate | titlecase }} >{{ 'library.account.pages.holds.title' | translate | titlecase }}
</ion-item> </ion-item>

View File

@@ -1,5 +1,5 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {DocumentAction, PAIADocument} from '../../types'; import {DocumentAction, PAIADocument, PAIADocumentStatus} from '../../types';
import {LibraryAccountService} from '../library-account.service'; import {LibraryAccountService} from '../library-account.service';
@Component({ @Component({
@@ -27,8 +27,9 @@ export class CheckedOutPageComponent {
async fetchItems() { async fetchItems() {
try { try {
this.checkedOutItems = undefined; this.checkedOutItems = undefined;
this.checkedOutItems = this.checkedOutItems = await this.libraryAccountService.getFilteredItems([
await this.libraryAccountService.getCheckedOutItems(); PAIADocumentStatus.Held,
]);
} catch { } catch {
await this.libraryAccountService.handleError(); await this.libraryAccountService.handleError();
this.checkedOutItems = []; this.checkedOutItems = [];

View File

@@ -1,52 +0,0 @@
<ion-header>
<ion-toolbar color="primary" mode="ios">
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>{{
'library.account.pages.holds.title' | translate | titlecase
}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-segment
(ionChange)="segmentChanged($event)"
[value]="paiaDocumentStatus.Ordered"
mode="md"
>
<ion-segment-button [value]="paiaDocumentStatus.Ordered">
<ion-label>{{
'library.account.pages.holds.holds' | translate
}}</ion-label>
</ion-segment-button>
<ion-segment-button [value]="paiaDocumentStatus.Reserved">
<ion-label>{{
'library.account.pages.holds.reservations' | translate
}}</ion-label>
</ion-segment-button>
</ion-segment>
<ion-list *ngIf="paiaDocuments && paiaDocuments.length > 0; else fallback">
<stapps-paia-item
*ngFor="let hold of paiaDocuments"
[item]="hold"
[propertiesToShow]="['label']"
(documentAction)="onDocumentAction($event)"
listName="holds"
>
</stapps-paia-item>
</ion-list>
<ng-template #fallback>
<stapps-skeleton-list-item
hideThumbnail="true"
*ngIf="!paiaDocuments; else nothingFound"
></stapps-skeleton-list-item>
<ng-template #nothingFound>
<ion-label
*ngIf="paiaDocuments && paiaDocuments.length === 0"
class="centeredMessageContainer"
>
{{ 'search.nothing_found' | translate | titlecase }}
</ion-label>
</ng-template>
</ng-template>
</ion-content>

View File

@@ -2,34 +2,45 @@ import {Component} from '@angular/core';
import {DocumentAction, PAIADocument, PAIADocumentStatus} from '../../types'; import {DocumentAction, PAIADocument, PAIADocumentStatus} from '../../types';
import {LibraryAccountService} from '../library-account.service'; import {LibraryAccountService} from '../library-account.service';
type Segment = 'orders' | 'reservations';
@Component({ @Component({
selector: 'app-holds-and-reservations', selector: 'stapps-holds',
templateUrl: './holds-and-reservations-page.html', templateUrl: './holds-page.html',
styleUrls: ['./holds-and-reservations-page.scss'], styleUrls: ['./holds-page.scss'],
}) })
export class HoldsAndReservationsPageComponent { export class HoldsPageComponent {
paiaDocuments?: PAIADocument[]; paiaDocuments?: PAIADocument[];
paiaDocumentStatus = PAIADocumentStatus; paiaDocumentStatus = PAIADocumentStatus;
activeSegment: Segment = 'orders';
constructor(private readonly libraryAccountService: LibraryAccountService) {} constructor(private readonly libraryAccountService: LibraryAccountService) {}
async ionViewWillEnter(): Promise<void> { async ionViewWillEnter(): Promise<void> {
await this.fetchItems(); await this.fetchItems(this.activeSegment);
} }
async fetchItems(status: PAIADocumentStatus = PAIADocumentStatus.Ordered) { async fetchItems(segment: Segment) {
this.activeSegment = segment;
this.paiaDocuments = undefined; this.paiaDocuments = undefined;
const itemsStatus =
segment === 'reservations'
? [PAIADocumentStatus.Reserved]
: [PAIADocumentStatus.Ordered, PAIADocumentStatus.Provided];
try { try {
this.paiaDocuments = await (Number(status) === PAIADocumentStatus.Ordered this.paiaDocuments = await this.libraryAccountService.getFilteredItems(
? this.libraryAccountService.getHolds() itemsStatus,
: this.libraryAccountService.getReservations()); );
} catch { } catch {
await this.libraryAccountService.handleError(); await this.libraryAccountService.handleError();
this.paiaDocuments = []; this.paiaDocuments = [];
} }
} }
toNumber = Number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
async segmentChanged(event: any) { async segmentChanged(event: any) {
await this.fetchItems(event.detail.value); await this.fetchItems(event.detail.value);
@@ -40,6 +51,6 @@ export class HoldsAndReservationsPageComponent {
documentAction, documentAction,
); );
if (answer) await this.fetchItems(); if (answer) await this.fetchItems(this.activeSegment);
} }
} }

View File

@@ -0,0 +1,81 @@
<ion-header>
<ion-toolbar color="primary" mode="ios">
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>{{
'library.account.pages.holds.title' | translate | titlecase
}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-segment
[(ngModel)]="activeSegment"
(ionChange)="segmentChanged($event)"
[value]="'orders'"
mode="md"
>
<ion-segment-button [value]="'orders'">
<ion-label>{{
'library.account.pages.holds.holds' | translate
}}</ion-label>
</ion-segment-button>
<ion-segment-button [value]="'reservations'">
<ion-label>{{
'library.account.pages.holds.reservations' | translate
}}</ion-label>
</ion-segment-button>
</ion-segment>
<ion-list *ngIf="paiaDocuments && paiaDocuments.length > 0; else fallback">
<ng-container [ngSwitch]="activeSegment">
<ng-container *ngSwitchCase="'orders'">
<ng-container *ngFor="let hold of paiaDocuments">
<stapps-paia-item
*ngIf="
toNumber(hold.status) === paiaDocumentStatus.Provided;
else ordered
"
[item]="hold"
[propertiesToShow]="['label', 'storage']"
(documentAction)="onDocumentAction($event)"
listName="holds"
>
</stapps-paia-item>
<ng-template #ordered>
<stapps-paia-item
[item]="hold"
[propertiesToShow]="['label']"
(documentAction)="onDocumentAction($event)"
listName="holds"
>
</stapps-paia-item>
</ng-template>
</ng-container>
</ng-container>
<ng-container *ngSwitchCase="'reservations'">
<stapps-paia-item
*ngFor="let hold of paiaDocuments"
[item]="hold"
[propertiesToShow]="['label']"
(documentAction)="onDocumentAction($event)"
listName="holds"
>
</stapps-paia-item>
</ng-container>
</ng-container>
</ion-list>
<ng-template #fallback>
<stapps-skeleton-list-item
hideThumbnail="true"
*ngIf="!paiaDocuments; else nothingFound"
></stapps-skeleton-list-item>
<ng-template #nothingFound>
<ion-label
*ngIf="paiaDocuments && paiaDocuments.length === 0"
class="centeredMessageContainer"
>
{{ 'search.nothing_found' | translate | titlecase }}
</ion-label>
</ng-template>
</ng-template>
</ion-content>

View File

@@ -125,21 +125,11 @@ export class LibraryAccountService {
return input.split(':').pop(); return input.split(':').pop();
} }
async getHolds() { async getFilteredItems(documentStatus: PAIADocumentStatus[]) {
return (await this.getItems())?.doc.filter(document => { return (await this.getItems())?.doc.filter(document => {
return [PAIADocumentStatus.Ordered].includes(Number(document.status)); return documentStatus.includes(
}); Number(document.status) as PAIADocumentStatus,
} );
async getReservations() {
return (await this.getItems())?.doc.filter(document => {
return [PAIADocumentStatus.Reserved].includes(Number(document.status));
});
}
async getCheckedOutItems() {
return (await this.getItems())?.doc.filter(document => {
return PAIADocumentStatus.Held === Number(document.status);
}); });
} }

View File

@@ -22,7 +22,7 @@ import {TranslateModule} from '@ngx-translate/core';
import {LibraryAccountPageComponent} from './account/account.page'; import {LibraryAccountPageComponent} from './account/account.page';
import {ProfilePageComponent} from './account/profile/profile-page.component'; import {ProfilePageComponent} from './account/profile/profile-page.component';
import {CheckedOutPageComponent} from './account/checked-out/checked-out-page.component'; import {CheckedOutPageComponent} from './account/checked-out/checked-out-page.component';
import {HoldsAndReservationsPageComponent} from './account/holds-and-reservations/holds-and-reservations-page.component'; import {HoldsPageComponent} from './account/holds/holds-page.component';
import {FinesPageComponent} from './account/fines/fines-page.component'; import {FinesPageComponent} from './account/fines/fines-page.component';
import {PAIAItemComponent} from './account/elements/paia-item/paiaitem.component'; import {PAIAItemComponent} from './account/elements/paia-item/paiaitem.component';
import {FirstLastNamePipe} from './account/first-last-name.pipe'; import {FirstLastNamePipe} from './account/first-last-name.pipe';
@@ -54,8 +54,8 @@ const routes: ProtectedRoutes | Routes = [
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
}, },
{ {
path: 'library-account/holds-and-reservations', path: 'library-account/holds',
component: HoldsAndReservationsPageComponent, component: HoldsPageComponent,
data: {authProvider: 'paia'}, data: {authProvider: 'paia'},
canActivate: [AuthGuardService], canActivate: [AuthGuardService],
}, },
@@ -83,7 +83,7 @@ const routes: ProtectedRoutes | Routes = [
LibraryAccountPageComponent, LibraryAccountPageComponent,
ProfilePageComponent, ProfilePageComponent,
CheckedOutPageComponent, CheckedOutPageComponent,
HoldsAndReservationsPageComponent, HoldsPageComponent,
FinesPageComponent, FinesPageComponent,
PAIAItemComponent, PAIAItemComponent,
FirstLastNamePipe, FirstLastNamePipe,

View File

@@ -24,6 +24,12 @@ export interface PAIAPatron {
note?: string; note?: string;
} }
/*
* Document representing a library item received from the HeBIS PAIA service
* TODO: would be good to standardize the items of HeBIS PAIA to match the official PAIA documentation
* e.g. status should be number (0-5), and queue, renewals, reminder should be numbers too
* https://gbv.github.io/paia/paia.html#documents
*/
export interface PAIADocument { export interface PAIADocument {
status: string; status: string;
item?: string; item?: string;
@@ -37,6 +43,7 @@ export interface PAIADocument {
duedate?: string; duedate?: string;
cancancel?: boolean; cancancel?: boolean;
canrenew?: boolean; canrenew?: boolean;
storage?: string;
// with locations // with locations
condition?: unknown; condition?: unknown;
} }

View File

@@ -187,10 +187,10 @@ export const profilePageSections: SCSection[] = [
...SCSectionLinkConstantValues, ...SCSectionLinkConstantValues,
}, },
{ {
name: 'Holdings & Reservations', name: 'Orders & Reservations',
icon: SCIcon`collections_bookmark`, icon: SCIcon`collections_bookmark`,
needsAuth: true, needsAuth: true,
link: ['/library-account/holds-and-reservations'], link: ['/library-account/holds'],
translations: { translations: {
de: { de: {
name: 'Bestellungen & Vormerkungen', name: 'Bestellungen & Vormerkungen',

View File

@@ -273,7 +273,8 @@
"title": "Titel", "title": "Titel",
"about": "Mehr Informationen", "about": "Mehr Informationen",
"label": "Signatur", "label": "Signatur",
"endtime": "Zum Abholen bis" "endtime": "Abzuholen bis",
"storage": "Abholbereit"
}, },
"holds": "Bestellungen", "holds": "Bestellungen",
"reservations": "Vormerkungen" "reservations": "Vormerkungen"

View File

@@ -268,14 +268,15 @@
} }
}, },
"holds": { "holds": {
"title": "holds and reservations", "title": "Orders and reservations",
"labels": { "labels": {
"title": "Title", "title": "Title",
"about": "More information", "about": "More information",
"label": "Label", "label": "Shelfmark",
"endtime": "Available for pickup until" "endtime": "Available for pickup until",
"storage": "Available for pickup"
}, },
"holds": "holds", "holds": "orders",
"reservations": "reservations" "reservations": "reservations"
}, },
"checked_out": { "checked_out": {