From 5cf6f5ed15f97342ba7cf5962adb9af743a57180 Mon Sep 17 00:00:00 2001
From: ievavold <ievavold@wisc.edu>
Date: Mon, 11 Feb 2019 13:25:26 -0600
Subject: [PATCH] fix missing saved-for-later titles

---
 src/app/core/models/saved-for-later-course.ts |  6 +-
 .../remove-course-confirm-dialog.component.ts |  2 +-
 .../favorites-container.component.ts          | 31 ++++++---
 .../degree-planner/services/api.service.ts    | 14 ++--
 .../store/actions/plan.actions.ts             | 22 ++++--
 .../store/effects/plan.effects.ts             | 68 +++++++++----------
 src/app/degree-planner/store/reducer.ts       | 21 +++---
 7 files changed, 90 insertions(+), 74 deletions(-)

diff --git a/src/app/core/models/saved-for-later-course.ts b/src/app/core/models/saved-for-later-course.ts
index aaee440..89c9bb9 100644
--- a/src/app/core/models/saved-for-later-course.ts
+++ b/src/app/core/models/saved-for-later-course.ts
@@ -1,12 +1,12 @@
 export interface SavedForLaterCourseBase {
   id: number | null;
   courseId: string;
-  termCode: string;
-  topicId: number;
+  termCode: '0000';
+  topicId: 0;
   subjectCode: string;
   title: string;
   catalogNumber: string;
-  courseOrder: number;
+  courseOrder: 0;
 }
 
 export interface SavedForLaterCourse extends SavedForLaterCourseBase {
diff --git a/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts
index e95af18..2c7f120 100644
--- a/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts
+++ b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts
@@ -43,7 +43,7 @@ export class RemoveCourseConfirmDialogComponent implements OnInit {
         console.log(this.course);
         const id = this.course.id;
         if (typeof id === 'number') {
-          this.store.dispatch(new RemoveCourseRequest({ id }));
+          this.store.dispatch(new RemoveCourseRequest({ recordId: id }));
         } else {
           throw new Error('cannot remove a course that does not have an ID');
         }
diff --git a/src/app/degree-planner/favorites-container/favorites-container.component.ts b/src/app/degree-planner/favorites-container/favorites-container.component.ts
index a0a4e5b..766eac9 100644
--- a/src/app/degree-planner/favorites-container/favorites-container.component.ts
+++ b/src/app/degree-planner/favorites-container/favorites-container.component.ts
@@ -4,6 +4,7 @@ import { Store, select } from '@ngrx/store';
 import { SavedForLaterCourse } from '@app/core/models/saved-for-later-course';
 import { GlobalState } from '@app/core/state';
 import { getSavedForLaterCourses } from '@app/degree-planner/store/selectors';
+import { Course } from '@app/core/models/course';
 
 // rsjx / ngrx
 import { DegreePlannerState } from '@app/degree-planner/store/state';
@@ -31,21 +32,29 @@ export class SavedForLaterContainerComponent implements OnInit {
     this.courses$ = this.store.pipe(select(getSavedForLaterCourses));
   }
 
-  drop(event) {
-    const newContainer = event.container.id;
-    const previousContainer = event.previousContainer.id;
+  drop(event: any) {
+    const newContainerId = event.container.id;
+    const previousContainerId = event.previousContainer.id;
+    const fromTerm = previousContainerId.indexOf('term-') === 0;
+    const fromDifferentContainer = newContainerId !== previousContainerId;
 
-    if (newContainer === previousContainer) {
-      // If the user dropped a course into the same container do nothing
-      return;
-    } else if (previousContainer.indexOf('term-') === 0) {
-      // If moving from term to to saved for later
+    if (fromDifferentContainer && fromTerm) {
+      const course = event.item.data as Course;
 
-      const { subjectCode, courseId, id } = event.item.data;
       this.store.dispatch(
-        new AddSavedForLaterRequest({ subjectCode, courseId }),
+        new AddSavedForLaterRequest({
+          courseId: course.courseId,
+          subjectCode: course.subjectCode,
+          title: course.title,
+          catalogNumber: course.catalogNumber,
+        }),
+      );
+
+      this.store.dispatch(
+        new RemoveCourseRequest({
+          recordId: course.id as number,
+        }),
       );
-      this.store.dispatch(new RemoveCourseRequest({ id }));
     }
   }
 }
diff --git a/src/app/degree-planner/services/api.service.ts b/src/app/degree-planner/services/api.service.ts
index dd7b77b..e2536ca 100644
--- a/src/app/degree-planner/services/api.service.ts
+++ b/src/app/degree-planner/services/api.service.ts
@@ -12,7 +12,7 @@ import { ConfigService } from '@app/core/config.service';
 // Models
 import { Note } from '@app/core/models/note';
 import { Term } from '@app/core/models/term';
-import { Course, CourseBase, SubjectMapping } from '@app/core/models/course';
+import { CourseBase, SubjectMapping } from '@app/core/models/course';
 import { DegreePlan } from '@app/core/models/degree-plan';
 import { SavedForLaterCourseBase } from '@app/core/models/saved-for-later-course';
 
@@ -73,7 +73,7 @@ export class DegreePlannerApiService {
   }
 
   public updateCourseTerm(roadmapId, recordId, termCode): Observable<any> {
-    return this.http.put<Course>(
+    return this.http.put<CourseBase>(
       this.config.apiPlannerUrl +
         '/degreePlan/' +
         roadmapId +
@@ -89,7 +89,7 @@ export class DegreePlannerApiService {
     const data = {
       subjectCode: '104',
       termCode: '0000',
-      matchText: search
+      matchText: search,
     };
 
     return this.http.post('/api/search/v1/autocomplete', data, HTTP_OPTIONS);
@@ -100,16 +100,16 @@ export class DegreePlannerApiService {
     subjectCode: string,
     courseId: string,
     termCode: string,
-  ): Observable<Course> {
-    return this.http.post<Course>(
+  ): Observable<CourseBase> {
+    return this.http.post<CourseBase>(
       this.config.apiPlannerUrl + '/degreePlan/' + planId + '/courses',
       { subjectCode, courseId, termCode },
       HTTP_OPTIONS,
     );
   }
 
-  public removeCourse(planId: number, recordId: string) {
-    return this.http.delete(
+  public removeCourse(planId: number, recordId: number): Observable<void> {
+    return this.http.delete<void>(
       this.config.apiPlannerUrl +
         '/degreePlan/' +
         planId +
diff --git a/src/app/degree-planner/store/actions/plan.actions.ts b/src/app/degree-planner/store/actions/plan.actions.ts
index 1ce3e17..ff7afaf 100644
--- a/src/app/degree-planner/store/actions/plan.actions.ts
+++ b/src/app/degree-planner/store/actions/plan.actions.ts
@@ -73,22 +73,36 @@ export class AddCourseResponse implements Action {
 
 export class RemoveCourseRequest implements Action {
   public readonly type = PlanActionTypes.RemoveCourseRequest;
-  constructor(public payload: { id: number }) {}
+  constructor(public payload: { recordId: number }) {}
 }
 
 export class RemoveCourseResponse implements Action {
   public readonly type = PlanActionTypes.RemoveCourseResponse;
-  constructor(public payload: { id: number }) {}
+  constructor(public payload: { recordId: number }) {}
 }
 
 export class AddSavedForLaterRequest implements Action {
   public readonly type = PlanActionTypes.AddSavedForLaterReqeust;
-  constructor(public payload: { subjectCode: string; courseId: string }) {}
+  constructor(
+    public payload: {
+      subjectCode: string;
+      courseId: string;
+      title: string;
+      catalogNumber: string;
+    },
+  ) {}
 }
 
 export class AddSavedForLaterResponse implements Action {
   public readonly type = PlanActionTypes.AddSavedForLaterResponse;
-  constructor(public payload: { subjectCode: string; courseId: string }) {}
+  constructor(
+    public payload: {
+      subjectCode: string;
+      courseId: string;
+      title: string;
+      catalogNumber: string;
+    },
+  ) {}
 }
 
 export class RemoveSavedForLaterRequest implements Action {
diff --git a/src/app/degree-planner/store/effects/plan.effects.ts b/src/app/degree-planner/store/effects/plan.effects.ts
index cefbda2..100de1c 100644
--- a/src/app/degree-planner/store/effects/plan.effects.ts
+++ b/src/app/degree-planner/store/effects/plan.effects.ts
@@ -21,12 +21,14 @@ import {
   RemoveCourseResponse,
   RemoveSavedForLaterResponse,
   AddSavedForLaterResponse,
+  AddCourseRequest,
+  RemoveCourseRequest,
 } from '@app/degree-planner/store/actions/plan.actions';
 
 // Models
 import { DegreePlan } from '@app/core/models/degree-plan';
 import { PlannedTerm } from '@app/core/models/planned-term';
-import { SubjectMapping } from '@app/core/models/course';
+import { Course, SubjectMapping, CourseBase } from '@app/core/models/course';
 import { SavedForLaterCourse } from '@app/core/models/saved-for-later-course';
 
 @Injectable()
@@ -146,7 +148,7 @@ export class DegreePlanEffects {
 
   @Effect()
   AddCourse$ = this.actions$.pipe(
-    ofType<any>(PlanActionTypes.AddCourseRequest),
+    ofType<AddCourseRequest>(PlanActionTypes.AddCourseRequest),
 
     withLatestFrom(this.store$.select(getDegreePlannerState)),
     filter(([_, state]) => state.visibleDegreePlan !== undefined),
@@ -156,53 +158,48 @@ export class DegreePlanEffects {
       // TODO error handle the API calls
       const roadmapId = (state.visibleDegreePlan as DegreePlan).roadmapId;
       const { subjectCode, termCode, courseId } = action.payload;
-      return this.api
-        .addCourse(roadmapId as number, subjectCode, courseId, termCode)
-        .pipe(
-          map(response => {
-            return {
-              response,
-              action,
-            };
-          }),
-        );
-    }),
 
-    // Wrap data in an Action for dispatch
-    map(({ response, action }) => {
-      // TODO add error handleing
-      return new AddCourseResponse({ course: response });
+      const addCourse$ = this.api.addCourse(
+        roadmapId,
+        subjectCode,
+        courseId,
+        termCode,
+      );
+
+      const courseBaseToCourse$ = addCourse$.pipe(
+        map<CourseBase, Course>(courseBase => ({
+          ...courseBase,
+          subject: state.subjects[courseBase.subjectCode],
+        })),
+      );
+
+      const toSuccessAction$ = courseBaseToCourse$.pipe(
+        map(course => new AddCourseResponse({ course })),
+      );
+
+      return toSuccessAction$;
     }),
   );
 
   @Effect()
   RemoveCourse$ = this.actions$.pipe(
-    ofType<any>(PlanActionTypes.RemoveCourseRequest),
+    ofType<RemoveCourseRequest>(PlanActionTypes.RemoveCourseRequest),
 
     withLatestFrom(this.store$.select(getDegreePlannerState)),
     filter(([_, state]) => state.visibleDegreePlan !== undefined),
 
     // Get term data for the degree plan specified by the roadmap ID.
     flatMap(([action, state]) => {
-      // TODO error handle the API calls
       const roadmapId = (state.visibleDegreePlan as DegreePlan).roadmapId;
-      return this.api.removeCourse(roadmapId, action.payload.id).pipe(
-        map(response => {
-          return {
-            response,
-            action,
-          };
-        }),
+      const recordId = action.payload.recordId;
+
+      const removeCourse$ = this.api.removeCourse(roadmapId, recordId);
+
+      const toSuccessAction$ = removeCourse$.pipe(
+        map(() => new RemoveCourseResponse({ recordId })),
       );
-    }),
 
-    // Wrap data in an Action for dispatch
-    map(({ response, action }) => {
-      if (response === null) {
-        const { id } = action.payload;
-        return new RemoveCourseResponse({ id });
-      }
-      return;
+      return toSuccessAction$;
     }),
   );
 
@@ -267,8 +264,7 @@ export class DegreePlanEffects {
     // // // Wrap data in an Action for dispatch
     map(({ response, action }) => {
       if (response === null) {
-        const { subjectCode, courseId } = action.payload;
-        return new AddSavedForLaterResponse({ subjectCode, courseId });
+        return new AddSavedForLaterResponse(action.payload);
       }
       // return;
       return;
diff --git a/src/app/degree-planner/store/reducer.ts b/src/app/degree-planner/store/reducer.ts
index 8a263e4..a89bf68 100644
--- a/src/app/degree-planner/store/reducer.ts
+++ b/src/app/degree-planner/store/reducer.ts
@@ -17,6 +17,7 @@ import {
   WriteNoteResponse,
   DeleteNoteResponse,
 } from '@app/degree-planner/store/actions/note.actions';
+import { SavedForLaterCourse } from '@app/core/models/saved-for-later-course';
 
 type SupportedActions =
   | InitialPlanLoadResponse
@@ -169,7 +170,7 @@ export function degreePlannerReducer(
     }
 
     case PlanActionTypes.RemoveCourseResponse: {
-      const { id } = action.payload;
+      const { recordId: id } = action.payload;
 
       // Create new visibleTerms array
       const newVisibleTerms = state.visibleTerms.map(term => {
@@ -195,22 +196,18 @@ export function degreePlannerReducer(
     }
 
     case PlanActionTypes.AddSavedForLaterResponse: {
-      const { courseId, subjectCode } = action.payload;
-
-      // // Create new saved for later array
-      const newSavedForLater = [
+      const newSavedForLater: SavedForLaterCourse[] = [
         ...state.savedForLaterCourses,
-        // TODO Update this when the API is fixed, the API should be sending a fav course as a response
         {
           id: null,
-          courseId,
-          subjectCode,
-          subject: state.subjects[subjectCode],
+          courseId: action.payload.courseId,
+          termCode: '0000',
           topicId: 0,
+          subjectCode: action.payload.subjectCode,
+          title: action.payload.title,
+          catalogNumber: action.payload.catalogNumber,
           courseOrder: 0,
-          catalogNumber: '',
-          title: '',
-          termCode: '0000',
+          subject: state.subjects[action.payload.subjectCode],
         },
       ];
       return { ...state, savedForLaterCourses: newSavedForLater };
-- 
GitLab