diff --git a/src/app/degree-planner/degree-planner.component.html b/src/app/degree-planner/degree-planner.component.html index 5c0face0792555d1cb3a4f624073b10e92057c07..e9d1a549420d7562a4671622165a8847d4a06483 100644 --- a/src/app/degree-planner/degree-planner.component.html +++ b/src/app/degree-planner/degree-planner.component.html @@ -1,4 +1,4 @@ -<mat-sidenav-container id="plans-container" *ngIf="hasLoadedDegreePlan$ | async"> +<mat-sidenav-container id="plans-container" *ngIf="(visibleDegreePlan$ | async) as degreePlan"> <!-- Menu side nav --> <mat-sidenav #rightMenu position="end" [mode]="mobileView.matches ? 'over' : 'side'" [opened]="mobileView.matches ? false : true"> <cse-sidenav-menu-item></cse-sidenav-menu-item> @@ -15,7 +15,7 @@ (selectionChange)="handleDegreePlanChange($event)"> <!-- Render the name of the currently visible degree plan. --> - <mat-select-trigger *ngIf="(visibleDegreePlan$ | async) as degreePlan"> + <mat-select-trigger> <mat-icon class="primary-star" *ngIf="degreePlan.primary">star_rate</mat-icon> <span class="plan-name">{{degreePlan.name}}</span> </mat-select-trigger> @@ -33,12 +33,12 @@ </button> <mat-menu #degreePlanMenu="matMenu"> <button mat-menu-item (click)="onCreatePlanClick()">Create new plan</button> - <button mat-menu-item (click)="onRenamePlanClick()">Rename plan</button> - <button mat-menu-item (click)="onDeletePlanClick()">Delete plan</button> - <button mat-menu-item (click)="onMakePrimayClick()">Make primary</button> + <button mat-menu-item (click)="onRenamePlanClick(degreePlan)">Rename plan</button> + <button mat-menu-item (click)="onDeletePlanClick(degreePlan)">Delete plan</button> + <button mat-menu-item (click)="onMakePrimayClick(degreePlan)">Make primary</button> <hr> - <button mat-menu-item (click)="onPrintPlanClick()">Print plan</button> - <button mat-menu-item (click)="onSharePlanClick()">Share plan</button> + <button mat-menu-item (click)="onPrintPlanClick(degreePlan)">Print plan</button> + <button mat-menu-item (click)="onSharePlanClick(degreePlan)">Share plan</button> </mat-menu> </div> diff --git a/src/app/degree-planner/degree-planner.component.ts b/src/app/degree-planner/degree-planner.component.ts index 1226c10021af6660be21ffe070033eb5b262cfe0..ac315541db6209c5b3c670c7e9cd8f9a0bd296ec 100644 --- a/src/app/degree-planner/degree-planner.component.ts +++ b/src/app/degree-planner/degree-planner.component.ts @@ -12,6 +12,7 @@ import { import { MatDialog } from '@angular/material'; import { Store } from '@ngrx/store'; import { MediaMatcher } from '@angular/cdk/layout'; +import { filter } from 'rxjs/operators'; // Models import { GlobalState } from '@app/core/state'; @@ -25,16 +26,20 @@ import { firstActiveTermCode, getAllVisibleTermsByYear, getVisibleDegreePlan, - hasLoadedDegreePlan, } from '@app/degree-planner/store/selectors'; // Actions import { SwitchPlan, MakePlanPrimary, + CreatePlan, + ChangePlanName, } from '@app/degree-planner/store/actions/plan.actions'; -import { ModifyPlanDialogComponent } from './dialogs/modify-plan-dialog/modify-plan-dialog.component'; +import { + ModifyPlanDialogComponent, + DialogMode, +} from './dialogs/modify-plan-dialog/modify-plan-dialog.component'; import { ToggleAcademicYear } from './store/actions/ui.actions'; @Component({ @@ -47,9 +52,8 @@ export class DegreePlannerComponent implements OnInit { public mobileView: MediaQueryList; public coursesData$: any; - public hasLoadedDegreePlan$: Observable<boolean>; public visibleRoadmapId$: Observable<number | undefined>; - public visibleDegreePlan$: Observable<DegreePlan | undefined>; + public visibleDegreePlan$: Observable<DegreePlan>; public allDegreePlans$: Observable<DegreePlan[]>; public firstActiveTermCode$: Observable<string | undefined>; public termsByYear$: Observable<Year[]>; @@ -63,9 +67,11 @@ export class DegreePlannerComponent implements OnInit { } public ngOnInit() { - this.hasLoadedDegreePlan$ = this.store.pipe(select(hasLoadedDegreePlan)); this.visibleRoadmapId$ = this.store.pipe(select(getVisibleRoadmapId)); - this.visibleDegreePlan$ = this.store.pipe(select(getVisibleDegreePlan)); + this.visibleDegreePlan$ = this.store.pipe( + select(getVisibleDegreePlan), + filter(isntUndefined), + ); this.allDegreePlans$ = this.store.pipe(select(getAllDegreePlans)); this.firstActiveTermCode$ = this.store.pipe(select(firstActiveTermCode)); this.termsByYear$ = this.store.pipe(select(getAllVisibleTermsByYear)); @@ -84,22 +90,37 @@ export class DegreePlannerComponent implements OnInit { } public onCreatePlanClick() { - // TODO - console.log('onCreatePlanClick'); - const data = {}; - this.dialog.open(ModifyPlanDialogComponent, { data }); + const data: DialogMode = { mode: 'create' }; + this.dialog + .open(ModifyPlanDialogComponent, { data }) + .afterClosed() + .subscribe((result: { name: string } | undefined) => { + if (result !== undefined && typeof result.name === 'string') { + const name = result.name; + const action = new CreatePlan({ name, primary: false }); + this.store.dispatch(action); + } + }); } - public onRenamePlanClick() { - // TODO - console.log('onRenamePlanClick'); - const data = {}; - this.dialog.open(ModifyPlanDialogComponent, { data }); + public onRenamePlanClick(currentPlan: DegreePlan) { + const data: DialogMode = { mode: 'rename', oldName: currentPlan.name }; + this.dialog + .open(ModifyPlanDialogComponent, { data }) + .afterClosed() + .subscribe((result: { name: string } | undefined) => { + if (result !== undefined && typeof result.name === 'string') { + const newName = result.name; + const { roadmapId } = currentPlan; + const action = new ChangePlanName({ roadmapId, newName }); + this.store.dispatch(action); + } + }); } - public onMakePrimayClick() { - // TODO open confirm dialog - this.store.dispatch(new MakePlanPrimary()); + public onMakePrimayClick(currentPlan: DegreePlan) { + // TODO + console.warn('onMakePrimayClick'); } public onDeletePlanClick() { @@ -137,3 +158,7 @@ export class DegreePlannerComponent implements OnInit { return termCodes; } } + +const isntUndefined = <T>(anything: T | undefined): anything is T => { + return anything !== undefined; +}; diff --git a/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.html b/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.html index 69d7213e25ca5bdf145771f3aa3254e077ea1870..901be641ff6d05625be80822dd4f33186cc0e162 100644 --- a/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.html +++ b/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.html @@ -6,22 +6,18 @@ </style> <mat-toolbar color="primary" class="dialog-toolbar"> - <span class="dialog-toolbar-title">Modify Plan</span> + <span class="dialog-toolbar-title" [ngSwitch]="data.mode"> + <span *ngSwitchCase="'rename'">Rename plan</span> + <span *ngSwitchCase="'create'">Create plan</span> + </span> <button mat-button mat-dialog-close class="close-btn"> <i class="material-icons">clear</i> </button> </mat-toolbar> <mat-dialog-content class="mat-typography dialog-with-toolbar"> - <div class="create-plan-content" *ngIf="true"> - <mat-dialog-content [formGroup]="form"> - <mat-form-field class="form-field-stretch"> - <input matInput placeholder="Name" formControlName="planName"> - </mat-form-field> - </mat-dialog-content> - </div> - - <div class="rename-plan-content" *ngIf="false"> + <ng-container [ngSwitch]="data.mode"> + <div class="rename-plan-content" *ngSwitchCase="'rename'"> <mat-dialog-content [formGroup]="form"> <mat-form-field class="form-field-stretch"> <input matInput placeholder="Name" formControlName="planName"> @@ -29,25 +25,25 @@ </mat-dialog-content> </div> - <div class="delete-plan-content" *ngIf="false"> + <div class="create-plan-content" *ngSwitchCase="'create'"> <mat-dialog-content [formGroup]="form"> - <mat-form-field> + <mat-form-field class="form-field-stretch"> <input matInput placeholder="Name" formControlName="planName"> </mat-form-field> </mat-dialog-content> </div> + </ng-container> - <div class="make-plan-primary-content" *ngIf="false"> - <mat-dialog-content [formGroup]="form"> - <mat-form-field> - <input matInput placeholder="Name" formControlName="planName"> - </mat-form-field> - </mat-dialog-content> - </div> + <mat-dialog-actions align="end"> + <button mat-button class="btn-secondary" mat-dialog-close aria-label="Close note dialog" (click)="onCancel()"> + Cancel + </button> - <mat-dialog-actions align="end"> - <button mat-button class="btn-secondary" mat-dialog-close aria-label="Close note dialog"> Cancel </button> - <button mat-raised-button class="btn-primary mat-button" (click)="createPlanSave()" *ngIf="false">Save</button> - <button mat-raised-button class="btn-primary mat-button" (click)="renamePlanSave()">Save</button> - </mat-dialog-actions> -</mat-dialog-content> \ No newline at end of file + <button mat-rasied-button class="btn-primary mat-button" [disabled]="form.invalid" (click)="onSubmit()"> + <ng-container [ngSwitch]="data.mode"> + <span *ngSwitchCase="'rename'">Rename plan</span> + <span *ngSwitchCase="'create'">Create plan</span> + </ng-container> + </button> + </mat-dialog-actions> +</mat-dialog-content> diff --git a/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.ts b/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.ts index 125dc019188fdd5ccedc161daf44d7a5e1b407c6..15814424e3996b0f058cde5236f40160278253ba 100644 --- a/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.ts +++ b/src/app/degree-planner/dialogs/modify-plan-dialog/modify-plan-dialog.component.ts @@ -1,37 +1,42 @@ -import { FormGroup, FormControl } from '@angular/forms'; -import { Component, OnInit } from '@angular/core'; -import { Store } from '@ngrx/store'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; +import { Component, Input, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; -// Models -import { GlobalState } from '@app/core/state'; - -// Actions -import { ChangePlanName } from '@app/degree-planner/store/actions/plan.actions'; +export type DialogMode = + | { mode: 'rename'; oldName: string } + | { mode: 'create' }; @Component({ selector: 'cse-course-details-dialog', templateUrl: './modify-plan-dialog.component.html', }) -export class ModifyPlanDialogComponent implements OnInit { +export class ModifyPlanDialogComponent { public form: FormGroup; - constructor(private store: Store<GlobalState>) { + constructor( + private dialogRef: MatDialogRef<ModifyPlanDialogComponent>, + @Inject(MAT_DIALOG_DATA) public data: DialogMode, + ) { + const initialName = this.data.mode === 'rename' ? this.data.oldName : ''; this.form = new FormGroup({ - planName: new FormControl(), + planName: new FormControl(initialName, Validators.required), }); } - ngOnInit() {} - - renamePlanSave() { - this.store.dispatch(new ChangePlanName(this.form.value.planName)); - console.log('PUT /degreePlan/<planId> { primary: <bool>, name: <string> }'); + onSubmit() { + switch (this.data.mode) { + case 'rename': + this.dialogRef.close({ name: `${this.form.value.planName}` }); + break; + case 'create': + this.dialogRef.close({ name: `${this.form.value.planName}` }); + break; + default: + this.dialogRef.close(); + } } - makePlanPrimarySave() { - // Open confirm dialog - console.log('PUT /degreePlan/<planId> { primary: true, name: <string> }'); - } - createPlanSave() { - console.log('POST /degreePlan { primary: <bool>, name: <string> }'); + + onCancel() { + this.dialogRef.close(); } } diff --git a/src/app/degree-planner/services/api.service.ts b/src/app/degree-planner/services/api.service.ts index 6f67da514da40fde7bad003ad1edab46b73a91c1..f2203e481590197b5923db8eadb359c5bc76f598 100644 --- a/src/app/degree-planner/services/api.service.ts +++ b/src/app/degree-planner/services/api.service.ts @@ -32,6 +32,17 @@ export class DegreePlannerApiService { ); } + public createDegreePlan(name: string, primary: boolean = false) { + const url = `${this.config.apiPlannerUrl}/degreePlan`; + const payload = { name, primary }; + return this.http.post<DegreePlan>(url, payload); + } + + public deleteDegreePlan(roadmapId: number) { + const url = `${this.config.apiPlannerUrl}/degreePlan/${roadmapId}`; + return this.http.delete<void>(url); + } + public getAllDegreePlans(): Observable<DegreePlan[]> { return this.http.get<DegreePlan[]>(this.degreePlanEndpoint()); } @@ -188,8 +199,8 @@ export class DegreePlannerApiService { planId: number, name: string, primary: boolean, - ): Observable<Object> { - return this.http.put( + ): Observable<1> { + return this.http.put<1>( this.degreePlanEndpoint(planId), { name, primary }, HTTP_OPTIONS, diff --git a/src/app/degree-planner/store/actions/plan.actions.ts b/src/app/degree-planner/store/actions/plan.actions.ts index 53a4098e6975ed9d5f7b85d5de9e16420013e009..25548f97e3119f46ca81b1a7a00f5473831b394f 100644 --- a/src/app/degree-planner/store/actions/plan.actions.ts +++ b/src/app/degree-planner/store/actions/plan.actions.ts @@ -9,15 +9,21 @@ export enum PlanActionTypes { SwitchPlan = '[Plan] Switch', SwitchPlanSuccess = '[Plan] Switch (Success)', + CreatePlan = '[Plan] Create', + CreatePlanSuccess = '[Plan] Create (Success)', + + DeletePlan = '[Plan] Delete', + DeletePlanSuccess = '[Plan] Delete (Success)', + PlanError = '[Plan] Error', MakePlanPrimary = '[Plan] Make Plan Primary', - MakePlanPrimarySuccess = '[Plan] Make Plan Primary Success', - MakePlanPrimaryFailure = '[Plan] Make Plan Primary Failure', + MakePlanPrimarySuccess = '[Plan] Make Plan Primary (Success)', + MakePlanPrimaryFailure = '[Plan] Make Plan Primary (Failure)', ChangePlanName = '[Plan] Change Plan Name', - ChangePlanNameSuccess = '[Plan] Change Plan Name Success', - ChangePlanNameFailure = '[Plan] Change Plan Name Failure', + ChangePlanNameSuccess = '[Plan] Change Plan Name (Success)', + ChangePlanNameFailure = '[Plan] CHange Plan Name (Failure)', } export class InitialLoadSuccess implements Action { @@ -40,6 +46,26 @@ export class SwitchPlanSuccess implements Action { ) {} } +export class CreatePlan implements Action { + public readonly type = PlanActionTypes.CreatePlan; + constructor(public payload: { name: string; primary: boolean }) {} +} + +export class CreatePlanSuccess implements Action { + public readonly type = PlanActionTypes.CreatePlanSuccess; + constructor(public payload: { newPlan: DegreePlan }) {} +} + +export class DeletePlan implements Action { + public readonly type = PlanActionTypes.DeletePlan; + constructor(public payload: { roadmapId: number }) {} +} + +export class DeletePlanSuccess implements Action { + public readonly type = PlanActionTypes.DeletePlanSuccess; + constructor(public payload: { roadmapId: number }) {} +} + export class PlanError implements Action { public readonly type = PlanActionTypes.PlanError; constructor(public payload: { message: string; error: any }) {} @@ -47,30 +73,27 @@ export class PlanError implements Action { export class MakePlanPrimary implements Action { public readonly type = PlanActionTypes.MakePlanPrimary; - constructor() {} } export class MakePlanPrimarySuccess implements Action { public readonly type = PlanActionTypes.MakePlanPrimarySuccess; - constructor() {} } export class MakePlanPrimaryFailure implements Action { public readonly type = PlanActionTypes.MakePlanPrimaryFailure; - constructor() {} } export class ChangePlanName implements Action { public readonly type = PlanActionTypes.ChangePlanName; - constructor(public name: string) {} + constructor(public payload: { roadmapId: number; newName: string }) {} } export class ChangePlanNameSuccess implements Action { public readonly type = PlanActionTypes.ChangePlanNameSuccess; - constructor(public name: string) {} + constructor(public payload: { roadmapId: number; newName: string }) {} } export class ChangePlanNameFailure implements Action { public readonly type = PlanActionTypes.ChangePlanNameFailure; - constructor(public name: string) {} + constructor(public payload: { roadmapId: number; oldName: string }) {} } diff --git a/src/app/degree-planner/store/effects/plan.effects.ts b/src/app/degree-planner/store/effects/plan.effects.ts index c590aae968e3fcf9eaf61a7f96850650a5213718..ca23f5367e9ebac342b890150b83f4bf208f6e88 100644 --- a/src/app/degree-planner/store/effects/plan.effects.ts +++ b/src/app/degree-planner/store/effects/plan.effects.ts @@ -11,7 +11,7 @@ import { filter, } from 'rxjs/operators'; import { GlobalState } from '@app/core/state'; -import { Store } from '@ngrx/store'; +import { Store, Action } from '@ngrx/store'; // Services import { DegreePlannerApiService } from '@app/degree-planner/services/api.service'; @@ -24,10 +24,16 @@ import { SwitchPlanSuccess, PlanActionTypes, PlanError, + MakePlanPrimary, MakePlanPrimarySuccess, MakePlanPrimaryFailure, + ChangePlanName, ChangePlanNameSuccess, ChangePlanNameFailure, + CreatePlan, + CreatePlanSuccess, + DeletePlan, + DeletePlanSuccess, } from '@app/degree-planner/store/actions/plan.actions'; // Models @@ -35,6 +41,7 @@ import { DegreePlan } from '@app/core/models/degree-plan'; import { PlannedTerm } from '@app/core/models/planned-term'; import { SubjectMapping } from '@app/core/models/course'; import { SavedForLaterCourse } from '@app/core/models/saved-for-later-course'; +import { DegreePlannerState } from '@app/degree-planner/store/state'; @Injectable() export class DegreePlanEffects { @@ -134,27 +141,19 @@ export class DegreePlanEffects { @Effect() MakePlanPrimary$ = this.actions$.pipe( - ofType<any>(PlanActionTypes.MakePlanPrimary), + ofType<MakePlanPrimary>(PlanActionTypes.MakePlanPrimary), withLatestFrom(this.store$.select(getDegreePlannerState)), filter(([_, state]) => state.visibleDegreePlan !== undefined), // Get term data for the degree plan specified by the roadmap ID. - flatMap(([action, state]) => { + flatMap(([_action, state]) => { const { roadmapId, name } = state.visibleDegreePlan as DegreePlan; - // TODO error handle the API calls - return this.api.updatePlan(roadmapId, name, true).pipe( - map(response => { - return { - response, - action, - }; - }), - ); + return this.api.updatePlan(roadmapId, name, true); }), // // Wrap data in an Action for dispatch - map(({ response, action }) => { + map(response => { if (response === 1) { return new MakePlanPrimarySuccess(); } else { @@ -165,41 +164,47 @@ export class DegreePlanEffects { @Effect() ChangePlanName$ = this.actions$.pipe( - ofType<any>(PlanActionTypes.ChangePlanName), - + ofType<ChangePlanName>(PlanActionTypes.ChangePlanName), withLatestFrom(this.store$.select(getDegreePlannerState)), - filter(([_, state]) => state.visibleDegreePlan !== undefined), - - // Get term data for the degree plan specified by the roadmap ID. flatMap(([action, state]) => { - console.log(action); - const { name } = action; - - const { - roadmapId, - name: previousName, - primary, - } = state.visibleDegreePlan as DegreePlan; - - action.previousName = previousName; - // TODO error handle the API calls - return this.api.updatePlan(roadmapId, name, primary).pipe( - map(response => { - return { - response, - action, - }; - }), - ); + const { roadmapId, newName } = action.payload; + const oldDegreePlan = state.allDegreePlans.find(plan => { + return plan.roadmapId === roadmapId; + }) as DegreePlan; + const oldName = oldDegreePlan.name; + + return this.api + .updatePlan(roadmapId, newName, oldDegreePlan.primary) + .pipe( + map(() => { + return new ChangePlanNameSuccess({ roadmapId, newName }); + }), + catchError(() => { + return of(new ChangePlanNameFailure({ roadmapId, oldName })); + }), + ); }), + ); - // // Wrap data in an Action for dispatch - map(({ response, action }) => { - if (response === 1) { - return new ChangePlanNameSuccess(action.name); - } else { - return new ChangePlanNameFailure(action.previousName); - } + @Effect() + createPlan$ = this.actions$.pipe( + ofType<CreatePlan>(PlanActionTypes.CreatePlan), + flatMap(action => { + const { name, primary } = action.payload; + return this.api + .createDegreePlan(name, primary) + .pipe(map(newPlan => new CreatePlanSuccess({ newPlan }))); + }), + ); + + @Effect() + deletePlan$ = this.actions$.pipe( + ofType<DeletePlan>(PlanActionTypes.DeletePlan), + flatMap(action => { + const { roadmapId } = action.payload; + return this.api + .deleteDegreePlan(roadmapId) + .pipe(map(() => new DeletePlanSuccess({ roadmapId }))); }), ); @@ -295,3 +300,9 @@ const pickPrimaryDegreePlan = (plans: DegreePlan[]): DegreePlan => { const checkExpanded = (activeTermCodes, visibleTerms) => { console.log(visibleTerms); }; + +const hasVisibleDegreePlan = <T extends Action>( + pair: [T, DegreePlannerState], +): pair is [T, { visibleDegreePlan: DegreePlan } & DegreePlannerState] => { + return pair[1].visibleDegreePlan !== undefined; +}; diff --git a/src/app/degree-planner/store/reducer.ts b/src/app/degree-planner/store/reducer.ts index 08e3c4615786ec5d83ae96247138c5b40ed1534e..a239988ac51ad25e37074c7ad6d56dd85f7b3801 100644 --- a/src/app/degree-planner/store/reducer.ts +++ b/src/app/degree-planner/store/reducer.ts @@ -12,6 +12,8 @@ import { MakePlanPrimaryFailure, ChangePlanNameSuccess, ChangePlanNameFailure, + CreatePlan, + CreatePlanSuccess, } from '@app/degree-planner/store/actions/plan.actions'; import { CourseActionTypes, @@ -45,6 +47,7 @@ type SupportedActions = | RemoveSaveForLaterSuccess | AddSaveForLaterSuccess | AddAcademicYearRequest + | CreatePlanSuccess | MakePlanPrimary | MakePlanPrimarySuccess | MakePlanPrimaryFailure @@ -262,6 +265,14 @@ export function degreePlannerReducer( return { ...state, savedForLaterCourses: newSavedForLater }; } + case PlanActionTypes.CreatePlanSuccess: { + const { newPlan } = action.payload; + return { + ...state, + allDegreePlans: state.allDegreePlans.concat(newPlan), + }; + } + case PlanActionTypes.MakePlanPrimary: { // TODO add global loading state return state; @@ -298,17 +309,42 @@ export function degreePlannerReducer( return state; } - case PlanActionTypes.ChangePlanNameSuccess: - case PlanActionTypes.ChangePlanNameFailure: { - // TODO add global loading state + case PlanActionTypes.ChangePlanNameSuccess: { + const visibleDegreePlan = { + ...(state.visibleDegreePlan as DegreePlan), + name: action.payload.newName, + }; - // Update the visible plan object - const newVisibleDegreePlan = { + return { + ...state, + allDegreePlans: state.allDegreePlans.map(plan => { + if (plan.roadmapId === action.payload.roadmapId) { + return { ...plan, name: action.payload.newName }; + } else { + return plan; + } + }), + visibleDegreePlan, + }; + } + + case PlanActionTypes.ChangePlanNameFailure: { + const visibleDegreePlan = { ...(state.visibleDegreePlan as DegreePlan), - name: action.name, + name: action.payload.oldName, }; - return { ...state, visibleDegreePlan: newVisibleDegreePlan }; + return { + ...state, + allDegreePlans: state.allDegreePlans.map(plan => { + if (plan.roadmapId === action.payload.roadmapId) { + return { ...plan, name: action.payload.oldName }; + } else { + return plan; + } + }), + visibleDegreePlan, + }; } /**