From 9f73733559d3bdade213ef6c43b60541fd038293 Mon Sep 17 00:00:00 2001 From: Paulina Nogal <pnogal@wisc.edu> Date: Wed, 19 Dec 2018 16:13:24 +0000 Subject: [PATCH] Create three dot menu for course items and add its functionality --- .../degree-planner.component.html | 3 +- .../degree-planner.component.ts | 7 ++ .../degree-planner/degree-planner.module.ts | 6 +- ...emove-course-confirm-dialog.component.html | 14 +++ ...emove-course-confirm-dialog.component.scss | 6 ++ ...ve-course-confirm-dialog.component.spec.ts | 25 +++++ .../remove-course-confirm-dialog.component.ts | 50 +++++++++ .../favorites-container.component.html | 4 + .../favorites-container.component.ts | 8 +- .../course-item/course-item.component.html | 62 +++++++---- .../course-item/course-item.component.scss | 35 +++--- .../course-item/course-item.component.ts | 101 +++++++++++++++++- .../sidenav-menu-item.component.html | 2 +- .../sidenav-menu-item.component.ts | 2 + .../term-container.component.html | 81 +++++++------- .../term-container.component.ts | 1 + src/app/shared/academic-year-range.pipe.ts | 23 ++++ src/app/shared/shared.module.ts | 5 +- src/assets/sass/general.scss | 27 +++++ 19 files changed, 376 insertions(+), 86 deletions(-) create mode 100644 src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.html create mode 100644 src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.scss create mode 100644 src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.spec.ts create mode 100644 src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts create mode 100644 src/app/shared/academic-year-range.pipe.ts diff --git a/src/app/degree-planner/degree-planner.component.html b/src/app/degree-planner/degree-planner.component.html index 6e05000..5604583 100644 --- a/src/app/degree-planner/degree-planner.component.html +++ b/src/app/degree-planner/degree-planner.component.html @@ -1,7 +1,7 @@ <mat-sidenav-container id="plans-container"> <!-- Menu side nav --> <mat-sidenav #rightMenu position="end" [mode]="mobileView.matches ? 'over' : 'side'" [opened]="mobileView.matches ? false : true"> - <cse-sidenav-menu-item [favoriteDropZone]="getTermDropZone()" [subjectsMap]="subjectsMap"></cse-sidenav-menu-item> + <cse-sidenav-menu-item [termsByAcademicYear]="termsByAcademicYear" [favoriteCourses]="favoriteCourses" [favoriteDropZone]="getTermDropZone()" [subjectsMap]="subjectsMap"></cse-sidenav-menu-item> </mat-sidenav> <mat-sidenav-content> @@ -33,6 +33,7 @@ *ngFor="let term of termsByAcademicYear[year.key].terms | keyvalue" [term]="termsByAcademicYear[year.key].terms[term.key]" [courses]="termsByAcademicYear[year.key].terms[term.key]['courses']" + [favoriteCourses]="favoriteCourses" [termCodes]="getTermDropZone()" [termsByAcademicYear]="termsByAcademicYear" [subjectsMap]="subjectsMap" diff --git a/src/app/degree-planner/degree-planner.component.ts b/src/app/degree-planner/degree-planner.component.ts index 6f6d25e..c6f84ba 100644 --- a/src/app/degree-planner/degree-planner.component.ts +++ b/src/app/degree-planner/degree-planner.component.ts @@ -6,6 +6,7 @@ import { Term } from '../core/models/term'; import { log } from 'util'; import { Note } from '../core/models/note'; import { MediaMatcher } from '@angular/cdk/layout'; +import { FavoriteCourse } from '../core/models/favorite-course'; @Component({ selector: 'cse-degree-planner', @@ -23,6 +24,7 @@ export class DegreePlannerComponent { notes: Note[]; firstCurrentTerm: null|string; mobileView: MediaQueryList; + favoriteCourses: FavoriteCourse[]; constructor(private dataService: DataService, public mediaMatcher: MediaMatcher) { @@ -76,6 +78,11 @@ export class DegreePlannerComponent { this.dataService.getTerms() .subscribe(terms => {}); + + this.dataService.getFavoriteCourses() + .subscribe(favoriteCourses => { + this.favoriteCourses = favoriteCourses; + }); } // Create a new year object to be used in this.termsByAcademicYear diff --git a/src/app/degree-planner/degree-planner.module.ts b/src/app/degree-planner/degree-planner.module.ts index 327334c..e3be2d0 100644 --- a/src/app/degree-planner/degree-planner.module.ts +++ b/src/app/degree-planner/degree-planner.module.ts @@ -10,6 +10,7 @@ import { CourseItemComponent } from './shared/course-item/course-item.component' import { CourseDetailsDialogComponent } from './dialogs/course-details-dialog/course-details-dialog.component'; import { NotesDialogComponent } from './dialogs/notes-dialog/notes-dialog.component'; import { DragDropModule } from '@angular/cdk/drag-drop'; +import { RemoveCourseConfirmDialogComponent } from './dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component'; @NgModule({ imports: [ @@ -27,8 +28,9 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; SidenavMenuItemComponent, FavoritesContainerComponent, CourseDetailsDialogComponent, - NotesDialogComponent + NotesDialogComponent, + RemoveCourseConfirmDialogComponent ], - entryComponents: [ CourseDetailsDialogComponent, NotesDialogComponent ] + entryComponents: [ CourseDetailsDialogComponent, NotesDialogComponent, RemoveCourseConfirmDialogComponent ] }) export class DegreePlannerModule { } diff --git a/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.html b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.html new file mode 100644 index 0000000..41ddaf1 --- /dev/null +++ b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.html @@ -0,0 +1,14 @@ +<mat-toolbar class="dialog-toolbar"> + <h1 class="dialog-toolbar-title">Are you sure?</h1> + <button mat-button mat-dialog-close class="close-btn" aria-label="Close note dialog"><i class="material-icons">clear</i></button> +</mat-toolbar> +<mat-dialog-content id="confirmation-dialog" class="mat-typography dialog-with-toolbar"> + <mat-dialog-content> + <p class="dialog-text" *ngIf="savedForLater">This will remove {{ course.title }} from Saved For Later and My Courses.</p> + <p class="dialog-text" *ngIf="!savedForLater">This will remove {{ course.title }} from your plan and from your cart.</p> + </mat-dialog-content> + <mat-dialog-actions align="end"> + <button mat-button class="mat-button btn-link" mat-dialog-close aria-label="Close dialog">Cancel</button> + <button mat-button class="btn-link" (click)="removeCourse()" mat-dialog-close aria-label="Delete course from selected term">Remove</button> + </mat-dialog-actions> +</mat-dialog-content> \ No newline at end of file diff --git a/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.scss b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.scss new file mode 100644 index 0000000..0b55a82 --- /dev/null +++ b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.scss @@ -0,0 +1,6 @@ + + .dialog-text { + color: #7e7e7e; + font-size: 16px; + margin-top: 1.2em; + } \ No newline at end of file diff --git a/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.spec.ts b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.spec.ts new file mode 100644 index 0000000..870bb46 --- /dev/null +++ b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RemoveCourseConfirmDialogComponent } from './remove-course-confirm-dialog.component'; + +describe('RemoveCourseConfirmDialogComponent', () => { + let component: RemoveCourseConfirmDialogComponent; + let fixture: ComponentFixture<RemoveCourseConfirmDialogComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RemoveCourseConfirmDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RemoveCourseConfirmDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000..4abb262 --- /dev/null +++ b/src/app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit, Input, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { DataService } from '../../../core/data.service'; +import { Course } from '../../../core/models/course'; +import { FavoriteCourse } from '../../../core/models/favorite-course'; + +@Component({ + selector: 'cse-remove-course-confirm-dialog', + templateUrl: './remove-course-confirm-dialog.component.html', + styleUrls: ['./remove-course-confirm-dialog.component.scss'] +}) +export class RemoveCourseConfirmDialogComponent implements OnInit { + course: Course; + savedForLater: Boolean; + courses: Course[]; + favoriteCourses: FavoriteCourse[]; + + // tslint:disable-next-line:max-line-length + constructor(private dataService: DataService, private dialogRef: MatDialogRef<RemoveCourseConfirmDialogComponent>, @Inject(MAT_DIALOG_DATA) data) { + this.course = data.course; + this.courses = data.courses; + this.favoriteCourses = data.favoriteCourses; + this.savedForLater = data.savedForLater; + } + + ngOnInit() { + } + + removeCourseFromUI(courseItem) { + const index = courseItem.indexOf(this.course, 0); + if (index > -1) { + courseItem = courseItem.splice(index, 1); + } + } + + // Remove this course from the degree plan + removeCourse() { + if (this.savedForLater) { + this.dataService.removeFavoriteCourse(this.course.subjectCode, this.course.courseId) + .subscribe(data => { + this.removeCourseFromUI(this.favoriteCourses); + }); + } else { + this.dataService.removeCourse(this.course.id) + .subscribe(data => { + this.removeCourseFromUI(this.courses); + }); + } + } +} diff --git a/src/app/degree-planner/favorites-container/favorites-container.component.html b/src/app/degree-planner/favorites-container/favorites-container.component.html index 728914f..6b69125 100644 --- a/src/app/degree-planner/favorites-container/favorites-container.component.html +++ b/src/app/degree-planner/favorites-container/favorites-container.component.html @@ -10,7 +10,11 @@ <div class="course-wrapper-inner"> <cse-course-item [course]="course" + [favoriteCourses]="favoriteCourses" [status]="'favorite'" + [savedForLater]="true" + [term]="term" + [termsByAcademicYear]="termsByAcademicYear" [subject]="subjectsMap[course.subjectCode]" class="course-favorite" ></cse-course-item> 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 6c61167..f353e50 100644 --- a/src/app/degree-planner/favorites-container/favorites-container.component.ts +++ b/src/app/degree-planner/favorites-container/favorites-container.component.ts @@ -10,17 +10,13 @@ import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/dr }) export class FavoritesContainerComponent implements OnInit { - favoriteCourses: FavoriteCourse[]; favoriteCourse: FavoriteCourse; @Input() subjectsMap: Object; @Input() favoriteDropZone: []; + @Input() termsByAcademicYear: Object; + @Input() favoriteCourses: FavoriteCourse[]; constructor(private dataService: DataService) { - - this.dataService.getFavoriteCourses() - .subscribe(favoriteCourses => { - this.favoriteCourses = favoriteCourses; - }); } ngOnInit() { 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 a5374f9..e610d35 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 @@ -1,21 +1,47 @@ <div class="course-item {{status}} {{disabled ? 'disabled' : ''}}"> - <div class="course-row course-info"> - <div class="icon-number-wrapper"> - <p class="course-number"> - {{subject}} {{course.catalogNumber}} - </p> - <div [ngSwitch]="status"> - <i *ngSwitchCase="'complete'" class="material-icons complete-icon">check_circle</i> - <i *ngSwitchCase="'in-progress'" class="material-icons in-progress-icon">check_circle</i> - <i *ngSwitchCase="'waitlist'" class="material-icons problem-icon">report_problem</i> - <i *ngSwitchCase="'incomplete'" class="material-icons error-icon">error</i> - <i *ngSwitchCase="'favorite'" class="material-icons favorite-icon">favorite_border</i> - </div> - </div> - <p class="course-credits">{{ course.credits !== undefined ? course.credits : "--" }} Cr</p> - </div> - <div class="course-row"> - <p class="course-title">{{course.title}}</p> - </div> + <div fxLayout="row" fxLayoutAlign="space-between start"> + <div fxLayout="column" fxLayoutAlign="space-between start" fxFlex="80" (click)="openCourseDetailsDialog(course)"> + <div fxLayout="row" fxLayoutAlign="start center"> + <div class="icon-number-wrapper"> + <p class="course-number"> + {{subject}} {{course.catalogNumber}} + </p> + <div [ngSwitch]="status"> + <i *ngSwitchCase="'complete'" class="material-icons complete-icon">check_circle</i> + <i *ngSwitchCase="'in-progress'" class="material-icons in-progress-icon">check_circle</i> + <i *ngSwitchCase="'waitlist'" class="material-icons problem-icon">report_problem</i> + <i *ngSwitchCase="'incomplete'" class="material-icons error-icon">error</i> + <i *ngSwitchCase="'favorite'" class="material-icons favorite-icon">favorite_border</i> + </div> + </div> + </div> + <div fxLayout="row" fxLayoutAlign="start center"> + <p class="course-title">{{course.title}}</p> + </div> + </div> + + <div fxLayout="column" fxLayoutAlign="space-between end" fxFlex="20"> + <div fxLayout="row" fxLayoutAlign="end center"> + <mat-icon [matMenuTriggerFor]="courseMenu" (click)="getAllTermCodes()" aria-label="Course menu" matTooltip="Course Menu" matTooltipPosition="right" class="material-icons">more_horiz</mat-icon> + <mat-menu #courseMenu="matMenu" class="course-item-menu"> + <button mat-menu-item (click)="openCourseDetailsDialog(course)">Course Details</button> + <button mat-menu-item [matMenuTriggerFor]="academicYearsGroup">Move</button> + <mat-menu #academicYearsGroup="matMenu" class="course-item-submenu"> + <button mat-menu-item (click)="moveToFavorites(course)" *ngIf="status !== 'favorite'" class="favorites-list">Favorites list</button> + <button mat-menu-item *ngFor="let academicYear of termsByAcademicYear | keyvalue" [matMenuTriggerFor]="termsInAcademicYearGroup"> + {{ academicYear.value.year | academicYearRange }} + <mat-menu #termsInAcademicYearGroup="matMenu" class="course-item-submenu"> + <button mat-menu-item *ngFor="let term of academicYear.value.terms | keyvalue" (click)="status !== 'favorite' ? switchTerm(term.value.termCode) : addToTerm(term.value.termCode)">{{ term.value.termCode | getTermDescription }}</button> + </mat-menu> + </button> + </mat-menu> + <button mat-menu-item (click)="openRemoveConfirmationDialog(savedForLater)">Remove</button> + </mat-menu> + </div> + <div fxLayout="row" fxLayoutAlign="end center"> + <p class="course-credits">{{ course.credits !== undefined ? course.credits : "--" }} Cr</p> + </div> + </div> + </div> </div> diff --git a/src/app/degree-planner/shared/course-item/course-item.component.scss b/src/app/degree-planner/shared/course-item/course-item.component.scss index bf3f1c8..344a1d4 100644 --- a/src/app/degree-planner/shared/course-item/course-item.component.scss +++ b/src/app/degree-planner/shared/course-item/course-item.component.scss @@ -36,14 +36,16 @@ margin: 0; padding: 0; } -} - -.course-row { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; + .mat-icon { + border-radius: 50%; + text-align: center; + font-size: 18px; + line-height: 1.4; + &:hover, &:focus { + background: #dadee0; + } + } } .course-number, @@ -57,12 +59,6 @@ display: inline-block; } -.material-icons { - font-size: 16px; - margin-left: 10px; - padding-top: 6px; -} - .icon-number-wrapper { display: flex; align-items: center; @@ -75,4 +71,15 @@ text-decoration: line-through; opacity: .5; } -} \ No newline at end of file +} + +button.mat-menu-item { + text-transform: none !important; +} + +@media screen and (max-width: 957px) { + .mat-icon { + padding: 0.5em; + margin-bottom: 0.5em; + } +} 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 068f800..7d27009 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 @@ -1,17 +1,112 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, ChangeDetectorRef, OnInit } from '@angular/core'; import { Course } from '../../../core/models/course'; +import { Term } from '../../../core/models/term'; +import { FavoriteCourse } from '../../../core/models/favorite-course'; +import { DataService } from '../../../core/data.service'; +import { CourseDetailsDialogComponent } from '../../dialogs/course-details-dialog/course-details-dialog.component'; +// tslint:disable-next-line:max-line-length +import { RemoveCourseConfirmDialogComponent } from '../../dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component'; +import { MatDialog } from '@angular/material'; @Component({ selector: 'cse-course-item', templateUrl: './course-item.component.html', styleUrls: ['./course-item.component.scss'] }) -export class CourseItemComponent { + +export class CourseItemComponent implements OnInit { + termsInAcademicYear: []; + favoriteCourse: FavoriteCourse; + degreePlanCourses: any[]; @Input() course: Course; + @Input() courses: Course[]; @Input() status: string; @Input() subject: string; @Input() disabled: string; + @Input() term: Term; + @Input() termsByAcademicYear: Object; + @Input() refreshContent; + @Input() savedForLater: Boolean; + @Input() favoriteCourses: FavoriteCourse[]; + + constructor( + private dataService: DataService, + public dialog: MatDialog, + private cdRef: ChangeDetectorRef) { + } + + ngOnInit() { + } + + removeCourseFromUI(courseItem) { + const index = courseItem.indexOf(this.course, 0); + if (index > -1) { + courseItem = courseItem.splice(index, 1); + } + } + + openCourseDetailsDialog(course) { + this.dataService.getCourseDetails(course.termCode, course.subjectCode, course.courseId) + .subscribe(courseDetails => { + const dialogRef = this.dialog.open(CourseDetailsDialogComponent, { + data: { courseDetails: courseDetails } + }); + }); + } + + // Get term codes to display in the course item menu + getAllTermCodes() { + const termYears: any = Object.values(this.termsByAcademicYear); + this.termsInAcademicYear = termYears.map(year => year.terms).flat(); + } + + // Add this coruse to the favorites list + moveToFavorites(course) { + this.dataService.saveFavoriteCourse(course.subjectCode, course.courseId) + .subscribe(favoriteCourse => { + this.favoriteCourses.push(this.course); + }); + + // Remove this course from term + this.dataService.removeCourse(course.id) + .subscribe(data => { + this.removeCourseFromUI(this.courses); + }); + } + + // Add Favorite course to term + addToTerm(newTermCode) { + this.dataService.addCourse( this.course.subjectCode, this.course.courseId, newTermCode) + .subscribe( data => { + const yearCode = newTermCode.substring(0, 3); + const termCode = newTermCode.substring(3); + this.termsByAcademicYear[yearCode].terms[termCode].courses.push(this.course); + }); + + // Remove course from favorites list + this.dataService.removeFavoriteCourse(this.course.subjectCode, this.course.courseId) + .subscribe(data => { + this.removeCourseFromUI(this.favoriteCourses); + }); + } - constructor() {} + // Move course to another term + switchTerm(newTermCode) { + this.dataService.updateCourseTerm(this.course.id, newTermCode) + .subscribe( data => { + const index = this.courses.indexOf(this.course, 0); + if (index > -1) { + this.courses = this.courses.splice(index, 1); + const yearCode = newTermCode.substring(0, 3); + const termCode = newTermCode.substring(3); + this.termsByAcademicYear[yearCode].terms[termCode].courses.push(this.course); + } + }); + } + openRemoveConfirmationDialog(savedForLater) { + const dialogRef = this.dialog.open(RemoveCourseConfirmDialogComponent, { + data: { course: this.course, courses: this.courses, favoriteCourses: this.favoriteCourses, savedForLater } + }); + } } 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 f7ffa7a..8d81fd2 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 @@ -20,7 +20,7 @@ <h3>Favorites</h3> </mat-panel-title> </mat-expansion-panel-header> - <cse-favorites-container [favoriteDropZone]='favoriteDropZone' [subjectsMap]="subjectsMap"></cse-favorites-container> + <cse-favorites-container [termsByAcademicYear]="termsByAcademicYear" [favoriteCourses]="favoriteCourses" [favoriteDropZone]='favoriteDropZone' [subjectsMap]="subjectsMap"></cse-favorites-container> </mat-expansion-panel> <mat-expansion-panel id="menu-items-container" expanded="true"> diff --git a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.ts b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.ts index 9c32d92..3688091 100644 --- a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.ts +++ b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.ts @@ -10,6 +10,8 @@ export class SidenavMenuItemComponent implements OnInit { opened: boolean; @Input() favoriteDropZone: []; @Input() subjectsMap: Object; + @Input() termsByAcademicYear: Object; + @Input() favoriteCourses; constructor() { } diff --git a/src/app/degree-planner/term-container/term-container.component.html b/src/app/degree-planner/term-container/term-container.component.html index f7cac00..c65f919 100644 --- a/src/app/degree-planner/term-container/term-container.component.html +++ b/src/app/degree-planner/term-container/term-container.component.html @@ -1,41 +1,44 @@ <mat-card class="term-container"> - <div class="term-inner"> - <div fxLayout="row" class="term-header" fxLayoutAlign="space-between center"> - <h2>{{ term.termCode | getTermDescription }}</h2> - <div fxLayout="row" fxLayoutAlign="end center"> - <p class="text-right semi-bold credits">{{getTotalCredits()}} Cr</p> - <button mat-icon-button> - <mat-icon aria-label="Open dialog with notes in this term" class="add-note-icon" (click)="openNotesDialog(false, term.termCode)" matTooltip="Add Note" matTooltipPosition="above">note_add</mat-icon> - <!-- <mat-icon aria-label="Open dialog with notes in this term" class="add-note-icon" (click)="openNotesDialog(false, term.termCode)" matTooltip="Edit Note" matTooltipPosition="above">insert_drive_file</mat-icon> --> - </button> - </div> - </div> - <div - cdkDropList - id="term-{{term.termCode}}" - [cdkDropListData]="courses" - [cdkDropListConnectedTo]="termCodes" - class="course-list" - (cdkDropListDropped)="drop($event)"> - <ng-container *ngFor="let note of notes | async"> - <div *ngIf="note.termCode == term.termCode" class="note-item" (click)="openNotesDialog(note, term.termCode)" > - <p class="semi-bold">Note</p> - <p class="note-excerpt">{{ note.note }}</p> - </div> - </ng-container> - <div class="course-wrapper" [cdkDragData]="course" *ngFor="let course of courses" cdkDrag> - <div class="course-wrapper-inner"> - <cse-course-item - [course]="course" - (click)="openCourseDetailsDialog(course)" - [status]="'in-progress'" - [subject]="subjectsMap[course.subjectCode]" - ></cse-course-item> - </div> - </div> - </div> - </div> - <div class="add-new-wrapper"> - <button mat-raised-button (click)="openAddSidenav()">+ Add Course</button> - </div> + <div class="term-inner"> + <div fxLayout="row" class="term-header" fxLayoutAlign="space-between center"> + <h2>{{ term.termCode | getTermDescription }}</h2> + <div fxLayout="row" fxLayoutAlign="end center"> + <p class="text-right semi-bold credits">{{getTotalCredits()}} Cr</p> + <button mat-icon-button> + <mat-icon aria-label="Open dialog with notes in this term" class="add-note-icon" (click)="openNotesDialog(false, term.termCode)" matTooltip="Add Note" matTooltipPosition="above">note_add</mat-icon> + <!-- <mat-icon aria-label="Open dialog with notes in this term" class="add-note-icon" (click)="openNotesDialog(false, term.termCode)" matTooltip="Edit Note" matTooltipPosition="above">insert_drive_file</mat-icon> --> + </button> + </div> + </div> + <div + cdkDropList + id="term-{{term.termCode}}" + [cdkDropListData]="courses" + [cdkDropListConnectedTo]="termCodes" + class="course-list" + (cdkDropListDropped)="drop($event)"> + <ng-container *ngFor="let note of notes | async"> + <div *ngIf="note.termCode == term.termCode" class="note-item" (click)="openNotesDialog(note, term.termCode)" > + <p class="semi-bold">Note</p> + <p class="note-excerpt">{{ note.note }}</p> + </div> + </ng-container> + <div class="course-wrapper" [cdkDragData]="course" *ngFor="let course of courses" cdkDrag> + <div class="course-wrapper-inner"> + <cse-course-item + [course]="course" + [courses]="courses" + [term]="term" + [favoriteCourses]="favoriteCourses" + [termsByAcademicYear]="termsByAcademicYear" + [status]="'in-progress'" + [subject]="subjectsMap[course.subjectCode]" + ></cse-course-item> + </div> + </div> + </div> + </div> + <div class="add-new-wrapper"> + <button mat-raised-button (click)="openAddSidenav()">+ Add Course</button> + </div> </mat-card> \ No newline at end of file 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 474465d..318fb7c 100644 --- a/src/app/degree-planner/term-container/term-container.component.ts +++ b/src/app/degree-planner/term-container/term-container.component.ts @@ -26,6 +26,7 @@ export class TermContainerComponent { @Input() course: CourseDetails; @Input() subjectsMap: Object; @Input() notes: Observable<Array<Note>>; + @Input() favoriteCourses; terms: any[]; note: Object; diff --git a/src/app/shared/academic-year-range.pipe.ts b/src/app/shared/academic-year-range.pipe.ts new file mode 100644 index 0000000..851182b --- /dev/null +++ b/src/app/shared/academic-year-range.pipe.ts @@ -0,0 +1,23 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'academicYearRange' +}) +export class AcademicYearRangePipe implements PipeTransform { + + transform(yearCode: string, args?: any): any { + // Get the century digit + const century = parseInt(yearCode.substring(0, 1), 0) + 19; + + // Get the year + const academicYear = parseInt(yearCode.substring(1), 0); + + const endYear = (century * 100) + academicYear; + const startYear = endYear - 1; + + const yearString = `${startYear} - ${endYear}`; + + return yearString; + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index c09a08e..f9c85f0 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -19,6 +19,7 @@ import { MatTooltipModule } from '@angular/material/tooltip'; import { GetTermDescriptionPipe } from './get-term-description.pipe'; import { AcademicYearStatePipe } from './academic-year-state.pipe'; import { CourseDetailsComponent } from './course-details/course-details.component'; +import { AcademicYearRangePipe } from './academic-year-range.pipe'; const modules = [ CommonModule, @@ -41,8 +42,8 @@ const modules = [ @NgModule({ imports: [ modules ], - exports: [ modules, GetTermDescriptionPipe, AcademicYearStatePipe, CourseDetailsComponent ], - declarations: [ GetTermDescriptionPipe, AcademicYearStatePipe, CourseDetailsComponent ] + exports: [ modules, GetTermDescriptionPipe, AcademicYearStatePipe, CourseDetailsComponent, AcademicYearRangePipe ], + declarations: [ GetTermDescriptionPipe, AcademicYearStatePipe, CourseDetailsComponent, AcademicYearRangePipe ] }) export class SharedModule { } diff --git a/src/assets/sass/general.scss b/src/assets/sass/general.scss index 3434a39..fded82f 100644 --- a/src/assets/sass/general.scss +++ b/src/assets/sass/general.scss @@ -44,6 +44,10 @@ body { border-radius: 4px !important; } +.btn-link { + color: map-get($uw-primary, 500) !important; +} + .btn-delete { background-color: #b5261e; color: white; @@ -73,6 +77,18 @@ body { color: map-get($uw-accent, 600); } +.complete-icon, +.in-progress-icon, +.problem-icon, +.error-icon, +.help-icon, +.favorite-icon, +.not-offered { + font-size: 16px !important; + margin-left: 5px; + padding-top: 5px; +} + #favoriteCourse-dropZone { .course-favorite { .course-item { @@ -141,6 +157,17 @@ body { } } +// Menus styles + +.course-item-menu, +.mat-menu-content { + width: 200px !important; +} + +.favorites-list { + border-bottom: 1px solid #f1f1f1 !important; +} + // Dialogs styles .mat-dialog-container { -- GitLab