]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-dialog.component.ts
LP1983628: Add editor for item notes
[Evergreen.git] / Open-ILS / src / eg2 / src / app / staff / share / holdings / copy-notes-dialog.component.ts
1 import {Component, Input, ViewChild} from '@angular/core';
2 import {Observable, throwError, from, empty} 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 {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
14 /**
15  * Dialog for managing copy notes.
16  */
17
18 export interface CopyNotesChanges {
19     newNotes: IdlObject[];
20     delNotes: IdlObject[];
21 }
22
23 @Component({
24   selector: 'eg-copy-notes-dialog',
25   templateUrl: 'copy-notes-dialog.component.html'
26 })
27
28 export class CopyNotesDialogComponent
29     extends DialogComponent {
30
31     // If there are multiple copyIds, only new notes may be applied.
32     // If there is only one copyId, then notes may be applied or removed.
33     @Input() copyIds: number[] = [];
34
35     mode: string; // create | manage | edit
36
37     // If true, no attempt is made to save the new notes 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
44     // In 'manage' mode we only handle a single copy.
45     copy: IdlObject;
46
47     curNote: string;
48     curNoteTitle: string;
49     curNotePublic = false;
50     newNotes: IdlObject[] = [];
51     delNotes: IdlObject[] = [];
52
53     autoId = -1;
54
55     idToEdit: number;
56
57     @ViewChild('successMsg', { static: true }) private successMsg: StringComponent;
58     @ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent;
59
60     constructor(
61         private modal: NgbModal, // required for passing to parent
62         private toast: ToastService,
63         private net: NetService,
64         private idl: IdlService,
65         private pcrud: PcrudService,
66         private org: OrgService,
67         private auth: AuthService) {
68         super(modal); // required for subclassing
69     }
70
71     /**
72      */
73     open(args: NgbModalOptions): Observable<CopyNotesChanges> {
74         this.copy = null;
75         this.copies = [];
76         this.newNotes = [];
77         this.delNotes = [];
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 notes 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         // Observify data loading
93         const obs = from(this.getCopies());
94
95         // Return open() observable to caller
96         return obs.pipe(switchMap(_ => super.open(args)));
97     }
98
99     getCopies(): Promise<any> {
100
101         // Avoid fetch if we're only adding notes to isnew copies.
102         const ids = this.copyIds.filter(id => id > 0);
103         if (ids.length === 0) { return Promise.resolve(); }
104
105         return this.pcrud.search('acp', {id: this.copyIds},
106             {flesh: 1, flesh_fields: {acp: ['notes']}},
107             {atomic: true}
108         )
109         .toPromise().then(copies => {
110             this.copies = copies;
111             if (copies.length === 1) {
112                 this.copy = copies[0];
113             }
114         });
115     }
116
117     editNote(note: IdlObject) {
118         this.idToEdit = note.id();
119         this.mode = 'edit';
120     }
121
122     returnToManage() {
123         this.getCopies().then(() => {
124             this.idToEdit = null;
125             this.mode = 'manage';
126         })
127     }
128
129     removeNote(note: IdlObject) {
130         this.newNotes = this.newNotes.filter(t => t.id() !== note.id());
131
132         if (note.isnew() || this.mode === 'create') { return; }
133
134         const existing = this.copy.notes().filter(n => n.id() === note.id())[0];
135         if (!existing) { return; }
136
137         existing.isdeleted(true);
138         this.delNotes.push(existing);
139
140         // Remove from copy for dialog display
141         this.copy.notes(this.copy.notes().filter(n => n.id() !== note.id()));
142     }
143
144     addNew() {
145         if (!this.curNoteTitle || !this.curNote) { return; }
146
147         const note = this.idl.create('acpn');
148         note.isnew(true);
149         note.creator(this.auth.user().id());
150         note.pub(this.curNotePublic ? 't' : 'f');
151         note.title(this.curNoteTitle);
152         note.value(this.curNote);
153         note.id(this.autoId--);
154
155         this.newNotes.push(note);
156
157         this.curNote = '';
158         this.curNoteTitle = '';
159         this.curNotePublic = false;
160     }
161
162     applyChanges() {
163
164         if (this.inPlaceCreateMode) {
165             this.close({ newNotes: this.newNotes, delNotes: this.delNotes });
166             return;
167         }
168
169         const notes = [];
170         this.newNotes.forEach(note => {
171             this.copies.forEach(copy => {
172                 const n = this.idl.clone(note);
173                 n.id(null); // remove temp ID, it will be duped
174                 n.owning_copy(copy.id());
175                 notes.push(n);
176             });
177         });
178
179         this.pcrud.create(notes).toPromise()
180         .then(_ => {
181             if (this.delNotes.length) {
182                 return this.pcrud.remove(this.delNotes).toPromise();
183             }
184         }).then(_ => {
185             this.successMsg.current().then(msg => this.toast.success(msg));
186             this.close({ newNotes: this.newNotes, delNotes: this.delNotes });
187         });
188     }
189 }
190