From ed8eea4b4b718e284277b16d86d540dc6357485c Mon Sep 17 00:00:00 2001 From: pnogal <paulina.nogal@wisc.edu> Date: Wed, 14 Nov 2018 11:19:32 -0600 Subject: [PATCH] Add and remove course from favorites --- src/app/core/data.service.ts | 25 +++++++++++- src/app/core/models/favorite-course.ts | 10 +++++ .../degree-planner.component.html | 4 +- .../degree-planner.component.ts | 4 +- .../favorites-container.component.html | 19 ++++++++-- .../favorites-container.component.ts | 30 ++++++++++++++- .../sidenav-menu-item.component.html | 2 +- .../sidenav-menu-item.component.scss | 1 + .../sidenav-menu-item.component.ts | 3 +- .../term-container.component.html | 6 +-- .../term-container.component.scss | 26 ------------- .../term-container.component.ts | 10 ++++- src/assets/sass/general.scss | 38 ++++++++++++++++++- 13 files changed, 134 insertions(+), 44 deletions(-) create mode 100644 src/app/core/models/favorite-course.ts diff --git a/src/app/core/data.service.ts b/src/app/core/data.service.ts index 15ebcc5..9d94cd2 100644 --- a/src/app/core/data.service.ts +++ b/src/app/core/data.service.ts @@ -1,12 +1,18 @@ -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { HttpErrorResponse } from '@angular/common/http'; import { throwError, Observable } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; import { ConfigService } from './config.service'; import { Course } from './models/course'; import { DegreePlan } from './models/degree-plan'; import { Term } from './models/term'; +import { FavoriteCourse } from './models/favorite-course'; + +const httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) +}; @Injectable() export class DataService { @@ -33,6 +39,21 @@ export class DataService { .pipe(catchError(this.errorHandler)); } + getFavoriteCourses(): Observable<FavoriteCourse[]> { + return this.http.get<FavoriteCourse[]>(this.plannerApiUrl + '/favorites') + .pipe(catchError(this.errorHandler)); + } + + saveFavoriteCourse(subjectCode: string, courseId: string): Observable<FavoriteCourse> { + return this.http.post<FavoriteCourse>(this.plannerApiUrl + 'favorites/' + subjectCode + '/' + courseId, httpOptions) + .pipe(catchError(this.errorHandler)); + } + + removeFavoriteCourse(subjectCode, courseId): Observable<FavoriteCourse> { + return this.http.delete<FavoriteCourse>(this.plannerApiUrl + 'favorites/' + subjectCode + '/' + courseId, httpOptions) + .pipe(catchError(this.errorHandler)); + } + private errorHandler(error: HttpErrorResponse) { return throwError(error || 'Server Error'); } diff --git a/src/app/core/models/favorite-course.ts b/src/app/core/models/favorite-course.ts new file mode 100644 index 0000000..45c1db7 --- /dev/null +++ b/src/app/core/models/favorite-course.ts @@ -0,0 +1,10 @@ +export interface FavoriteCourse { + id: number; + courseId: string; + termCode: string; + topicId: number; + subjectCode: string; + title: string; + catalogNumber: string; + courseOrder: number; +} diff --git a/src/app/degree-planner/degree-planner.component.html b/src/app/degree-planner/degree-planner.component.html index 3597744..7797147 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 #rightSideNav position="end" mode="side" [opened]="true" disableClose> - <cse-sidenav-menu-item></cse-sidenav-menu-item> + <cse-sidenav-menu-item [favoriteDropZone]="getTermDropZone()"></cse-sidenav-menu-item> </mat-sidenav> <!-- Add course sidenav --> @@ -46,7 +46,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']" - [termCodes]="getTermCodes()" + [termCodes]="getTermDropZone()" fxFlex="33%" ></cse-term-container> </div> diff --git a/src/app/degree-planner/degree-planner.component.ts b/src/app/degree-planner/degree-planner.component.ts index 0d579c3..c182c2c 100644 --- a/src/app/degree-planner/degree-planner.component.ts +++ b/src/app/degree-planner/degree-planner.component.ts @@ -95,12 +95,12 @@ export class DegreePlannerComponent { return []; } - getTermCodes() { + getTermDropZone() { if (!this.degreePlanCourses) { return false; } - const termCodes = []; + const termCodes = ['favoriteCourse-dropZone']; for (const yearCode in this.termsByAcademicYear) { if (this.termsByAcademicYear[yearCode]) { 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 f4d0423..9c9ef4d 100644 --- a/src/app/degree-planner/favorites-container/favorites-container.component.html +++ b/src/app/degree-planner/favorites-container/favorites-container.component.html @@ -1,3 +1,16 @@ -<div id="favorite-container"> - My favorite courses! -</div> \ No newline at end of file +<div class="term-container"> + <div + cdkDropList + id="favoriteCourse-dropZone" + class="course-list" + [cdkDropListData]="favoriteCourses" + [cdkDropListConnectedTo]="favoriteDropZone" + (cdkDropListDropped)="drop($event)"> + <div class="course-wrapper" [cdkDragData]="course" *ngFor="let course of favoriteCourses" cdkDrag> + <div class="course-wrapper-inner"> + <cse-course-item [course]="course" [status]="'favorite'" class="course-favorite"></cse-course-item> + </div> + </div> + <p *ngIf="!favoriteCourses || favoriteCourses.length === 0" class="no-courses text-center semi-bold">No Favorite Courses</p> + </div> +</div> 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 12a3734..e3f3756 100644 --- a/src/app/degree-planner/favorites-container/favorites-container.component.ts +++ b/src/app/degree-planner/favorites-container/favorites-container.component.ts @@ -1,15 +1,41 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; +import { DataService } from '../../core/data.service'; +import { FavoriteCourse } from '../../core/models/favorite-course'; +import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; @Component({ selector: 'cse-favorites-container', templateUrl: './favorites-container.component.html', styleUrls: ['./favorites-container.component.scss'] }) + export class FavoritesContainerComponent implements OnInit { + favoriteCourses: FavoriteCourse[]; + favoriteCourse: FavoriteCourse; + @Input() favoriteDropZone: []; + + constructor(private dataService: DataService) { - constructor() { } + this.dataService.getFavoriteCourses() + .subscribe(favoriteCourses => { + this.favoriteCourses = favoriteCourses; + }); + } ngOnInit() { } + drop(event: CdkDragDrop<string[]>) { + if (event.previousContainer.id !== event.container.id) { + transferArrayItem(event.previousContainer.data, + event.container.data, + event.previousIndex, + event.currentIndex); + } + + this.dataService.saveFavoriteCourse(event.item.data.subjectCode, event.item.data.courseId) + .subscribe(favoriteCourse => { + this.favoriteCourse = favoriteCourse; + }); + } } 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 a5d771b..3a5596b 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 @@ -37,6 +37,6 @@ <h3>Favorites</h3> </mat-panel-title> </mat-expansion-panel-header> - <cse-favorites-container></cse-favorites-container> + <cse-favorites-container [favoriteDropZone]='favoriteDropZone'></cse-favorites-container> </mat-expansion-panel> </div> \ No newline at end of file diff --git a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.scss b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.scss index 41019fe..1c34884 100644 --- a/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.scss +++ b/src/app/degree-planner/sidenav-menu-item/sidenav-menu-item.component.scss @@ -5,6 +5,7 @@ height: 100vh; .mat-expansion-panel { border-radius: 0px; + overflow: visible; } h3 { font-weight: 400; 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 eb57284..185f821 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 @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'cse-sidenav-menu-item', @@ -8,6 +8,7 @@ import { Component, OnInit } from '@angular/core'; export class SidenavMenuItemComponent implements OnInit { events: string[] = []; opened: boolean; + @Input() favoriteDropZone: []; 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 ad65b81..018385c 100644 --- a/src/app/degree-planner/term-container/term-container.component.html +++ b/src/app/degree-planner/term-container/term-container.component.html @@ -9,9 +9,9 @@ [cdkDropListConnectedTo]="termCodes" class="course-list" (cdkDropListDropped)="drop($event)"> - <div class="course-wrapper" *ngFor="let course of courses" cdkDrag> - <div class="coure-wrapper-inner"> - <cse-course-item [course]="course" [status]="'complete'"></cse-course-item> + <div class="course-wrapper" [cdkDragData]="course" *ngFor="let course of courses" cdkDrag> + <div class="course-wrapper-inner"> + <cse-course-item [course]="course" [status]="'in-progress'"></cse-course-item> </div> </div> <p *ngIf="!courses || courses.length === 0" class="no-courses text-center semi-bold">No Courses Taken</p> diff --git a/src/app/degree-planner/term-container/term-container.component.scss b/src/app/degree-planner/term-container/term-container.component.scss index 1c1e108..2174fba 100644 --- a/src/app/degree-planner/term-container/term-container.component.scss +++ b/src/app/degree-planner/term-container/term-container.component.scss @@ -11,29 +11,3 @@ .term-container h2 { margin: 0 0 20px 0; } - -.no-courses { - padding: 20px 10px; -} - -.cdk-drag-placeholder { - position: relative; - &:after { - content: ''; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: #C7CACB; - border-radius: 5px; - } -} - -.cdk-drag-preview { - .coure-wrapper-inner { - transform: rotate(-3deg); - border-radius: 5px; - box-shadow: -3px 3px 3px 2px rgba(0, 0, 0, 0.26); - } -} \ 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 41c8864..9e007ca 100644 --- a/src/app/degree-planner/term-container/term-container.component.ts +++ b/src/app/degree-planner/term-container/term-container.component.ts @@ -1,6 +1,8 @@ import { Component, Input } from '@angular/core'; import { Term } from '../../core/models/term'; import { Course } from '../../core/models/course'; +import { FavoriteCourse } from '../../core/models/favorite-course'; +import { DataService } from '../../core/data.service'; import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; @Component({ @@ -14,8 +16,9 @@ export class TermContainerComponent { @Input() courses: Course[]; @Input() termCodes: String[]; terms: any[]; + favoriteCourse: FavoriteCourse; - constructor() {} + constructor(private dataService: DataService) {} getTotalCredits() { if (!this.courses) { @@ -36,5 +39,10 @@ export class TermContainerComponent { event.previousIndex, event.currentIndex); } + + this.dataService.removeFavoriteCourse(event.item.data.subjectCode, event.item.data.courseId) + .subscribe(favoriteCourse => { + this.favoriteCourse = favoriteCourse; + }); } } diff --git a/src/assets/sass/general.scss b/src/assets/sass/general.scss index 905649d..5e78ea7 100644 --- a/src/assets/sass/general.scss +++ b/src/assets/sass/general.scss @@ -49,4 +49,40 @@ body { .favorite-icon { color: map-get($uw-accent, 600); -} \ No newline at end of file +} + +#favoriteCourse-dropZone { + .course-favorite { + .course-item { + border: 1px solid #b7b7b7; + border-radius: 4px; + padding: 5px 10px; + } + } +} + +.cdk-drag-placeholder { + position: relative; + &:after { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: #C7CACB; + border-radius: 5px; + } +} + +.cdk-drag-preview { + .course-wrapper-inner { + transform: rotate(-3deg); + border-radius: 5px; + box-shadow: -3px 3px 3px 2px rgba(0, 0, 0, 0.26); + } +} + +.no-courses { + padding: 20px 10px; +} -- GitLab