lpxxx Angular holdings maintenance wip
authorBill Erickson <berickxx@gmail.com>
Thu, 21 Mar 2019 16:14:30 +0000 (09:14 -0700)
committerBill Erickson <berickxx@gmail.com>
Thu, 21 Mar 2019 16:14:30 +0000 (09:14 -0700)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/combobox/combobox.component.ts
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.ts
Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alerts-dialog.component.html
Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alerts-dialog.component.ts

index 323623c..02c54c1 100644 (file)
@@ -79,7 +79,7 @@ export class ComboboxComponent implements OnInit {
 
     // Useful for massaging the match string prior to comparison
     // and display.  Default version trims leading/trailing spaces.
-    formatDisplayString: (ComboboxEntry) => string;
+    formatDisplayString: (e: ComboboxEntry) => string;
 
     constructor(
       private elm: ElementRef,
index 808f247..b7cfc57 100644 (file)
     </eg-grid-toolbar-action>
 
     <eg-grid-toolbar-action
-      i18n-group group="Add" i18n-label label="Add Items Notes"
+      i18n-group group="Add" i18n-label label="Add Item Alerts"
       (onClick)="openItemNotes($event, 'create')">
     </eg-grid-toolbar-action>
+
+    <!-- row actions: Edit -->
+    
+    <eg-grid-toolbar-action
+      i18n-group group="Edit" i18n-label label="Edit Item Alerts"
+      (onClick)="openItemNotes($event, 'manage')">
+    </eg-grid-toolbar-action>
     
     <!-- row actions : Show -->
 
index c47d7a6..707944d 100644 (file)
@@ -192,7 +192,11 @@ export class HoldingsMaintenanceComponent implements OnInit {
             'cat.holdings_show_vols'
         ]);
 
-        this.volsCheckbox.checked(settings['cat.holdings_show_vols']);
+        // Show volumes by default when no preference is set.
+        let showVols = settings['cat.holdings_show_vols'];
+        if (showVols === null) { showVols = true; }
+
+        this.volsCheckbox.checked(showVols);
         this.copiesCheckbox.checked(settings['cat.holdings_show_copies']);
         this.emptyVolsCheckbox.checked(settings['cat.holdings_show_empty']);
         this.emptyLibsCheckbox.checked(settings['cat.holdings_show_empty_org']);
@@ -733,7 +737,7 @@ export class HoldingsMaintenanceComponent implements OnInit {
 
         this.copyAlertsDialog.copyIds = copyIds;
         this.copyAlertsDialog.mode = mode;
-        this.copyAlertsDialog.open({}).then(
+        this.copyAlertsDialog.open({size: 'lg'}).then(
             modified => {
                 if (modified) {
                     this.hardRefresh();
index f76e9fd..8375652 100644 (file)
@@ -1,28 +1,98 @@
 <eg-string #successMsg text="Successfully Modified Copy Alerts" i18n-text></eg-string>
 <eg-string #errorMsg text="Failed To Modify Copy Alerts" i18n-text></eg-string>
+<eg-confirm-dialog #confirmDeleteDialog dialogBody="Delete Alert?" 
+  i18n-dialogBody></eg-confirm-dialog>
 
 <ng-template #dialogContent>
-  <div class="modal-header bg-info">
+  <div class="modal-header">
     <h4 class="modal-title">
-      <span i18n>Manage Copy Alerts</span>
+      <ng-container *ngIf="mode == 'create'">
+        <span i18n>Adding alerts for {{copies.length}} item(s).</span>
+      </ng-container>
+      <ng-container *ngIf="mode == 'manage'">
+        <span i18n>Managing alerts for item {{copies[0].barcode()}}</span>
+      </ng-container>
+      <span i18n></span>
     </h4>
     <button type="button" class="close" 
       i18n-aria-label aria-label="Close" (click)="dismiss('cross_click')">
       <span aria-hidden="true">&times;</span>
     </button>
   </div>
-  <div class="modal-body">
-    <ng-container *ngIf="mode == 'create'">
-      <span i18n>Adding alerts for {{copies.length}} item(s).</span>
-    </ng-container>
+  <div class="modal-body p-4">
+    <div class="row mt-2 p-2 rounded border border-success">
+      <div class="col-lg-5">
+        <div class="d-flex flex-column">
+          <eg-combobox [entries]="alertTypes" 
+            i18n-placeholder placeholder="New Alert Type..."
+            (onChange)="newAlert.alert_type($event ? $event.id : null)">
+          </eg-combobox>
+          <div class="form-check pt-2">
+            <input class="form-check-input" type="checkbox" 
+              [ngModel]="newAlert.temp() == 't'" 
+              (ngModelChange)="newAlert.temp($event ? 't' : 'f')"
+              id="new-alert-temporary">
+            <label class="form-check-label" for="new-alert-temporary" i18n>
+              Temporary?
+            </label>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-5">
+        <textarea class="form-control" rows="2" 
+          i18n-placeholder placeholder="New Alert Note..."
+          (ngModelChange)="newAlert.note($event)" [ngModel]="newAlert.note()">
+        </textarea>
+      </div>
+      <div class="col-lg-2">
+        <button class="btn btn-success" (click)="addNew()" i18n>
+          Add New
+        </button>
+      </div>
+    </div>
     <ng-container *ngIf="mode == 'manage'">
-      <span i18n>Managing alerts for item {{copies[0].barcode()}}</span>
+      <!-- in manage mode list all of the alerts linked to the copy -->
+      <div class="row mt-2" 
+        *ngFor="let alert of copy.copy_alerts()">
+        <div class="col-lg-12 pb-2"><hr/></div>
+        <div class="col-lg-5">
+          <div class="d-flex flex-column">
+            <eg-combobox [entries]="alertTypes" [startId]="alert.alert_type()"
+              i18n-placeholder placeholder="Alert Type..."
+              (onChange)="alert.alert_type($event ? $event.id : null); alert.ischanged(true)">
+            </eg-combobox>
+            <div class="form-check pt-2">
+              <input class="form-check-input" type="checkbox" 
+                [ngModel]="alert.temp() == 't'" 
+                (ngModelChange)="alert.temp($event ? 't' : 'f'); alert.ischanged(true)"
+                id="alert-temporary-{{alert.id()}}">
+              <label class="form-check-label" for="alert-temporary-{{alert.id()}}" i18n>
+                Temporary?
+              </label>
+            </div>
+          </div>
+        </div>
+        <div class="col-lg-5">
+          <textarea class="form-control" rows="2" 
+            i18n-placeholder placeholder="Alert Note..."
+            (ngModelChange)="alert.note($event); alert.ischanged(true)"
+            [ngModel]="alert.note()">
+          </textarea>
+        </div>
+        <div class="col-lg-2">
+          <button class="btn btn-warning" (click)="deleteAlert(alert)" i18n>
+            Delete
+          </button>
+        </div>
+      </div>
     </ng-container>
   </div>
   <div class="modal-footer">
-    <button type="button" class="btn btn-warning" 
-      (click)="dismiss('canceled')" i18n>Cancel</button>
-    <button class="btn btn-info mr-2" 
-      (click)="save()" i18n>Apply Changes</button>
+    <button type="button" class="btn btn-secondary" 
+      (click)="dismiss('canceled')" i18n>Close</button>
+    <ng-container *ngIf="mode == 'manage'">
+      <button class="btn btn-success mr-2" 
+        (click)="applyChanges()" i18n>Apply Changes</button>
+    </ng-container>
   </div>
 </ng-template>
index 72ec0c5..464d117 100644 (file)
@@ -1,6 +1,6 @@
 import {Component, OnInit, Input, ViewChild} from '@angular/core';
 import {NetService} from '@eg/core/net.service';
-import {IdlObject} from '@eg/core/idl.service';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
 import {EventService} from '@eg/core/event.service';
 import {ToastService} from '@eg/share/toast/toast.service';
 import {AuthService} from '@eg/core/auth.service';
@@ -10,6 +10,7 @@ import {StringComponent} from '@eg/share/string/string.component';
 import {DialogComponent} from '@eg/share/dialog/dialog.component';
 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
 
 /**
  * Dialog for managing copy alerts.
@@ -31,7 +32,7 @@ export class CopyAlertsDialogComponent
         return this._copyIds;
     }
 
-    _mode: string;
+    _mode: string; // create | manage
     @Input() set mode(m: string) {
         this._mode = m;
     }
@@ -39,17 +40,24 @@ export class CopyAlertsDialogComponent
         return this._mode;
     }
 
+    // In 'create' mode, we may be adding notes to multiple copies.
     copies: IdlObject[];
-    alertTypes: IdlObject[];
+    // In 'manage' mode we only handle a single copy.
+    copy: IdlObject;
+    alertTypes: ComboboxEntry[];
+    newAlert: IdlObject;
+    changesMade: boolean;
 
     @ViewChild('successMsg') private successMsg: StringComponent;
     @ViewChild('errorMsg') private errorMsg: StringComponent;
+    @ViewChild('confirmDeleteDialog')
+        private confirmDeleteDialog: ConfirmDialogComponent;
 
     constructor(
         private modal: NgbModal, // required for passing to parent
         private toast: ToastService,
         private net: NetService,
-        private evt: EventService,
+        private idl: IdlService,
         private pcrud: PcrudService,
         private org: OrgService,
         private auth: AuthService) {
@@ -66,7 +74,10 @@ export class CopyAlertsDialogComponent
      * the mark-damanged action occured or was dismissed.
      */
     async open(args: NgbModalOptions): Promise<boolean> {
+        this.copy = null;
         this.copies = [];
+        this.newAlert = this.idl.create('aca');
+        this.newAlert.create_staff(this.auth.user().id());
 
         if (this.copyIds.length === 0) {
             return Promise.reject('copy ID required');
@@ -91,8 +102,13 @@ export class CopyAlertsDialogComponent
     }
 
     async getAlertTypes(): Promise<any> {
-        return this.pcrud.retrieveAll('aca', {}, {atomic: true})
-        .toPromise().then(alerts => this.alertTypes = alerts);
+        return this.pcrud.retrieveAll('ccat',
+        {   active: true,
+            scope_org: this.org.ancestors(this.auth.user().ws_ou(), true)
+        }, {atomic: true}
+        ).toPromise().then(alerts => {
+            this.alertTypes = alerts.map(a => ({id: a.id(), label: a.name()}));
+        });
     }
 
     async getCopies(): Promise<any> {
@@ -100,11 +116,72 @@ export class CopyAlertsDialogComponent
             {id: this.copyIds},
             {flesh: 1, flesh_fields: {acp: ['call_number', 'copy_alerts']}},
             {atomic: true}
-        ).toPromise().then(copies => this.copies = copies);
+        ).toPromise().then(copies => {
+            this.copies = copies;
+            if (this.mode === 'manage') {
+                this.copy = copies[0];
+            }
+        });
+    }
+
+    // Add the in-progress new note to all copies.
+    addNew() {
+        if (!this.newAlert.alert_type()) { return; }
+
+        const alerts: IdlObject[] = [];
+        this.copies.forEach(c => {
+            const a = this.idl.clone(this.newAlert);
+            a.copy(c.id());
+            alerts.push(a);
+        });
+
+        this.pcrud.create(alerts).toPromise().then(
+            newAlert => {
+                this.successMsg.current().then(msg => this.toast.success(msg));
+                this.changesMade = true;
+                if (this.mode === 'create') {
+                    // In create mode, we assume the user wants to create
+                    // a single alert and be done with it.
+                    this.close(this.changesMade);
+                } else {
+                    // Otherwise, add the alert to the copy
+                    this.copy.copy_alerts().push(newAlert);
+                }
+            },
+            err => {
+                this.errorMsg.current().then(msg => this.toast.danger(msg))
+            }
+        );
+    }
+
+    deleteAlert(copyAlert: IdlObject) {
+        this.confirmDeleteDialog.open().then(
+            ok => {
+                this.pcrud.remove(copyAlert).toPromise().then(
+                    ok => {
+                        this.changesMade = true;
+                        this.copy.copy_alerts( // Remove the delete alert
+                            this.copy.copy_alerts()
+                                .filter(a => a.id() !== copyAlert.id())
+                        )
+                        this.successMsg.current().then(msg => this.toast.success(msg));
+                    },
+                    err => {
+                        this.errorMsg.current().then(msg => this.toast.danger(msg))
+                    }
+                );
+            },
+            dismissed => {}
+        );
     }
 
-    save() {
-        this.close(false);
+    applyChanges() {
+        const alerts = this.copy.copy_alerts().filter(a => a.ischanged());
+        if (alerts.length === 0) { return ;}
+        this.pcrud.update(alerts).toPromise().then(
+            ok => this.successMsg.current().then(msg => this.toast.success(msg)),
+            err => this.errorMsg.current().then(msg => this.toast.danger(msg))
+        )
     }
 }