ebde77643ec0b2b8d8d190dedc1b69daec774a03
[evergreen-equinox.git] / Open-ILS / src / eg2 / src / app / staff / admin / local / course-reserves / course-list.component.ts
1 import {Component, Input, ViewChild, OnInit} from '@angular/core';
2 import { Router, ActivatedRoute }    from '@angular/router';
3 import {IdlObject} from '@eg/core/idl.service';
4 import {PcrudService} from '@eg/core/pcrud.service';
5 import {AuthService} from '@eg/core/auth.service';
6 import {CourseService} from '@eg/staff/share/course.service';
7 import {NetService} from '@eg/core/net.service';
8 import {OrgService} from '@eg/core/org.service';
9 import {GridComponent} from '@eg/share/grid/grid.component';
10 import {Pager} from '@eg/share/util/pager';
11 import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
12 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
13 import {StringComponent} from '@eg/share/string/string.component';
14 import {ToastService} from '@eg/share/toast/toast.service';
15
16 import {CourseAssociateMaterialComponent
17     } from './course-associate-material.component';
18
19 import {CourseAssociateUsersComponent
20     } from './course-associate-users.component';
21
22 @Component({
23     templateUrl: './course-list.component.html'
24 })
25
26 export class CourseListComponent implements OnInit { 
27  
28     @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
29     @ViewChild('grid', { static: true }) grid: GridComponent;
30     @ViewChild('successString', { static: true }) successString: StringComponent;
31     @ViewChild('createString', { static: false }) createString: StringComponent;
32     @ViewChild('createErrString', { static: false }) createErrString: StringComponent;
33     @ViewChild('updateFailedString', { static: false }) updateFailedString: StringComponent;
34     @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
35     @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
36     @ViewChild('archiveFailedString', { static: true }) archiveFailedString: StringComponent;
37     @ViewChild('archiveSuccessString', { static: true }) archiveSuccessString: StringComponent;
38     @ViewChild('courseMaterialDialog', {static: true})
39         private courseMaterialDialog: CourseAssociateMaterialComponent;
40     @ViewChild('courseUserDialog', {static: true})
41         private courseUserDialog: CourseAssociateUsersComponent;
42
43     @Input() sort_field: string;
44     @Input() idl_class = "acmc";
45     @Input() dialog_size: 'sm' | 'lg' = 'lg';
46     @Input() table_name = "Course";
47     grid_source: GridDataSource = new GridDataSource();
48     currentMaterials: any[] = [];
49     search_value = '';
50
51     constructor(
52         private auth: AuthService,
53         private courseSvc: CourseService,
54         private net: NetService,
55         private org: OrgService,
56         private pcrud: PcrudService,
57         private route: ActivatedRoute,
58         private router: Router,
59         private toast: ToastService
60     ){}
61
62     ngOnInit() {
63         this.getSource();
64         this.grid.onRowActivate.subscribe((course:IdlObject) => {
65             let idToEdit = course.id();
66             this.navigateToCoursePage(idToEdit);
67         })
68     }
69
70     /**
71      * Gets the data, specified by the class, that is available.
72      */
73     getSource() {
74         this.grid_source.getRows = (pager: Pager, sort: any[]) => {
75             const orderBy: any = {};
76             if (sort.length) {
77                 // Sort specified from grid
78                 orderBy[this.idl_class] = sort[0].name + ' ' + sort[0].dir;
79             } else if (this.sort_field) {
80                 // Default sort field
81                 orderBy[this.idl_class] = this.sort_field;
82             }
83             const searchOps = {
84                 offset: pager.offset,
85                 limit: pager.limit,
86                 order_by: orderBy
87             };
88             return this.pcrud.retrieveAll(this.idl_class, searchOps, {fleshSelectors: true})
89         };
90     }
91
92     navigateToCoursePage(id: any) {
93         this.router.navigate(["/staff/admin/local/asset/course_list/" + id]);
94     }
95
96     showEditDialog(standingPenalty: IdlObject): Promise<any> {
97         this.editDialog.mode = 'update';
98         this.editDialog.recordId = standingPenalty['id']();
99         return new Promise((resolve, reject) => {
100             this.editDialog.open({size: this.dialog_size}).subscribe(
101                 result => {
102                     this.successString.current()
103                         .then(str => this.toast.success(str));
104                     this.grid.reload();
105                     resolve(result);
106                 },
107                 error => {
108                     this.updateFailedString.current()
109                         .then(str => this.toast.danger(str));
110                     reject(error);
111                 }
112             );
113         });
114     }
115
116     createNew() {
117         this.editDialog.mode = 'create';
118         this.editDialog.recordId = null;
119         this.editDialog.record = null;
120         this.editDialog.open({size: this.dialog_size}).subscribe(
121             ok => {
122                 this.createString.current()
123                     .then(str => this.toast.success(str));
124                 this.grid.reload();
125             },
126             rejection => {
127                 if (!rejection.dismissed) {
128                     this.createErrString.current()
129                         .then(str => this.toast.danger(str));
130                 }
131             }
132         );
133     }
134
135     editSelected(fields: IdlObject[]) {
136         // Edit each IDL thing one at a time
137         const editOneThing = (field_object: IdlObject) => {
138             if (!field_object) { return; }
139             this.showEditDialog(field_object).then(
140                 () => editOneThing(fields.shift()));
141         };
142         editOneThing(fields.shift());
143     }
144
145     archiveSelected(course: IdlObject[]) {
146         this.courseSvc.disassociateMaterials(course).then(res => {
147             course.forEach(course => {
148                 console.log(course);
149                 course.is_archived(true);
150             });
151             this.pcrud.update(course).subscribe(
152                 val => {
153                     console.debug('archived: ' + val);
154                     this.archiveSuccessString.current()
155                         .then(str => this.toast.success(str));
156                 }, err => {
157                     this.archiveFailedString.current()
158                         .then(str => this.toast.danger(str));
159                 }, () => {
160                     this.grid.reload();
161                 }
162             );
163         });
164     }
165
166     deleteSelected(idl_object: IdlObject[]) {
167         this.courseSvc.disassociateMaterials(idl_object).then(res => {
168             idl_object.forEach(idl_object => {
169                 idl_object.isdeleted(true)
170             });
171             this.pcrud.autoApply(idl_object).subscribe(
172                 val => {
173                     console.debug('deleted: ' + val);
174                     this.deleteSuccessString.current()
175                         .then(str => this.toast.success(str));
176                 },
177                 err => {
178                     this.deleteFailedString.current()
179                         .then(str => this.toast.danger(str));
180                 },
181                 () => this.grid.reload()
182             );
183         });
184     };
185
186     fetchCourseMaterials(course, currentMaterials): Promise<any> {
187         return new Promise((resolve, reject) => {
188             this.pcrud.search('acmcm', {course: course}).subscribe(res => {
189                 if (res) this.fleshItemDetails(res.item(), res.relationship());
190             }, err => {
191                 reject(err);
192             }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
193         });
194     }
195
196     /**
197      * Uses the course id to fetch the different users associated with that course.
198      * @param course The course id
199      * @param currentMaterials 
200      */
201     fetchCourseUsers(course, currentMaterials): Promise<any> {
202         return new Promise((resolve, reject) => {
203             this.pcrud.search('acmcu', {course: course}).subscribe(res => {
204                 if(res) this.fleshUserDetails(res.usr(), res.usr_role());
205             }, err => {
206                 reject(err);
207             }, () => resolve(this.courseUserDialog.gridDataSource.data));
208         });
209     }
210
211     /**
212      * Takes the user id from the course table, and cross references that with the user table,
213      * to find the right data.
214      * @param userId The user id that is to be cross referenced.
215      * @param usr_role The user role that is to be added to the grid.
216      */
217     fleshUserDetails(userId, usr_role) {
218         return new Promise((resolve, reject) => {
219             this.pcrud.search("au", {id:userId}).subscribe(res => {
220                 if (res) {
221                     let user = res;
222                     user._usr_role = usr_role;
223                     this.courseUserDialog.gridDataSource.data.push(user);
224                 }
225             }, err => {
226                 reject(err);
227             }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
228         });
229     }
230
231     fleshItemDetails(itemId, relationship): Promise<any> {
232         return new Promise((resolve, reject) => {
233             this.net.request(
234                 'open-ils.circ',
235                 'open-ils.circ.copy_details.retrieve',
236                 this.auth.token(), itemId
237             ).subscribe(res => {
238                 if (res) {
239                     let item = res.copy;
240                     item.call_number(res.volume);
241                     item._title = res.mvr.title();
242                     item.circ_lib(this.org.get(item.circ_lib()));
243                     item._relationship = relationship;
244                     this.courseMaterialDialog.gridDataSource.data.push(item);
245                 }
246             }, err => {
247                 reject(err);
248             }, () => resolve(this.courseMaterialDialog.gridDataSource.data));
249         });
250     }
251
252     openMaterialsDialog(course) {
253         let currentMaterials = []
254         this.courseMaterialDialog.gridDataSource.data = [];
255         this.fetchCourseMaterials(course[0].id(), currentMaterials).then(res => {
256             this.courseMaterialDialog.currentCourse = course[0];
257             this.courseMaterialDialog.materials = currentMaterials;
258             this.courseMaterialDialog.open({size: 'lg'}).subscribe(res => {
259                 console.log(res);
260             });
261         });
262     }
263
264     /**
265      * Opens the user dialog component using the course id
266      * @param course 
267      */
268     openUsersDialog(course) { 
269         let currentUsers = []
270         this.courseUserDialog.gridDataSource.data = [];
271         this.fetchCourseUsers(course[0].id(), currentUsers).then(res => {
272             this.courseUserDialog.currentCourse = course[0];
273             this.courseUserDialog.users = currentUsers;
274             this.courseUserDialog.open({size: 'lg'}).subscribe(res => {
275                 console.log(res);
276             });
277         });
278     }
279 }
280