From 037b1936d1cac5ac6c40cda56805998111a8620a Mon Sep 17 00:00:00 2001 From: ievavold <ievavold@wisc.edu> Date: Mon, 10 Jun 2019 15:23:13 -0500 Subject: [PATCH] make alert component generic Previously, the alert component only worked with the degree planner view. Now the alert component can be used in any view that supplies a list of alerts. --- src/app/dars/dars-view/dars-view.component.html | 5 ++++- src/app/dars/dars-view/dars-view.component.ts | 9 ++++++++- src/app/dars/store/actions.ts | 7 +++++++ src/app/dars/store/reducer.ts | 11 ++++++++++- src/app/dars/store/selectors.ts | 5 +++++ .../degree-planner-view.component.html | 5 ++++- .../degree-planner-view.component.ts | 10 +++++++++- src/app/degree-planner/store/selectors.ts | 6 ++---- .../alert-container.component.html | 2 +- .../alert-container/alert-container.component.ts | 16 ++++------------ 10 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/app/dars/dars-view/dars-view.component.html b/src/app/dars/dars-view/dars-view.component.html index dca2532..735a5fd 100644 --- a/src/app/dars/dars-view/dars-view.component.html +++ b/src/app/dars/dars-view/dars-view.component.html @@ -21,7 +21,10 @@ <!-- Main DARS Content --> <div id="dars-main"> - <cse-alert-container></cse-alert-container> + <cse-alert-container + [alerts]="alerts$ | async" + (dismiss)="onDismissAlert($event)"> + </cse-alert-container> <h2 class="mat-h1">Completed Audit Requests</h2> <div id="dars-header-bar"> diff --git a/src/app/dars/dars-view/dars-view.component.ts b/src/app/dars/dars-view/dars-view.component.ts index d3ea00e..74b1103 100644 --- a/src/app/dars/dars-view/dars-view.component.ts +++ b/src/app/dars/dars-view/dars-view.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +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'; @@ -10,6 +10,7 @@ import { Observable } from 'rxjs'; import * as darsActions from '../store/actions'; import { Audit } from '../models/audit'; import { DarsApiService } from '../services/api.service'; +import { Alert } from '@app/core/models/alert'; @Component({ selector: 'cse-dars-view', @@ -20,6 +21,7 @@ export class DARSViewComponent implements OnInit { public metadataStatus$: Observable<DARSState['metadata']['status']>; public visibleAuditStatus$: Observable<DARSState['visibleAudit']['status']>; public audit$: Observable<Audit | null>; + public alerts$: Observable<Alert[]>; constructor( private store: Store<GlobalState>, @@ -33,6 +35,11 @@ export class DARSViewComponent implements OnInit { this.visibleAuditStatus$ = this.store.select(selectors.visibleAuditStatus); // this.audit$ = this.store.select(selectors.visibleAudit); this.audit$ = this.api.getAudit(3); + this.alerts$ = this.store.select(selectors.alerts); + } + + public onDismissAlert(key: string) { + this.store.dispatch(new darsActions.DismissAlert({ key })); } public openNewAuditOptionsDialog() { diff --git a/src/app/dars/store/actions.ts b/src/app/dars/store/actions.ts index 83aba03..b7aed37 100644 --- a/src/app/dars/store/actions.ts +++ b/src/app/dars/store/actions.ts @@ -15,6 +15,8 @@ export enum DarsActionTypes { CloseAudit = '[DARS] Close Audit', PopulateDarsState = '[DARS] Done Loading state', + + DismissAlert = '[DARS] Dismiss Alert', } export class ErrorLoadingMetadata implements Action { @@ -64,3 +66,8 @@ export class DoneLoadingAudit implements Action { export class CloseAudit implements Action { public readonly type = DarsActionTypes.CloseAudit; } + +export class DismissAlert implements Action { + public readonly type = DarsActionTypes.DismissAlert; + constructor(public payload: { key: string }) {} +} diff --git a/src/app/dars/store/reducer.ts b/src/app/dars/store/reducer.ts index 57cdf97..a64bef4 100644 --- a/src/app/dars/store/reducer.ts +++ b/src/app/dars/store/reducer.ts @@ -8,7 +8,8 @@ type SupportedActions = | darsActions.PopulateDarsState | darsActions.StartLoadingAudit | darsActions.DoneLoadingAudit - | darsActions.CloseAudit; + | darsActions.CloseAudit + | darsActions.DismissAlert; export function darsReducer( state = INITIAL_DARS_STATE, @@ -72,6 +73,14 @@ export function darsReducer( visibleAudit: { status: 'NotLoaded' }, }; } + case DarsActionTypes.DismissAlert: { + return { + ...state, + alerts: state.alerts.filter(({ key }) => { + return key !== action.payload.key; + }), + }; + } default: return state; } diff --git a/src/app/dars/store/selectors.ts b/src/app/dars/store/selectors.ts index a164fb0..37792d1 100644 --- a/src/app/dars/store/selectors.ts +++ b/src/app/dars/store/selectors.ts @@ -6,6 +6,11 @@ export const getDARSState = ({ dars }: GlobalState) => { return dars; }; +export const alerts = createSelector( + getDARSState, + (state: DARSState) => state.alerts, +); + export const metadataStatus = createSelector( getDARSState, (state: DARSState) => state.metadata.status, diff --git a/src/app/degree-planner/degree-planner-view/degree-planner-view.component.html b/src/app/degree-planner/degree-planner-view/degree-planner-view.component.html index e01a5cf..202cba5 100644 --- a/src/app/degree-planner/degree-planner-view/degree-planner-view.component.html +++ b/src/app/degree-planner/degree-planner-view/degree-planner-view.component.html @@ -9,7 +9,10 @@ [ngClass]="{ isLoadingPlan: isLoadingPlan$ | async }" *ngIf="(degreePlan$ | async) as degreePlan"> - <cse-alert-container></cse-alert-container> + <cse-alert-container + [alerts]="alerts$ | async" + (dismiss)="onDismissAlert($event)"> + </cse-alert-container> <div id="maincontent" diff --git a/src/app/degree-planner/degree-planner-view/degree-planner-view.component.ts b/src/app/degree-planner/degree-planner-view/degree-planner-view.component.ts index e25a8e1..11f25f7 100644 --- a/src/app/degree-planner/degree-planner-view/degree-planner-view.component.ts +++ b/src/app/degree-planner/degree-planner-view/degree-planner-view.component.ts @@ -42,7 +42,8 @@ import { ConstantsService } from '../services/constants.service'; import { TermCodeFactory } from '../services/termcode.factory'; import { IE11WarningDialogComponent } from '../dialogs/ie11-warning-dialog/ie11-warning-dialog.component'; import { getUserPreference } from '@app/core/selectors'; -import { UpdateUserPreferences } from '@app/core/actions'; +import { UpdateUserPreferences, DismissAlert } from '@app/core/actions'; +import { Alert } from '@app/core/models/alert'; // From: https://stackoverflow.com/a/21825207 const isIE11 = @@ -67,6 +68,7 @@ export class DegreePlannerViewComponent implements OnInit { public isSidenavOpen$: Observable<boolean>; public hasDismissedIEWarning$: Observable<boolean>; public version: string; + public alerts$: Observable<Alert[]>; constructor( private store: Store<GlobalState>, @@ -140,6 +142,12 @@ export class DegreePlannerViewComponent implements OnInit { }); } }); + + this.alerts$ = this.store.select(selectors.alerts); + } + + public onDismissAlert(key: string) { + this.store.dispatch(new DismissAlert({ key })); } public openSidenav() { diff --git a/src/app/degree-planner/store/selectors.ts b/src/app/degree-planner/store/selectors.ts index 677134e..1bc4729 100644 --- a/src/app/degree-planner/store/selectors.ts +++ b/src/app/degree-planner/store/selectors.ts @@ -90,11 +90,9 @@ export const getActiveSelectedSearchTerm = createSelector( }, ); -export const getAlerts = createSelector( +export const alerts = createSelector( getDegreePlannerState, - (state: DegreePlannerState) => { - return state.alerts; - }, + (state: DegreePlannerState) => state.alerts, ); export const isLoadingPlan = createSelector( diff --git a/src/app/shared/components/alert-container/alert-container.component.html b/src/app/shared/components/alert-container/alert-container.component.html index 242aca4..939d819 100644 --- a/src/app/shared/components/alert-container/alert-container.component.html +++ b/src/app/shared/components/alert-container/alert-container.component.html @@ -1,5 +1,5 @@ <div class="cse-alert-container"> - <div *ngFor="let alert of (alerts$ | async)" class="cse-alert"> + <div *ngFor="let alert of alerts" class="cse-alert"> <div class="alert-icon"> <mat-icon>warning</mat-icon> </div> diff --git a/src/app/shared/components/alert-container/alert-container.component.ts b/src/app/shared/components/alert-container/alert-container.component.ts index 53ed031..0a1e1d6 100644 --- a/src/app/shared/components/alert-container/alert-container.component.ts +++ b/src/app/shared/components/alert-container/alert-container.component.ts @@ -1,10 +1,5 @@ -import { Component } from '@angular/core'; -import { Store, select } from '@ngrx/store'; -import { GlobalState } from '@app/core/state'; -import * as selectors from '@app/degree-planner/store/selectors'; +import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Alert } from '@app/core/models/alert'; -import { Observable } from 'rxjs'; -import { DismissAlert } from '@app/core/actions'; @Component({ selector: 'cse-alert-container', @@ -12,14 +7,11 @@ import { DismissAlert } from '@app/core/actions'; styleUrls: ['./alert-container.component.scss'], }) export class AlertContainerComponent { - public alerts$: Observable<Alert[]>; - - constructor(private store: Store<GlobalState>) { - this.alerts$ = store.pipe(select(selectors.getAlerts)); - } + @Input() public alerts: Alert[]; + @Output() public dismiss = new EventEmitter<string>(); public dismissAlert(key: string, callback?: () => void) { - this.store.dispatch(new DismissAlert({ key })); + this.dismiss.emit(key); if (typeof callback === 'function') { callback(); } -- GitLab