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';
17 import {CourseAssociateMaterialComponent
18 } from './course-associate-material.component';
20 import {CourseAssociateUsersComponent
21 } from './course-associate-users.component';
24 templateUrl: './course-list.component.html',
25 styleUrls: ['./course-page.component.css']
28 export class CourseListComponent implements OnInit, AfterViewInit {
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('duplicateFailedString', { static: true }) duplicateFailedString: StringComponent;
43 @ViewChild('duplicateSuccessString', { static: true }) duplicateSuccessString: StringComponent;
44 @ViewChild('courseMaterialDialog', {static: true})
45 private courseMaterialDialog: CourseAssociateMaterialComponent;
46 @ViewChild('courseUserDialog', {static: true})
47 private courseUserDialog: CourseAssociateUsersComponent;
49 @Input() sortField: string;
50 @Input() idlClass = 'acmc';
51 @Input() dialog_size: 'sm' | 'lg' = 'lg';
52 @Input() tableName = 'Course';
53 grid_source: GridDataSource = new GridDataSource();
54 currentMaterials: any[] = [];
57 searchOrgs: OrgFamily;
58 defaultTerm: IdlObject;
62 private courseSvc: CourseService,
63 private locale: LocaleService,
64 private auth: AuthService,
65 private idl: IdlService,
66 private org: OrgService,
67 private pcrud: PcrudService,
68 private router: Router,
69 private toast: ToastService
74 this.defaultTerm = this.idl.create('acmt');
75 this.defaultOuId = this.auth.user().ws_ou() || this.org.root().id();
76 this.defaultTerm.owning_lib(this.defaultOuId);
77 this.searchOrgs = {primaryOrgId: this.defaultOuId};
81 this.grid.onRowActivate.subscribe((course: IdlObject) => {
82 const idToEdit = course.id();
83 this.navigateToCoursePage(idToEdit);
88 acmtcmQueryParams (row: any): {gridFilters: string} {
89 return {gridFilters: '{"course":' + row.id() + '}'};
94 * Gets the data, specified by the class, that is available.
97 this.grid_source.getRows = (pager: Pager, sort: any[]) => {
98 const orderBy: any = {};
100 // Sort specified from grid
101 orderBy[this.idlClass] = sort[0].name + ' ' + sort[0].dir;
102 } else if (this.sortField) {
103 // Default sort field
104 orderBy[this.idlClass] = this.sortField;
106 const search: any = new Array();
107 const orgFilter: any = {};
108 orgFilter['owning_lib'] =
109 this.searchOrgs.orgIds || [this.defaultOuId];
110 search.push(orgFilter);
112 offset: pager.offset,
116 return this.pcrud.search(this.idlClass, search, searchOps, {fleshSelectors: true});
120 navigateToCoursePage(id_arr: IdlObject[]) {
121 if (typeof id_arr === 'number') { id_arr = [id_arr]; }
123 id_arr.forEach(id => {
124 console.log(this.router.url);
125 urls.push([this.locale.currentLocaleCode() + this.router.url + '/' + id]);
127 if (id_arr.length === 1) {
128 this.router.navigate([this.router.url + '/' + id_arr[0]]);
130 urls.forEach(url => {
137 this.editDialog.mode = 'create';
138 const course_module_course = this.idl.create('acmc');
139 course_module_course.owning_lib(this.auth.user().ws_ou());
140 this.editDialog.recordId = null;
141 this.editDialog.record = course_module_course;
142 this.editDialog.open({size: this.dialog_size}).subscribe(
144 this.createString.current()
145 .then(str => this.toast.success(str));
148 // eslint-disable-next-line rxjs/no-implicit-any-catch
149 (rejection: any) => {
150 if (!rejection.dismissed) {
151 this.createErrString.current()
152 .then(str => this.toast.danger(str));
158 editSelected(fields: IdlObject[]) {
159 // Edit each IDL thing one at a time
160 const course_ids = [];
161 fields.forEach(field => {
162 if (typeof field['id'] === 'function') {
163 course_ids.push(field.id());
165 course_ids.push(field['id']);
168 this.navigateToCoursePage(course_ids);
171 archiveSelected(course: IdlObject[]) {
172 this.courseSvc.disassociateMaterials(course).then(res => {
173 course.forEach(courseToArchive => {
174 courseToArchive.is_archived(true);
176 this.pcrud.update(course).subscribe(
178 console.debug('archived: ' + val);
179 this.archiveSuccessString.current()
180 .then(str => this.toast.success(str));
181 }, (err: unknown) => {
182 this.archiveFailedString.current()
183 .then(str => this.toast.danger(str));
191 courseArchiveableOrNot(course: IdlObject[], archiveBool) {
192 course.forEach(courseToMod => {
193 // eslint-disable-next-line eqeqeq
194 if (archiveBool == false) {return courseToMod.is_archived() == 't';}
195 // eslint-disable-next-line eqeqeq
196 return courseToMod.is_archived() == 'f';
200 unarchiveSelected(course: IdlObject[]) {
201 course.forEach(courseToUnarchive => {
202 courseToUnarchive.is_archived(false);
204 this.pcrud.update(course).subscribe(
206 course.forEach(courseEntry => {
207 this.courseSvc.removeNonPublicUsers(courseEntry.id());
209 console.debug('archived: ' + val);
210 this.unarchiveSuccessString.current()
211 .then(str => this.toast.success(str));
212 }, (err: unknown) => {
213 this.unarchiveFailedString.current()
214 .then(str => this.toast.danger(str));
221 duplicateSelected(course: IdlObject[]) {
222 course.forEach(courseToCopy => {
223 const new_course = this.idl.create('acmc');
224 new_course.name(courseToCopy.name() + $localize`:duplicate of an existing course: (Copy)`);
225 new_course.course_number(courseToCopy.course_number());
226 new_course.section_number(courseToCopy.section_number());
227 new_course.owning_lib(courseToCopy.owning_lib());
228 new_course.is_archived(courseToCopy.is_archived());
229 this.pcrud.create(new_course).subscribe({next: (val) => {
230 console.debug('duplicated: ' + val);
231 this.duplicateSuccessString.current()
232 .then(str => this.toast.success(str));
233 }, error: (err: unknown) => {
234 this.duplicateFailedString.current()
235 .then(str => this.toast.danger(str));
236 }, complete: () => this.grid.reload()
241 deleteSelected(idlObject: IdlObject[]) {
242 this.courseSvc.disassociateMaterials(idlObject).then(res => {
243 idlObject.forEach(object => {
244 object.isdeleted(true);
246 this.pcrud.autoApply(idlObject).subscribe(
248 console.debug('deleted: ' + val);
249 this.deleteSuccessString.current()
250 .then(str => this.toast.success(str));
253 this.deleteFailedString.current()
254 .then(str => this.toast.danger(str));
256 () => this.grid.reload()