Forked from an inaccessible project.
-
jvanboxtel@wisc.edu authoredjvanboxtel@wisc.edu authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
new-degree-audit-dialog.component.ts 9.03 KiB
import { Component, OnInit } from '@angular/core';
import { DarsApiService } from '../services/api.service';
import { DegreePrograms } from '../models/degree-program';
import { StudentDegreeProgram } from '../models/student-degree-program';
import { Observable, combineLatest, Subject } from 'rxjs';
import {
FormBuilder,
FormGroup,
Validators,
FormControl,
FormArray,
} from '@angular/forms';
import { HonorsOption } from '../models/honors-option';
import { map, share, filter, flatMap, shareReplay } from 'rxjs/operators';
import { CourseBase } from '@app/core/models/course';
import { Store } from '@ngrx/store';
import { GlobalState } from '@app/core/state';
import { degreePlans } from '../store/selectors';
import { DegreePlan } from '@app/core/models/degree-plan';
import { MatDialogRef } from '@angular/material';
const inclusiveRange = (from: number, to: number) => {
const range: number[] = [];
for (let i = from; i <= to; i++) {
range.push(i);
}
return range;
};
export interface NewDegreeAuditFields {
darsInstitutionCode: string;
darsDegreeProgramCode: string;
degreePlannerPlanName: string;
darsHonorsOptionCode: string;
whichEnrolledCoursesIncluded: string;
fixedCredits: {
termCode: string;
subjectCode: string;
courseId: string;
credits: number;
}[];
}
@Component({
selector: 'cse-new-degree-audit-dialog',
templateUrl: './new-degree-audit-dialog.component.html',
styleUrls: ['./new-degree-audit-dialog.component.scss'],
})
export class NewDegreeAuditDialogComponent implements OnInit {
// Form-builder objects
public chosenProgram: FormControl;
public chosenAuditSettings: FormGroup;
public chosenCreditSettings: FormArray;
// API observables
public degreePrograms$: Observable<StudentDegreeProgram[]>;
public institutions$: Observable<DegreePrograms>;
public degreePlans$: Observable<DegreePlan[]>;
public chosenRoadmapId$ = new Subject<number>();
public honorsOptions$: Observable<HonorsOption[]>;
public variableCreditCourses$: Observable<
(CourseBase & { range: number[] })[]
>;
constructor(
private fb: FormBuilder,
private api: DarsApiService,
private store: Store<GlobalState>,
private dialogRef: MatDialogRef<NewDegreeAuditDialogComponent>,
) {
this.chosenProgram = fb.control('', Validators.required);
this.chosenAuditSettings = fb.group({
honorsOptions: fb.control(' ', Validators.required),
includeCoursesFrom: fb.control('future', Validators.required),
degreePlan: fb.control('', Validators.required),
});
this.chosenCreditSettings = fb.array([]);
}
public ngOnInit() {
this.degreePrograms$ = this.api.getStudentDegreePrograms().pipe(share());
this.degreePrograms$.subscribe(programs => {
if (programs.length > 0) {
this.chosenProgram.setValue(programs[0]);
}
});
this.institutions$ = this.api.getStaticData().pipe(share());
this.honorsOptions$ = combineLatest([
this.institutions$,
this.chosenProgram.valueChanges.pipe(
filter(value => value.hasOwnProperty('darsInstitutionCode')),
map(value => value.darsInstitutionCode as string),
),
]).pipe(
map(([institutions, darsInstitutionCode]) => {
return institutions.hasOwnProperty(darsInstitutionCode)
? institutions[darsInstitutionCode].honorsOptions
: [];
}),
);
this.degreePlans$ = this.store.select(degreePlans).pipe(shareReplay());
this.degreePlans$.subscribe(plans => {
const primaryPlan = plans.find(p => p.primary);
this.chosenAuditSettings.controls['degreePlan'].setValue(primaryPlan);
});
const degreePlanFormControl = this.chosenAuditSettings.get('degreePlan');
const includeCoursesFrom = this.chosenAuditSettings.get(
'includeCoursesFrom',
);
if (degreePlanFormControl) {
degreePlanFormControl.valueChanges.subscribe(currentPlan => {
this.chosenRoadmapId$.next(currentPlan.roadmapId);
this.variableCreditCourses$ = this.store.select(degreePlans).pipe(
flatMap(plan => this.api.getAllCourses(currentPlan.roadmapId)),
map(courses => {
return courses.filter(course => {
return (
!!course.creditMin &&
!!course.creditMax &&
course.creditMax > course.creditMin
);
});
}),
map(courses =>
courses.map(course => ({
...course,
range: inclusiveRange(
course.creditMin as number,
course.creditMax as number,
),
})),
),
share(),
);
this.variableCreditCourses$.subscribe(courses => {
while (this.chosenCreditSettings.length !== 0) {
this.chosenCreditSettings.removeAt(0);
}
courses.forEach(course => {
this.chosenCreditSettings.push(
this.fb.group({
course,
credits: this.fb.control(
course.credits || '',
Validators.required,
),
}),
);
});
});
});
if (includeCoursesFrom) {
includeCoursesFrom.valueChanges.subscribe(selected => {
if (selected === 'planned') {
this.variableCreditCourses$ = this.store.select(degreePlans).pipe(
map(plans => plans.find(plan => plan.primary)),
filter((plan): plan is DegreePlan => plan !== undefined),
flatMap(plan => this.api.getAllCourses(plan.roadmapId)),
map(courses => {
return courses.filter(course => {
return (
!!course.creditMin &&
!!course.creditMax &&
course.creditMax > course.creditMin
);
});
}),
map(courses =>
courses.map(course => ({
...course,
range: inclusiveRange(
course.creditMin as number,
course.creditMax as number,
),
})),
),
share(),
);
this.variableCreditCourses$.subscribe(courses => {
while (this.chosenCreditSettings.length !== 0) {
this.chosenCreditSettings.removeAt(0);
}
courses.forEach(course => {
this.chosenCreditSettings.push(
this.fb.group({
course,
credits: this.fb.control(
course.credits || '',
Validators.required,
),
}),
);
});
});
}
});
}
}
}
public darsInstitutionCode<T>(fallback: T): string | T {
if (typeof this.chosenProgram.value === 'object') {
return this.chosenProgram.value.darsInstitutionCode;
} else {
return fallback;
}
}
public darsDegreeProgramCode<T>(fallback: T): string | T {
if (typeof this.chosenProgram.value === 'object') {
return this.chosenProgram.value.darsDegreeProgramCode;
} else {
return fallback;
}
}
public degreePlannerPlanName<T>(fallback: T): string | T {
const control = this.chosenAuditSettings.get('degreePlan');
const coursesControl = this.chosenAuditSettings.get('includeCoursesFrom');
if (coursesControl && coursesControl.value === 'planned') {
if (control && control.value !== null) {
return control.value.name;
} else {
return fallback;
}
} else {
return fallback;
}
}
public darsHonorsOptionCode<T>(fallback: T): string | T {
const control = this.chosenAuditSettings.get('honorsOptions');
if (control !== null) {
return control.value.toString();
} else {
return fallback;
}
}
// If a degree plan name is included in the request we do not need this property
public includeCoursesFrom<T>(fallback: T): string | T {
const control = this.chosenAuditSettings.get('includeCoursesFrom');
if (control && control.value !== 'planned') {
return control.value.toString();
} else {
return fallback;
}
}
public fixedCredits(): NewDegreeAuditFields['fixedCredits'] {
return (this.chosenCreditSettings.value as any[]).map(
(group: { course: CourseBase; credits: number }) => {
return {
termCode: group.course.termCode || '',
subjectCode: group.course.subjectCode || '',
courseId: group.course.courseId || '',
credits: group.credits,
};
},
);
}
public submitAudit() {
this.dialogRef.close({
darsInstitutionCode: this.darsInstitutionCode(''),
darsDegreeProgramCode: this.darsDegreeProgramCode(''),
degreePlannerPlanName: this.degreePlannerPlanName(''),
darsHonorsOptionCode: this.darsHonorsOptionCode(''),
whichEnrolledCoursesIncluded: this.includeCoursesFrom(''),
fixedCredits: this.fixedCredits(),
});
}
}