diff --git a/src/app/degree-planner/shared/course-item/course-item.component.html b/src/app/degree-planner/shared/course-item/course-item.component.html index 10caf33945e7caab82df53b1f11ea1333f0ef315..bb67e1bdcf094b60ee6f0cdc52756e3083c73b05 100644 --- a/src/app/degree-planner/shared/course-item/course-item.component.html +++ b/src/app/degree-planner/shared/course-item/course-item.component.html @@ -28,9 +28,16 @@ </i> <i *ngSwitchCase="'Incomplete'" - class="material-icons error-icon" + class="material-icons cancel-icon" matTooltip="Course is incomplete" matTooltipPosition="above"> + cancel + </i> + <i + *ngSwitchCase="'NotOfferedInTerm'" + class="material-icons error-icon" + matTooltip="Course is not offered in term" + matTooltipPosition="above"> error </i> </span> diff --git a/src/app/degree-planner/shared/course-item/course-item.component.ts b/src/app/degree-planner/shared/course-item/course-item.component.ts index 815fc4aaa8670e49ae70c57138f0c76c4a0a802a..34f09d6d1eeb6070bf93a002b750b44b88e06109 100644 --- a/src/app/degree-planner/shared/course-item/course-item.component.ts +++ b/src/app/degree-planner/shared/course-item/course-item.component.ts @@ -38,11 +38,18 @@ export class CourseItemComponent implements OnInit { @Input() era?: unknown; visibleTerms: any; activeTerm: any; - public status: 'InProgress' | 'Waitlisted' | 'Incomplete' | 'Normal'; + public status: + | 'InProgress' + | 'Waitlisted' + | 'Incomplete' + | 'NotOfferedInTerm' + | 'NoLongerOffered' + | 'Normal'; public visibleTermCodes$: Observable<string[]>; public droppableTermCodes$: Observable<string[]>; public term$: Observable<PlannedTerm>; public plannedCourses: Course[]; + public toActiveTerm: boolean; public isStruckthrough = false; constructor( @@ -55,7 +62,9 @@ export class CourseItemComponent implements OnInit { const isActive = this.era === 'active'; const isPast = this.era === 'past'; const isNotOffered = this.course.studentEnrollmentStatus === 'NOTOFFERED'; - this.isStruckthrough = (isPast || isActive) && isNotOffered; + const isNoLongerOffered = + this.course.studentEnrollmentStatus === 'DOESNOTEXIST'; + this.isStruckthrough = (isPast || isActive) && isNoLongerOffered; const isIncomplete = isPast && this.course.grade === null; const isWaitlisted = this.course.studentEnrollmentStatus === 'Waitlisted'; @@ -68,6 +77,8 @@ export class CourseItemComponent implements OnInit { this.status = 'Waitlisted'; } else if (isInProgress) { this.status = 'InProgress'; + } else if (isNotOffered) { + this.status = 'NotOfferedInTerm'; } else { this.status = 'Normal'; } @@ -100,7 +111,6 @@ export class CourseItemComponent implements OnInit { */ onMove(termCode: string) { const toTermCode = new TermCode(termCode); - this.term$ = this.store.pipe( select(selectors.selectVisibleTerm, { termCode: toTermCode }), filter(isntUndefined), @@ -109,11 +119,17 @@ export class CourseItemComponent implements OnInit { this.term$.subscribe(term => { this.plannedCourses = term.plannedCourses; + this.toActiveTerm = term.era === 'active'; }); const isCourseInPlannedCourses = this.plannedCourses.some( course => course.courseId === this.course.courseId, ); + const courseNotOfferedInTerm = this.plannedCourses.some( + course => + course.studentEnrollmentStatus === 'DOESNOTEXIST' || + course.studentEnrollmentStatus === 'NOTOFFERED', + ); if (isCourseInPlannedCourses) { this.dialog .open(ConfirmDialogComponent, { @@ -128,6 +144,24 @@ export class CourseItemComponent implements OnInit { return; } + if (this.toActiveTerm && courseNotOfferedInTerm) { + const notOfferedCourse = + this.course.subject + ' ' + this.course.catalogNumber; + this.dialog + .open(ConfirmDialogComponent, { + data: { + title: "Can't add course to term", + confirmText: 'OK', + dialogClass: 'alertDialog', + text: `${notOfferedCourse} is not offered in ${ + toTermCode.description + }`, + }, + }) + .afterClosed(); + return; + } + switch (this.type) { case 'course': { const id = this.course.id as number; diff --git a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.html b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.html index 326fd476c1945f2d0ee506ca92a43a976e807f77..3ceb116a7d912396b93e0cbdb2242ce04fc29bfa 100644 --- a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.html +++ b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.html @@ -26,13 +26,31 @@ </li> <li> <i - class="material-icons error-icon" + class="material-icons cancel-icon" matTooltip="Course is incomplete" matTooltipPosition="left" - >error</i + >cancel</i > Course is incomplete </li> + <li> + <i + class="material-icons error-icon" + matTooltip="Course not offered in term" + matTooltipPosition="left" + >error</i + > + Course not offered in term + </li> + <li> + <i + class="material-icons not-offered-icon" + matTooltip="Course no loger offered" + matTooltipPosition="left" + >remove</i + > + Course no loger offered + </li> </ul> </mat-expansion-panel> <mat-expansion-panel id="course-keys-container" expanded="true"> diff --git a/src/app/degree-planner/term-container/term-container.component.ts b/src/app/degree-planner/term-container/term-container.component.ts index a945690865d57f7fe42bd465bd473b326821d88d..071bfa046e28f9c0a957e5c7b20caa4e565953e1 100644 --- a/src/app/degree-planner/term-container/term-container.component.ts +++ b/src/app/degree-planner/term-container/term-container.component.ts @@ -26,7 +26,8 @@ import { TermCode } from '@app/core/models/termcode'; // Dialogs import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component'; - +import { maybeQueueResolutionOfComponentResources } from '@angular/core/src/metadata/resource_loading'; +import { WeekDay } from '@angular/common'; const isntUndefined = <T>(thing: T | undefined): thing is T => { return thing !== undefined; }; @@ -44,17 +45,16 @@ export class TermContainerComponent implements OnInit, OnDestroy { public dropZoneIds$: Observable<string[]>; public termSubscription: Subscription; - + public activeTermHasNotOffered: boolean; // List of courses pulled for the Observable public plannedCourses: Course[]; public enrolledCourses: Course[]; public era: 'past' | 'active' | 'future'; - public hasItemDraggedOver: boolean; public plannedCredits: string; public enrolledCredits: number; public visibleCredits: 'enrolled' | 'planned'; - + public courseNotOfferedInTerm: Course[]; constructor( public dialog: MatDialog, private store: Store<{ degreePlanner: DegreePlannerState }>, @@ -78,7 +78,9 @@ export class TermContainerComponent implements OnInit, OnDestroy { this.enrolledCredits = this.sumEnrolledCredits(term.enrolledCourses); this.era = term.era; - + const activeTermEnrollmentStatus = this.plannedCourses.forEach( + course => course.studentEnrollmentStatus, + ); this.visibleCredits = 'planned'; if (term.era === 'past' && this.plannedCourses.length === 0) { this.visibleCredits = 'enrolled'; @@ -135,10 +137,15 @@ export class TermContainerComponent implements OnInit, OnDestroy { const previousContainer = event.previousContainer.id; const { courseId } = event.item.data as Course; + const { studentEnrollmentStatus } = event.item.data as Course; const isCourseInPlannedCourses = this.plannedCourses.some( course => course.courseId === courseId, ); - + const courseNotOfferedInTerm = this.plannedCourses.some( + course => + course.studentEnrollmentStatus === 'DOESNOTEXIST' || + course.studentEnrollmentStatus === 'NOTOFFERED', + ); if (newContainer !== previousContainer && isCourseInPlannedCourses) { this.dialog .open(ConfirmDialogComponent, { @@ -152,6 +159,22 @@ export class TermContainerComponent implements OnInit, OnDestroy { .afterClosed(); return; } + if (this.era === 'active' && courseNotOfferedInTerm) { + const notOfferedCourse = + event.item.data.subject + ' ' + event.item.data.catalogNumber; + const touchedTerm = event.container.data.description; + this.dialog + .open(ConfirmDialogComponent, { + data: { + title: "Can't add course to term", + confirmText: 'OK', + dialogClass: 'alertDialog', + text: `${notOfferedCourse} is not offered in ${touchedTerm}`, + }, + }) + .afterClosed(); + return; + } if (newContainer === previousContainer) { const newIndex = event.currentIndex; diff --git a/src/assets/sass/general.scss b/src/assets/sass/general.scss index 5e9a5c85996ac0eef97ff8c51ee9e9a8b9618249..ee3cf31d6e551763b5d89867932088d6dbc158bc 100644 --- a/src/assets/sass/general.scss +++ b/src/assets/sass/general.scss @@ -64,6 +64,10 @@ body { color: #f7c376; } +.cancel-icon { + color: #6e655f; +} + .error-icon { color: map-get($uw-accent, 600); } @@ -74,9 +78,10 @@ body { .in-progress-icon, .problem-icon, +.cancel-icon, .error-icon, .help-icon, -.not-offered { +.not-offered-icon { font-size: 16px !important; margin-left: 5px; padding-top: 5px;