import { Component, OnInit, OnDestroy, Inject, Input } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, map, filter } from 'rxjs/operators'; import { MatDialog } from '@angular/material'; import { Store, select } from '@ngrx/store'; import { CourseDetails } from '@app/core/models/course-details'; import * as selectors from '@app/degree-planner/store/selectors'; import * as utils from '@app/degree-planner/shared/utils'; import { TermCode } from '@app/core/models/termcode'; import { GlobalState } from '@app/core/state'; import { Course } from '@app/core/models/course'; import { PlannedTerm } from '@app/core/models/planned-term'; import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component'; import { AddCourse, RemoveSaveForLater, } from '@app/degree-planner/store/actions/course.actions'; const isntUndefined = <T>(thing: T | undefined): thing is T => { return thing !== undefined; }; @Component({ selector: 'cse-course-details', templateUrl: './course-details.component.html', styleUrls: ['./course-details.component.scss'], }) export class CourseDetailsComponent implements OnInit, OnDestroy { @Input() termCode: TermCode; public courseDetails: CourseDetails; public type: 'course' | 'search' | 'saved'; public selectedSearchTerm: string; public term$: Observable<PlannedTerm>; public termSelector: FormGroup; public selectedSearchTerm$: Observable<string>; public droppableTermCodes$: Observable<string[]>; public searchTermSubscription: Subscription; public termSubscription: Subscription; public plannedCourses: ReadonlyArray<Course>; constructor( @Inject(MAT_DIALOG_DATA) public data: any, private store: Store<GlobalState>, private fb: FormBuilder, public dialog: MatDialog, ) { this.courseDetails = data.courseDetails; this.type = data.courseType; } ngOnInit() { this.selectedSearchTerm$ = this.store.pipe( select(selectors.getSelectedSearchTerm), map(termCode => (termCode ? termCode.toString() : '0000')), ); this.droppableTermCodes$ = this.store.pipe( select(selectors.selectAllVisibleYears), utils.yearsToDroppableTermCodes(), distinctUntilChanged(utils.compareStringArrays), ); this.searchTermSubscription = this.selectedSearchTerm$.subscribe( termCode => { this.selectedSearchTerm = termCode; }, ); this.termSelector = this.fb.group({ term: this.selectedSearchTerm, }); } ngOnDestroy() { this.searchTermSubscription.unsubscribe(); } addCourseToPlan($event) { $event.preventDefault(); const termCode = new TermCode(this.termSelector.value.term); const subjectCode = this.courseDetails.subject.subjectCode; const courseId = this.courseDetails.courseId; const payload = { courseId, termCode, subjectCode, title: this.courseDetails.title, catalogNumber: this.courseDetails.catalogNumber, }; this.term$ = this.store.pipe( select(selectors.selectVisibleTerm, { termCode: new TermCode(this.termSelector.value.term), }), filter(isntUndefined), distinctUntilChanged(), ); this.termSubscription = this.term$.subscribe(term => { this.plannedCourses = term.plannedCourses; }); const isCourseInPlannedCourses = this.plannedCourses.some( course => course.courseId === this.courseDetails.courseId, ); if (isCourseInPlannedCourses) { this.dialog .open(ConfirmDialogComponent, { data: { title: "Can't add course to term", confirmText: 'OK', dialogClass: 'alertDialog', text: `This course already exists in selected term`, }, }) .afterClosed(); } else { switch (this.type) { case 'search': this.store.dispatch(new AddCourse(payload)); break; case 'saved': this.store.dispatch(new AddCourse(payload)); this.store.dispatch( new RemoveSaveForLater({ subjectCode, courseId }), ); break; } } } }