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.
course.effects.ts 6.11 KiB
// Libraries
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import {
tap,
map,
flatMap,
withLatestFrom,
filter,
catchError,
} from 'rxjs/operators';
import { GlobalState } from '@app/core/state';
import { Store } from '@ngrx/store';
import { MatSnackBar } from '@angular/material';
// Services
import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
import * as selectors from '@app/degree-planner/store/selectors';
// Actions
import {
AddCourse,
AddCourseSuccess,
AddSaveForLater,
AddSaveForLaterSuccess,
CourseActionTypes,
CourseError,
MoveCourseBetweenTerms,
MoveCourseBetweenTermsSuccess,
RemoveCourse,
RemoveCourseSuccess,
RemoveSaveForLater,
RemoveSaveForLaterSuccess,
} from '@app/degree-planner/store/actions/course.actions';
// Models
import { DegreePlan } from '@app/core/models/degree-plan';
import { Course, CourseBase } from '@app/core/models/course';
// Pipes
import { GetTermDescriptionPipe } from '@app/shared/pipes/get-term-description.pipe';
@Injectable()
export class CourseEffects {
constructor(
private actions$: Actions,
private api: DegreePlannerApiService,
private store$: Store<GlobalState>,
private snackBar: MatSnackBar,
) {}
@Effect()
MoveCourseBetweenTerms$ = this.actions$.pipe(
ofType<MoveCourseBetweenTerms>(CourseActionTypes.MoveCourseBetweenTerms),
withLatestFrom(this.store$.select(selectors.selectVisibleDegreePlan)),
filter<[MoveCourseBetweenTerms, DegreePlan]>(([_, degreePlan]) => {
return degreePlan !== undefined;
}),
// Get term data for the degree plan specified by the roadmap ID.
flatMap(([action, degreePlan]) => {
const roadmapId = degreePlan.roadmapId;
const recordId = action.payload.id;
const termCode = action.payload.to;
return this.api
.updateCourseTerm(roadmapId, recordId, termCode)
.pipe(map(() => action));
}),
map(action => new MoveCourseBetweenTermsSuccess(action.payload)),
tap(state => {
const touchedTerm = new GetTermDescriptionPipe().transform(
state.payload.to,
);
const message = `Course has been moved to ${touchedTerm}`;
this.snackBar.open(message, undefined, {});
}),
catchError(error => {
return of(
new CourseError({
message: 'Unable to move course',
error,
}),
);
}),
);
@Effect()
AddCourse$ = this.actions$.pipe(
ofType<AddCourse>(CourseActionTypes.AddCourse),
withLatestFrom(this.store$.select(selectors.selectVisibleDegreePlan)),
filter(([_, visibleDegreePlan]) => visibleDegreePlan !== undefined),
withLatestFrom(this.store$.select(selectors.selectSubjects)),
flatMap(([[action, visibleDegreePlan], subjects]) => {
// TODO error handle the API calls
const roadmapId = (visibleDegreePlan as DegreePlan).roadmapId;
const { subjectCode, termCode, courseId, newIndex } = action.payload;
const addCourse$ = this.api.addCourse(
roadmapId,
subjectCode,
courseId,
termCode,
);
const courseBaseToCourse$ = addCourse$.pipe(
map<CourseBase, Course>(courseBase => ({
...courseBase,
termCode,
subject: subjects[courseBase.subjectCode],
})),
);
const toSuccessAction$ = courseBaseToCourse$.pipe(
map(course => new AddCourseSuccess({ course, newIndex })),
);
return toSuccessAction$;
}),
tap(state => {
const touchedCourse: any = state.payload.course;
const touchedTerm: any = new GetTermDescriptionPipe().transform(
touchedCourse.termCode,
);
const message = `${touchedCourse.subject} ${
touchedCourse.catalogNumber
} has been added to ${touchedTerm}`;
this.snackBar.open(message, undefined, {});
}),
catchError(error => {
return of(
new CourseError({
message: 'Unable to add course',
error,
}),
);
}),
);
@Effect()
RemoveCourse$ = this.actions$.pipe(
ofType<RemoveCourse>(CourseActionTypes.RemoveCourse),
withLatestFrom(this.store$.select(selectors.selectVisibleDegreePlan)),
filter(([_, visibleDegreePlan]) => visibleDegreePlan !== undefined),
flatMap(([action, visibleDegreePlan]) => {
const roadmapId = (visibleDegreePlan as DegreePlan).roadmapId;
const recordId = action.payload.recordId;
const fromTermCode = action.payload.fromTermCode;
const removeCourse$ = this.api.removeCourse(roadmapId, recordId);
const toSuccessAction$ = removeCourse$.pipe(
map(() => new RemoveCourseSuccess({ fromTermCode, recordId })),
);
return toSuccessAction$;
}),
catchError(error => {
return of(
new CourseError({
message: 'Unable to remove course',
error,
}),
);
}),
);
@Effect()
RemoveSavedForLater$ = this.actions$.pipe(
ofType<RemoveSaveForLater>(CourseActionTypes.RemoveSaveForLater),
flatMap(action => {
const { subjectCode, courseId } = action.payload;
return this.api
.removeSavedForLater(subjectCode, courseId)
.pipe(map(() => action));
}),
map(action => new RemoveSaveForLaterSuccess(action.payload)),
catchError(error => {
return of(
new CourseError({
message: 'Unable to remove saved course',
error,
}),
);
}),
);
@Effect()
SaveForLater$ = this.actions$.pipe(
ofType<AddSaveForLater>(CourseActionTypes.AddSaveForLater),
flatMap(action => {
const { subjectCode, courseId } = action.payload;
return this.api
.saveForLater(subjectCode, courseId)
.pipe(map(() => action));
}),
map(action => new AddSaveForLaterSuccess(action.payload)),
tap(() => {
const message = 'Course has been saved for later';
this.snackBar.open(message, undefined, {});
}),
catchError(error => {
return of(
new CourseError({
message: 'Unable to save course for later',
error,
}),
);
}),
);
}