<div class="row pb-2 pt-2">
<div class="ml-auto">
- <button class="btn btn-outline-dark" i18n>Print</button>
- <button class="btn btn-outline-dark ml-3" i18n>Save</button>
- <button class="btn btn-outline-dark ml-3" i18n>Save & Clone</button>
+ <button class="btn btn-outline-dark"
+ (click)="printClicked.emit()" i18n>Print</button>
+ <button class="btn btn-outline-dark ml-3"
+ (click)="saveClicked.emit()" i18n>Save</button>
+ <button class="btn btn-outline-dark ml-3"
+ (click)="saveCloneClicked.emit()" i18n>Save & Clone</button>
</div>
</div>
-import {Component, OnInit, Input} from '@angular/core';
+import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
import {OrgService} from '@eg/core/org.service';
})
export class EditToolbarComponent implements OnInit {
+ @Output() saveClicked: EventEmitter<void> = new EventEmitter<void>();
+ @Output() saveCloneClicked: EventEmitter<void> = new EventEmitter<void>();
+ @Output() printClicked: EventEmitter<void> = new EventEmitter<void>();
+
constructor(
private org: OrgService,
private net: NetService,
--- /dev/null
+
+
+.patron-edit-container {
+
+}
+
+<span class="font-weight-bold" i18n>Show:</span>
+<a class="ml-2" href="javascript:;'" (click)="showFields='required'" i18n>Required Fields</a>
+<a class="ml-2" href="javascript:;'" (click)="showFields='suggested'" i18n>Suggested Fields</a>
+<a class="ml-2" href="javascript:;'" (click)="showFields='all'" i18n>All Fields</a>
+
+
+<ng-template #fieldLabel
+ let-cls="cls" let-field="field" let-override="override">
+ <div class="col-lg-3 field-label">
+ <label for="{{cls}}-{{field}}-input">
+ {{getFieldLabel(cls, field, override)}}
+ </label>
+ <!-- TODO doc links -->
+ </div>
+</ng-template>
+
+<ng-template #fieldInput let-cls="cls" let-field="field"
+ let-type="type" let-disabled="disabled" let-path="path">
+ <div class="col-lg-3">
+ <input
+ type="{{type || 'text'}}"
+ class="form-control"
+ name="{{cls}}-{{field}}-input"
+ id="{{cls}}-{{field}}-input"
+ [ngModel]="objectFromPath(path)[field]()"
+ (ngModelChange)="fieldValueChange(path, field, $event)"
+ (change)="fieldMaybeModified(path, field)"
+ [required]="fieldRequired(cls, field)"
+ [pattern]="fieldPattern(cls, field)"
+ [disabled]="disabled"
+ />
+ </div>
+</ng-template>
+
+
+<div class="mt-3 striped-rows-even patron-edit-container" *ngIf="patron">
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'ac', field: 'barcode'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context:
+ {cls: 'ac', field: 'barcode', disabled: !patron.isnew(), path: 'card'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'usrname'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'usrname'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'passwd'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'passwd'}">
+ </ng-container>
+ <div class="col-lg-3">
+ <button class="btn btn-outline-dark" (click)="generatePassword()" i18n>
+ Generate Password
+ </button>
+ </div>
+ </div>
+ <ul ngbNav #nameNav="ngbNav" class="nav-tabs" [activeId]="nameTab">
+ <li ngbNavItem="primary">
+ <a ngbNavLink i18n>Primary Name</a>
+ <ng-template ngbNavContent>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'prefix'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'prefix'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'first_given_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'first_given_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'second_given_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'second_given_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'family_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'family_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'suffix'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'suffix'}">
+ </ng-container>
+ </div>
+ </ng-template>
+ </li>
+ <li ngbNavItem="preferred">
+ <a ngbNavLink i18n>Preferred Name</a>
+ <ng-template ngbNavContent>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'pref_prefix'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'pref_prefix'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'pref_first_given_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'pref_first_given_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'pref_second_given_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'pref_second_given_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'pref_family_name'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'pref_family_name'}">
+ </ng-container>
+ </div>
+ <div class="row pt-1 pb-1 mt-2">
+ <ng-container
+ *ngTemplateOutlet="fieldLabel; context: {cls: 'au', field: 'pref_suffix'}">
+ </ng-container>
+ <ng-container
+ *ngTemplateOutlet="fieldInput; context: {cls: 'au', field: 'pref_suffix'}">
+ </ng-container>
+ </div>
+ </ng-template>
+ </li>
+ </ul>
+ <div [ngbNavOutlet]="nameNav"></div>
+ <hr class="m-2"/>
+
+
+</div>
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
import {OrgService} from '@eg/core/org.service';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
import {NetService} from '@eg/core/net.service';
import {PatronService} from '@eg/staff/share/patron/patron.service';
import {PatronContextService} from './patron.service';
+const FLESH_PATRON_FIELDS = {
+ flesh: 1,
+ flesh_fields: {
+ au: ['card', 'mailing_address', 'billing_address', 'addresses']
+ }
+};
+
@Component({
templateUrl: 'edit.component.html',
- selector: 'eg-patron-edit'
+ selector: 'eg-patron-edit',
+ styleUrls: ['edit.component.css']
})
export class EditComponent implements OnInit {
+ @Input() patronId: number;
+ @Input() cloneId: number;
+ @Input() stageUsername: string;
+
+ patron: IdlObject;
+ changeHandlerNeeded = false;
+ nameTab = 'primary';
+
constructor(
private org: OrgService,
private net: NetService,
+ private idl: IdlService,
public patronService: PatronService,
public context: PatronContextService
) {}
ngOnInit() {
+
+ if (this.patronId) {
+ this.patronService.getById(this.patronId, FLESH_PATRON_FIELDS)
+ .then(patron => this.patron = patron);
+ } else {
+ this.createNewPatron();
+ }
+ }
+
+ createNewPatron() {
+ const patron = this.idl.create('au');
+ patron.isnew(true);
+
+ const card = this.idl.create('ac');
+ card.isnew(true);
+ card.usr(-1);
+ patron.card(card);
+
+ this.patron = patron;
+ }
+
+ objectFromPath(path: string): IdlObject {
+ return path ? this.patron[path]() : this.patron;
+ }
+
+ getFieldLabel(idlClass: string, field: string, override?: string): string {
+ return override ? override :
+ this.idl.classes[idlClass].field_map[field].label;
+ }
+
+ fieldValueChange(path: string, field: string, value: any) {
+ this.changeHandlerNeeded = true;
+ this.objectFromPath(path)[field](value);
+ }
+
+ fieldMaybeModified(path: string, field: string) {
+ if (!this.changeHandlerNeeded) { return; } // no changes applied
+
+ // TODO: set dirty = true
+
+ this.changeHandlerNeeded = false;
+
+ console.debug(`Modifying field path=${path} field=${field}`);
+
+ // check stuff here..
+
+ const obj = path ? this.patron[path]() : this.patron;
+ }
+
+ fieldRequired(idlClass: string, field: string): boolean {
+ // TODO
+ return false;
+ }
+
+ fieldPattern(idlClass: string, field: string): string {
+ // TODO
+ return null;
+ }
+
+ generatePassword() {
+ this.fieldValueChange(null,
+ 'passwd', Math.floor(Math.random()*9000) + 1000);
+
+ // Normally this is called on (blur), but the input is not
+ // focused when using the generate button.
+ this.fieldMaybeModified(null, 'passwd');
}
}
</div>
</div>
+<hr class="m-2"/>
-<div class="mt-4">
+<div class="mt-3">
- <eg-grid idlClass="au" #groupGrid
- [dataSource]="dataSource" [sortable]="true" [useLocalSort]="true"
- showFields="active,barred,dob,family_name,first_given_name,
+ <ng-template #barcodeTemplate let-r="row">
+ <ng-container *ngIf="r.card()">
+ <a routerLink="/staff/circ/patron/{{r.id()}}/checkout">
+ {{r.card().barcode()}}
+ </a>
+ </ng-container>
+ </ng-template>
+
+ <eg-grid idlClass="au" #groupGrid
+ [cellTextGenerator]="cellTextGenerator"
+ [dataSource]="dataSource"
+ [sortable]="true"
+ [useLocalSort]="true"
+ (onRowActivate)="onRowActivate($event)"
+ showFields="active,barred,dob,family_name,first_given_name,barcode,
master_account,second_given_name,balance_owed,total_out,overdue">
<eg-grid-toolbar-button label="Move Another Patron To This Group"
i18n-label (onClick)="movePatronToGroup()">
</eg-grid-toolbar-button>
+ <eg-grid-toolbar-action
+ label="Register a New Group Member By Cloning Selected Patron"
+ i18n-label (onClick)="cloneSelected($event)">
+ </eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action label="Remove Selected From Group"
+ i18n-label (onClick)="removeSelected($event)">
+ </eg-grid-toolbar-action>
+
+ <eg-grid-toolbar-action label="Move Selected To Another Patron's Group"
+ i18n-label (onClick)="movePatronToGroup($event)">
+ </eg-grid-toolbar-action>
+
<eg-grid-column name="balance_owed" path="_stats.fines.balance_owed"
datatype="currency" label="Balance Owed" i18n-label>
</eg-grid-column>
+
<eg-grid-column name="total_out" path="_stats.checkouts.total_out"
label="Items Out" i18n-label>
</eg-grid-column>
+
<eg-grid-column name="overdue" path="_stats.checkouts.overdue"
label="Items Overdue" i18n-label>
</eg-grid-column>
+ <eg-grid-column name="barcode" [cellTemplate]="barcodeTemplate"
+ label="Barcode" i18n-label>
+ </eg-grid-column>
+
</eg-grid>
</div>
import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
+import {Location} from '@angular/common';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
-import {from, empty, range} from 'rxjs';
-import {concatMap, tap, takeLast} from 'rxjs/operators';
+import {of, from, empty, range} from 'rxjs';
+import {concatMap, map, tap, takeLast} from 'rxjs/operators';
import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
import {IdlObject} from '@eg/core/idl.service';
import {EventService} from '@eg/core/event.service';
totalOverdue = 0;
usergroup: number;
+ cellTextGenerator: GridCellTextGenerator;
dataSource: GridDataSource = new GridDataSource();
@ViewChild('groupGrid') private groupGrid: GridComponent;
@ViewChild('moveToGroupDialog') private moveToGroupDialog: PromptDialogComponent;
private auth: AuthService,
private org: OrgService,
private pcrud: PcrudService,
+ private ngLocation: Location,
private patronService: PatronService,
private context: PatronContextService
) {}
ngOnInit() {
+ this.cellTextGenerator = {
+ barcode: row => row.card().barcode()
+ }
+
this.dataSource.getRows = (pager: Pager, sort: any[]) =>
from(this.patrons.slice(pager.offset, pager.offset + pager.limit));
}
}
- getGroupUsers(usergroup: number) {
+ getGroupUsers(usergroup: number): Promise<any> {
this.usergroup = usergroup;
this.patrons = [];
- this.pcrud.search('au',
- {usrgroup: usergroup, deleted: 'f'}, {authoritative: true})
+ return this.pcrud.search('au',
+ {usrgroup: usergroup, deleted: 'f'},
+ {flesh: 1, flesh_fields: {au: ['card']}},
+ {authoritative: true})
.pipe(concatMap(u => {
const promise = this.context.getPatronVitalStats(u.id())
return from(promise);
- })).subscribe(null, null, () => this.groupGrid.reload());
+ })).toPromise().then(_ => this.groupGrid.reload());
}
- movePatronToGroup() {
+ // If rows are present, we are moving selected rows to a different group
+ // Otherwise, we are moving another user into this group.
+ movePatronToGroup(rows?: IdlObject[]) {
+
+ this.moveToGroupDialog.promptValue = '';
this.moveToGroupDialog.open().subscribe(barcode => {
if (!barcode) { return null; }
return null;
}
- resp.usrgroup(this.usergroup);
- resp.ischanged(true);
-
- return this.net.request(
- 'open-ils.actor',
- 'open-ils.actor.patron.update',
- this.auth.token(), resp
- ).toPromise();
- })
- .then(resp => {
- if (resp === null) { return null; }
-
- const evt = this.evt.parse(resp);
- if (evt) {
- console.error(evt);
- alert(evt);
- return null;
+ let users: IdlObject[] = [resp];
+ let usergroup: number = this.usergroup;
+ if (rows) {
+ users = rows;
+ usergroup = resp.usrgroup();
}
- return this.getGroupUsers(this.usergroup);
- })
- .then(resp => {
- if (resp === null) { return null; }
- this.groupGrid.reload();
+ let allOk = true;
+ from(users).pipe(concatMap(user => {
+
+ user.usrgroup(usergroup);
+ user.ischanged(true);
+
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.patron.update',
+ this.auth.token(), user
+ );
+ })).subscribe(
+ resp => { if (this.evt.parse(resp)) { allOk = false; } },
+ err => console.error(err),
+ () => { if (allOk) { this.refresh(); } }
+ );
});
});
}
+
+ refresh() {
+ this.context.refreshPatron()
+ .then(_ => this.usergroup = this.context.patron.usrgroup())
+ .then(_ => this.getGroupUsers(this.usergroup))
+ .then(_ => this.groupGrid.reload());
+ }
+
+ removeSelected(rows: IdlObject[]) {
+
+ from(rows.map(r => r.id())).pipe(concatMap(id => {
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.usergroup.new',
+ this.auth.token(), id, true
+ );
+ }))
+ .subscribe(null, null, () => this.refresh());
+ }
+
+ onRowActivate(row: IdlObject) {
+ const url = this.ngLocation.prepareExternalUrl(
+ `/staff/circ/patron/${row.id()}/checkout`);
+ window.open(url);
+ }
+
+ cloneSelected(rows: IdlObject[]) {
+ if (rows.length) {
+ const url = this.ngLocation.prepareExternalUrl(
+ `/staff/circ/patron/register/clone/${rows[0].id()}`);
+ window.open(url);
+ }
+ }
}
<li ngbNavItem="edit" [disabled]="!context.patron">
<a ngbNavLink i18n>Edit</a>
<ng-template ngbNavContent>
- <eg-patron-edit
- contentPaneClass="patron-content-pane div-scroll-vert">
- </eg-patron-edit>
+ <eg-patron-edit [patronId]="patronId"></eg-patron-edit>
</ng-template>
</li>
import {PatronSurveyResponsesComponent} from './surveys.component';
import {PatronStatCatsComponent} from './statcats.component';
import {PatronGroupComponent} from './group.component';
+import {RegisterPatronComponent} from './register.component';
@NgModule({
declarations: [
TestPatronPasswordComponent,
PatronSurveyResponsesComponent,
PatronGroupComponent,
+ RegisterPatronComponent,
PatronStatCatsComponent
],
imports: [
];
interface PatronStats {
- fines: {balance_owed: number};
+ fines: {
+ balance_owed: number,
+ group_balance_owed: number
+ };
checkouts: {
overdue: number,
claims_returned: number,
.then(stats => this.patronStats = stats)
.then(_ => {
-
if (!this.patron) { return; }
return this.net.request(
'open-ils.circ',
'open-ils.circ.open_non_cataloged_circulation.user.authoritative',
- this.auth.token(), id).toPromise();
+ this.auth.token(), id
+ ).toPromise();
}).then(noncats => {
+ if (!this.patron) { return; }
+
if (noncats && this.patronStats) {
this.patronStats.checkouts.noncat = noncats.length;
}
+
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.usergroup.members.balance_owed.authoritative',
+ this.auth.token(), this.patron.usrgroup()
+ ).toPromise();
+
+ }).then(fines => {
+ if (!this.patron) { return; }
+
+ let total = 0;
+ fines.forEach(f => total += Number(f.balance_owed) * 100);
+ this.patronStats.fines.group_balance_owed = total / 100;
});
}
--- /dev/null
+<eg-staff-banner i18n-bannerText bannerText="Register New Patron">
+</eg-staff-banner>
+
+
+<div class="sticky-top-with-nav bg-white">
+ <eg-patron-edit-toolbar></eg-patron-edit-toolbar>
+ <eg-patron-edit [stageUsername]="stageUsername" [cloneId]="cloneId">
+ </eg-patron-edit>
+</div>
--- /dev/null
+import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
+import {Location} from '@angular/common';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {of, from, empty, range} from 'rxjs';
+import {concatMap, map, tap, takeLast} from 'rxjs/operators';
+import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {IdlObject} from '@eg/core/idl.service';
+import {EventService} from '@eg/core/event.service';
+import {OrgService} from '@eg/core/org.service';
+import {NetService} from '@eg/core/net.service';
+import {PcrudService, PcrudContext} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
+import {PatronContextService} from './patron.service';
+import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {Pager} from '@eg/share/util/pager';
+import {PromptDialogComponent} from '@eg/share/dialog/prompt.component';
+import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
+import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
+
+@Component({
+ templateUrl: 'register.component.html'
+})
+export class RegisterPatronComponent implements OnInit {
+
+ stageUsername: string;
+ cloneId: number;
+
+ constructor(
+ private router: Router,
+ private route: ActivatedRoute,
+ private evt: EventService,
+ private net: NetService,
+ private auth: AuthService,
+ private org: OrgService,
+ private pcrud: PcrudService,
+ private ngLocation: Location,
+ private patronService: PatronService,
+ private context: PatronContextService
+ ) {}
+
+ ngOnInit() {
+ this.route.paramMap.subscribe((params: ParamMap) => {
+ this.stageUsername = params.get('stageUsername');
+ this.cloneId = +params.get('cloneId');
+ });
+ }
+}
+
import {BcSearchComponent} from './bcsearch.component';
import {PatronResolver} from './resolver.service';
import {TestPatronPasswordComponent} from './test-password.component';
+import {RegisterPatronComponent} from './register.component';
const routes: Routes = [{
path: '',
loadChildren: () =>
import('./event-log/event-log.module').then(m => m.EventLogModule)
}, {
+ path: 'register',
+ component: RegisterPatronComponent
+ }, {
+ path: 'register/clone/:cloneId',
+ component: RegisterPatronComponent
+ }, {
+ path: 'register/stage/:stageUsername',
+ component: RegisterPatronComponent
+ }, {
path: 'credentials',
component: TestPatronPasswordComponent
}, {
<hr class="m-1"/>
- <ng-container *ngIf="context.patronStats">
+ <ng-container *ngIf="stats()">
<div class="row mb-1"
- [ngClass]="{'alert alert-danger p-0': context.patronStats.fines.balance_owed > 0}">
+ [ngClass]="{'alert alert-danger p-0': stats().fines.balance_owed > 0}">
<div class="col-lg-5" i18n>Fines Owed</div>
- <div class="col-lg-7">{{context.patronStats.fines.balance_owed | currency}}</div>
+ <div class="col-lg-7">{{stats().fines.balance_owed | currency}}</div>
</div>
- <!-- TODO GROUP FINES -->
+ <ng-container
+ *ngIf="stats().fines.group_balance_owed > stats().fines.balance_owed">
+ <div class="row mb-1 alert alert-danger p-0">
+ <div class="col-lg-5" i18n>Group Fines</div>
+ <div class="col-lg-7">{{stats().fines.group_balance_owed | currency}}</div>
+ </div>
+ </ng-container>
<div class="row mb-1">
<div class="col-lg-5" i18n>Items Out</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.total_out}}</div>
+ <div class="col-lg-7">{{stats().checkouts.total_out}}</div>
</div>
<div class="row mb-1"
- [ngClass]="{'alert alert-danger p-0': context.patronStats.checkouts.overdue > 0}">
+ [ngClass]="{'alert alert-danger p-0': stats().checkouts.overdue > 0}">
<div class="col-lg-5" i18n>Overdue</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.overdue}}</div>
+ <div class="col-lg-7">{{stats().checkouts.overdue}}</div>
</div>
<div class="row mb-1"
- [ngClass]="{'alert alert-danger p-0': context.patronStats.checkouts.long_overdue > 0}">
+ [ngClass]="{'alert alert-danger p-0': stats().checkouts.long_overdue > 0}">
<div class="col-lg-5" i18n>Long Overdue</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.long_overdue}}</div>
+ <div class="col-lg-7">{{stats().checkouts.long_overdue}}</div>
</div>
<div class="row mb-1"
- [ngClass]="{'alert alert-danger p-0': context.patronStats.checkouts.claims_returned > 0}">
+ [ngClass]="{'alert alert-danger p-0': stats().checkouts.claims_returned > 0}">
<div class="col-lg-5" i18n>Claimed Returned</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.claims_returned}}</div>
+ <div class="col-lg-7">{{stats().checkouts.claims_returned}}</div>
</div>
<div class="row mb-1"
- [ngClass]="{'alert alert-danger p-0': context.patronStats.checkouts.lost > 0}">
+ [ngClass]="{'alert alert-danger p-0': stats().checkouts.lost > 0}">
<div class="col-lg-5" i18n>Lost</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.lost}}</div>
+ <div class="col-lg-7">{{stats().checkouts.lost}}</div>
</div>
<div class="row mb-1">
<div class="col-lg-5" i18n>Non-Cataloged</div>
- <div class="col-lg-7">{{context.patronStats.checkouts.noncat}}</div>
+ <div class="col-lg-7">{{stats().checkouts.noncat}}</div>
</div>
<div class="row">
<div class="col-lg-5" i18n>Holds</div>
<div class="col-lg-7">
- {{context.patronStats.holds.ready}} / {{context.patronStats.holds.total}}
+ {{stats().holds.ready}} / {{stats().holds.total}}
</div>
</div>
return this.context.patron;
}
+ stats(): any {
+ return this.context.patronStats;
+ }
+
hasPrefName(): boolean {
if (this.patron()) {
return (