From cc615ac0bfcc0483ab36168f60f9922659a35a85 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Fri, 2 Mar 2018 19:26:24 +0100 Subject: [PATCH] Added notifications state --- src/app/app.effects.ts | 4 +- src/app/app.reducer.ts | 61 +++++++++-------- .../models/notification-options.model.ts | 28 ++++++++ .../notifications/models/notification-type.ts | 8 +++ .../models/notification.model.ts | 32 +++++++++ .../notifications/notifications.actions.ts | 66 +++++++++++++++++++ .../notifications/notifications.effects.ts | 46 +++++++++++++ .../notifications/notifications.reducers.ts | 39 +++++++++++ 8 files changed, 254 insertions(+), 30 deletions(-) create mode 100644 src/app/shared/notifications/models/notification-options.model.ts create mode 100644 src/app/shared/notifications/models/notification-type.ts create mode 100644 src/app/shared/notifications/models/notification.model.ts create mode 100644 src/app/shared/notifications/notifications.actions.ts create mode 100644 src/app/shared/notifications/notifications.effects.ts create mode 100644 src/app/shared/notifications/notifications.reducers.ts diff --git a/src/app/app.effects.ts b/src/app/app.effects.ts index 7fc42da80d..6a53d7b619 100644 --- a/src/app/app.effects.ts +++ b/src/app/app.effects.ts @@ -1,8 +1,10 @@ import { HeaderEffects } from './header/header.effects'; import { StoreEffects } from './store.effects'; +import { NotificationsEffects } from './shared/notifications/notifications.effects'; export const appEffects = [ StoreEffects, - HeaderEffects + HeaderEffects, + NotificationsEffects ]; diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index 72b29519de..a31cc54ec4 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -1,29 +1,32 @@ -import { ActionReducerMap } from '@ngrx/store'; -import * as fromRouter from '@ngrx/router-store'; - -import { headerReducer, HeaderState } from './header/header.reducer'; -import { hostWindowReducer, HostWindowState } from './shared/host-window.reducer'; -import { - SearchSidebarState, - sidebarReducer -} from './+search-page/search-sidebar/search-sidebar.reducer'; -import { - filterReducer, - SearchFiltersState -} from './+search-page/search-filters/search-filter/search-filter.reducer'; - -export interface AppState { - router: fromRouter.RouterReducerState; - hostWindow: HostWindowState; - header: HeaderState; - searchSidebar: SearchSidebarState; - searchFilter: SearchFiltersState; -} - -export const appReducers: ActionReducerMap = { - router: fromRouter.routerReducer, - hostWindow: hostWindowReducer, - header: headerReducer, - searchSidebar: sidebarReducer, - searchFilter: filterReducer -}; +import { ActionReducerMap } from '@ngrx/store'; +import * as fromRouter from '@ngrx/router-store'; + +import { headerReducer, HeaderState } from './header/header.reducer'; +import { hostWindowReducer, HostWindowState } from './shared/host-window.reducer'; +import { + SearchSidebarState, + sidebarReducer +} from './+search-page/search-sidebar/search-sidebar.reducer'; +import { + filterReducer, + SearchFiltersState +} from './+search-page/search-filters/search-filter/search-filter.reducer'; +import { notificationsReducer, NotificationsState } from './shared/notifications/notifications.reducers'; + +export interface AppState { + router: fromRouter.RouterReducerState; + hostWindow: HostWindowState; + header: HeaderState; + notifications: NotificationsState; + searchSidebar: SearchSidebarState; + searchFilter: SearchFiltersState; +} + +export const appReducers: ActionReducerMap = { + router: fromRouter.routerReducer, + hostWindow: hostWindowReducer, + header: headerReducer, + notifications: notificationsReducer, + searchSidebar: sidebarReducer, + searchFilter: filterReducer +}; diff --git a/src/app/shared/notifications/models/notification-options.model.ts b/src/app/shared/notifications/models/notification-options.model.ts new file mode 100644 index 0000000000..b651a0b3d1 --- /dev/null +++ b/src/app/shared/notifications/models/notification-options.model.ts @@ -0,0 +1,28 @@ +export interface INotificationOptions { + timeOut: number; + clickToClose: boolean; + rtl: boolean; + animate: 'fade' | 'fromTop' | 'fromRight' | 'fromBottom' | 'fromLeft' | 'rotate' | 'scale'; + position: ['top' | 'bottom' | 'middle', 'right' | 'left' | 'center']; +} + +export class NotificationOptions implements INotificationOptions { + public timeOut: number; + public clickToClose: boolean; + public rtl: boolean; + public animate: any; + public position: any; + + constructor(timeOut = 0, + clickToClose = true, + animate = 'scale', + position = ['top' , 'right'], + rtl = false) { + + this.timeOut = timeOut; + this.clickToClose = clickToClose; + this.animate = animate; + this.position = position; + this.rtl = rtl; + } +} diff --git a/src/app/shared/notifications/models/notification-type.ts b/src/app/shared/notifications/models/notification-type.ts new file mode 100644 index 0000000000..43680d6933 --- /dev/null +++ b/src/app/shared/notifications/models/notification-type.ts @@ -0,0 +1,8 @@ +export enum NotificationType { + Success = 'success', + Error = 'error', + Alert = 'alert', + Info = 'info', + Warning = 'warn', + Bare = 'bare' +} diff --git a/src/app/shared/notifications/models/notification.model.ts b/src/app/shared/notifications/models/notification.model.ts new file mode 100644 index 0000000000..b909b8ef26 --- /dev/null +++ b/src/app/shared/notifications/models/notification.model.ts @@ -0,0 +1,32 @@ +import { INotificationOptions, NotificationOptions } from './notification-options.model'; +import { NotificationType } from './notification-type'; +import { isEmpty } from '../../empty.util'; + +export interface INotification { + id: string + type: NotificationType + title?: any + content?: any + options?: INotificationOptions +} + +export class Notification implements INotification { + public id: string; + public type: NotificationType; + public title: any; + public content: any; + public options: INotificationOptions; + + constructor(id: string, + type: NotificationType, + title?: any, + content?: any, + options?: INotificationOptions) { + + this.id = id; + this.type = type; + this.title = title; + this.content = content; + this.options = isEmpty(options) ? new NotificationOptions() : options; + } +} diff --git a/src/app/shared/notifications/notifications.actions.ts b/src/app/shared/notifications/notifications.actions.ts new file mode 100644 index 0000000000..e086e409e5 --- /dev/null +++ b/src/app/shared/notifications/notifications.actions.ts @@ -0,0 +1,66 @@ +// import @ngrx +import { Action } from '@ngrx/store'; + +// import type function +import { type } from '../../shared/ngrx/type'; + +// import models +import { Notification } from './models/notification.model'; + +export const NotificationsActionTypes = { + NEW_NOTIFICATION: type('dspace/notifications/NEW_NOTIFICATION'), + NEW_NOTIFICATION_WITH_TIMER: type('dspace/notifications/NEW_NOTIFICATION_WITH_TIMER'), + REMOVE_NOTIFICATION: type('dspace/notifications/REMOVE_NOTIFICATION'), +}; + +/* tslint:disable:max-classes-per-file */ + +/** + * New notification. + * @class NewNotificationAction + * @implements {Action} + */ +export class NewNotificationAction implements Action { + public type: string = NotificationsActionTypes.NEW_NOTIFICATION; + payload: Notification; + + constructor(notification: Notification) { + this.payload = notification; + } +} + +/** + * New notification. + * @class NewNotificationAction + * @implements {Action} + */ +export class NewNotificationWithTimerAction implements Action { + public type: string = NotificationsActionTypes.NEW_NOTIFICATION_WITH_TIMER; + payload: Notification; + + constructor(notification: Notification) { + this.payload = notification; + } +} + +/** + * New notification. + * @class NewNotificationAction + * @implements {Action} + */ +export class RemoveNotificationAction implements Action { + public type: string = NotificationsActionTypes.REMOVE_NOTIFICATION; + + constructor(public payload?: any) { } +} + +/* tslint:enable:max-classes-per-file */ + +/** + * Actions type. + * @type {NotificationsActions} + */ +export type NotificationsActions + = NewNotificationAction + | NewNotificationWithTimerAction + | RemoveNotificationAction; diff --git a/src/app/shared/notifications/notifications.effects.ts b/src/app/shared/notifications/notifications.effects.ts new file mode 100644 index 0000000000..75fd319ba2 --- /dev/null +++ b/src/app/shared/notifications/notifications.effects.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@angular/core'; + +// import @ngrx +import { Effect, Actions } from '@ngrx/effects'; +import { Action, Store } from '@ngrx/store'; + +// import rxjs +import { Observable } from 'rxjs/Observable'; + +// import services + +// import actions + +import { AppState } from '../../app.reducer'; +import { + NewNotificationWithTimerAction, NotificationsActionTypes, + RemoveNotificationAction +} from './notifications.actions'; + +@Injectable() +export class NotificationsEffects { + + /** + * Authenticate user. + * @method authenticate + */ + @Effect() + public timer: Observable = this.actions$ + .ofType(NotificationsActionTypes.NEW_NOTIFICATION_WITH_TIMER) + .debounceTime((action) => action.payload.options.timeOut) + .map(() => new RemoveNotificationAction()); + /* .switchMap((action: NewNotificationWithTimerAction) => Observable + .timer(30000) + .mapTo(() => new RemoveNotificationAction()) + );*/ + + /** + * @constructor + * @param {Actions} actions$ + * @param {AuthService} authService + * @param {Store} store + */ + constructor(private actions$: Actions, + private store: Store) { + } +} diff --git a/src/app/shared/notifications/notifications.reducers.ts b/src/app/shared/notifications/notifications.reducers.ts new file mode 100644 index 0000000000..4b02ee905d --- /dev/null +++ b/src/app/shared/notifications/notifications.reducers.ts @@ -0,0 +1,39 @@ +// import actions +import { NotificationsActions, NotificationsActionTypes } from './notifications.actions'; + +// import models +import { INotification } from './models/notification.model'; + +/** + * The auth state. + * @interface State + */ +export interface NotificationsState { + [index: number]: INotification; +} + +/** + * The initial state. + */ +const initialState: NotificationsState = []; + +/** + * The reducer function. + * @function reducer + * @param {State} state Current state + * @param {NotificationsActions} action Incoming action + */ +export function notificationsReducer(state: any = initialState, action: NotificationsActions): NotificationsState { + + switch (action.type) { + case NotificationsActionTypes.NEW_NOTIFICATION: + case NotificationsActionTypes.NEW_NOTIFICATION_WITH_TIMER: + return [...state, action.payload]; + + case NotificationsActionTypes.REMOVE_NOTIFICATION: + return []; + + default: + return state; + } +}