LP1936233 Item status list view
authorBill Erickson <berickxx@gmail.com>
Wed, 21 Jul 2021 17:07:55 +0000 (13:07 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 24 Oct 2022 15:07:24 +0000 (11:07 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/item/item.module.ts
Open-ILS/src/eg2/src/app/staff/cat/item/item.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/cat/item/routing.module.ts
Open-ILS/src/eg2/src/app/staff/cat/item/status.component.html
Open-ILS/src/eg2/src/app/staff/cat/item/status.component.ts

index 8f90048..f5b45d7 100644 (file)
@@ -16,6 +16,7 @@ import {ItemCircHistoryComponent} from './circ-history.component';
 import {ItemHoldsTransitsComponent} from './holds.component';
 import {GroupedMenuModule} from '@eg/share/grouped-menu/grouped-menu.module';
 import {WorkLogModule} from '@eg/staff/share/worklog/worklog.module';
+import {ItemStatusService} from './item.service';
 
 @NgModule({
   declarations: [
@@ -40,6 +41,7 @@ import {WorkLogModule} from '@eg/staff/share/worklog/worklog.module';
     GroupedMenuModule
   ],
   providers: [
+    ItemStatusService
   ]
 })
 
diff --git a/Open-ILS/src/eg2/src/app/staff/cat/item/item.service.ts b/Open-ILS/src/eg2/src/app/staff/cat/item/item.service.ts
new file mode 100644 (file)
index 0000000..1b1700b
--- /dev/null
@@ -0,0 +1,9 @@
+import {Injectable, EventEmitter} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
+
+@Injectable()
+export class ItemStatusService {
+    // These must persist route changes.
+    scannedItems: IdlObject[] = [];
+}
+
index f7f4bb4..57ce0b7 100644 (file)
@@ -13,6 +13,9 @@ const routes: Routes = [{
     path: 'list',
     component: ItemStatusComponent
   }, {
+    path: 'list/:copyIdList',
+    component: ItemStatusComponent
+  }, {
     path: ':id/:tab',
     component: ItemStatusComponent
   }, {
index ddcab8a..463604e 100644 (file)
 
     <div class="flex-1"></div>
 
+    <button *ngIf="tab == 'list'" 
+      class="btn btn-outline-dark mr-2" (click)="showDetails()">
+      Detail View
+    </button>
+
+    <button *ngIf="tab != 'list'" 
+      class="btn btn-outline-dark mr-2" (click)="showList()">
+      List View
+    </button>
+
+
     <!-- ACTIONS MENU -->
     <eg-grouped-menu i18n-label label="Actions" *ngIf="item && tab != 'list'">
 
   </div>
 </div>
 
+<ng-template #callNumberTemplate let-r="row">
+  {{r.call_number().prefix().label()}}
+  {{r.call_number().label()}}
+  {{r.call_number().suffix().label()}}
+</ng-template>
+
+<eg-grid *ngIf="tab == 'list'" #grid [dataSource]="dataSource"
+  [useLocalSort]="true" [sortable]="true" [showDeclaredFieldsOnly]="true">
+
+  <eg-grid-column i18n-label label="Item ID" path="id" [index]="true">
+  </eg-grid-column>
+
+  <eg-grid-column i18n-label label="Alert Message" path="alert_message">
+  </eg-grid-column>
+
+  <eg-grid-column i18n-label label="Barcode" path="barcode">
+  </eg-grid-column>
+
+  <eg-grid-column i18n-label label="Location" path="location.name">
+  </eg-grid-column>
+
+  <eg-grid-column i18n-label label="Due Date" path="_circ.due_date"
+    timezoneContextOrg="_circ.circ_lib" dateOnlyIntervalField="_circ.duration"
+    datatype="timestamp">
+  </eg-grid-column>
+
+  <eg-grid-column i18n-label label="Call Number" name="call_number_label" 
+    [cellTemplate]="callNumberTemplate"></eg-grid-column>
+
+  <eg-grid-column i18n-label label="Title"
+    path="call_number.record.simple_record.title"></eg-grid-column>
+
+  <eg-grid-column i18n-label label="Author"
+    path="call_number.record.simple_record.author"></eg-grid-column>
+
+  <eg-grid-column path="call_number.*" [hidden]="true"></eg-grid-column>
+  <eg-grid-column path="call_number.record.simple_record.*" [hidden]="true">
+  </eg-grid-column>
 
+</eg-grid>
 
 <div *ngIf="tab != 'list' && item">
 
index 1d0e51f..f2537b2 100644 (file)
@@ -46,6 +46,10 @@ import {StringService} from '@eg/share/string/string.service';
 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 import {MarkItemsDialogComponent
     } from '@eg/staff/share/holdings/mark-items-dialog.component';
+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 {ItemStatusService} from './item.service';
 
 @Component({
   templateUrl: 'status.component.html'
@@ -58,7 +62,10 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
     noSuchItem = false;
     item: IdlObject;
     tab: string;
-    discardCount = 0;
+    preloadCopyIds: number[];
+
+    dataSource: GridDataSource = new GridDataSource();
+    @ViewChild('grid') private grid: GridComponent;
 
     @ViewChild('barcodeSelect') private barcodeSelect: BarcodeSelectComponent;
 
@@ -107,7 +114,8 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
         private holdings: HoldingsService,
         private toast: ToastService,
         private strings: StringService,
-        private anonCache: AnonCacheService
+        private anonCache: AnonCacheService,
+        private itemService: ItemStatusService
     ) {}
 
     ngOnInit() {
@@ -115,6 +123,11 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
         this.itemId = +this.route.snapshot.paramMap.get('id');
         this.tab = this.route.snapshot.paramMap.get('tab');
 
+        const copyIdList = this.route.snapshot.paramMap.get('copyIdList');
+        if (copyIdList) {
+            this.preloadCopyIds = copyIdList.split(',').map(id => Number(id));
+        }
+
         if (!this.tab) {
             if (this.itemId) {
                 this.tab = 'summary';
@@ -123,31 +136,40 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
             }
         }
 
-        this.worklog.loadSettings().then(_ => this.load());
+        this.worklog.loadSettings().then(_ => this.load(true));
+
+        this.dataSource.getRows = (pager: Pager, sort: any[]) => {
+            return from(this.itemService.scannedItems);
+        };
     }
 
-    load() {
+    load(first?: boolean) {
 
         this.cat.fetchCcvms()
         .then(_ => this.cat.fetchCmfs())
         .then(_ => {
             if (this.itemId) {
                 return this.getItemById(this.itemId);
+            } else if (this.preloadCopyIds) {
+                return from(this.preloadCopyIds).pipe(concatMap(id => {
+                    return of(this.getItemById(id));
+                })).toPromise().then(_ => this.preloadCopyIds = null);
             }
         })
         .then(_ => {
+
+            // Avoid multiple subscriptions
+            if (!first) { return; }
+
             // Avoid watching for changes until after ngOnInit is complete
             // so we don't grab the same copy twice.
-
             this.route.paramMap.subscribe((params: ParamMap) => {
-                this.tab = params.get('tab');
+                this.tab = params.get('tab') || 'list';
                 const id = +params.get('id');
 
-                if (id !== this.itemId) {
+                if (id && id !== this.itemId) {
                     this.itemId = id;
-                    if (id) {
-                        this.getItemById(id);
-                    }
+                    this.getItemById(id);
                 }
             });
         });
@@ -194,6 +216,8 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
 
     getItemById(id: number): Promise<any> {
 
+        // TODO fetch open circ and store it on the copy
+
         const flesh = {
             flesh : 4,
             flesh_fields : {
@@ -216,9 +240,10 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
         return this.pcrud.retrieve('acp', id, flesh)
         .toPromise().then(item => {
             this.item = item;
-            this.itemId = item.id();
             this.mungeIsbns();
             this.selectInput();
+            this.itemService.scannedItems.unshift(item);
+            this.grid.reload();
         });
     }
 
@@ -227,7 +252,8 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
         const item = this.item;
         const isbn = item.call_number().record().simple_record().isbn();
         if (isbn) {
-            item._isbns = isbn.match(/"(.*?)"/g).map(i => i.replace(/"/g, ''));
+            const matches = isbn.match(/"(.*?)"/g);
+            item._isbns = matches ? matches.map(i => i.replace(/"/g, '')) : [];
         } else {
             item._isbns = [item.dummy_isbn()];
         }
@@ -567,6 +593,13 @@ export class ItemStatusComponent implements OnInit, AfterViewInit {
         this.transferItems.transferItems(copies.map(c => c.id()), cnId)
         .then(success => success ? this.load() : null);
     }
+
+    showDetails() {
+    }
+
+    showList() {
+        this.router.navigate(['/staff/cat/item/list']);
+    }
 }