Newer
Older
import { Component, Input, OnInit } from '@angular/core';
import { MatDialog, MatSnackBar } from '@angular/material';
import { Store, select } from '@ngrx/store';
import {
AddCourse,
AddSaveForLater,
MoveCourseBetweenTerms,
import { GlobalState } from '@app/core/state';
import * as selectors from '@app/degree-planner/store/selectors';
import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component';
import { CourseDetailsDialogComponent } from '@app/degree-planner/dialogs/course-details-dialog/course-details-dialog.component';
import { distinctUntilChanged, filter } from 'rxjs/operators';
import { TermCode } from '@app/core/models/termcode';
import { PlannedTerm } from '@app/core/models/planned-term';
import { ConstantsService } from '@app/degree-planner/services/constants.service';
const isntUndefined = <T>(thing: T | undefined): thing is T => {
return thing !== undefined;
};
selector: 'cse-course-item',
templateUrl: './course-item.component.html',
styleUrls: ['./course-item.component.scss'],
export class CourseItemComponent implements OnInit {
@Input() isCurrentTerm: boolean;
@Input() isPastTerm: boolean;
@Input() disabled: boolean;
activeTerm: any;
public status:
| 'InProgress'
| 'Waitlisted'
| 'Incomplete'
| 'NotOfferedInTerm'
| 'NoLongerOffered'
| 'Normal';
public visibleTermCodes$: Observable<string[]>;
public droppableTermCodes$: Observable<string[]>;
public term$: Observable<PlannedTerm>;
public plannedCourses: ReadonlyArray<Course>;
public toActiveTerm: boolean;
constructor(
private api: DegreePlannerApiService,
public dialog: MatDialog,
private store: Store<GlobalState>,
private constants: ConstantsService,
private snackBar: MatSnackBar,
ngOnInit() {
const isActive = this.era === 'active';
const isPast = this.era === 'past';
const isNotOffered = this.course.studentEnrollmentStatus === 'NOTOFFERED';
const isNoLongerOffered =
this.course.studentEnrollmentStatus === 'DOESNOTEXIST';
this.isStruckthrough = (isPast || isActive) && isNoLongerOffered;
const isIncomplete =
isPast &&
this.course.grade === null &&
this.course.studentEnrollmentStatus !== 'cart';
const isWaitlisted = this.course.studentEnrollmentStatus === 'Waitlisted';
const isInProgress =
isActive && this.course.studentEnrollmentStatus === 'Enrolled';
if (isIncomplete) {
this.status = 'Incomplete';
} else if (isWaitlisted) {
this.status = 'Waitlisted';
} else if (isInProgress) {
this.status = 'InProgress';
} else if (isNotOffered) {
this.status = 'NotOfferedInTerm';
} else if (isNoLongerOffered) {
this.status = 'NoLongerOffered';
this.droppableTermCodes$ = this.store.pipe(
select(selectors.selectAllVisibleYears),
utils.yearsToDroppableTermCodes(),
distinctUntilChanged(utils.compareStringArrays),
);
this.store.dispatch(
new AddSaveForLater({
courseId: course.courseId,
subjectCode: course.subjectCode,
title: course.title,
catalogNumber: course.catalogNumber,
newIndex: 0,
/**
*
* Handle moving a course to different terms based on course type
*
*/
onMove(termCode: string) {
const toTermCode = new TermCode(termCode);
this.term$ = this.store.pipe(
select(selectors.selectVisibleTerm, { termCode: toTermCode }),
filter(isntUndefined),
distinctUntilChanged(),
);
this.term$.subscribe(term => {
this.plannedCourses = term.plannedCourses;
this.toActiveTerm = term.era === 'active';
});
const isCourseInPlannedCourses = this.plannedCourses.some(
course => course.courseId === this.course.courseId,
);
const courseNotOfferedInTerm = this.plannedCourses.some(
course =>
course.studentEnrollmentStatus === 'DOESNOTEXIST' ||
course.studentEnrollmentStatus === 'NOTOFFERED',
);
if (isCourseInPlannedCourses) {
this.dialog
.open(ConfirmDialogComponent, {
data: {
confirmText: 'OK',
dialogClass: 'alertDialog',
},
})
.afterClosed();
return;
}
if (this.toActiveTerm && courseNotOfferedInTerm) {
const { short } = this.constants.subjectDescription(
this.course.subjectCode,
);
const catalogNum = this.course.catalogNumber;
const termDesc = toTermCode.description;
this.dialog
.open(ConfirmDialogComponent, {
data: {
confirmText: 'OK',
dialogClass: 'alertDialog',
text: `${short} ${catalogNum} is not offered in ${termDesc}`,
},
})
.afterClosed();
return;
}
case 'course': {
const id = this.course.id as number;
new MoveCourseBetweenTerms({
to: toTermCode,
from,
id,
newIndex: 0,
this.store.dispatch(new RemoveSaveForLater({ subjectCode, courseId }));
break;
}
}
/**
*
* Handle saving a course for later (This is not possible if a course is already saved)
*
*/
onSaveForLater() {
const {
courseId,
subjectCode,
title,
catalogNumber,
termCode,
} = this.course;
// Dispatch a save for later event
this.store.dispatch(
new AddSaveForLater({
courseId: courseId,
subjectCode: subjectCode,
title: title,
catalogNumber: catalogNumber,
newIndex: 0,
}),
);
// If course is in a term, we need to remove it
if (this.type === 'course') {
this.store.dispatch(
new RemoveCourse({
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
recordId: this.course.id as number,
}),
);
}
}
/**
*
* Handle removing a course (This is not possible for type 'search')
*
*/
onRemove() {
const dialogOptions = {
title: 'Remove Course?',
text: '',
confirmText: 'Remove Course',
confirmColor: 'accent',
};
switch (this.type) {
case 'saved':
dialogOptions.text = `This will remove "${
this.course.title
}" from your saved courses.`;
break;
default:
if (this.era === 'future') {
dialogOptions.text = `This will remove "${
this.course.title
}" from your degree plan.`;
} else {
dialogOptions.text = `This will remove "${
this.course.title
}" from your degree plan and your cart.`;
}
}
this.dialog
.open(ConfirmDialogComponent, { data: dialogOptions })
.afterClosed()
.subscribe((result: { confirmed: boolean }) => {
// If the user confirmed the removal, remove course
console.log(this.type);
console.log({
type: this.type,
fromTermCode: this.course.termCode,
recordId: this.course.id,
});
switch (this.type) {
case 'course':
this.store.dispatch(
new RemoveCourse({
recordId: this.course.id as number,
}),
);
break;
case 'saved':
const { subjectCode, courseId } = this.course;
this.store.dispatch(
new RemoveSaveForLater({ subjectCode, courseId }),
);
break;
}
}
});
}
this.store.dispatch(
new AddCourse({
courseId: this.course.courseId,
termCode: toTermCode,
subjectCode: this.course.subjectCode,
title: this.course.title,
catalogNumber: this.course.catalogNumber,
}),
);
const { subjectCode, courseId, catalogNumber } = this.course;
if (this.course.studentEnrollmentStatus === 'DOESNOTEXIST') {
const { short } = this.constants.subjectDescription(subjectCode);
this.snackBar.open(`'${short} ${catalogNumber}' no longer offered`);
return;
}
.subscribe(courseDetails => {
const dialogRef = this.dialog.open(CourseDetailsDialogComponent, {
width: '80%',
data: { courseDetails: courseDetails, courseType: this.type },
// Check for enter key presses
detectEnter($event) {
if ($event.keyCode === 13) {
this.openCourseDetailsDialog();
}
}