From 3c93e247f8e177951783136bd1acee4a703f9107 Mon Sep 17 00:00:00 2001
From: ievavold <ievavold@wisc.edu>
Date: Mon, 10 Jun 2019 09:57:31 -0500
Subject: [PATCH] move user preferences to core module

---
 src/app/app.component.ts                      |  6 ++++
 src/app/app.module.ts                         | 10 -------
 src/app/core/actions.ts                       | 20 +++++++++----
 src/app/core/core.module.ts                   |  6 ++++
 src/app/core/effects.ts                       | 19 +++++++++----
 src/app/core/reducer.ts                       | 14 ++++++++--
 src/app/dars/dars.module.ts                   |  3 ++
 src/app/dars/store/effects.ts                 | 28 ++-----------------
 .../degree-planner/degree-planner.module.ts   |  3 ++
 .../store/effects/plan.effects.ts             | 16 ++++-------
 src/app/degree-planner/store/reducer.ts       |  2 +-
 src/app/degree-planner/store/selectors.ts     |  1 -
 12 files changed, 68 insertions(+), 60 deletions(-)

diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 3c9473c..e47a23e 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -9,6 +9,9 @@ import {
 } from '@angular/forms';
 import { Course } from '@app/core/models/course';
 import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
+import { Store } from '@ngrx/store';
+import { GlobalState } from './core/state';
+import { Initialize } from './core/actions';
 
 @Component({
   selector: 'cse-root',
@@ -28,6 +31,7 @@ export class AppComponent implements OnInit {
     public dialog: MatDialog,
     private fb: FormBuilder,
     private api: DegreePlannerApiService,
+    private store: Store<GlobalState>,
   ) {
     this.subjectCode = new FormControl('', [Validators.required]);
     this.coursesForm = this.fb.group({
@@ -36,6 +40,8 @@ export class AppComponent implements OnInit {
   }
 
   ngOnInit() {
+    this.store.dispatch(new Initialize());
+
     this.api.getUserProfile().subscribe(profile => {
       const customEvent = new CustomEvent('myuw-login', {
         detail: {
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index eb358f3..32d6cb3 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -18,23 +18,13 @@ import { FeedbackDialogComponent } from './degree-planner/dialogs/feedback-dialo
 import { CreditOverloadDialogComponent } from './degree-planner/dialogs/credit-overload-dialog/credit-overload-dialog.component';
 import { GoogleAnalyticsService } from './shared/services/google-analytics.service';
 import { IE11WarningDialogComponent } from './degree-planner/dialogs/ie11-warning-dialog/ie11-warning-dialog.component';
-import { darsReducer } from './dars/store/reducer';
 import { DARSModule } from './dars/dars.module';
 import { DegreePlannerModule } from './degree-planner/degree-planner.module';
-import { preferencesReducer } from './core/reducer';
-import { UserPreferencesEffects } from './core/effects';
-import { EffectsModule } from '@ngrx/effects';
 
 @NgModule({
   imports: [
     DARSModule,
     DegreePlannerModule,
-    StoreModule.forRoot({
-      preferences: preferencesReducer,
-      degreePlanner: degreePlannerReducer,
-      dars: darsReducer,
-    }),
-    EffectsModule.forFeature([UserPreferencesEffects]),
     BrowserModule,
     BrowserAnimationsModule,
     HttpClientModule,
diff --git a/src/app/core/actions.ts b/src/app/core/actions.ts
index 0b224cb..44d6a52 100644
--- a/src/app/core/actions.ts
+++ b/src/app/core/actions.ts
@@ -1,20 +1,30 @@
 import { Action } from '@ngrx/store';
 import { UserPreferences } from '@app/core/models/user-preferences';
 
-export enum UserPreferencesActionTypes {
+export enum CoreActionTypes {
+  Initialize = '[Core] Initialize',
+
+  PopulateUserPreferences = '[User Preferences] Populate',
   UpdateUserPreferences = '[User Preferences] Update',
+
+  DismissAlert = '[UI] Dismiss Alert',
+}
+
+export class Initialize implements Action {
+  public readonly type = CoreActionTypes.Initialize;
 }
 
-export enum NotificationActionTypes {
-  DismissAlert = '[UI] Dismiss alert',
+export class InitializeUserPreferences implements Action {
+  public readonly type = CoreActionTypes.PopulateUserPreferences;
+  constructor(public payload: { preferences: UserPreferences }) {}
 }
 
 export class UpdateUserPreferences implements Action {
-  public readonly type = UserPreferencesActionTypes.UpdateUserPreferences;
+  public readonly type = CoreActionTypes.UpdateUserPreferences;
   constructor(public payload: Partial<UserPreferences>) {}
 }
 
 export class DismissAlert implements Action {
-  public readonly type = NotificationActionTypes.DismissAlert;
+  public readonly type = CoreActionTypes.DismissAlert;
   constructor(public payload: { key: string }) {}
 }
diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts
index 628a950..96a2b0f 100644
--- a/src/app/core/core.module.ts
+++ b/src/app/core/core.module.ts
@@ -7,12 +7,18 @@ import { environment } from './../../environments/environment';
 import { SharedModule } from '../shared/shared.module';
 import { NavigationComponent } from './navigation/navigation.component';
 import { throwIfAlreadyLoaded } from './module-import-check';
+import { EffectsModule } from '@ngrx/effects';
+import { CoreEffects } from './effects';
+import { StoreModule } from '@ngrx/store';
+import { preferencesReducer } from './reducer';
 
 @NgModule({
   imports: [
     CommonModule, // we use *ngFor
     RouterModule, // we use router-outlet and routerLink
     SharedModule,
+    StoreModule.forRoot({ preferences: preferencesReducer }),
+    EffectsModule.forFeature([CoreEffects]),
   ],
   exports: [NavigationComponent],
   declarations: [NavigationComponent],
diff --git a/src/app/core/effects.ts b/src/app/core/effects.ts
index 5a29880..bc43990 100644
--- a/src/app/core/effects.ts
+++ b/src/app/core/effects.ts
@@ -1,23 +1,32 @@
 import { Injectable } from '@angular/core';
 import { Actions, Effect, ofType } from '@ngrx/effects';
-import { tap, withLatestFrom } from 'rxjs/operators';
+import { tap, withLatestFrom, flatMap, map } from 'rxjs/operators';
 import { GlobalState } from '@app/core/state';
 import { Store } from '@ngrx/store';
 import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
-import { UpdateUserPreferences, UserPreferencesActionTypes } from './actions';
+import * as actions from './actions';
+import { CoreActionTypes } from './actions';
 import { UserPreferences } from './models/user-preferences';
 
 @Injectable()
-export class UserPreferencesEffects {
+export class CoreEffects {
   constructor(
     private actions$: Actions,
     private api: DegreePlannerApiService,
     private store$: Store<GlobalState>,
   ) {}
+
+  @Effect()
+  initializeUserPreferences$ = this.actions$.pipe(
+    ofType(CoreActionTypes.Initialize),
+    flatMap(() => this.api.getUserPreferences()),
+    map(preferences => new actions.InitializeUserPreferences({ preferences })),
+  );
+
   @Effect({ dispatch: false })
   updateUserPreferences$ = this.actions$.pipe(
-    ofType<UpdateUserPreferences>(
-      UserPreferencesActionTypes.UpdateUserPreferences,
+    ofType<actions.UpdateUserPreferences>(
+      CoreActionTypes.UpdateUserPreferences,
     ),
     withLatestFrom(this.store$),
     tap(([update, state]) => {
diff --git a/src/app/core/reducer.ts b/src/app/core/reducer.ts
index 0069409..2d69b13 100644
--- a/src/app/core/reducer.ts
+++ b/src/app/core/reducer.ts
@@ -1,13 +1,21 @@
-import { UserPreferencesActionTypes, UpdateUserPreferences } from './actions';
+import { CoreActionTypes, UpdateUserPreferences } from './actions';
+import * as actions from './actions';
 import { INITIAL_PREFERENCES_STATE } from './state';
 import { UserPreferences } from './models/user-preferences';
 
+type SupportedActions =
+  | actions.InitializeUserPreferences
+  | actions.UpdateUserPreferences;
+
 export function preferencesReducer(
   state = INITIAL_PREFERENCES_STATE,
-  action: UpdateUserPreferences,
+  action: SupportedActions,
 ): UserPreferences {
   switch (action.type) {
-    case UserPreferencesActionTypes.UpdateUserPreferences: {
+    case CoreActionTypes.PopulateUserPreferences: {
+      return action.payload.preferences;
+    }
+    case CoreActionTypes.UpdateUserPreferences: {
       const update: UserPreferences = { ...state };
 
       // Remove properties who's value is undefined
diff --git a/src/app/dars/dars.module.ts b/src/app/dars/dars.module.ts
index 1a2b72c..87605b0 100644
--- a/src/app/dars/dars.module.ts
+++ b/src/app/dars/dars.module.ts
@@ -8,9 +8,12 @@ import { DarsMetadataTableComponent } from './metadata-table/metadata-table.comp
 import { NewAuditOptionsComponent } from './dars-view/new-audit-options/new-audit-options.component';
 import { MatStepperModule } from '@angular/material';
 import { AlertContainerComponent } from '../shared/components/alert-container/alert-container.component';
+import { StoreModule } from '@ngrx/store';
+import { darsReducer } from './store/reducer';
 
 @NgModule({
   imports: [
+    StoreModule.forFeature('dars', darsReducer),
     EffectsModule.forFeature([DARSEffects]),
     SharedModule,
     MatStepperModule,
diff --git a/src/app/dars/store/effects.ts b/src/app/dars/store/effects.ts
index 82b4b08..b8804d6 100644
--- a/src/app/dars/store/effects.ts
+++ b/src/app/dars/store/effects.ts
@@ -1,4 +1,3 @@
-import { visibleAudit } from './selectors';
 import { UpdateUserPreferences } from './../../core/actions';
 import { GlobalState } from '@app/core/state';
 import { Store } from '@ngrx/store';
@@ -7,12 +6,10 @@ import { Injectable } from '@angular/core';
 import { Actions, Effect, ofType } from '@ngrx/effects';
 import { DarsActionTypes } from '@app/dars/store/actions';
 import * as darsActions from '@app/dars/store/actions';
-import { flatMap, map, catchError, switchMap, mergeMap } from 'rxjs/operators';
+import { flatMap, map } from 'rxjs/operators';
 import { DarsApiService } from '../services/api.service';
-import { of } from 'rxjs';
 import { Alert, DarsDisclaimerAlert } from '@app/core/models/alert';
 import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
-import { INITIAL_DARS_STATE } from './state';
 
 @Injectable()
 export class DARSEffects {
@@ -34,7 +31,7 @@ export class DARSEffects {
       });
     }),
 
-    flatMap(({ metadata, userPreferences }) => {
+    map(({ metadata, userPreferences }) => {
       const alerts: Alert[] = [];
       if (userPreferences.darsHasDismissedDisclaimer !== true) {
         alerts.push(
@@ -48,27 +45,8 @@ export class DARSEffects {
         );
       }
 
-      return forkJoinWithKeys({
-        metadata: of(metadata),
-        visibleAudit: of({}),
-        alerts: of(alerts),
-      }).pipe(
-        switchMap(payload => {
-          return [
-            new darsActions.AddAuditMetadata({ metadata }),
-            new UpdateUserPreferences(userPreferences),
-          ];
-        }),
-      );
+      return new darsActions.AddAuditMetadata({ metadata });
     }),
-
-    // catchError(() => {
-    //   return of(
-    //     new darsActions.ErrorLoadingMetadata({
-    //       message: 'Unable to load audit metadata. Please try again',
-    //     }),
-    //   );
-    // }),
   );
 
   @Effect()
diff --git a/src/app/degree-planner/degree-planner.module.ts b/src/app/degree-planner/degree-planner.module.ts
index 1a58879..827396c 100644
--- a/src/app/degree-planner/degree-planner.module.ts
+++ b/src/app/degree-planner/degree-planner.module.ts
@@ -16,11 +16,14 @@ import { DegreePlanEffects } from './store/effects/plan.effects';
 import { NoteEffects } from './store/effects/note.effects';
 import { CourseEffects } from './store/effects/course.effects';
 import { ErrorEffects } from './store/effects/error.effects';
+import { StoreModule } from '@ngrx/store';
+import { degreePlannerReducer } from './store/reducer';
 
 @NgModule({
   imports: [
     SharedModule,
     DragDropModule,
+    StoreModule.forFeature('degreePlanner', degreePlannerReducer),
     EffectsModule.forRoot([
       DegreePlanEffects,
       NoteEffects,
diff --git a/src/app/degree-planner/store/effects/plan.effects.ts b/src/app/degree-planner/store/effects/plan.effects.ts
index 9301e8d..fec0b33 100644
--- a/src/app/degree-planner/store/effects/plan.effects.ts
+++ b/src/app/degree-planner/store/effects/plan.effects.ts
@@ -9,7 +9,6 @@ import {
   withLatestFrom,
   catchError,
   filter,
-  switchMap,
 } from 'rxjs/operators';
 import { GlobalState } from '@app/core/state';
 import { Store } from '@ngrx/store';
@@ -112,15 +111,12 @@ export class DegreePlanEffects {
         allDegreePlans: of(allDegreePlans),
         alerts: of(alerts),
       }).pipe(
-        switchMap(payload => {
-          return [
-            new InitialLoadSuccess({
-              ...INITIAL_DEGREE_PLANNER_STATE,
-              ...payload,
-              isLoadingPlan: false,
-            }),
-            new UpdateUserPreferences(userPreferences),
-          ];
+        map(payload => {
+          return new InitialLoadSuccess({
+            ...INITIAL_DEGREE_PLANNER_STATE,
+            ...payload,
+            isLoadingPlan: false,
+          });
         }),
       );
     }),
diff --git a/src/app/degree-planner/store/reducer.ts b/src/app/degree-planner/store/reducer.ts
index 1770f8f..1f16a12 100644
--- a/src/app/degree-planner/store/reducer.ts
+++ b/src/app/degree-planner/store/reducer.ts
@@ -144,7 +144,7 @@ export function degreePlannerReducer(
       return newState;
     }
 
-    case globalActions.NotificationActionTypes.DismissAlert: {
+    case globalActions.CoreActionTypes.DismissAlert: {
       const keyToRemove = action.payload.key;
       const newAlerts = state.alerts.filter(({ key }) => key !== keyToRemove);
       return { ...state, alerts: newAlerts };
diff --git a/src/app/degree-planner/store/selectors.ts b/src/app/degree-planner/store/selectors.ts
index a7677dc..677134e 100644
--- a/src/app/degree-planner/store/selectors.ts
+++ b/src/app/degree-planner/store/selectors.ts
@@ -4,7 +4,6 @@ import { DegreePlannerState } from './state';
 import { TermCode } from '@app/degree-planner/shared/term-codes/termcode';
 import { YearCode } from '@app/degree-planner/shared/term-codes/yearcode';
 import { YearMapping, Year } from '@app/core/models/year';
-import { UserPreferences } from '@app/core/models/user-preferences';
 
 export const getDegreePlannerState = ({ degreePlanner }: GlobalState) => {
   return degreePlanner;
-- 
GitLab