Skip to content
Snippets Groups Projects
term-container.component.ts 5.72 KiB
Newer Older
Isaac Evavold's avatar
Isaac Evavold committed
import { Component, Input, OnInit } from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
pnogal's avatar
pnogal committed
import { MatDialog } from '@angular/material';
Isaac Evavold's avatar
Isaac Evavold committed
import { filter, map, distinctUntilChanged } from 'rxjs/operators';
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
import { DegreePlannerState } from '@app/degree-planner/store/state';
import {
  ToggleCourseSearch,
  OpenCourseSearch,
} from '@app/degree-planner/store/actions/ui.actions';
Isaac Evavold's avatar
Isaac Evavold committed
import * as actions from '@app/degree-planner/store/actions/course.actions';
import * as selectors from '@app/degree-planner/store/selectors';
Isaac Evavold's avatar
Isaac Evavold committed
import { PlannedTerm, PlannedTermNote } from '@app/core/models/planned-term';
Isaac Evavold's avatar
Isaac Evavold committed
import { Note } from '@app/core/models/note';
import { Course } from '@app/core/models/course';
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
  NotesDialogComponent,
  NotesDialogData,
Isaac Evavold's avatar
Isaac Evavold committed
} from '@app/degree-planner/dialogs/notes-dialog/notes-dialog.component';
import * as utils from '@app/degree-planner/shared/utils';

const isntUndefined = <T>(thing: T | undefined): thing is T => {
  return thing !== undefined;
};

const sumCredits = (courses: Course[]): number => {
  return courses.reduce((sum, course) => {
    return sum + course.credits;
  }, 0);
};
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
  selector: 'cse-term-container',
  templateUrl: './term-container.component.html',
  styleUrls: ['./term-container.component.scss'],
export class TermContainerComponent implements OnInit {
Isaac Evavold's avatar
Isaac Evavold committed
  @Input() yearCode: string;
  @Input() termName: 'fall' | 'spring' | 'summer';

  public termCode: string;
  public term$: Observable<PlannedTerm>;
Isaac Evavold's avatar
Isaac Evavold committed
  public note$: Observable<PlannedTermNote | undefined>;
Isaac Evavold's avatar
Isaac Evavold committed
  public courses$: Observable<Course[]>;
  public credits$: Observable<number>;
  public isPastTerm$: Observable<boolean>;
  public dropZoneIds$: Observable<string[]>;
  public isCurrentTerm$: Observable<boolean>;
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed

  constructor(
    public dialog: MatDialog,
    private store: Store<{ degreePlanner: DegreePlannerState }>,
  ) {}

  public ngOnInit() {
Isaac Evavold's avatar
Isaac Evavold committed
    const termOffset = { fall: 2, spring: 4, summer: 6 };
    this.termCode = `${this.yearCode}${termOffset[this.termName]}`;

    this.term$ = this.store.pipe(
      select(selectors.selectVisibleTerm, { termCode: this.termCode }),
      filter(isntUndefined),
      distinctUntilChanged(),
Isaac Evavold's avatar
Isaac Evavold committed
    this.note$ = this.term$.pipe(
      map(term => term.note),
      distinctUntilChanged(),
    );
Isaac Evavold's avatar
Isaac Evavold committed
    this.courses$ = this.term$.pipe(
      map(term => term.courses),
      distinctUntilChanged(),
    );

    this.credits$ = this.courses$.pipe(
      map(sumCredits),
      distinctUntilChanged(),
    );

    this.isPastTerm$ = this.term$.pipe(
      map(term => term.era === 'past'),
      distinctUntilChanged(),
    );

    this.dropZoneIds$ = this.store.pipe(
      select(selectors.selectAllVisibleYears),
      utils.yearsToDropZoneIds(),
      distinctUntilChanged(utils.compareStringArrays),
    );

    this.isPastTerm$ = this.store.pipe(
      select(selectors.isPastTerm(this.termCode)),
    );

    this.isCurrentTerm$ = this.store.pipe(
      select(selectors.isCurrentTerm(this.termCode)),
    );
Isaac Evavold's avatar
Isaac Evavold committed
  openNotesDialog(note?: PlannedTermNote) {
    if (note === undefined || note.isLoaded) {
      const termCode = this.termCode;
      const data: NotesDialogData = note
        ? {
            termCode,
            hasExistingNote: true,
            initialText: note.text,
            noteId: note.id,
          }
        : { termCode, hasExistingNote: false };
      this.dialog.open(NotesDialogComponent, { data });
    }
  openCourseSearch() {
    this.store.dispatch(new OpenCourseSearch(this.termCode));
Scott Berg's avatar
Scott Berg committed
  }

  drop(event: CdkDragDrop<string>) {
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
    const newContainer = event.container.id;
    const previousContainer = event.previousContainer.id;

    if (newContainer === previousContainer) {
      const newIndex = event.currentIndex;
      const { id: recordId, termCode } = event.item.data as Course;

      if (recordId !== null) {
        const action = new actions.MoveCourseInsideTerm({
          termCode,
          recordId,
          newIndex,
        });
        this.store.dispatch(action);
      }
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
    } else if (previousContainer.indexOf('term-') === 0) {
      // If moving from term to term

      // Get the pervious and new term code, and the record ID
      const from = event.previousContainer.data;
      const to = event.container.data;
      const { id } = event.item.data;
      const newIndex = event.currentIndex;
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed

      // Dispatch a new change request
      this.store.dispatch(
        new actions.MoveCourseBetweenTerms({ to, from, id, newIndex }),
      );
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
    } else if (previousContainer === 'saved-courses') {
      // If moving from saved courses to term

      // Get the term code from the new term dropzone's ID
      const termCode = newContainer.substr(5);
      const newIndex = event.currentIndex;
jvanboxtel@wisc.edu's avatar
jvanboxtel@wisc.edu committed
      // Pull the course data from the moved item
Isaac Evavold's avatar
Isaac Evavold committed
      const { subjectCode, courseId, title, catalogNumber } = event.item.data;
Isaac Evavold's avatar
Isaac Evavold committed
      this.store.dispatch(
        new actions.AddCourse({
          courseId,
          termCode,
Isaac Evavold's avatar
Isaac Evavold committed
          subjectCode,
          title,
          catalogNumber,
Isaac Evavold's avatar
Isaac Evavold committed
        }),
      );
      this.store.dispatch(
        new actions.RemoveSaveForLater({ subjectCode, courseId }),
      );
Scott Berg's avatar
Scott Berg committed
    } else if (
      previousContainer === 'queried-courses-list' &&
      newContainer.indexOf('term-') === 0
    ) {
      const termCode = newContainer.substr(5);
      const newIndex = event.currentIndex;
Isaac Evavold's avatar
Isaac Evavold committed
      this.store.dispatch(
Isaac Evavold's avatar
Isaac Evavold committed
        new actions.AddCourse({
          courseId: event.item.data.courseId,
          termCode,
          subjectCode: event.item.data.subjectCode,
          title: event.item.data.title,
          catalogNumber: event.item.data.catalogNumber,
          newIndex,
        }),
Isaac Evavold's avatar
Isaac Evavold committed
      );