]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/share/holdings/copy-alerts-dialog.component.ts
LP1888723 Angular Holdings Maintenance / Item Attributes Editor
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / share / holdings / copy-alerts-dialog.component.ts
1 import {Component, OnInit, Input, ViewChild} from '@angular/core';
2 import {Observable, throwError, from} from 'rxjs';
3 import {switchMap} from 'rxjs/operators';
4 import {NetService} from '@eg/core/net.service';
5 import {IdlService, IdlObject} from '@eg/core/idl.service';
6 import {EventService} from '@eg/core/event.service';
7 import {ToastService} from '@eg/share/toast/toast.service';
8 import {AuthService} from '@eg/core/auth.service';
9 import {PcrudService} from '@eg/core/pcrud.service';
10 import {OrgService} from '@eg/core/org.service';
11 import {StringComponent} from '@eg/share/string/string.component';
12 import {DialogComponent} from '@eg/share/dialog/dialog.component';
13 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
14 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
15
16 /**
17  * Dialog for managing copy alerts.
18  */
19
20 @Component({
21   selector: 'eg-copy-alerts-dialog',
22   templateUrl: 'copy-alerts-dialog.component.html'
23 })
24
25 export class CopyAlertsDialogComponent
26     extends DialogComponent implements OnInit {
27
28     // If there are multiple copyIds, only new alerts may be applied.
29     // If there is only one copyId, then tags may be applied or removed.
30     @Input() copyIds: number[] = [];
31
32     mode: string; // create | manage
33
34     // If true, no attempt is made to save the new alerts to the
35     // database.  It's assumed this takes place in the calling code.
36     // This is useful for creating alerts for new copies.
37     @Input() inPlaceMode = false;
38
39     // In 'create' mode, we may be adding notes to multiple copies.
40     copies: IdlObject[];
41     // In 'manage' mode we only handle a single copy.
42     copy: IdlObject;
43
44     alertTypes: ComboboxEntry[];
45     newAlert: IdlObject;
46     changesMade: boolean;
47
48     @ViewChild('successMsg', { static: true }) private successMsg: StringComponent;
49     @ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent;
50
51     constructor(
52         private modal: NgbModal, // required for passing to parent
53         private toast: ToastService,
54         private net: NetService,
55         private idl: IdlService,
56         private pcrud: PcrudService,
57         private org: OrgService,
58         private auth: AuthService) {
59         super(modal); // required for subclassing
60         this.copyIds = [];
61         this.copies = [];
62     }
63
64     ngOnInit() {}
65
66     /**
67      * Fetch the item/record, then open the dialog.
68      * Dialog promise resolves with true/false indicating whether
69      * the mark-damanged action occured or was dismissed.
70      */
71     open(args: NgbModalOptions): Observable<boolean> {
72         this.copy = null;
73         this.copies = [];
74         this.newAlert = this.idl.create('aca');
75         this.newAlert.create_staff(this.auth.user().id());
76
77         if (this.copyIds.length === 0 && !this.inPlaceMode) {
78             return throwError('copy ID required');
79         }
80
81         // In manage mode, we can only manage a single copy.
82         // But in create mode, we can add tags to multiple copies.
83         if (this.copyIds.length === 1 && !this.inPlaceMode) {
84             this.mode = 'manage';
85         } else {
86             this.mode = 'create';
87         }
88
89         // Observerify data loading
90         const obs = from(
91             this.getAlertTypes()
92             .then(_ => this.getCopies())
93             .then(_ => this.mode === 'manage' ? this.getCopyAlerts() : null)
94         );
95
96         // Return open() observable to caller
97         return obs.pipe(switchMap(_ => super.open(args)));
98     }
99
100     getAlertTypes(): Promise<any> {
101         if (this.alertTypes) { return Promise.resolve(); }
102
103         return this.pcrud.retrieveAll('ccat',
104         {   active: true,
105             scope_org: this.org.ancestors(this.auth.user().ws_ou(), true)
106         }, {atomic: true}
107         ).toPromise().then(alerts => {
108             this.alertTypes = alerts.map(a => ({id: a.id(), label: a.name()}));
109         });
110     }
111
112     getCopies(): Promise<any> {
113         if (this.inPlaceMode) { return Promise.resolve(); }
114
115         return this.pcrud.search('acp', {id: this.copyIds}, {}, {atomic: true})
116         .toPromise().then(copies => {
117             this.copies = copies;
118             copies.forEach(c => c.copy_alerts([]));
119             if (this.mode === 'manage') {
120                 this.copy = copies[0];
121             }
122         });
123     }
124
125     // Copy alerts for the selected copies which have not been
126     // acknowledged by staff and are within org unit range of
127     // the alert type.
128     getCopyAlerts(): Promise<any> {
129         const copyIds = this.copies.map(c => c.id());
130         const typeIds = this.alertTypes.map(a => a.id);
131
132         return this.pcrud.search('aca',
133             {copy: copyIds, ack_time: null, alert_type: typeIds},
134             {}, {atomic: true})
135         .toPromise().then(alerts => {
136             alerts.forEach(a => {
137                 const copy = this.copies.filter(c => c.id() === a.copy())[0];
138                 copy.copy_alerts().push(a);
139             });
140         });
141     }
142
143     // Add the in-progress new note to all copies.
144     addNew() {
145         if (!this.newAlert.alert_type()) { return; }
146
147         if (this.inPlaceMode) {
148             this.close(this.newAlert);
149             return;
150         }
151
152         const alerts: IdlObject[] = [];
153         this.copies.forEach(c => {
154             const a = this.idl.clone(this.newAlert);
155             a.copy(c.id());
156             alerts.push(a);
157         });
158
159         this.pcrud.create(alerts).toPromise().then(
160             newAlert => {
161                 this.successMsg.current().then(msg => this.toast.success(msg));
162                 this.changesMade = true;
163                 if (this.mode === 'create') {
164                     // In create mode, we assume the user wants to create
165                     // a single alert and be done with it.
166                     this.close(this.changesMade);
167                 } else {
168                     // Otherwise, add the alert to the copy
169                     this.copy.copy_alerts().push(newAlert);
170                 }
171             },
172             err => {
173                 this.errorMsg.current().then(msg => this.toast.danger(msg));
174             }
175         );
176     }
177
178     applyChanges() {
179         const alerts = this.copy.copy_alerts().filter(a => a.ischanged());
180         if (alerts.length === 0) { return; }
181         this.pcrud.update(alerts).toPromise().then(
182             ok => this.successMsg.current().then(msg => this.toast.success(msg)),
183             err => this.errorMsg.current().then(msg => this.toast.danger(msg))
184         );
185     }
186 }
187