<form (ngSubmit)="submitStaffLogin()" #staffLoginForm="ngForm" class="form-validated">
<div class="form-group row">
- <label class="col-lg-4 text-right font-weight-bold" for="username" i18n>Username</label>
+ <label class="col-lg-4 text-right font-weight-bold"
+ for="staff-username" i18n>Username</label>
<input
type="text"
class="form-control col-lg-8"
</div>
<div class="form-group row">
- <label class="col-lg-4 text-right font-weight-bold" for="password" i18n>Password</label>
+ <label class="col-lg-4 text-right font-weight-bold"
+ for="staff-password" i18n>Password</label>
<input
type="password"
class="form-control col-lg-8"
</div>
<div class="form-group row" *ngIf="workstations && workstations.length">
- <label class="col-lg-4 text-right font-weight-bold" for="workstation" i18n>Workstation</label>
+ <label class="col-lg-4 text-right font-weight-bold"
+ for="workstation" i18n>Workstation</label>
<select
class="form-control col-lg-8"
id="workstation"
-import {Component, OnInit, NgZone, HostListener} from '@angular/core';
+import {Component, OnInit, AfterViewInit, NgZone, HostListener} from '@angular/core';
import {Location} from '@angular/common';
import {Router, ActivatedRoute, NavigationEnd} from '@angular/router';
import {AuthService, AuthWsState} from '@eg/core/auth.service';
templateUrl: 'banner.component.html'
})
-export class SckoBannerComponent implements OnInit {
+export class SckoBannerComponent implements OnInit, AfterViewInit {
workstations: any[];
workstationNotFound = false;
ngOnInit() {
- // TODO focus the right thing on page load
- const node = document.getElementById('staff-username');
-
// NOTE: Displaying a list of workstations will not work for users
// of Hatch until the extension is updated to support /eg2/*/scko
this.store.getWorkstations()
});
}
+ ngAfterViewInit() {
+ if (this.auth.token()) {
+ this.focusNode('patron-username');
+ } else {
+ this.focusNode('staff-username');
+ }
+
+ this.scko.focusBarcode.subscribe(_ => this.focusNode('item-barcode'));
+ }
+
+ focusNode(id: string) {
+ setTimeout(() => {
+ const node = document.getElementById(id);
+ if (node) { (node as HTMLInputElement).select(); }
+ });
+ }
+
applyWorkstation() {
const wanted = this.route.snapshot.queryParamMap.get('workstation');
if (!wanted) { return; } // use the default
submitPatronLogin() {
this.patronLoginFailed = false;
this.scko.loadPatron(this.patronUsername, this.patronPassword).finally(() => {
- this.patronLoginFailed = this.scko.patronSummary === null;
+ if (this.scko.patronSummary === null) {
+ this.patronLoginFailed = true;
+ } else {
+ this.focusNode('item-barcode');
+ }
});
}
padding: 3px;
}
-
+.scko-status-row {
+ font-size: 20px;
+}
<eg-scko-banner></eg-scko-banner>
-<div class="d-flex">
+<div class="d-flex scko-status-row mt-2">
<div class="flex-1"></div>
- <div class="text-primary">{{scko.statusDisplayText}}</div>
+ <div [ngClass]="{
+ 'text-success': scko.statusDisplaySuccess,
+ 'text-danger': !scko.statusDisplaySuccess}">{{scko.statusDisplayText}}</div>
<div class="flex-1"></div>
</div>
text="Item is checked out to another patron"></eg-string>
<eg-string i18n-text key="scko.error.max_renewals"
text="No more renewals allowed for item {{barcode}}"></eg-string>
+
+<eg-string i18n-text key="scko.error.patron_fines"
+ text="This account has too many fines to checkout."></eg-string>
+
<eg-string i18n-text key="scko.error.item_not_cataloged"
text="Item {{barcode}} was not found in the system. Try re-scanning the item."></eg-string>
+
+<eg-string i18n-text key="scko.error.copy_circ_not_allowed"
+ text="Item {{barcode}} is not allowed to circulate"></eg-string>
<eg-string i18n-text key="scko.error.actor_usr_barred"
text="The patron is barred"></eg-string>
<eg-string i18n-text key="scko.error.asset_copy_circulate"
logoutWarningTimeout = 20;
logoutWarningTimerId: number;
statusDisplayText = '';
+ statusDisplaySuccess: boolean;
alertAudio = false;
alertPopup = false;
// We get this from the main scko component.
logoutDialog: ConfirmDialogComponent;
alertDialog: AlertDialogComponent;
+ focusBarcode: EventEmitter<void> = new EventEmitter<void>();
constructor(
private router: Router,
return this.renew(barcode);
}
+ return ctx;
+
// Checkout actions always takes us back to the main page
// so we can see our items out in progress.
})
}
notifyPatron(ctx: CheckoutContext) {
+ console.debug("notifyPatron()", ctx);
+
this.statusDisplayText = '';
+ this.statusDisplaySuccess = !ctx.shouldPopup;
+
+ this.focusBarcode.emit();
+
if (this.alertAudio && ctx.alertSound) {
this.audio.play(ctx.alertSound);
}
return this.handleOpenCirc(ctx);
}
- if (this.overrideCheckoutEvents.length > 0) {
- return this.handleOverride(ctx);
- }
-
- ctx.alertSound = 'error.scko.checkout';
- ctx.shouldPopup = true;
- return Promise.resolve(ctx);
+ return this.handleEvents(ctx);
}
handleOpenCirc(ctx: CheckoutContext): Promise<any> {
return Promise.resolve(ctx);
}
- handleOverride(ctx: CheckoutContext): Promise<CheckoutContext> {
- if (this.overrideCheckoutEvents.length === 0) {
- return Promise.resolve(ctx);
- }
-
+ handleEvents(ctx: CheckoutContext): Promise<CheckoutContext> {
let override = true;
let abortTransit = false;
let lastErrorText = '';
+
[].concat(ctx.result).some(res => {
if (!this.overrideCheckoutEvents.includes(res.textcode)) {
return 'scko.error.max_renewals';
case 'ITEM_NOT_CATALOGED':
return 'scko.error.item_not_cataloged';
+ case 'COPY_CIRC_NOT_ALLOWED':
+ return 'scko.error.copy_circ_not_allowed';
case 'OPEN_CIRCULATION_EXISTS':
return 'scko.error.already_out';
+ case 'PATRON_EXCEEDS_FINES':
+ return 'scko.error.patron_fines';
default:
if (evt.payload && evt.payload.fail_part) {
return 'scko.error.' +