Skip to content
Snippets Groups Projects
Commit 39473db0 authored by Paulina Nogal's avatar Paulina Nogal Committed by Isaac Evavold
Browse files

Plan settings menu reorder

parent 51b9881a
No related branches found
No related tags found
No related merge requests found
Showing
with 363 additions and 206 deletions
<mat-sidenav-container hasBackdrop="false"> <mat-sidenav-container hasBackdrop="false">
<mat-sidenav #addMenu position="end" mode="over" [opened]="isCourseSearchOpen$ | async"> <mat-sidenav
#addMenu
position="end"
mode="over"
[opened]="isCourseSearchOpen$ | async"
>
<mat-toolbar color="primary" class="dialog-toolbar"> <mat-toolbar color="primary" class="dialog-toolbar">
<span class="dialog-toolbar-title">Course Search</span> <span class="dialog-toolbar-title">Course Search</span>
<button mat-button class="close-btn" (click)="closeCourseSearch();"><i class="material-icons">keyboard_arrow_right</i></button> <button mat-button class="close-btn" (click)="closeCourseSearch()">
<i class="material-icons">keyboard_arrow_right</i>
</button>
</mat-toolbar> </mat-toolbar>
<cse-course-search></cse-course-search> <cse-course-search></cse-course-search>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>
<mat-progress-bar id="loading-plan-progress" mode="indeterminate" *ngIf="isLoadingPlan$ | async"></mat-progress-bar> <mat-progress-bar
id="loading-plan-progress"
mode="indeterminate"
*ngIf="(isLoadingPlan$ | async)"
></mat-progress-bar>
<mat-sidenav-container id="plans-container"> <mat-sidenav-container id="plans-container">
<!-- Menu side nav --> <!-- Menu side nav -->
<mat-sidenav #rightMenu position="end" [mode]="mobileView.matches ? 'over' : 'side'" [opened]="mobileView.matches ? false : true"> <mat-sidenav
#rightMenu
position="end"
[mode]="mobileView.matches ? 'over' : 'side'"
[opened]="mobileView.matches ? false : true"
>
<cse-sidenav-menu-item></cse-sidenav-menu-item> <cse-sidenav-menu-item></cse-sidenav-menu-item>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content id="degree-plan-wrapper" [ngClass]="{ isLoadingPlan: (isLoadingPlan$ | async) }" *ngIf="(degreePlan$ | async) as degreePlan"> <mat-sidenav-content
<div fxLayout="row" fxLayout.lt-sm="column" fxLayoutGap="20px" fxLayoutAlign="start center" style="margin: 24px 0px 24px 24px;"> id="degree-plan-wrapper"
[ngClass]="{ isLoadingPlan: isLoadingPlan$ | async }"
*ngIf="(degreePlan$ | async) as degreePlan"
>
<div
fxLayout="row"
fxLayout.lt-sm="column"
fxLayoutGap="20px"
fxLayoutAlign="start center"
style="margin: 24px 0px 24px 24px;"
>
<mat-form-field> <mat-form-field>
<mat-select <mat-select
[disabled]="isLoadingPlan$ | async" [disabled]="isLoadingPlan$ | async"
...@@ -25,46 +51,83 @@ ...@@ -25,46 +51,83 @@
class="degree-plan-selector" class="degree-plan-selector"
[value]="degreePlan.roadmapId" [value]="degreePlan.roadmapId"
[disableOptionCentering]="true" [disableOptionCentering]="true"
(selectionChange)="handleDegreePlanChange($event)"> (selectionChange)="handleDegreePlanChange($event)"
>
<!-- Render the name of the currently visible degree plan. --> <!-- Render the name of the currently visible degree plan. -->
<mat-select-trigger> <mat-select-trigger>
<mat-icon class="primary-star" *ngIf="degreePlan.primary">star_rate</mat-icon> <mat-icon class="primary-star" *ngIf="degreePlan.primary"
<span class="plan-name">{{degreePlan.name}}</span> >star_rate</mat-icon
>
<span class="plan-name">{{ degreePlan.name }}</span>
</mat-select-trigger> </mat-select-trigger>
<!-- Show all degree plans in the dropdown list and ddd a star next to the user's primary plan. --> <!-- Show all degree plans in the dropdown list and ddd a star next to the user's primary plan. -->
<mat-option *ngFor="let degreePlan of (allDegreePlans$ | async)" [value]="degreePlan.roadmapId"> <mat-option
<mat-icon class="primary-star" *ngIf="degreePlan.primary">star_rate</mat-icon> *ngFor="let degreePlan of (allDegreePlans$ | async)"
<span class="plan-name">{{degreePlan.name}}</span> [value]="degreePlan.roadmapId"
>
<mat-icon class="primary-star" *ngIf="degreePlan.primary"
>star_rate</mat-icon
>
<span class="plan-name">{{ degreePlan.name }}</span>
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<button mat-icon-button [matMenuTriggerFor]="degreePlanMenu" [disabled]="isLoadingPlan$ | async"> <button
<mat-icon>settings</mat-icon> mat-icon-button
[matMenuTriggerFor]="degreePlanMenu"
[disabled]="isLoadingPlan$ | async"
>
<mat-icon matTooltip="Plan settings" matTooltipPosition="right"
>settings</mat-icon
>
</button> </button>
<mat-menu #degreePlanMenu="matMenu"> <mat-menu #degreePlanMenu="matMenu">
<button mat-menu-item (click)="onCreatePlanClick()">Create new plan</button> <button mat-menu-item (click)="onRenamePlanClick(degreePlan)">
<button mat-menu-item (click)="onRenamePlanClick(degreePlan)">Rename plan</button> Rename plan
<button mat-menu-item (click)="onDeletePlanClick(degreePlan)" [disabled]="degreePlan.primary">Delete plan</button> </button>
<button mat-menu-item (click)="onMakePrimayClick(degreePlan)" [disabled]="degreePlan.primary">Make primary</button> <button
<hr> mat-menu-item
<button mat-menu-item (click)="onPrintPlanClick()">Print plan</button> (click)="onMakePrimayClick(degreePlan)"
<button mat-menu-item (click)="onSharePlanClick()">Share plan</button> [disabled]="degreePlan.primary"
>
Make primary
</button>
<button mat-menu-item (click)="onPrintPlanClick()">
Print plan
</button>
<button mat-menu-item>
Download PDF
</button>
<button
mat-menu-item
(click)="onDeletePlanClick(degreePlan)"
[disabled]="degreePlan.primary"
>
Delete plan
</button>
<hr />
<button mat-menu-item (click)="onCreatePlanClick()">
Add degree plan
</button>
</mat-menu> </mat-menu>
</div> </div>
<div id="year-wrapper" fxLayout="column" fxLayoutGap="20px" fxLayoutAlign="start stretch" style="margin: 24px"> <div
<div id="year-mask" *ngIf="isLoadingPlan$ | async"></div> id="year-wrapper"
fxLayout="column"
fxLayoutGap="20px"
fxLayoutAlign="start stretch"
style="margin: 24px"
>
<div id="year-mask" *ngIf="(isLoadingPlan$ | async)"></div>
<mat-accordion multi="true"> <mat-accordion multi="true">
<ng-container *ngFor="let yearCode of (yearCodes$ | async)"> <ng-container *ngFor="let yearCode of (yearCodes$ | async)">
<cse-year-container [yearCode]="yearCode"></cse-year-container> <cse-year-container [yearCode]="yearCode"></cse-year-container>
</ng-container> </ng-container>
</mat-accordion> </mat-accordion>
</div> </div>
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container> </mat-sidenav-container>
</mat-sidenav-content> </mat-sidenav-content>
......
import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component';
import { import {
filter, filter,
map, map,
...@@ -28,13 +27,12 @@ import { ...@@ -28,13 +27,12 @@ import {
ChangePlanName, ChangePlanName,
DeletePlan, DeletePlan,
} from '@app/degree-planner/store/actions/plan.actions'; } from '@app/degree-planner/store/actions/plan.actions';
import {
ModifyPlanDialogComponent,
DialogMode,
} from './dialogs/modify-plan-dialog/modify-plan-dialog.component';
import { PromptDialogComponent } from '@app/shared/dialogs/prompt-dialog/prompt-dialog.component'; import { PromptDialogComponent } from '@app/shared/dialogs/prompt-dialog/prompt-dialog.component';
import { CloseCourseSearch } from './store/actions/ui.actions'; import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component';
import {
ToggleAcademicYear,
CloseCourseSearch,
} from './store/actions/ui.actions';
@Component({ @Component({
selector: 'cse-degree-planner', selector: 'cse-degree-planner',
...@@ -100,26 +98,31 @@ export class DegreePlannerComponent implements OnInit { ...@@ -100,26 +98,31 @@ export class DegreePlannerComponent implements OnInit {
} }
public onCreatePlanClick() { public onCreatePlanClick() {
const data: DialogMode = { mode: 'create' };
this.dialog this.dialog
.open(ModifyPlanDialogComponent, { data }) .open(PromptDialogComponent, {
data: {
initialValue: name,
title: 'Add degree plan',
confirmText: 'Save',
inputName: 'i.e. Psychology',
},
})
.afterClosed() .afterClosed()
.subscribe((result: { name: string } | undefined) => { .subscribe((result: { confirmed: boolean; value: string }) => {
if (result !== undefined && typeof result.name === 'string') { const { confirmed, value } = result;
const name = result.name; if (confirmed) {
const action = new CreatePlan({ name, primary: false }); const action = new CreatePlan({ name: value, primary: false });
this.store.dispatch(action); this.store.dispatch(action);
} }
}); });
} }
public onRenamePlanClick(currentPlan: DegreePlan) { public onRenamePlanClick(currentPlan: DegreePlan) {
// const data: DialogMode = { mode: 'rename', oldName: currentPlan.name };
this.dialog this.dialog
.open(PromptDialogComponent, { .open(PromptDialogComponent, {
data: { data: {
initalValue: currentPlan.name, initialValue: currentPlan.name,
title: 'Rename Degree Plan', title: 'Rename plan',
confirmText: 'Save', confirmText: 'Save',
inputName: 'Plan name', inputName: 'Plan name',
}, },
...@@ -127,7 +130,6 @@ export class DegreePlannerComponent implements OnInit { ...@@ -127,7 +130,6 @@ export class DegreePlannerComponent implements OnInit {
.afterClosed() .afterClosed()
.subscribe((result: { confirmed: boolean; value: string }) => { .subscribe((result: { confirmed: boolean; value: string }) => {
const { confirmed, value } = result; const { confirmed, value } = result;
if (confirmed) { if (confirmed) {
const { roadmapId } = currentPlan; const { roadmapId } = currentPlan;
const action = new ChangePlanName({ roadmapId, newName: value }); const action = new ChangePlanName({ roadmapId, newName: value });
...@@ -136,13 +138,14 @@ export class DegreePlannerComponent implements OnInit { ...@@ -136,13 +138,14 @@ export class DegreePlannerComponent implements OnInit {
}); });
} }
public onMakePrimayClick(_currentPlan: DegreePlan) { public onMakePrimayClick(currentPlan: DegreePlan) {
const data: DialogMode = { mode: 'makePrimary' };
this.dialog this.dialog
.open(ConfirmDialogComponent, { .open(ConfirmDialogComponent, {
data: { data: {
title: 'Are you sure?',
confirmText: 'Change plan',
text: text:
"This will change your primary plan and replace the current courses in your cart with the courses in this plan's term.", "This will change your primary plan and replace the current courses in your cart with the courses in this plan's active term",
}, },
}) })
.afterClosed() .afterClosed()
...@@ -159,11 +162,11 @@ export class DegreePlannerComponent implements OnInit { ...@@ -159,11 +162,11 @@ export class DegreePlannerComponent implements OnInit {
this.snackBar.open('The primary degree plan cannot be deleted'); this.snackBar.open('The primary degree plan cannot be deleted');
return; return;
} }
const data: DialogMode = { mode: 'delete', name: currentPlan.name };
this.dialog this.dialog
.open(ConfirmDialogComponent, { .open(ConfirmDialogComponent, {
data: { data: {
title: 'Are you sure?',
confirmText: 'Delete',
text: text:
'This will delete this plan and course information related to this plan.', 'This will delete this plan and course information related to this plan.',
}, },
...@@ -171,7 +174,7 @@ export class DegreePlannerComponent implements OnInit { ...@@ -171,7 +174,7 @@ export class DegreePlannerComponent implements OnInit {
.afterClosed() .afterClosed()
.pipe(withLatestFrom(this.store)) .pipe(withLatestFrom(this.store))
.subscribe(([result, state]) => { .subscribe(([result, state]) => {
if (result.confirmed) { if (typeof result === 'object' && result.confirmed === true) {
const { roadmapId } = currentPlan; const { roadmapId } = currentPlan;
const deleteAction = new DeletePlan({ roadmapId }); const deleteAction = new DeletePlan({ roadmapId });
this.store.dispatch(deleteAction); this.store.dispatch(deleteAction);
......
...@@ -10,7 +10,6 @@ import { CourseItemComponent } from './shared/course-item/course-item.component' ...@@ -10,7 +10,6 @@ import { CourseItemComponent } from './shared/course-item/course-item.component'
import { NotesDialogComponent } from './dialogs/notes-dialog/notes-dialog.component'; import { NotesDialogComponent } from './dialogs/notes-dialog/notes-dialog.component';
import { DragDropModule } from '@angular/cdk/drag-drop'; import { DragDropModule } from '@angular/cdk/drag-drop';
import { RemoveCourseConfirmDialogComponent } from './dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component'; import { RemoveCourseConfirmDialogComponent } from './dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component';
import { ModifyPlanDialogComponent } from './dialogs/modify-plan-dialog/modify-plan-dialog.component';
import { YearContainerComponent } from '@app/degree-planner/year-container/year-container.component'; import { YearContainerComponent } from '@app/degree-planner/year-container/year-container.component';
import { CourseSearchComponent } from '@app/degree-planner/course-search/course-search.component'; import { CourseSearchComponent } from '@app/degree-planner/course-search/course-search.component';
...@@ -25,14 +24,9 @@ import { CourseSearchComponent } from '@app/degree-planner/course-search/course- ...@@ -25,14 +24,9 @@ import { CourseSearchComponent } from '@app/degree-planner/course-search/course-
SavedForLaterContainerComponent, SavedForLaterContainerComponent,
NotesDialogComponent, NotesDialogComponent,
RemoveCourseConfirmDialogComponent, RemoveCourseConfirmDialogComponent,
ModifyPlanDialogComponent,
YearContainerComponent, YearContainerComponent,
CourseSearchComponent, CourseSearchComponent,
], ],
entryComponents: [ entryComponents: [NotesDialogComponent, RemoveCourseConfirmDialogComponent],
NotesDialogComponent,
RemoveCourseConfirmDialogComponent,
ModifyPlanDialogComponent,
],
}) })
export class DegreePlannerModule {} export class DegreePlannerModule {}
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Component, Input, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
export type DialogMode =
| { mode: 'makePrimary' }
| { mode: 'delete'; name: string }
| { mode: 'rename'; oldName: string }
| { mode: 'create' };
@Component({
selector: 'cse-course-details-dialog',
templateUrl: './modify-plan-dialog.component.html',
})
export class ModifyPlanDialogComponent {
public form: FormGroup;
constructor(
private dialogRef: MatDialogRef<ModifyPlanDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: DialogMode,
) {
const initialName = this.data.mode === 'rename' ? this.data.oldName : '';
if (this.data.mode === 'rename' || this.data.mode === 'create') {
this.form = new FormGroup({
planName: new FormControl(initialName, Validators.required),
});
} else {
this.form = new FormGroup({});
}
}
onSubmit() {
switch (this.data.mode) {
case 'makePrimary':
case 'delete': {
this.dialogRef.close({ areYouSure: true });
break;
}
case 'rename':
case 'create': {
const name = `${this.form.value.planName}`;
this.dialogRef.close({ name });
break;
}
default:
this.dialogRef.close();
}
}
onCancel() {
this.dialogRef.close();
}
}
.dialog-text {
color: #7e7e7e;
font-size: 16px;
margin-top: 1.2em;
}
<div id="sidenav-container" fxLayout="column" fxLayout.sm="column"> <div id="sidenav-container" fxLayout="column" fxLayout.sm="column">
<mat-expansion-panel id="course-keys-container" expanded="true"> <mat-expansion-panel id="course-keys-container" expanded="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<h3>Course Key</h3> <h3>Course Key</h3>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<ul id="course-key-list"> <ul id="course-key-list">
<li><i class="material-icons in-progress-icon" matTooltip="Course in progress" matTooltipPosition="left">check_circle</i> Course is currently in progress</li> <li>
<li><i class="material-icons problem-icon" matTooltip="Course is waitlisted" matTooltipPosition="left">report_problem</i> Course is waitlisted</li> <i
<li><i class="material-icons error-icon" matTooltip="Course is incomplete" matTooltipPosition="left">error</i> Course is incomplete</li> class="material-icons in-progress-icon"
</ul> matTooltip="Course in progress"
</mat-expansion-panel> matTooltipPosition="left"
<mat-expansion-panel id="course-keys-container" expanded="true"> >check_circle</i
<mat-expansion-panel-header> >
<mat-panel-title> Course is currently in progress
<h3>Saved for later</h3> </li>
</mat-panel-title> <li>
</mat-expansion-panel-header> <i
<cse-saved-for-later-container></cse-saved-for-later-container> class="material-icons problem-icon"
</mat-expansion-panel> matTooltip="Course is waitlisted"
matTooltipPosition="left"
>report_problem</i
>
Course is waitlisted
</li>
<li>
<i
class="material-icons error-icon"
matTooltip="Course is incomplete"
matTooltipPosition="left"
>error</i
>
Course is incomplete
</li>
</ul>
</mat-expansion-panel>
<mat-expansion-panel id="course-keys-container" expanded="true">
<mat-expansion-panel-header>
<mat-panel-title>
<h3>Saved for later</h3>
</mat-panel-title>
</mat-expansion-panel-header>
<cse-saved-for-later-container></cse-saved-for-later-container>
</mat-expansion-panel>
<mat-expansion-panel id="menu-items-container" expanded="true"> <mat-expansion-panel id="menu-items-container" expanded="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<h3>Menu</h3> <h3>Menu</h3>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div> <div>
<button mat-button class="sidenav-link-btn"><i class="material-icons">print</i> Print</button> <button mat-button class="sidenav-link-btn">
<button mat-button class="sidenav-link-btn"> <i class="material-icons">print</i> Print
<svg class="material-icons" style="width:24px;height:24px" viewBox="0 0 24 24"> </button>
<path fill="#0479a8" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" /> <button mat-button class="sidenav-link-btn">
</svg> <svg
Download PDF class="material-icons"
</button> style="width:24px;height:24px"
<button mat-button class="sidenav-link-btn" (click)="addDegreePlan()"><i class="material-icons">add_box</i> Add Degree Plan</button> viewBox="0 0 24 24"
<button mat-button class="sidenav-link-btn" (click)="addAcademicYear()"> >
<svg class="material-icons" style="width:24px;height:24px" viewBox="0 0 24 24"> <path fill="#0479a8" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" />
<path fill="#0479a8" d="M19,19V7H5V19H19M16,1H18V3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1M11,9H13V12H16V14H13V17H11V14H8V12H11V9Z" /> </svg>
</svg> Download PDF
Add Academic Year </button>
</button> <button mat-button class="sidenav-link-btn" (click)="onCreatePlanClick()">
</div> <i class="material-icons">add_box</i> Add Degree Plan
</mat-expansion-panel> </button>
<button mat-button class="sidenav-link-btn" (click)="onAddAcademicYear()">
<svg
class="material-icons"
style="width:24px;height:24px"
viewBox="0 0 24 24"
>
<path
fill="#0479a8"
d="M19,19V7H5V19H19M16,1H18V3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1M11,9H13V12H16V14H13V17H11V14H8V12H11V9Z"
/>
</svg>
Add Academic Year
</button>
</div>
</mat-expansion-panel>
</div> </div>
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { FormGroup } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Observable } from 'rxjs';
// State management // State management
import { GlobalState } from '@app/core/state'; import { GlobalState } from '@app/core/state';
import { AddAcademicYearRequest } from '@app/degree-planner/store/actions/addAcademicYear.actions'; import { AddAcademicYearRequest } from '@app/degree-planner/store/actions/addAcademicYear.actions';
import { import { PromptDialogComponent } from '@app/shared/dialogs/prompt-dialog/prompt-dialog.component';
ModifyPlanDialogComponent,
DialogMode,
} from '@app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component';
import { CreatePlan } from '@app/degree-planner/store/actions/plan.actions'; import { CreatePlan } from '@app/degree-planner/store/actions/plan.actions';
@Component({ @Component({
...@@ -18,21 +18,34 @@ import { CreatePlan } from '@app/degree-planner/store/actions/plan.actions'; ...@@ -18,21 +18,34 @@ import { CreatePlan } from '@app/degree-planner/store/actions/plan.actions';
styleUrls: ['./sidenav-menu-item.component.scss'], styleUrls: ['./sidenav-menu-item.component.scss'],
}) })
export class SidenavMenuItemComponent { export class SidenavMenuItemComponent {
constructor(private store: Store<GlobalState>, public dialog: MatDialog) {} public inputForm: FormGroup;
public yearCodes$: Observable<string[]>;
constructor(
private store: Store<GlobalState>,
public dialog: MatDialog,
private snackBar: MatSnackBar,
) {}
public addAcademicYear() { public onAddAcademicYear() {
this.store.dispatch(new AddAcademicYearRequest()); this.store.dispatch(new AddAcademicYearRequest());
this.snackBar.open('New academic year has been created');
} }
public addDegreePlan() { public onCreatePlanClick() {
const data: DialogMode = { mode: 'create' };
this.dialog this.dialog
.open(ModifyPlanDialogComponent, { data }) .open(PromptDialogComponent, {
data: {
initialValue: name,
title: 'Add degree plan',
confirmText: 'Save',
inputName: 'i.e. Psychology',
},
})
.afterClosed() .afterClosed()
.subscribe((result: { name: string } | undefined) => { .subscribe((result: { confirmed: boolean; value: string }) => {
if (result !== undefined && typeof result.name === 'string') { const { confirmed, value } = result;
const name = result.name; if (confirmed) {
const action = new CreatePlan({ name, primary: false }); const action = new CreatePlan({ name: value, primary: false });
this.store.dispatch(action); this.store.dispatch(action);
} }
}); });
......
...@@ -54,7 +54,7 @@ export class CreatePlan implements Action { ...@@ -54,7 +54,7 @@ export class CreatePlan implements Action {
export class CreatePlanSuccess implements Action { export class CreatePlanSuccess implements Action {
public readonly type = PlanActionTypes.CreatePlanSuccess; public readonly type = PlanActionTypes.CreatePlanSuccess;
constructor(public payload: { newPlan: DegreePlan }) {} constructor(public payload: { newPlan: DegreePlan; newYears: YearMapping }) {}
} }
export class DeletePlan implements Action { export class DeletePlan implements Action {
......
...@@ -240,10 +240,27 @@ export class DegreePlanEffects { ...@@ -240,10 +240,27 @@ export class DegreePlanEffects {
@Effect() @Effect()
createPlan$ = this.actions$.pipe( createPlan$ = this.actions$.pipe(
ofType<CreatePlan>(PlanActionTypes.CreatePlan), ofType<CreatePlan>(PlanActionTypes.CreatePlan),
flatMap(action => { withLatestFrom(this.store$.select(selectors.selectSubjects)),
withLatestFrom(this.store$.select(selectors.selectActiveTermCodes)),
flatMap(([[action, subjects], activeTermCodes]) => {
const { name, primary } = action.payload; const { name, primary } = action.payload;
return this.api.createDegreePlan(name, primary).pipe( return this.api.createDegreePlan(name, primary).pipe(
map(newPlan => new CreatePlanSuccess({ newPlan })), flatMap(newPlan => {
const newYears = loadPlanYears(
this.api,
newPlan.roadmapId,
subjects,
activeTermCodes,
);
return forkJoinWithKeys({
newPlan: of(newPlan),
newYears,
});
}),
map(({ newPlan, newYears }) => {
return new CreatePlanSuccess({ newPlan, newYears });
}),
tap(() => { tap(() => {
const message = `New plan has been created`; const message = `New plan has been created`;
this.snackBar.open(message, undefined, { duration: 2000 }); this.snackBar.open(message, undefined, { duration: 2000 });
......
...@@ -14,6 +14,7 @@ import { ...@@ -14,6 +14,7 @@ import {
MakePlanPrimaryFailure, MakePlanPrimaryFailure,
ChangePlanNameSuccess, ChangePlanNameSuccess,
ChangePlanNameFailure, ChangePlanNameFailure,
CreatePlan,
CreatePlanSuccess, CreatePlanSuccess,
DeletePlanSuccess, DeletePlanSuccess,
PlanError, PlanError,
...@@ -67,6 +68,7 @@ type SupportedActions = ...@@ -67,6 +68,7 @@ type SupportedActions =
| RemoveSaveForLater | RemoveSaveForLater
| AddSaveForLater | AddSaveForLater
| AddAcademicYearRequest | AddAcademicYearRequest
| CreatePlan
| CreatePlanSuccess | CreatePlanSuccess
| MakePlanPrimary | MakePlanPrimary
| MakePlanPrimarySuccess | MakePlanPrimarySuccess
...@@ -90,6 +92,9 @@ export function degreePlannerReducer( ...@@ -90,6 +92,9 @@ export function degreePlannerReducer(
return { ...state, isLoadingPlan: false }; return { ...state, isLoadingPlan: false };
} }
case PlanActionTypes.CreatePlan: {
return { ...state, isLoadingPlan: true };
}
/** /**
* The `InitialPlanLoadResponse` action is triggered on initial Degree * The `InitialPlanLoadResponse` action is triggered on initial Degree
* Planner app load. It downloads a list of the user's degree plans and * Planner app load. It downloads a list of the user's degree plans and
...@@ -405,10 +410,13 @@ export function degreePlannerReducer( ...@@ -405,10 +410,13 @@ export function degreePlannerReducer(
} }
case PlanActionTypes.CreatePlanSuccess: { case PlanActionTypes.CreatePlanSuccess: {
const { newPlan } = action.payload; const { newPlan, newYears } = action.payload;
return { return {
...state, ...state,
visibleDegreePlan: newPlan,
visibleYears: newYears,
allDegreePlans: state.allDegreePlans.concat(newPlan), allDegreePlans: state.allDegreePlans.concat(newPlan),
isLoadingPlan: false,
}; };
} }
......
<div id="confirmation-dialog" class="mat-dialog-content mat-typography"> <mat-toolbar class="dialog-toolbar">
<h1 mat-dialog-title>{{title}}</h1> <h1 class="dialog-toolbar-title">{{ title }}</h1>
<mat-dialog-content> <button
<p class="dialog-text" *ngFor="let line of text">{{line}}</p> mat-button
</mat-dialog-content> mat-dialog-close
<mat-dialog-actions align="end"> class="close-btn"
<button mat-button (click)="cancel()" aria-label="Cancel">{{cancelText}}</button> aria-label="Close note dialog"
<button mat-button [color]="confirmColor" class="mat-button" mat-raised-button (click)="confirm()" aria-label="Confirm">{{confirmText}}</button> >
</mat-dialog-actions> <i class="material-icons">clear</i>
</div> </button>
\ No newline at end of file </mat-toolbar>
<mat-dialog-content
id="confirmation-dialog"
class="mat-typography dialog-with-toolbar"
>
<mat-dialog-content>
<p class="dialog-text" *ngFor="let line of text">{{ line }}</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button
class="confirm-button"
mat-button
(click)="cancel()"
aria-label="Cancel"
>
{{ cancelText }}
</button>
<button
mat-button
class="confirm-button"
mat-raised-button
(click)="confirm()"
aria-label="Confirm"
>
{{ confirmText }}
</button>
</mat-dialog-actions>
</mat-dialog-content>
...@@ -19,7 +19,7 @@ export class ConfirmDialogComponent { ...@@ -19,7 +19,7 @@ export class ConfirmDialogComponent {
) { ) {
const { const {
title = 'Are you sure?', title = 'Are you sure?',
text = 'Are you sure you want to do this?', text = '',
cancelText = 'Cancel', cancelText = 'Cancel',
confirmText = 'Confirm', confirmText = 'Confirm',
confirmColor = 'primary', confirmColor = 'primary',
......
...@@ -7,3 +7,14 @@ ...@@ -7,3 +7,14 @@
margin: 0; margin: 0;
width: 400px; width: 400px;
} }
.confirm-button {
box-shadow: none;
text-transform: uppercase;
color: #0479a8;
}
.mat-button,
button.mat-primary {
text-transform: uppercase;
}
<mat-toolbar color="primary" class="dialog-toolbar"> <mat-toolbar color="primary" class="dialog-toolbar">
<h1 class="dialog-toolbar-title">{{title}}</h1> <h1 class="dialog-toolbar-title">{{ title }}</h1>
<button mat-button mat-dialog-close class="close-btn" aria-label="Close note dialog"><i class="material-icons">clear</i></button> <button
mat-button
mat-dialog-close
class="close-btn"
aria-label="Close dialog"
>
<i class="material-icons">clear</i>
</button>
</mat-toolbar> </mat-toolbar>
<mat-dialog-content id="confirmation-dialog" class="mat-typography dialog-with-toolbar"> <mat-dialog-content
<mat-dialog-content> id="confirmation-dialog"
<p class="dialog-text" *ngFor="let line of text">{{line}}</p> class="mat-typography dialog-with-toolbar"
>
<mat-dialog-content>
<p class="dialog-text" *ngFor="let line of text">{{ line }}</p>
<form [formGroup]='inputForm' (ngSubmit)="confirm()" fxLayout="column" fxLayoutAlign="space-around none" style="padding: 12px 22px;"> <form
<mat-form-field> [formGroup]="inputForm"
<input matInput [placeholder]="inputName" formControlName="value"> (ngSubmit)="confirm()"
</mat-form-field> fxLayout="column"
</form> fxLayoutAlign="space-around none"
</mat-dialog-content> style="padding: 12px 22px;"
<mat-dialog-actions align="end"> >
<button mat-button class="btn-secondary" (click)="cancel()" aria-label="Cancel">{{cancelText}}</button> <mat-form-field>
<button mat-button class="btn-primary mat-button" mat-raised-button (click)="confirm()" aria-label="Confirm">{{confirmText}}</button> <input matInput [placeholder]="inputName" formControlName="value" />
</mat-dialog-actions> </mat-form-field>
</mat-dialog-content> </form>
\ No newline at end of file </mat-dialog-content>
<mat-dialog-actions align="end">
<button
mat-button
class="btn-secondary mat-button"
(click)="cancel()"
aria-label="Cancel"
>
{{ cancelText }}
</button>
<button
mat-buttondialogs
with
differe
[color]="confirmColor"
mat-raised-button
(click)="confirm()"
aria-label="Confirm"
[disabled]="inputForm.invalid"
>
{{ confirmText }}
</button>
</mat-dialog-actions>
</mat-dialog-content>
.mat-dialog-content {
padding: 30px 24px 6px 24px !important;
}
...@@ -8,6 +8,8 @@ import { ...@@ -8,6 +8,8 @@ import {
FormControl, FormControl,
Validators, Validators,
} from '@angular/forms'; } from '@angular/forms';
import { Observable } from 'rxjs';
import { Year } from '@app/core/models/year';
@Component({ @Component({
selector: 'cse-prompt-dialog', selector: 'cse-prompt-dialog',
...@@ -23,10 +25,10 @@ export class PromptDialogComponent implements OnInit { ...@@ -23,10 +25,10 @@ export class PromptDialogComponent implements OnInit {
cancelText: string; cancelText: string;
confirmText: string; confirmText: string;
confirmColor: string; confirmColor: string;
public termsByYear$: Observable<Year[]>;
inputForm: FormGroup; inputForm: FormGroup;
initalValue: string; initialValue: string;
constructor( constructor(
private dialogRef: MatDialogRef<PromptDialogComponent>, private dialogRef: MatDialogRef<PromptDialogComponent>,
private fb: FormBuilder, private fb: FormBuilder,
...@@ -36,7 +38,7 @@ export class PromptDialogComponent implements OnInit { ...@@ -36,7 +38,7 @@ export class PromptDialogComponent implements OnInit {
title = 'User Input Required', title = 'User Input Required',
text = [], text = [],
inputName = 'Data', inputName = 'Data',
initalValue = '', initialValue = '',
placeholder, placeholder,
tooltip, tooltip,
cancelText = 'Cancel', cancelText = 'Cancel',
...@@ -52,7 +54,7 @@ export class PromptDialogComponent implements OnInit { ...@@ -52,7 +54,7 @@ export class PromptDialogComponent implements OnInit {
this.cancelText = cancelText; this.cancelText = cancelText;
this.confirmText = confirmText; this.confirmText = confirmText;
this.confirmColor = confirmColor; this.confirmColor = confirmColor;
this.initalValue = initalValue; this.initialValue = initialValue;
if (typeof text === 'string') { if (typeof text === 'string') {
this.text = [text]; this.text = [text];
...@@ -62,7 +64,7 @@ export class PromptDialogComponent implements OnInit { ...@@ -62,7 +64,7 @@ export class PromptDialogComponent implements OnInit {
ngOnInit() { ngOnInit() {
// Deafults for input form // Deafults for input form
this.inputForm = this.fb.group({ this.inputForm = this.fb.group({
value: this.initalValue, value: [this.initialValue, Validators.required],
}); });
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment