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