LP1994711 Semantic H1 headings for page titles
[evergreen-equinox.git] / Open-ILS / src / eg2 / src / app / staff / admin / local / course-reserves / course-list.component.ts
1 import {Component, Input, ViewChild, OnInit, AfterViewInit} from '@angular/core';
2 import {Router} from '@angular/router';
3 import {IdlObject, IdlService} from '@eg/core/idl.service';
4 import {PcrudService} from '@eg/core/pcrud.service';
5 import {CourseService} from '@eg/staff/share/course.service';
6 import {GridComponent} from '@eg/share/grid/grid.component';
7 import {Pager} from '@eg/share/util/pager';
8 import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
9 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
10 import {StringComponent} from '@eg/share/string/string.component';
11 import {ToastService} from '@eg/share/toast/toast.service';
12 import {LocaleService} from '@eg/core/locale.service';
13 import {AuthService} from '@eg/core/auth.service';
14 import {OrgService} from '@eg/core/org.service';
15 import {OrgFamily} from '@eg/share/org-family-select/org-family-select.component';
16
17 import {CourseAssociateMaterialComponent
18     } from './course-associate-material.component';
19
20 import {CourseAssociateUsersComponent
21     } from './course-associate-users.component';
22
23 @Component({
24     templateUrl: './course-list.component.html',
25     styleUrls: ['./course-page.component.css']
26 })
27
28 export class CourseListComponent implements OnInit, AfterViewInit {
29
30     @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
31     @ViewChild('grid') grid: GridComponent;
32     @ViewChild('successString', { static: true }) successString: StringComponent;
33     @ViewChild('createString') createString: StringComponent;
34     @ViewChild('createErrString') createErrString: StringComponent;
35     @ViewChild('updateFailedString') updateFailedString: StringComponent;
36     @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
37     @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
38     @ViewChild('archiveFailedString', { static: true }) archiveFailedString: StringComponent;
39     @ViewChild('archiveSuccessString', { static: true }) archiveSuccessString: StringComponent;
40     @ViewChild('unarchiveFailedString', { static: true }) unarchiveFailedString: StringComponent;
41     @ViewChild('unarchiveSuccessString', { static: true }) unarchiveSuccessString: StringComponent;
42     @ViewChild('courseMaterialDialog', {static: true})
43         private courseMaterialDialog: CourseAssociateMaterialComponent;
44     @ViewChild('courseUserDialog', {static: true})
45         private courseUserDialog: CourseAssociateUsersComponent;
46
47     @Input() sortField: string;
48     @Input() idlClass = 'acmc';
49     @Input() dialog_size: 'sm' | 'lg' = 'lg';
50     @Input() tableName = 'Course';
51     grid_source: GridDataSource = new GridDataSource();
52     currentMaterials: any[] = [];
53     search_value = '';
54     defaultOuId: number;
55     searchOrgs: OrgFamily;
56     defaultTerm: IdlObject;
57
58
59     constructor(
60         private courseSvc: CourseService,
61         private locale: LocaleService,
62         private auth: AuthService,
63         private idl: IdlService,
64         private org: OrgService,
65         private pcrud: PcrudService,
66         private router: Router,
67         private toast: ToastService
68     ) {}
69
70     ngOnInit() {
71         this.getSource();
72         this.defaultTerm = this.idl.create('acmt');
73         this.defaultOuId = this.auth.user().ws_ou() || this.org.root().id();
74         this.defaultTerm.owning_lib(this.defaultOuId);
75         this.searchOrgs = {primaryOrgId: this.defaultOuId};
76     }
77
78     ngAfterViewInit() {
79         this.grid.onRowActivate.subscribe((course: IdlObject) => {
80             const idToEdit = course.id();
81             this.navigateToCoursePage(idToEdit);
82         });
83
84     }
85
86     acmtcmQueryParams (row: any): {gridFilters: string} {
87         return {gridFilters: '{"course":' + row.id() + '}'};
88     }
89
90
91     /**
92      * Gets the data, specified by the class, that is available.
93      */
94     getSource() {
95         this.grid_source.getRows = (pager: Pager, sort: any[]) => {
96             const orderBy: any = {};
97             if (sort.length) {
98                 // Sort specified from grid
99                 orderBy[this.idlClass] = sort[0].name + ' ' + sort[0].dir;
100             } else if (this.sortField) {
101                 // Default sort field
102                 orderBy[this.idlClass] = this.sortField;
103             }
104             const search: any = new Array();
105             const orgFilter: any = {};
106             orgFilter['owning_lib'] =
107                 this.searchOrgs.orgIds || [this.defaultOuId];
108             search.push(orgFilter);
109             const searchOps = {
110                 offset: pager.offset,
111                 limit: pager.limit,
112                 order_by: orderBy
113             };
114             return this.pcrud.search(this.idlClass, search, searchOps, {fleshSelectors: true});
115         };
116     }
117
118     navigateToCoursePage(id_arr: IdlObject[]) {
119         if (typeof id_arr === 'number') { id_arr = [id_arr]; }
120         const urls = [];
121         id_arr.forEach(id => {console.log(this.router.url);
122             urls.push([this.locale.currentLocaleCode() + this.router.url + '/' +  id]);
123         });
124         if (id_arr.length === 1) {
125         this.router.navigate([this.router.url + '/' + id_arr[0]]);
126         } else {
127             urls.forEach(url => {
128                 window.open(url);
129             });
130         }
131     }
132
133     createNew() {
134         this.editDialog.mode = 'create';
135         const course_module_course = this.idl.create('acmc');
136         course_module_course.owning_lib(this.auth.user().ws_ou());
137         this.editDialog.recordId = null;
138         this.editDialog.record = course_module_course;
139         this.editDialog.open({size: this.dialog_size}).subscribe(
140             ok => {
141                 this.createString.current()
142                     .then(str => this.toast.success(str));
143                 this.grid.reload();
144             },
145             rejection => {
146                 if (!rejection.dismissed) {
147                     this.createErrString.current()
148                         .then(str => this.toast.danger(str));
149                 }
150             }
151         );
152     }
153
154     editSelected(fields: IdlObject[]) {
155         // Edit each IDL thing one at a time
156         const course_ids = [];
157         fields.forEach(field => {
158             if (typeof field['id'] === 'function') {
159                 course_ids.push(field.id());
160             } else {
161                 course_ids.push(field['id']);
162             }
163         });
164         this.navigateToCoursePage(course_ids);
165     }
166
167     archiveSelected(course: IdlObject[]) {
168         this.courseSvc.disassociateMaterials(course).then(res => {
169             course.forEach(courseToArchive => {
170                 courseToArchive.is_archived(true);
171             });
172             this.pcrud.update(course).subscribe(
173                 val => {
174                     console.debug('archived: ' + val);
175                     this.archiveSuccessString.current()
176                         .then(str => this.toast.success(str));
177                 }, err => {
178                     this.archiveFailedString.current()
179                         .then(str => this.toast.danger(str));
180                 }, () => {
181                     this.grid.reload();
182                 }
183             );
184         });
185     }
186     
187     courseArchiveableOrNot(course: IdlObject[], archiveBool) {
188         course.forEach(courseToMod => {
189             if (archiveBool == false) return courseToMod.is_archived() == 't';
190             return courseToMod.is_archived() == 'f';
191         });
192     }
193
194     unarchiveSelected(course: IdlObject[]) {
195         course.forEach(courseToUnarchive => {
196             courseToUnarchive.is_archived(false);
197         });
198         this.pcrud.update(course).subscribe(
199             val => {
200                 course.forEach(courseEntry => {
201                     this.courseSvc.removeNonPublicUsers(courseEntry.id());
202                 });
203                 console.debug('archived: ' + val);
204                 this.unarchiveSuccessString.current()
205                     .then(str => this.toast.success(str));
206             }, err => {
207                 this.unarchiveFailedString.current()
208                     .then(str => this.toast.danger(str));
209             }, () => {
210                 this.grid.reload();
211             }
212         );
213     }
214
215     deleteSelected(idlObject: IdlObject[]) {
216         this.courseSvc.disassociateMaterials(idlObject).then(res => {
217             idlObject.forEach(object => {
218                 object.isdeleted(true);
219             });
220             this.pcrud.autoApply(idlObject).subscribe(
221                 val => {
222                     console.debug('deleted: ' + val);
223                     this.deleteSuccessString.current()
224                         .then(str => this.toast.success(str));
225                 },
226                 err => {
227                     this.deleteFailedString.current()
228                         .then(str => this.toast.danger(str));
229                 },
230                 () => this.grid.reload()
231             );
232         });
233     }
234 }
235