From bfd4239408accebf8d4d4ef0e3a206241be7f3c1 Mon Sep 17 00:00:00 2001
From: ievavold <ievavold@wisc.edu>
Date: Fri, 28 Jun 2019 10:35:55 -0500
Subject: [PATCH] split stepper component into two dialogs, add form validation
 logic

---
 src/app/app.routing.module.ts                 |   2 +
 .../dars/dars-view/dars-view.component.html   |   4 +-
 src/app/dars/dars-view/dars-view.component.ts |  25 +-
 src/app/dars/dars.module.ts                   |  11 +-
 .../new-audit-options.component.html          | 133 ----------
 .../new-audit-options.component.scss          |  39 ---
 .../new-audit-options.component.spec.ts       |  25 --
 .../new-audit-options.component.ts            | 178 --------------
 .../new-degree-audit-dialog.component.html    | 120 +++++++++
 .../new-degree-audit-dialog.component.scss    |  46 ++++
 .../new-degree-audit-dialog.component.ts      | 193 +++++++++++++++
 .../new-what-if-audit-dialog.component.html   | 154 ++++++++++++
 .../new-what-if-audit-dialog.component.scss   |  46 ++++
 .../new-what-if-audit-dialog.component.ts     | 228 ++++++++++++++++++
 src/app/dars/services/api.service.ts          |   9 +-
 15 files changed, 821 insertions(+), 392 deletions(-)
 delete mode 100644 src/app/dars/new-audit-options/new-audit-options.component.html
 delete mode 100644 src/app/dars/new-audit-options/new-audit-options.component.scss
 delete mode 100644 src/app/dars/new-audit-options/new-audit-options.component.spec.ts
 delete mode 100644 src/app/dars/new-audit-options/new-audit-options.component.ts
 create mode 100644 src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.html
 create mode 100644 src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.scss
 create mode 100644 src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.ts
 create mode 100644 src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.html
 create mode 100644 src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.scss
 create mode 100644 src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.ts

diff --git a/src/app/app.routing.module.ts b/src/app/app.routing.module.ts
index 4711141..fb09a39 100644
--- a/src/app/app.routing.module.ts
+++ b/src/app/app.routing.module.ts
@@ -7,10 +7,12 @@ import { DARSViewComponent } from './dars/dars-view/dars-view.component';
 const routes: Routes = [
   {
     path: 'dars',
+    resolve: { constants: ConstantsService },
     component: DARSViewComponent,
   },
   {
     path: 'dars-beta',
+    resolve: { constants: ConstantsService },
     component: DARSViewComponent,
   },
   {
diff --git a/src/app/dars/dars-view/dars-view.component.html b/src/app/dars/dars-view/dars-view.component.html
index 7aa7173..f3bb66c 100644
--- a/src/app/dars/dars-view/dars-view.component.html
+++ b/src/app/dars/dars-view/dars-view.component.html
@@ -45,7 +45,7 @@
           aria-label="Run new degree audit"
           color="primary"
           [disabled]="(metadataStatus$ | async) != 'Loaded'"
-          (click)="openNewAuditOptionsDialog('degree')">
+          (click)="openDegreeAuditDialog()">
         Run new degree audit
       </button>
       </div>
@@ -77,7 +77,7 @@
           aria-label="Run new degree audit"
           [disabled]="(metadataStatus$ | async) != 'Loaded'"
           color="primary"
-          (click)="openNewAuditOptionsDialog('whatif')">
+          (click)="openWhatIfAuditDialog()">
           Run new &lsquo;what if&rsquo; audit
         </button>
       </div>
diff --git a/src/app/dars/dars-view/dars-view.component.ts b/src/app/dars/dars-view/dars-view.component.ts
index ffd480a..7240c02 100644
--- a/src/app/dars/dars-view/dars-view.component.ts
+++ b/src/app/dars/dars-view/dars-view.component.ts
@@ -2,7 +2,6 @@ import { MediaMatcher } from '@angular/cdk/layout';
 import { Component, OnInit } from '@angular/core';
 import { AuditMetadata } from '../models/audit-metadata';
 import { MatDialog } from '@angular/material';
-import { NewAuditOptionsComponent } from '../new-audit-options/new-audit-options.component';
 import { DARSState } from '../store/state';
 import { Store } from '@ngrx/store';
 import { GlobalState } from '@app/core/state';
@@ -12,6 +11,14 @@ import * as darsActions from '../store/actions';
 import { Audit } from '../models/audit/audit';
 import { DarsApiService } from '../services/api.service';
 import { Alert } from '@app/core/models/alert';
+import {
+  NewDegreeAuditDialogComponent,
+  NewDegreeAuditFields,
+} from '../new-degree-audit-dialog/new-degree-audit-dialog.component';
+import {
+  NewWhatIfAuditDialogComponent,
+  NewWhatIfAuditFields,
+} from '../new-what-if-audit-dialog/new-what-if-audit-dialog.component';
 
 @Component({
   selector: 'cse-dars-view',
@@ -51,10 +58,18 @@ export class DARSViewComponent implements OnInit {
     this.store.dispatch(new darsActions.DismissAlert({ key }));
   }
 
-  public openNewAuditOptionsDialog(selectedAuditType) {
-    this.dialog.open(NewAuditOptionsComponent, {
-      data: { selectedAuditType: selectedAuditType },
-    });
+  public openDegreeAuditDialog() {
+    this.dialog
+      .open<any, any, NewDegreeAuditFields>(NewDegreeAuditDialogComponent)
+      .afterClosed()
+      .subscribe(event => console.log(event));
+  }
+
+  public openWhatIfAuditDialog() {
+    this.dialog
+      .open<any, any, NewWhatIfAuditFields>(NewWhatIfAuditDialogComponent)
+      .afterClosed()
+      .subscribe(event => console.log(event));
   }
 
   public openAudit(metadata: AuditMetadata) {
diff --git a/src/app/dars/dars.module.ts b/src/app/dars/dars.module.ts
index 38963c7..0f7ab8e 100644
--- a/src/app/dars/dars.module.ts
+++ b/src/app/dars/dars.module.ts
@@ -5,12 +5,13 @@ import { SharedModule } from '@app/shared/shared.module';
 import { DARSEffects } from './store/effects';
 import { DarsAuditComponent } from './audit/audit.component';
 import { DarsMetadataTableComponent } from './metadata-table/metadata-table.component';
-import { NewAuditOptionsComponent } from './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';
 import { AuditLinePipe } from './pipes/audit-line.pipe';
+import { NewDegreeAuditDialogComponent } from './new-degree-audit-dialog/new-degree-audit-dialog.component';
+import { NewWhatIfAuditDialogComponent } from './new-what-if-audit-dialog/new-what-if-audit-dialog.component';
 
 @NgModule({
   imports: [
@@ -22,12 +23,16 @@ import { AuditLinePipe } from './pipes/audit-line.pipe';
   exports: [MatStepperModule],
   declarations: [
     AuditLinePipe,
-    NewAuditOptionsComponent,
+    NewDegreeAuditDialogComponent,
+    NewWhatIfAuditDialogComponent,
     DARSViewComponent,
     DarsAuditComponent,
     DarsMetadataTableComponent,
   ],
-  entryComponents: [NewAuditOptionsComponent],
+  entryComponents: [
+    NewDegreeAuditDialogComponent,
+    NewWhatIfAuditDialogComponent,
+  ],
   schemas: [CUSTOM_ELEMENTS_SCHEMA],
 })
 export class DARSModule {}
diff --git a/src/app/dars/new-audit-options/new-audit-options.component.html b/src/app/dars/new-audit-options/new-audit-options.component.html
deleted file mode 100644
index 9eaf3cf..0000000
--- a/src/app/dars/new-audit-options/new-audit-options.component.html
+++ /dev/null
@@ -1,133 +0,0 @@
-<mat-toolbar color="primary" class="dialog-toolbar">
-    <h2 class="dialog-toolbar-title">
-      Request Degree Audit
-    </h2>
-    <button
-      mat-button
-      mat-dialog-close
-      class="close-btn"
-      aria-label="Close audit dialog"
-      cdkFocusRegionEnd>
-      <i
-        class="material-icons"
-        alt="Close audit dialog"
-        matTooltip="Close audit dialog"
-        matTooltipPosition="above"
-        >clear</i>
-    </button>
-  </mat-toolbar>
-
-  <mat-dialog-content id="new-audit-options-stepper" class="mat-typography dialog-with-toolbar">
-
-    <div fxLayout="column" fxLayoutAlign="none" fxLayoutGap="10px">
-      <form [formGroup]="newAuditForm" id="newAuditForm">
-        <mat-vertical-stepper linear #stepper formArrayName="formArray">
-            <mat-step class="audit-step" formGroupName="0" [stepControl]="formArray?.get([0])">
-                <ng-template matStepLabel>Choose audit type</ng-template>
-                  <mat-radio-group  [(ngModel)]="selectedAuditType" class="audit-radio-group" formControlName="auditType">
-                    <mat-radio-button [checked]="selectedAuditType === 'declaredMajorAudit'" class="audit-radio-button" name="declared-audit-type" id="declared-audit-type" value="declaredMajorAudit" aria-label="Select run a degree audit with declared major">
-                      <p>Run a degree audit with declared major <br />
-                      <span class="sub-line">See the progress towards your current program of study.</span></p>
-                    </mat-radio-button>
-
-                    <mat-radio-button [checked]="selectedAuditType === 'whatIfAudit'" class="audit-radio-button" name="what-if-audit-type" id="what-if-audit-type" value="whatIfAudit" aria-label="Select run a what-if degree audit">
-                      <p>Run a what-if degree audit <br />
-                      <span class="sub-line">See the progress towards a new program of study and degree plans.</span></p>
-                    </mat-radio-button>
-                  </mat-radio-group>
-                <div class="step-buttons-group">
-                  <button mat-button matStepperNext mat-stroked-button color="primary">Next</button>
-                </div>
-            </mat-step>
-
-            <mat-step class="audit-step" formGroupName="1" [stepControl]="formArray?.get([1])">
-              <ng-template matStepLabel>Select program of study</ng-template>
-              <mat-radio-group *ngIf="newAuditForm.value.formArray[0].auditType === 'declaredMajorAudit'" class="audit-radio-group" formControlName="darsDegreeProgram">
-                <mat-radio-button *ngFor="let program of studentDegreeProgram; let i = index" [value]="i" [checked]="i === 0" class="audit-radio-button" name="darsDegreeProgramCode" id="{{ program.darsDegreeProgramCode }}" aria-label="{{ program.darsDegreeProgramCode }}">
-                    {{ program.sisAcademicPlanDescription }}
-                </mat-radio-button>
-              </mat-radio-group>
-
-              <!-- If what-if audit was selected in #1 -->
-              <mat-form-field *ngIf="newAuditForm.value.formArray[0].auditType === 'whatIfAudit'" class="audit-program">
-                <mat-select formControlName="darsInstitution" placeholder="School, College or Population" aria-label="Select School, College or Population" [disableOptionCentering]="true">
-                  <mat-option value="{{ programOfStudy }}">{{ programOfStudy }}</mat-option>
-                </mat-select>
-              </mat-form-field>
-
-              <!-- Show after School, College or Population was selected -->
-              <mat-form-field *ngIf="(newAuditForm.value.formArray[0].auditType === 'whatIfAudit') && (newAuditForm.value.formArray[1].darsInstitution)" class="audit-program">
-                <mat-select formControlName="darsInstitutionProgram" placeholder="Academic Plan Program" aria-label="Academic Plan Program" [disableOptionCentering]="true">
-                  <mat-option class="mat-option-long" *ngFor="let program of DARSprograms" value="{{ program.darsDegreeProgramDescription }}">{{ program.darsDegreeProgramDescription | titlecase }}</mat-option>
-                </mat-select>
-              </mat-form-field>
-
-              <div class="step-buttons-group">
-                <button mat-button matStepperPrevious color="primary">Back</button>
-                <button mat-button matStepperNext mat-stroked-button color="primary">Next</button>
-              </div>
-            </mat-step>
-
-            <mat-step class="audit-step" formGroupName="2" [stepControl]="formArray?.get([2])">
-              <ng-template matStepLabel>Choose audit settings</ng-template>
-              <mat-form-field class="audit-settings-option">
-                <mat-label>Honors Degree Options</mat-label>
-                <mat-select formControlName="honors" placeholder="Honors Degree Option" aria-label="Honors Degree Options" [disableOptionCentering]="true">
-                  <mat-option *ngFor="let honor of honorsOptions" value="{{ honor.darsHonorsOptionDescription }}">{{ honor.darsHonorsOptionDescription }}</mat-option>
-                </mat-select>
-              </mat-form-field>
-              <mat-form-field class="audit-settings-option">
-                <mat-label>Include Courses From</mat-label>
-                <mat-select formControlName="includeCoursesFrom" placeholder="Include Courses From" aria-label="Include Courses From" [disableOptionCentering]="true">
-                 <mat-option *ngFor="let term of termsToInclude" [value]='term' id="{{ term.id }}">{{ term.name }}</mat-option>
-                </mat-select>
-              </mat-form-field>
-
-              <p style="margin-top: 12px;"><strong>Run against which degree plan?</strong></p>
-              <mat-form-field class="audit-settings-option">
-                <mat-label>Degree Plan</mat-label>
-                <mat-select formControlName="runAgainst" placeholder="Degree Plan" aria-label="Degree Plan" [disableOptionCentering]="true">
-                  <mat-option *ngFor="let degreePlan of degreePlans" value="{{ degreePlan.roadmapId }}">{{ degreePlan.name }}</mat-option>
-                </mat-select>
-              </mat-form-field>
-              <div class="step-buttons-group">
-                <button mat-button matStepperPrevious color="primary">Back</button>
-                <button mat-button matStepperNext mat-stroked-button color="primary" (click)="getCoursesList(newAuditForm.value.formArray[2].runAgainst)">Next</button>
-              </div>
-            </mat-step>
-
-            <mat-step class="audit-step" formGroupName="3" [stepControl]="formArray?.get([3])">
-              <ng-template matStepLabel>Select credits</ng-template>
-              <p>To provide more accurate audit, specify the number of credits you planto make in the following course(s):</p>
-
-              <p *ngIf="!hasVariableCredits && isLoaded"><strong>No variable credits found.The audit is ready to be run.</strong></p>
-              <div class="course-items-loading">
-                <mat-progress-spinner *ngIf="!isLoaded"
-                  mode="indeterminate"
-                  diameter="24">
-                </mat-progress-spinner>
-              </div>
-
-              <div *ngFor="let course of courses">
-                <div *ngIf="hasVariableCredits" fxLayout="row" fxFlex="100" style="margin-top: 18px;">
-                  <div fxLayoutAlign="start center" fxFlex="80">
-                    <span>{{ course.termCode | getTermDescription }}: {{ course.subjectDescription }} {{ course.catalogNumber }} <br /> {{ course.title }}</span>
-                  </div>
-                  <div fxLayoutAlign="end center" fxFlex="20">
-                    <mat-form-field id="audit-credits-selector">
-                      <mat-select formControlName="credits" placeholder="" aria-label="Number of credits" [disableOptionCentering]="true">
-                          <mat-option class="mat-option-center" *ngFor="let credit of course.creditsRange" value="{{ credit }}">{{ credit }}</mat-option>
-                      </mat-select>
-                    </mat-form-field>
-                  </div>
-              </div>
-            </div>
-            <div class="step-buttons-group">
-              <button mat-button matStepperPrevious color="primary">Back</button>
-              <button mat-button mat-raised-button color="primary" (click)="runDARSAudit();">Run Audit</button>
-            </div>
-          </mat-step>
-        </mat-vertical-stepper>
-      </form>
-    </div>
-  </mat-dialog-content>
diff --git a/src/app/dars/new-audit-options/new-audit-options.component.scss b/src/app/dars/new-audit-options/new-audit-options.component.scss
deleted file mode 100644
index 8b1624d..0000000
--- a/src/app/dars/new-audit-options/new-audit-options.component.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-.mat-form-field {
-  display: flex !important;
-}
-
-.audit-radio-button {
-  margin-bottom: 1em;
-  .mat-radio-label {
-    white-space: normal !important;
-  }
-  p {
-    margin-bottom: 0px;
-    margin-left: 12px;
-    font-weight: 500;
-    .sub-line {
-      color: #6e655f;
-      font-weight: normal;
-    }
-  }
-}
-
-.audit-radio-group {
-  display: flex;
-  flex-direction: column;
-  margin: 15px 0;
-}
-
-.step-buttons-group {
-  margin-top: 2em;
-  button {
-    text-transform: uppercase;
-  }
-}
-
-.course-items-loading {
-  mat-progress-spinner {
-    position: relative;
-    top: 8px;
-  }
-}
diff --git a/src/app/dars/new-audit-options/new-audit-options.component.spec.ts b/src/app/dars/new-audit-options/new-audit-options.component.spec.ts
deleted file mode 100644
index c910771..0000000
--- a/src/app/dars/new-audit-options/new-audit-options.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { NewAuditOptionsComponent } from './new-audit-options.component';
-
-describe('NewAuditOptionsComponent', () => {
-  let component: NewAuditOptionsComponent;
-  let fixture: ComponentFixture<NewAuditOptionsComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [ NewAuditOptionsComponent ]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(NewAuditOptionsComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/app/dars/new-audit-options/new-audit-options.component.ts b/src/app/dars/new-audit-options/new-audit-options.component.ts
deleted file mode 100644
index 61cf8be..0000000
--- a/src/app/dars/new-audit-options/new-audit-options.component.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-import { Component, OnInit, Inject } from '@angular/core';
-import { MatDialogRef, MatSnackBar } from '@angular/material';
-import { DarsApiService } from '../services/api.service';
-import { DegreeProgram, DegreePrograms } from '../models/degree-program';
-import { SingleAuditRequest } from '../models/single-audit-request';
-import { StudentDegreeProgram } from '../models/student-degree-program';
-import { Observable } from 'rxjs';
-import { Store, select } from '@ngrx/store';
-import { GlobalState } from '@app/core/state';
-import * as selectors from '../store/selectors';
-import * as darsActions from '../store/actions';
-import { DARSState } from '../store/state';
-import { MAT_DIALOG_DATA } from '@angular/material';
-import {
-  FormBuilder,
-  FormGroup,
-  FormControl,
-  AbstractControl,
-} from '@angular/forms';
-import { HonorsOption } from '../models/honors-option';
-import { DegreePlan } from '@app/core/models/degree-plan';
-import { CourseBase } from '@app/core/models/course';
-
-@Component({
-  selector: 'cse-new-audit-options',
-  templateUrl: './new-audit-options.component.html',
-  styleUrls: ['./new-audit-options.component.scss'],
-})
-export class NewAuditOptionsComponent implements OnInit {
-  public newAuditForm: FormGroup;
-  public degreeProgram: DegreeProgram;
-  public degreePrograms: DegreePrograms;
-  public programOfStudy: string;
-  public studentDegreeProgram: StudentDegreeProgram[];
-  public DARSprograms: DegreeProgram[] = [];
-  public honorsOptions: HonorsOption[] = [];
-  public courses: { termCode: string; courses: CourseBase[] }[];
-  public degreePlans$: Observable<DARSState['degreePlans']>;
-  public singleAuditRequest$: Observable<SingleAuditRequest>;
-  public degreePlans: DegreePlan[];
-  public primaryPlan: DegreePlan[];
-  public primaryPlanId: string;
-  public hasVariableCredits: boolean;
-  public creditsRange: (CourseBase & { creditRange: number[] })[];
-  public isLoaded: boolean;
-  public selectedAuditType: string;
-  public termsToInclude: { name: string; id: string; value: string }[];
-  get formArray(): AbstractControl | null {
-    return this.newAuditForm.get('formArray');
-  }
-
-  constructor(
-    private fb: FormBuilder,
-    private dialogRef: MatDialogRef<NewAuditOptionsComponent>,
-    private snackBar: MatSnackBar,
-    private api: DarsApiService,
-    private store: Store<GlobalState>,
-    @Inject(MAT_DIALOG_DATA)
-    data: {
-      selectedAuditType: string;
-    },
-  ) {
-    this.selectedAuditType = 'declaredMajorAudit';
-    this.termsToInclude = [
-      {
-        name: 'Previous, current, future, and planned terms',
-        id: 'future-whatif',
-        value: 'future',
-      },
-      {
-        name: 'Previous, current, future',
-        id: 'future-degree',
-        value: 'future',
-      },
-      { name: 'Previous, current', id: 'current', value: 'current' },
-      { name: 'Previous', id: 'previous', value: 'previous' },
-    ];
-  }
-
-  ngOnInit() {
-    // Get Degree plans
-    this.degreePlans$ = this.store.pipe(select(selectors.degreePlans));
-    this.degreePlans$.subscribe(plans => {
-      this.degreePlans = plans;
-      this.primaryPlan = plans.filter(function(plan) {
-        return plan.primary === true;
-      });
-      this.primaryPlanId = this.primaryPlan[0].roadmapId.toString();
-    });
-    // Get student degree programs
-    this.api.getStudentDegreePrograms().subscribe(studentDegreeProgram => {
-      this.studentDegreeProgram = studentDegreeProgram;
-    });
-
-    this.api.getStaticData().subscribe(degreePrograms => {
-      this.degreePrograms = degreePrograms;
-
-      for (const institution of Object.values(degreePrograms)) {
-        this.programOfStudy = institution.darsInstitutionCodeDescription;
-        this.honorsOptions.push(...institution.honorsOptions);
-        this.DARSprograms.push(...institution.programs);
-      }
-    });
-    this.newAuditForm = this.fb.group({
-      formArray: this.fb.array([
-        this.fb.group({
-          auditType: new FormControl(''),
-        }),
-        this.fb.group({
-          darsDegreeProgram: new FormControl(''),
-          darsInstitution: new FormControl(''),
-          darsInstitutionProgram: new FormControl(''),
-        }),
-        this.fb.group({
-          honors: new FormControl('Keep current status'),
-          includeCoursesFrom: new FormControl(
-            this.selectedAuditType === 'declaredMajorAudit'
-              ? this.termsToInclude[1]
-              : this.termsToInclude[0],
-          ),
-          runAgainst: new FormControl(this.primaryPlanId),
-        }),
-        this.fb.group({
-          credits: new FormControl(''),
-        }),
-      ]),
-    });
-  }
-
-  public getCoursesList(roadmapId) {
-    this.isLoaded = false;
-
-    this.api.getAllCourses(roadmapId).subscribe(courses => {
-      this.courses = courses;
-      this.creditsRange = [];
-      this.isLoaded = true;
-      this.hasVariableCredits = false;
-
-      courses.forEach(term => {
-        term.courses.forEach(course => {
-          const { creditMin: min, creditMax: max } = course;
-          if (min !== undefined && max !== undefined && min < max) {
-            this.hasVariableCredits = true;
-            const creditRange: number[] = [];
-            for (let i = min; i <= max; i++) {
-              creditRange.push(i);
-            }
-            this.creditsRange.push({ ...course, creditRange });
-          }
-        });
-      });
-    });
-  }
-
-  public runDARSAudit() {
-    const {
-      auditType,
-      programOfStudy,
-      academicProgram,
-      honors,
-      includeCoursesFrom,
-      runAgainst,
-      credits,
-    } = this.newAuditForm.value;
-
-    this.store.dispatch(
-      new darsActions.StartSendingAudit({
-        darsInstitutionCode: programOfStudy,
-        darsDegreeProgramCode: academicProgram,
-      }),
-    );
-
-    this.dialogRef.close();
-    this.snackBar.open(
-      'Audit in progress. You will be notified when the audit is ready to be viewed.',
-    );
-  }
-}
diff --git a/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.html b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.html
new file mode 100644
index 0000000..cf2d695
--- /dev/null
+++ b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.html
@@ -0,0 +1,120 @@
+<mat-toolbar class="dialog-toolbar" color="primary">
+  <h2 class="dialog-toolbar-title">Run degree audit</h2>
+  <button
+    class="close-btn"
+    mat-button
+    mat-dialog-close
+    cdkFocusRegionEnd
+    aria-label="Close audit dialog"
+    matTooltip="Close audit dialog"
+    matTooltipPosition="above">
+    <i class="material-icons">clear</i>
+  </button>
+</mat-toolbar>
+
+<mat-dialog-content dialog-with-toolbar>
+  <mat-vertical-stepper linear>
+    <ng-template matStepperIcon="edit" let-index="index">
+      {{ index + 1 }}
+    </ng-template>
+
+    <mat-step [stepControl]="chosenProgram" label="Select program of study">
+      <!--
+        User picks one of the majors or certificates that they're already enrolled in
+      -->
+      <ng-container *ngIf="degreePrograms$ | async as degreePrograms; else loading">
+        <mat-radio-group [formControl]="chosenProgram">
+          <mat-radio-button *ngFor="let dp of degreePrograms" [value]="dp">
+            {{ dp.sisAcademicPlanDescription }}
+          </mat-radio-button>
+        </mat-radio-group>
+      </ng-container>
+
+      <div class="step-actions">
+        <button mat-stroked-button matStepperNext [disabled]="!chosenProgram.valid">Next</button>
+      </div>
+    </mat-step>
+
+    <mat-step [stepControl]="chosenAuditSettings" label="Choose audit settings">
+      <form [formGroup]="chosenAuditSettings">
+        <ng-container *ngIf="honorsOptions$ | async as honorsOptions; else loading">
+          <!--
+            User picks one of the honors options provided by the institution
+            associated with the program they selected in step 1
+          -->
+          <mat-form-field>
+            <mat-label>Honors Degree Options</mat-label>
+            <mat-select formControlName="honorsOptions">
+              <mat-option
+                *ngFor="let op of honorsOptions"
+                value="{{ op.darsHonorsOptionCode }}">
+                {{ op.darsHonorsOptionDescription }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+
+          <!--
+            User picks whether to include courses from the past, current, or planned future
+          -->
+          <mat-form-field>
+            <mat-label>Include Courses From</mat-label>
+            <mat-select formControlName="includeCoursesFrom">
+              <mat-option value="future">Previous, current, and future terms</mat-option>
+              <mat-option value="current">Previous and current terms</mat-option>
+              <mat-option value="previous">Previous terms</mat-option>
+            </mat-select>
+          </mat-form-field>
+        </ng-container>
+
+        <div class="step-actions">
+          <button mat-button matStepperPrevious>Back</button>
+          <button mat-stroked-button matStepperNext [disabled]="!chosenAuditSettings.valid">Next</button>
+        </div>
+      </form>
+    </mat-step>
+
+    <mat-step [stepControl]="chosenCreditSettings" label="Select credits">
+      <p>To provide a more accurate audit, specify the number of credits you plant to take in the following courses:</p>
+
+      <form [formGroup]="chosenCreditSettings">
+        <ng-container *ngIf="variableCreditCourses$ | async as variableCreditCourses; else loading">
+          <ng-container *ngIf="variableCreditCourses.length > 0; else noVariableCreditCourses">
+            <div class="credit-selector" *ngFor="let course of variableCreditCourses; let i = index" [formGroupName]="i">
+              <label>
+                {{ course.termCode | getTermDescription }}: {{ course | courseDescription }}
+                <br>
+                <small>{{ course.title }}</small>
+              </label>
+              <mat-select formControlName="credits">
+                <mat-option
+                  *ngFor="let credit of course.range"
+                  [value]="credit">
+                  {{ credit }}
+                </mat-option>
+              </mat-select>
+            </div>
+          </ng-container>
+
+          <ng-template #noVariableCreditCourses>
+            <p><strong>No variable credits found. The audit is ready to be run.</strong></p>
+          </ng-template>
+        </ng-container>
+
+        <div class="step-actions">
+          <button mat-button matStepperPrevious>Back</button>
+          <button
+            mat-raised-button
+            color="primary"
+            [disabled]="!chosenCreditSettings.valid"
+            (click)="submitAudit()">
+            Request audit
+          </button>
+        </div>
+      </form>
+    </mat-step>
+  </mat-vertical-stepper>
+</mat-dialog-content>
+
+<ng-template #loading>
+  <mat-spinner diameter="20"></mat-spinner>
+</ng-template>
diff --git a/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.scss b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.scss
new file mode 100644
index 0000000..22af959
--- /dev/null
+++ b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.scss
@@ -0,0 +1,46 @@
+.mat-dialog-content {
+  max-width: 512px;
+}
+
+.mat-radio-group {
+  display: flex;
+  flex-direction: column;
+}
+
+.mat-radio-button {
+  margin: 5px;
+}
+
+.mat-form-field {
+  display: block;
+
+  & + & {
+    margin-top: 15px;
+  }
+}
+
+.step-actions {
+  margin-top: 15px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.credit-selector {
+  display: flex;
+  flex-direction: row;
+
+  & + & {
+    margin-top: 15px;
+  }
+
+  label {
+    display: block;
+    flex-grow: 1;
+  }
+
+  mat-select {
+    width: 48px;
+    display: block;
+    flex-grow: 0;
+  }
+}
diff --git a/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.ts b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.ts
new file mode 100644
index 0000000..e835031
--- /dev/null
+++ b/src/app/dars/new-degree-audit-dialog/new-degree-audit-dialog.component.ts
@@ -0,0 +1,193 @@
+import { Component, OnInit } from '@angular/core';
+import { DarsApiService } from '../services/api.service';
+import { DegreePrograms } from '../models/degree-program';
+import { StudentDegreeProgram } from '../models/student-degree-program';
+import { Observable, combineLatest } from 'rxjs';
+import {
+  FormBuilder,
+  FormGroup,
+  Validators,
+  FormControl,
+  FormArray,
+} from '@angular/forms';
+import { HonorsOption } from '../models/honors-option';
+import { map, share, filter, flatMap } from 'rxjs/operators';
+import { CourseBase } from '@app/core/models/course';
+import { Store } from '@ngrx/store';
+import { GlobalState } from '@app/core/state';
+import { degreePlans } from '../store/selectors';
+import { DegreePlan } from '@app/core/models/degree-plan';
+import { MatDialogRef } from '@angular/material';
+
+const inclusiveRange = (from: number, to: number) => {
+  const range: number[] = [];
+  for (let i = from; i <= to; i++) {
+    range.push(i);
+  }
+  return range;
+};
+
+export interface NewDegreeAuditFields {
+  darsInstitutionCode: string;
+  darsDegreeProgramCode: string;
+  darsHonorsOptionCode: string;
+  includeCoursesFrom: string;
+  fixedCredits: {
+    termCode: string;
+    subjectCode: string;
+    courseId: string;
+    credits: number;
+  }[];
+}
+
+@Component({
+  selector: 'cse-new-degree-audit-dialog',
+  templateUrl: './new-degree-audit-dialog.component.html',
+  styleUrls: ['./new-degree-audit-dialog.component.scss'],
+})
+export class NewDegreeAuditDialogComponent implements OnInit {
+  // Form-builder objects
+  public chosenProgram: FormControl;
+  public chosenAuditSettings: FormGroup;
+  public chosenCreditSettings: FormArray;
+
+  // API observables
+  public degreePrograms$: Observable<StudentDegreeProgram[]>;
+  public institutions$: Observable<DegreePrograms>;
+  public honorsOptions$: Observable<HonorsOption[]>;
+  public variableCreditCourses$: Observable<
+    (CourseBase & { range: number[] })[]
+  >;
+
+  constructor(
+    private fb: FormBuilder,
+    private api: DarsApiService,
+    private store: Store<GlobalState>,
+    private dialogRef: MatDialogRef<NewDegreeAuditDialogComponent>,
+  ) {
+    this.chosenProgram = fb.control('', Validators.required);
+
+    this.chosenAuditSettings = fb.group({
+      honorsOptions: fb.control('', Validators.required),
+      includeCoursesFrom: fb.control('future', Validators.required),
+    });
+
+    this.chosenCreditSettings = fb.array([]);
+  }
+
+  public ngOnInit() {
+    this.degreePrograms$ = this.api.getStudentDegreePrograms().pipe(share());
+    this.institutions$ = this.api.getStaticData().pipe(share());
+
+    this.honorsOptions$ = combineLatest([
+      this.institutions$,
+      this.chosenProgram.valueChanges.pipe(
+        filter(value => value.hasOwnProperty('darsInstitutionCode')),
+        map(value => value.darsInstitutionCode as string),
+      ),
+    ]).pipe(
+      map(([institutions, darsInstitutionCode]) => {
+        return institutions.hasOwnProperty(darsInstitutionCode)
+          ? institutions[darsInstitutionCode].honorsOptions
+          : [];
+      }),
+    );
+
+    this.variableCreditCourses$ = this.store.select(degreePlans).pipe(
+      map(plans => plans.find(plan => plan.primary)),
+      filter((plan): plan is DegreePlan => plan !== undefined),
+      flatMap(plan => this.api.getAllCourses(plan.roadmapId)),
+      map(courses => {
+        return courses.filter(course => {
+          return (
+            !!course.creditMin &&
+            !!course.creditMax &&
+            course.creditMax > course.creditMin
+          );
+        });
+      }),
+      map(courses =>
+        courses.map(course => ({
+          ...course,
+          range: inclusiveRange(
+            course.creditMin as number,
+            course.creditMax as number,
+          ),
+        })),
+      ),
+      share(),
+    );
+
+    this.variableCreditCourses$.subscribe(courses => {
+      while (this.chosenCreditSettings.length !== 0) {
+        this.chosenCreditSettings.removeAt(0);
+      }
+
+      courses.forEach(course => {
+        this.chosenCreditSettings.push(
+          this.fb.group({
+            course,
+            credits: this.fb.control('', Validators.required),
+          }),
+        );
+      });
+    });
+  }
+
+  public darsInstitutionCode<T>(fallback: T): string | T {
+    if (typeof this.chosenProgram.value === 'object') {
+      return this.chosenProgram.value.darsInstitutionCode;
+    } else {
+      return fallback;
+    }
+  }
+
+  public darsDegreeProgramCode<T>(fallback: T): string | T {
+    if (typeof this.chosenProgram.value === 'object') {
+      return this.chosenProgram.value.darsDegreeProgramCode;
+    } else {
+      return fallback;
+    }
+  }
+
+  public darsHonorsOptionCode<T>(fallback: T): string | T {
+    const control = this.chosenAuditSettings.get('honorsOptions');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public includeCoursesFrom<T>(fallback: T): string | T {
+    const control = this.chosenAuditSettings.get('includeCoursesFrom');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public fixedCredits(): NewDegreeAuditFields['fixedCredits'] {
+    return (this.chosenCreditSettings.value as any[]).map(
+      (group: { course: CourseBase; credits: number }) => {
+        return {
+          termCode: group.course.termCode || '',
+          subjectCode: group.course.subjectCode || '',
+          courseId: group.course.courseId || '',
+          credits: group.credits,
+        };
+      },
+    );
+  }
+
+  public submitAudit() {
+    this.dialogRef.close({
+      darsInstitutionCode: this.darsInstitutionCode(''),
+      darsDegreeProgramCode: this.darsDegreeProgramCode(''),
+      darsHonorsOptionCode: this.darsHonorsOptionCode(''),
+      includeCoursesFrom: this.includeCoursesFrom(''),
+      fixedCredits: this.fixedCredits(),
+    });
+  }
+}
diff --git a/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.html b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.html
new file mode 100644
index 0000000..0cedef4
--- /dev/null
+++ b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.html
@@ -0,0 +1,154 @@
+<mat-toolbar class="dialog-toolbar" color="primary">
+  <h2 class="dialog-toolbar-title">Run &lsquo;what-if&rsquo; audit</h2>
+  <button
+    class="close-btn"
+    mat-button
+    mat-dialog-close
+    cdkFocusRegionEnd
+    aria-label="Close audit dialog"
+    matTooltip="Close audit dialog"
+    matTooltipPosition="above">
+    <i class="material-icons">clear</i>
+  </button>
+</mat-toolbar>
+
+<mat-dialog-content dialog-with-toolbar>
+  <mat-vertical-stepper linear>
+    <ng-template matStepperIcon="edit" let-index="index">
+      {{ index + 1 }}
+    </ng-template>
+
+    <mat-step [stepControl]="chosenProgram" label="Select program of study">
+      <form [formGroup]="chosenProgram">
+        <ng-container *ngIf="institutions$ | async as institutions; else loading">
+          <!--
+            User picks one of the institutions to narrow the number of choices in the next step
+          -->
+          <mat-form-field>
+            <mat-label>School, College, or Population</mat-label>
+            <mat-select formControlName="institution">
+              <mat-option
+                *ngFor="let pair of institutions | keyvalue"
+                [value]="pair.key">
+                {{ pair.value.darsInstitutionCodeDescription }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+
+          <!--
+            User picks one of the insitution's programs
+            -->
+          <mat-form-field>
+            <mat-label>Academic Plan / Program</mat-label>
+            <mat-select formControlName="planOrProgram">
+              <mat-option
+                *ngFor="let p of (programOrPlanOptions$ | async)"
+                value="{{ p.darsDegreeProgramCode }}">
+                {{ p.darsDegreeProgramDescription }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+        </ng-container>
+
+        <ng-container *ngIf="degreePlans$ | async as degreePlans; else loading">
+          <mat-form-field>
+            <mat-label>Degree Plan</mat-label>
+            <mat-select formControlName="degreePlan">
+              <mat-option
+                *ngFor="let plan of degreePlans"
+                [value]="plan">
+                {{ plan.name }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+        </ng-container>
+      </form>
+
+      <div class="step-actions">
+        <button mat-stroked-button matStepperNext [disabled]="!chosenProgram.valid">Next</button>
+      </div>
+    </mat-step>
+
+    <mat-step [stepControl]="chosenAuditSettings" label="Choose audit settings">
+      <form [formGroup]="chosenAuditSettings">
+        <ng-container *ngIf="honorsOptions$ | async as honorsOptions; else loading">
+          <!--
+            User picks one of the honors options provided by the institution
+            associated with the program they selected in step 1
+          -->
+          <mat-form-field>
+            <mat-label>Honors Degree Options</mat-label>
+            <mat-select formControlName="honorsOptions">
+              <mat-option
+                *ngFor="let op of honorsOptions"
+                value="{{ op.darsHonorsOptionCode }}">
+                {{ op.darsHonorsOptionDescription }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+
+          <!--
+            User picks whether to include courses from the past, current, or planned future
+          -->
+          <mat-form-field>
+            <mat-label>Include Courses From</mat-label>
+            <mat-select formControlName="includeCoursesFrom">
+              <mat-option value="future">Previous, current, and future terms</mat-option>
+              <mat-option value="current">Previous and current terms</mat-option>
+              <mat-option value="previous">Previous terms</mat-option>
+            </mat-select>
+          </mat-form-field>
+        </ng-container>
+
+        <div class="step-actions">
+          <button mat-button matStepperPrevious>Back</button>
+          <button mat-stroked-button matStepperNext [disabled]="!chosenAuditSettings.valid">Next</button>
+        </div>
+      </form>
+    </mat-step>
+
+    <mat-step [stepControl]="chosenCreditSettings" label="Select credits">
+      <p>To provide a more accurate audit, specify the number of credits you plant to take in the following courses:</p>
+
+      <form [formGroup]="chosenCreditSettings">
+        <ng-container *ngIf="variableCreditCourses$ | async as variableCreditCourses; else loading">
+          <ng-container *ngIf="variableCreditCourses.length > 0; else noVariableCreditCourses">
+            <div class="credit-selector" *ngFor="let course of variableCreditCourses; let i = index" [formGroupName]="i">
+              <label>
+                {{ course.termCode | getTermDescription }}: {{ course | courseDescription }}
+                <br>
+                <small>{{ course.title }}</small>
+              </label>
+              <mat-select formControlName="credits">
+                <mat-option
+                  *ngFor="let credit of course.range"
+                  [value]="credit">
+                  {{ credit }}
+                </mat-option>
+              </mat-select>
+            </div>
+          </ng-container>
+
+          <ng-template #noVariableCreditCourses>
+            <p><strong>No variable credits found. The audit is ready to be run.</strong></p>
+          </ng-template>
+        </ng-container>
+
+        <div class="step-actions">
+          <button mat-button matStepperPrevious>Back</button>
+          <button
+            mat-raised-button
+            color="primary"
+            [disabled]="!chosenCreditSettings.valid"
+            (click)="submitAudit()">
+            Request audit
+          </button>
+        </div>
+      </form>
+    </mat-step>
+  </mat-vertical-stepper>
+</mat-dialog-content>
+
+<ng-template #loading>
+  <mat-spinner diameter="20"></mat-spinner>
+</ng-template>
diff --git a/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.scss b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.scss
new file mode 100644
index 0000000..22af959
--- /dev/null
+++ b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.scss
@@ -0,0 +1,46 @@
+.mat-dialog-content {
+  max-width: 512px;
+}
+
+.mat-radio-group {
+  display: flex;
+  flex-direction: column;
+}
+
+.mat-radio-button {
+  margin: 5px;
+}
+
+.mat-form-field {
+  display: block;
+
+  & + & {
+    margin-top: 15px;
+  }
+}
+
+.step-actions {
+  margin-top: 15px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.credit-selector {
+  display: flex;
+  flex-direction: row;
+
+  & + & {
+    margin-top: 15px;
+  }
+
+  label {
+    display: block;
+    flex-grow: 1;
+  }
+
+  mat-select {
+    width: 48px;
+    display: block;
+    flex-grow: 0;
+  }
+}
diff --git a/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.ts b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.ts
new file mode 100644
index 0000000..823300c
--- /dev/null
+++ b/src/app/dars/new-what-if-audit-dialog/new-what-if-audit-dialog.component.ts
@@ -0,0 +1,228 @@
+import { Component, OnInit } from '@angular/core';
+import { DarsApiService } from '../services/api.service';
+import { DegreePrograms, DegreeProgram } from '../models/degree-program';
+import { Observable, combineLatest } from 'rxjs';
+import {
+  FormBuilder,
+  FormGroup,
+  Validators,
+  FormArray,
+  FormControl,
+} from '@angular/forms';
+import { HonorsOption } from '../models/honors-option';
+import { map, share, filter, flatMap, withLatestFrom } from 'rxjs/operators';
+import { CourseBase } from '@app/core/models/course';
+import { Store } from '@ngrx/store';
+import { GlobalState } from '@app/core/state';
+import { degreePlans } from '../store/selectors';
+import { DegreePlan } from '@app/core/models/degree-plan';
+import { MatDialogRef } from '@angular/material';
+
+const inclusiveRange = (from: number, to: number) => {
+  const range: number[] = [];
+  for (let i = from; i <= to; i++) {
+    range.push(i);
+  }
+  return range;
+};
+
+export interface NewWhatIfAuditFields {
+  darsInstitutionCode: string;
+  darsDegreeProgramCode: string;
+  roadmapId: number;
+  darsHonorsOptionCode: string;
+  includeCoursesFrom: string;
+  fixedCredits: {
+    termCode: string;
+    subjectCode: string;
+    courseId: string;
+    credits: number;
+  }[];
+}
+
+@Component({
+  selector: 'cse-new-what-if-audit-dialog',
+  templateUrl: './new-what-if-audit-dialog.component.html',
+  styleUrls: ['./new-what-if-audit-dialog.component.scss'],
+})
+export class NewWhatIfAuditDialogComponent implements OnInit {
+  // Form-builder objects
+  public chosenProgram: FormGroup;
+  public chosenAuditSettings: FormGroup;
+  public chosenCreditSettings: FormArray;
+
+  // API observables
+  public institutions$: Observable<DegreePrograms>;
+  public programOrPlanOptions$: Observable<DegreeProgram[]>;
+  public degreePlans$: Observable<DegreePlan[]>;
+  public honorsOptions$: Observable<HonorsOption[]>;
+  public variableCreditCourses$: Observable<
+    (CourseBase & { range: number[] })[]
+  >;
+
+  constructor(
+    private fb: FormBuilder,
+    private api: DarsApiService,
+    private store: Store<GlobalState>,
+    private dialogRef: MatDialogRef<
+      NewWhatIfAuditDialogComponent,
+      NewWhatIfAuditFields
+    >,
+  ) {
+    this.chosenProgram = fb.group({
+      institution: fb.control('', Validators.required),
+      planOrProgram: fb.control(
+        { value: '', disabled: true },
+        Validators.required,
+      ),
+      degreePlan: fb.control('', Validators.required),
+    });
+
+    this.chosenAuditSettings = fb.group({
+      honorsOptions: fb.control('', Validators.required),
+      includeCoursesFrom: fb.control('future', Validators.required),
+    });
+
+    this.chosenCreditSettings = fb.array([]);
+  }
+
+  public ngOnInit() {
+    this.institutions$ = this.api.getStaticData().pipe(share());
+
+    this.programOrPlanOptions$ = combineLatest([
+      this.institutions$,
+      (this.chosenProgram.get('institution') as FormControl).valueChanges,
+    ]).pipe(
+      map(([institutions, darsInstitutionCode]) => {
+        this.chosenProgram.controls.planOrProgram.enable();
+        if (institutions.hasOwnProperty(darsInstitutionCode)) {
+          return institutions[darsInstitutionCode].programs;
+        } else {
+          return [];
+        }
+      }),
+    );
+
+    this.degreePlans$ = this.store.select(degreePlans);
+
+    this.honorsOptions$ = combineLatest([
+      this.institutions$,
+      (this.chosenProgram.get('institution') as FormControl).valueChanges,
+    ]).pipe(
+      map(([institutions, darsInstitutionCode]) => {
+        return institutions.hasOwnProperty(darsInstitutionCode)
+          ? institutions[darsInstitutionCode].honorsOptions
+          : [];
+      }),
+    );
+
+    this.variableCreditCourses$ = (this.chosenProgram.get(
+      'degreePlan',
+    ) as FormControl).valueChanges.pipe(
+      flatMap(plan => this.api.getAllCourses(plan.roadmapId)),
+      map(courses => {
+        return courses.filter(course => {
+          return (
+            !!course.creditMin &&
+            !!course.creditMax &&
+            course.creditMax > course.creditMin
+          );
+        });
+      }),
+      map(courses =>
+        courses.map(course => ({
+          ...course,
+          range: inclusiveRange(
+            course.creditMin as number,
+            course.creditMax as number,
+          ),
+        })),
+      ),
+      share(),
+    );
+
+    this.variableCreditCourses$.subscribe(courses => {
+      while (this.chosenCreditSettings.length !== 0) {
+        this.chosenCreditSettings.removeAt(0);
+      }
+
+      courses.forEach(course => {
+        this.chosenCreditSettings.push(
+          this.fb.group({
+            course,
+            credits: this.fb.control('', Validators.required),
+          }),
+        );
+      });
+    });
+  }
+
+  public darsInstitutionCode<T>(fallback: T): string | T {
+    const control = this.chosenProgram.get('institution');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public darsDegreeProgramCode<T>(fallback: T): string | T {
+    const control = this.chosenProgram.get('planOrProgram');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public roadmapId<T>(fallback: T): number | T {
+    const control = this.chosenProgram.get('degreePlan');
+    if (control !== null) {
+      return control.value.roadmapId;
+    } else {
+      return fallback;
+    }
+  }
+
+  public darsHonorsOptionCode<T>(fallback: T): string | T {
+    const control = this.chosenAuditSettings.get('honorsOptions');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public includeCoursesFrom<T>(fallback: T): string | T {
+    const control = this.chosenAuditSettings.get('includeCoursesFrom');
+    if (control !== null) {
+      return control.value.toString();
+    } else {
+      return fallback;
+    }
+  }
+
+  public fixedCredits(): NewWhatIfAuditFields['fixedCredits'] {
+    return (this.chosenCreditSettings.value as any[]).map(
+      (group: { course: CourseBase; credits: number }) => {
+        return {
+          termCode: group.course.termCode || '',
+          subjectCode: group.course.subjectCode || '',
+          courseId: group.course.courseId || '',
+          credits: group.credits,
+        };
+      },
+    );
+  }
+
+  public submitAudit() {
+    this.dialogRef.close({
+      darsInstitutionCode: this.darsInstitutionCode(''),
+      darsDegreeProgramCode: this.darsDegreeProgramCode(''),
+      roadmapId: this.roadmapId(-1),
+      darsHonorsOptionCode: this.darsHonorsOptionCode(''),
+      includeCoursesFrom: this.includeCoursesFrom(''),
+      fixedCredits: this.fixedCredits(),
+    });
+  }
+}
diff --git a/src/app/dars/services/api.service.ts b/src/app/dars/services/api.service.ts
index ca614b6..ae64371 100644
--- a/src/app/dars/services/api.service.ts
+++ b/src/app/dars/services/api.service.ts
@@ -7,11 +7,8 @@ import { StudentDegreeProgram } from '../models/student-degree-program';
 import { environment } from './../../../environments/environment';
 import { Audit } from '../models/audit/audit';
 import { CourseBase } from '@app/core/models/course';
-import { delay } from 'rxjs/operators';
 const auditResponse: Audit = require('../../../assets/mock-data/audit-response.json');
 const degreeProgramsResponse: DegreePrograms = require('../../../assets/mock-data/degreeprograms-response.json');
-const auditMetadata: AuditMetadata[] = require('../../../assets/mock-data/auditmetadata.json');
-const studentplans: StudentDegreeProgram[] = require('../../../assets/mock-data/studentplans.json');
 
 const HTTP_OPTIONS = {
   headers: new HttpHeaders({
@@ -42,10 +39,8 @@ export class DarsApiService {
    *
    * Get courses
    */
-  public getAllCourses(
-    roadmapId: number,
-  ): Observable<{ termCode: string; courses: CourseBase[] }[]> {
-    return this.http.get<{ termCode: string; courses: CourseBase[] }[]>(
+  public getAllCourses(roadmapId: number): Observable<CourseBase[]> {
+    return this.http.get<CourseBase[]>(
       `${environment.apiPlannerUrl}/degreePlan/${roadmapId}/courses`,
       HTTP_OPTIONS,
     );
-- 
GitLab