diff --git a/src/app/core/models/course.ts b/src/app/core/models/course.ts index 0a31f9df634cbc89d495c24119b98c0025e1ed26..6185a41dd86db35dc36c838348b7f3cf58d5c42a 100644 --- a/src/app/core/models/course.ts +++ b/src/app/core/models/course.ts @@ -1,7 +1,7 @@ interface CourseBase { - id: number; + id: number | null; courseId: string; - termCode: string; + termCode: string | null; topicId: number; title: string; subjectCode: string; 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 d44598736a17cff3b249a6c1741c22aeead62541..e95af18275042bba8e0bf8180739416b73431361 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 @@ -41,7 +41,12 @@ export class RemoveCourseConfirmDialogComponent implements OnInit { case 'course': console.log('remove course from term'); console.log(this.course); - this.store.dispatch(new RemoveCourseRequest({ id: this.course.id })); + const id = this.course.id; + if (typeof id === 'number') { + this.store.dispatch(new RemoveCourseRequest({ id })); + } else { + throw new Error('cannot remove a course that does not have an ID'); + } break; } } diff --git a/src/app/degree-planner/store/effects/plan.effects.ts b/src/app/degree-planner/store/effects/plan.effects.ts index cf46847a1b537f147a0c4101620cf4de2d1cb733..094d1bb1d1e47d99aa3e87f6144cdcd0ec6da2b4 100644 --- a/src/app/degree-planner/store/effects/plan.effects.ts +++ b/src/app/degree-planner/store/effects/plan.effects.ts @@ -314,31 +314,41 @@ export class DegreePlanEffects { this.api.getActiveTerms(), ).pipe( // Combine courses and notes by term. - map(([notes, termCourses, currentTerms]) => { + map(([notes, termCourses, activeTerms]) => { + const noteTermCodes = notes.map(note => note.termCode); + const courseTermCodes = termCourses.map(term => term.termCode); + const activeTermCodes = activeTerms.map(term => term.termCode); + /** * Using the notes & courses relevant to the current degree plan and * the active terms, generate a sorted list of all unqiue term codes. */ - const uniqueTermCodes = termCourses.map(course => course.termCode); + const uniqueTermCodes = unique([ + ...noteTermCodes, + ...courseTermCodes, + ...activeTermCodes, + ]).sort(); + /** - * For each unique termCode, build a Term object that includes any - * courses or notes relevant to that termCode. + * Group the notes and courses into a list of visible terms. */ const visibleTerms: PlannedTerm[] = uniqueTermCodes.map(termCode => { - return { - termCode, - note: notes.find(note => note.termCode === termCode), - courses: termCourses.filter(term => term.termCode === termCode)[0] - .courses, - }; + const note = notes.find(matchesTermCode(termCode)); + const termCourse = termCourses.find(matchesTermCode(termCode)); + const courses = termCourse ? termCourse.courses : []; + return { termCode, note, courses }; }); - const activeTermCodes = uniqueTermCodes.filter(termCode => { - return termCode >= currentTerms[0].termCode; - }); - - return Object.assign({}, stdin, { visibleTerms }, { activeTermCodes }); + return { ...stdin, visibleTerms, activeTermCodes }; }), ); } } + +const unique = <T>(things: T[]): T[] => { + return things.filter((thing, index, all) => all.indexOf(thing) === index); +}; + +const matchesTermCode = (termCode: string) => (thing: { termCode: string }) => { + return thing.termCode === termCode; +}; diff --git a/src/app/degree-planner/store/selectors.ts b/src/app/degree-planner/store/selectors.ts index 9ae5c24dc82566df18c65d391763a31903997781..f5c2c9f44691e8402934f526c1294e8809eb552c 100644 --- a/src/app/degree-planner/store/selectors.ts +++ b/src/app/degree-planner/store/selectors.ts @@ -6,6 +6,7 @@ import { GlobalState } from '@app/core/state'; import { Year } from '@app/core/models/year'; import { Note } from '@app/core/models/note'; import { Course } from '@app/core/models/course'; +import { PlannedTerm } from '@app/core/models/planned-term'; import { DegreePlannerState } from './state'; export const getDegreePlannerState = ({ degreePlanner }: GlobalState) => { @@ -61,27 +62,15 @@ export const getAllVisibleTermsByYear = createSelector( .filter((year, index, self) => self.indexOf(year) === index) .sort(); - const allNotes = state.visibleTerms - .map(term => term.note) - .filter((note): note is Note => note !== undefined); - - const allCourses = state.visibleTerms - .map(term => term.courses) - .reduce((flat, nested) => flat.concat(nested), []) - .map(course => { - course.subject = state.subjects[course.subjectCode]; - return course; - }); - return unqiueYears.map<Year>(year => { const century = year[0] === '0' ? 0 : 1; const twoDigitYearCode = parseInt(year.substr(1, 2), 10); return { century, twoDigitYearCode, - fall: getTermForCode(`${year}2`, allCourses, allNotes), - spring: getTermForCode(`${year}4`, allCourses, allNotes), - summer: getTermForCode(`${year}6`, allCourses, allNotes), + fall: getTermForCode(`${year}2`, state.visibleTerms), + spring: getTermForCode(`${year}4`, state.visibleTerms), + summer: getTermForCode(`${year}6`, state.visibleTerms), }; }); }, @@ -107,10 +96,12 @@ export const isActiveTerm = (termCode: string) => }, ); -const getTermForCode = (termCode: string, courses: Course[], notes: Note[]) => { - return { - termCode, - note: notes.find(note => note.termCode === termCode), - courses: courses.filter(course => course.termCode === termCode), - }; +const getTermForCode = (termCode: string, terms: PlannedTerm[]) => { + const foundTerm = terms.find(term => term.termCode === termCode); + + if (foundTerm !== undefined) { + return foundTerm; + } + + return { termCode, courses: [] }; };