place holds cont.
authorBill Erickson <berickxx@gmail.com>
Fri, 16 Nov 2018 19:33:55 +0000 (14:33 -0500)
committerBill Erickson <berickxx@gmail.com>
Fri, 30 Nov 2018 16:34:20 +0000 (11:34 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.ts
Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.ts

index a71008f..f0677be 100644 (file)
@@ -1,6 +1,7 @@
-<h4>Place Hold</h4>
+<h3 i18n>Place Hold</h3>
 
-<form class="form form-validated common-form striped-odd" autocomplete="off">
+<form class="form form-validated common-form striped-odd" 
+  autocomplete="off" (keydown.enter)="$event.preventDefault()">
   <div class="row">
     <div class="col-lg-3">
       <div class="form-check">
       </div>
     </div>
     <div class="col-lg-3">
-      <input type='text' class="form-control" name="patronBarcode"
-        [disabled]="holdFor!='patron'" id='patron-barcode' [(ngModel)]="patronBarcode"/>
+      <div class="input-group">
+        <input type='text' class="form-control" name="userBarcode"
+          [disabled]="holdFor!='patron'" id='patron-barcode' 
+          (keyup.enter)="userBarcodeChanged()"
+          [(ngModel)]="userBarcode" (change)="userBarcodeChanged()"/>
+        <div class="input-group-append">
+          <button class="btn btn-outline-dark" 
+            (click)="userSearch()" i18n>Search</button>
+        </div>
+      </div>
     </div>
-  </div>
-  <div class="row mt-2">
     <div class="col-lg-3">
       <div class="form-check">
         <input class="form-check-input" type="radio" 
           name="holdFor" value="staff" [(ngModel)]="holdFor"/>
         <label class="form-check-label" i18n>
-          Place hold for this staff account:
+          Place hold for this staff account: {{requestor.usrname()}}
         </label>
       </div>
     </div>
-    <div class="col-lg-3">
-      <span class="font-weight-bold">{{requestor.usrname()}}</span>
-    </div>
   </div>
   <div class="row mt-2">
     <div class="col-lg-3">
@@ -42,7 +46,7 @@
     <div class="col-lg-3">
       <div class="form-check">
         <input class="form-check-input" type="checkbox" name="notifyEmail"
-          [disabled]="!user.email()" [(ngModel)]="notifyEmail"/>
+          [disabled]="!user || !user.email()" [(ngModel)]="notifyEmail"/>
         <label class="form-check-label" i18n>Notify by Email</label>
       </div>
     </div>
@@ -52,7 +56,7 @@
           <span class="input-group-text" i18n>Email Address</span>
         </div>
         <input type="text" class="form-control" name="userEmail"
-          [disabled]="true" value="{{user.email()}}"/>
+          [disabled]="true" value="{{user ? user.email() : ''}}"/>
       </div>
     </div>
   </div>
   </div>
 </form>
 
+<h4 class="p-3" i18n>Placing Hold(s) On Records...</h4>
+
+<ng-container *ngFor="let recId of recordIds">
+  <div class="row mt-2 ml-2 mr-2">
+    <div class="col-lg-12">
+      <eg-bib-summary [recordId]="recId" [expand]="false"></eg-bib-summary> 
+    </div>
+  </div>
+</ng-container>
+
 
index 9b2acc4..4d86428 100644 (file)
@@ -1,13 +1,13 @@
 import {Component, OnInit, Input, ViewChild, Renderer2} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {EventService} from '@eg/core/event.service';
+import {NetService} from '@eg/core/net.service';
 import {AuthService} from '@eg/core/auth.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {IdlObject} from '@eg/core/idl.service';
 import {CatalogSearchContext, CatalogSearchState} from '@eg/share/catalog/search-context';
 import {CatalogService} from '@eg/share/catalog/catalog.service';
-import {BibRecordService, BibRecordSummary} from '@eg/share/catalog/bib-record.service';
 import {StaffCatalogService} from '../catalog.service';
-import {BibSummaryComponent} from '@eg/staff/share/bib-summary/bib-summary.component';
 
 @Component({
   templateUrl: 'hold.component.html'
@@ -17,6 +17,7 @@ export class HoldComponent implements OnInit {
     holdType: string;
     holdTargets: number[];
     user: IdlObject; //
+    userBarcode: string;
     requestor: IdlObject;
     holdFor: string;
     pickupLib: number;
@@ -25,14 +26,18 @@ export class HoldComponent implements OnInit {
     phoneValue: string;
     suspend: boolean;
     activeDate: string;
+    recordIds: number[];
+
+    barcodeInFlight: string;
 
     constructor(
         private router: Router,
         private route: ActivatedRoute,
         private renderer: Renderer2,
+        private evt: EventService,
+        private net: NetService,
         private auth: AuthService,
         private pcrud: PcrudService,
-        private bib: BibRecordService,
         private cat: CatalogService,
         private staffCat: StaffCatalogService
     ) {}
@@ -49,12 +54,20 @@ export class HoldComponent implements OnInit {
         this.holdFor = 'patron';
         this.requestor = this.user = this.auth.user();
         this.pickupLib = this.auth.user().ws_ou();
+        this.findRecords();
 
-        // Focus barcode input
-        setTimeout(() => 
+        setTimeout(() => // Focus barcode input
             this.renderer.selectRootElement('#patron-barcode').focus());
     }
 
+    findRecords() {
+        if (this.holdType === 'T') {
+            this.recordIds = this.holdTargets;
+        } else {
+            // TODO OTHER HOLD TYPES
+        }
+    }
+
     holdForChanged() {
         console.log('placing hold for ' + this.holdFor);
 
@@ -69,6 +82,49 @@ export class HoldComponent implements OnInit {
     activeDateSelected(dateStr: string) {
         this.activeDate = dateStr;
     }
+
+    userBarcodeChanged() {
+        this.user = null;
+
+        if (!this.userBarcode) { return; }
+
+        // Avoid simultaneous lookups caused by firing the
+        // keyup handler and change handler in quick succession.
+        // keyup handler applied so barcode scanner will result
+        // in immediate lookup.  change handler for humans 
+        // copy/paste'ing then tabbing through the form or off-clicking.
+        if (this.userBarcode === this.barcodeInFlight) { return; }
+        this.barcodeInFlight = this.userBarcode;
+
+        this.net.request(
+            'open-ils.actor',
+            'open-ils.actor.get_barcodes',
+            this.auth.token(), this.auth.user().ws_ou(), 
+            'actor', this.userBarcode
+        ).subscribe(barcodes => {
+
+            // Use the first successful barcode response.
+            // TODO: What happens when there are multiple responses?
+            // Use for-loop for early exit since we have async
+            // action within the loop.
+            for (let i = 0; i < barcodes.length; i++) {
+                const bc = barcodes[i];
+                if (!this.evt.parse(bc)) {
+                    this.getUser(bc.id);
+                    break;
+                }
+            }
+        });
+    }
+
+    getUser(id: number) {
+        // TODO fetch user settings for PU lib, etc.
+        this.pcrud.retrieve('au', id).subscribe(user => {
+            this.user = user;
+            this.notifyPhone = user.day_phone() || user.evening_phone();
+            this.barcodeInFlight = null;
+        });
+    }
 }
 
 
index 78d2653..645b56c 100644 (file)
@@ -14,6 +14,9 @@ export class BibSummaryComponent implements OnInit {
 
     initDone = false;
     expandDisplay = true;
+    @Input() set expand(e: boolean) {
+        this.expandDisplay = e;
+    }
 
     // If provided, the record will be fetched by the component.
     @Input() recordId: number;