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