LP1823041: Converting new dialogs to observables
[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 'rxjs';
3 import {NetService} from '@eg/core/net.service';
4 import {IdlService, IdlObject} from '@eg/core/idl.service';
5 import {EventService} from '@eg/core/event.service';
6 import {ToastService} from '@eg/share/toast/toast.service';
7 import {AuthService} from '@eg/core/auth.service';
8 import {PcrudService} from '@eg/core/pcrud.service';
9 import {OrgService} from '@eg/core/org.service';
10 import {StringComponent} from '@eg/share/string/string.component';
11 import {DialogComponent} from '@eg/share/dialog/dialog.component';
12 import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
13 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
14 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.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     _copyIds: number[];
29     @Input() set copyIds(ids: number[]) {
30         this._copyIds = [].concat(ids);
31     }
32     get copyIds(): number[] {
33         return this._copyIds;
34     }
35
36     _mode: string; // create | manage
37     @Input() set mode(m: string) {
38         this._mode = m;
39     }
40     get mode(): string {
41         return this._mode;
42     }
43
44     // In 'create' mode, we may be adding notes to multiple copies.
45     copies: IdlObject[];
46     // In 'manage' mode we only handle a single copy.
47     copy: IdlObject;
48     alertTypes: ComboboxEntry[];
49     newAlert: IdlObject;
50     changesMade: boolean;
51
52     @ViewChild('successMsg') private successMsg: StringComponent;
53     @ViewChild('errorMsg') private errorMsg: StringComponent;
54     @ViewChild('confirmDeleteDialog')
55         private confirmDeleteDialog: ConfirmDialogComponent;
56
57     constructor(
58         private modal: NgbModal, // required for passing to parent
59         private toast: ToastService,
60         private net: NetService,
61         private idl: IdlService,
62         private pcrud: PcrudService,
63         private org: OrgService,
64         private auth: AuthService) {
65         super(modal); // required for subclassing
66         this.copyIds = [];
67         this.copies = [];
68     }
69
70     ngOnInit() {}
71
72     /**
73      * Fetch the item/record, then open the dialog.
74      * Dialog promise resolves with true/false indicating whether
75      * the mark-damanged action occured or was dismissed.
76      */
77     open(args: NgbModalOptions): Observable<boolean> {
78         this.copy = null;
79         this.copies = [];
80         this.newAlert = this.idl.create('aca');
81         this.newAlert.create_staff(this.auth.user().id());
82
83         if (this.copyIds.length === 0) {
84             return throwError('copy ID required');
85         }
86
87         // In manage mode, we can only manage a single copy.
88         // But in create mode, we can add alerts to multiple copies.
89
90         if (this.mode === 'manage') {
91             if (this.copyIds.length > 1) {
92                 console.warn('Attempt to manage alerts for multiple copies.');
93                 this.copyIds = [this.copyIds[0]];
94             }
95         }
96
97         this.getAlertTypes()
98         .then(() => this.getCopies())
99         .then(() => {
100             if (this.mode === 'manage') {
101                 this.getCopyAlerts()
102                 .then(() => super.open(args) );
103             }
104             return super.open(args);
105         });
106     }
107
108     getAlertTypes(): Promise<any> {
109         if (this.alertTypes) {
110             return Promise.resolve();
111         }
112         return this.pcrud.retrieveAll('ccat',
113         {   active: true,
114             scope_org: this.org.ancestors(this.auth.user().ws_ou(), true)
115         }, {atomic: true}
116         ).toPromise().then(alerts => {
117             this.alertTypes = alerts.map(a => ({id: a.id(), label: a.name()}));
118         });
119     }
120
121     getCopies(): Promise<any> {
122         return this.pcrud.search('acp', {id: this.copyIds}, {}, {atomic: true})
123         .toPromise().then(copies => {
124             this.copies = copies;
125             copies.forEach(c => c.copy_alerts([]));
126             if (this.mode === 'manage') {
127                 this.copy = copies[0];
128             }
129         });
130     }
131
132     // Copy alerts for the selected copies which have not been
133     // acknowledged by staff and are within org unit range of
134     // the alert type.
135     getCopyAlerts(): Promise<any> {
136         const copyIds = this.copies.map(c => c.id());
137         const typeIds = this.alertTypes.map(a => a.id);
138
139         return this.pcrud.search('aca',
140             {copy: copyIds, ack_time: null, alert_type: typeIds},
141             {}, {atomic: true})
142         .toPromise().then(alerts => {
143             alerts.forEach(a => {
144                 const copy = this.copies.filter(c => c.id() === a.copy())[0];
145                 copy.copy_alerts().push(a);
146             });
147         });
148     }
149
150     // Add the in-progress new note to all copies.
151     addNew() {
152         if (!this.newAlert.alert_type()) { return; }
153
154         const alerts: IdlObject[] = [];
155         this.copies.forEach(c => {
156             const a = this.idl.clone(this.newAlert);
157             a.copy(c.id());
158             alerts.push(a);
159         });
160
161         this.pcrud.create(alerts).toPromise().then(
162             newAlert => {
163                 this.successMsg.current().then(msg => this.toast.success(msg));
164                 this.changesMade = true;
165                 if (this.mode === 'create') {
166                     // In create mode, we assume the user wants to create
167                     // a single alert and be done with it.
168                     this.close(this.changesMade);
169                 } else {
170                     // Otherwise, add the alert to the copy
171                     this.copy.copy_alerts().push(newAlert);
172                 }
173             },
174             err => {
175                 this.errorMsg.current().then(msg => this.toast.danger(msg));
176             }
177         );
178     }
179
180     applyChanges() {
181         const alerts = this.copy.copy_alerts().filter(a => a.ischanged());
182         if (alerts.length === 0) { return; }
183         this.pcrud.update(alerts).toPromise().then(
184             ok => this.successMsg.current().then(msg => this.toast.success(msg)),
185             err => this.errorMsg.current().then(msg => this.toast.danger(msg))
186         );
187     }
188 }
189