From f61f246f23920349e8add876a054d03e1464968c Mon Sep 17 00:00:00 2001 From: Andrea Chiapparelli - 4Science Date: Mon, 5 Mar 2018 15:15:40 +0100 Subject: [PATCH] starting with redux --- src/app/+home-page/home-page.component.ts | 7 +- .../models/notification.model.ts | 2 +- .../notification/notification.component.scss | 8 +- .../notification/notification.component.ts | 3 +- .../notifications-board.component.ts | 190 ++++++++++-------- .../notifications/notifications.effects.ts | 2 +- .../notifications/notifications.service.ts | 145 ++++++++----- 7 files changed, 217 insertions(+), 140 deletions(-) diff --git a/src/app/+home-page/home-page.component.ts b/src/app/+home-page/home-page.component.ts index 0d66d4e503..1acd4951fa 100644 --- a/src/app/+home-page/home-page.component.ts +++ b/src/app/+home-page/home-page.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { NotificationsService } from '../shared/notifications/notifications.service'; import { Options } from '../shared/notifications/interfaces/options.type'; +import { NotificationOptions } from '../shared/notifications/models/notification-options.model'; @Component({ selector: 'ds-home-page', @@ -24,11 +25,9 @@ export class HomePageComponent { createNotification() { const n1 = this.notificationsService.success('Welcome in DSpace', 'Good choice!', - { - animate: 'rotate', - timeout: 2000}); + new NotificationOptions(2000, false, 'fromLeft')); const n2 = this.notificationsService.info('Info in DSpace', 'For your info...!'); - const n3 = this.notificationsService.warn('Warning in DSpace', 'This is a fake alert!'); + const n3 = this.notificationsService.warning('Warning in DSpace', 'This is a fake alert!'); const n4 = this.notificationsService.danger(this.example); console.log('Notifications pushed'); console.log(n1); diff --git a/src/app/shared/notifications/models/notification.model.ts b/src/app/shared/notifications/models/notification.model.ts index f7293f0e36..91f2f9bbe9 100644 --- a/src/app/shared/notifications/models/notification.model.ts +++ b/src/app/shared/notifications/models/notification.model.ts @@ -23,7 +23,7 @@ export class Notification implements INotification { type: NotificationType, title?: any, content?: any, - options?: INotificationOptions) { + options?: NotificationOptions) { this.id = id; this.type = type; diff --git a/src/app/shared/notifications/notification/notification.component.scss b/src/app/shared/notifications/notification/notification.component.scss index 80acc733ad..6d2a1469d6 100644 --- a/src/app/shared/notifications/notification/notification.component.scss +++ b/src/app/shared/notifications/notification/notification.component.scss @@ -109,19 +109,15 @@ .close { - //position: absolute; - //top: 5px; - //right: 5px; float: right; padding-right: 5px; + color: darkslategray; } .icon { - //position: absolute; - //top: 5px; - //left: 5px; float: left; padding: 5px; + color: darkslategray; } // //.icon > fa-times-circle { diff --git a/src/app/shared/notifications/notification/notification.component.ts b/src/app/shared/notifications/notification/notification.component.ts index fa8f44f5e6..d228018d25 100644 --- a/src/app/shared/notifications/notification/notification.component.ts +++ b/src/app/shared/notifications/notification/notification.component.ts @@ -246,7 +246,8 @@ export class NotificationComponent implements OnInit, OnDestroy { // this.notificationService.set(this.item, false); // } - this.notificationService.set(this.item, false); + // this.notificationService.set(this.item, false); + this.notificationService.remove(this.item); } private contentType(item: any, key: string) { diff --git a/src/app/shared/notifications/notifications-board/notifications-board.component.ts b/src/app/shared/notifications/notifications-board/notifications-board.component.ts index 3e186f9c45..6501bc7653 100644 --- a/src/app/shared/notifications/notifications-board/notifications-board.component.ts +++ b/src/app/shared/notifications/notifications-board/notifications-board.component.ts @@ -2,10 +2,14 @@ import { Component, EventEmitter, OnInit, OnDestroy, ViewEncapsulation, Input, Output, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; -import {Subscription} from 'rxjs/Subscription'; -import {Options} from '../interfaces/options.type'; -import {Notification} from '../interfaces/notification.type'; -import {NotificationsService} from '../notifications.service'; +import { Subscription } from 'rxjs/Subscription'; +import { Options } from '../interfaces/options.type'; +import { Notification } from '../interfaces/notification.type'; +import { NotificationsService } from '../notifications.service'; +import { Store } from '@ngrx/store'; +import { NotificationsActions, NotificationsActionTypes } from '../notifications.actions'; +import { notificationsReducer } from '../notifications.reducers'; +import { AppState } from '../../../app.reducer'; @Component({ selector: 'ds-notifications-board', @@ -30,10 +34,10 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { private listener: Subscription; // Received values - private lastOnBottom = true; + private lastOnBottom = false; private maxStack = 8; - private preventLastDuplicates: any = false; - private preventDuplicates = false; + // private preventLastDuplicates: any = true; + // private preventDuplicates = true; // Sent values public timeOut = 0; @@ -46,39 +50,59 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { public rtl = false; public animate: 'fade' | 'fromTop' | 'fromRight' | 'fromBottom' | 'fromLeft' | 'rotate' | 'scale' = 'fromRight'; - constructor( - private service: NotificationsService, - private cdr: ChangeDetectorRef - ) {} + constructor(private service: NotificationsService, + private store: Store, + private cdr: ChangeDetectorRef) { + } ngOnInit(): void { - // Listen for changes in the service - this.listener = this.service.emitter - .subscribe((item) => { // Subscribe a stato di redux - switch (item.command) { - case 'cleanAll': - this.notifications = []; - break; + this.listener = this.store.select() + (action: NotificationsActions) => { + notificationsReducer(this.notifications, action); - case 'clean': - this.cleanSingle(item.id!); - break; - - case 'set': - if (item.add) { - this.add(item.notification!); - } else { - this.defaultBehavior(item); - } - break; - - default: - this.defaultBehavior(item); - break; - } - - this.cdr.markForCheck(); + // switch (action.type) { + // case NotificationsActionTypes.NEW_NOTIFICATION: + // + // break; + // case NotificationsActionTypes.NEW_NOTIFICATION_WITH_TIMER: + // + // break; + // case NotificationsActionTypes.REMOVE_NOTIFICATION: + // + // break; + // case NotificationsActionTypes.REMOVE_ALL_NOTIFICATIONS: + // + // break; + // } }); + + // Listen for changes in the service + // this.listener = this.service.emitter + // .subscribe((item) => { // Subscribe a stato di redux + // switch (item.command) { + // case 'cleanAll': + // this.notifications = []; + // break; + // + // case 'clean': + // this.cleanSingle(item.id!); + // break; + // + // case 'set': + // if (item.add) { + // this.add(item.notification!); + // } else { + // this.defaultBehavior(item); + // } + // break; + // + // default: + // this.defaultBehavior(item); + // break; + // } + // + // this.cdr.markForCheck(); + // }); } // Default behavior on event @@ -91,7 +115,7 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { add(item: Notification): void { item.createdOn = new Date(); - const toBlock: boolean = this.preventLastDuplicates || this.preventDuplicates ? this.block(item) : false; + // const toBlock: boolean = this.preventLastDuplicates || this.preventDuplicates ? this.block(item) : false; // Save this as the last created notification this.lastNotificationCreated = item; @@ -100,24 +124,24 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { item.icon = item.override.icons[item.type]; } - if (!toBlock) { - // Check if the notification should be added at the start or the end of the array - if (this.lastOnBottom) { - if (this.notifications.length >= this.maxStack) { - this.notifications.splice(0, 1); - } - - this.notifications.push(item); - } else { - if (this.notifications.length >= this.maxStack) { - this.notifications.splice(this.notifications.length - 1, 1); - } - - this.notifications.splice(0, 0, item); - } - - this.onCreate.emit(this.buildEmit(item, true)); - } + // if (!toBlock) { + // // Check if the notification should be added at the start or the end of the array + // if (this.lastOnBottom) { + // if (this.notifications.length >= this.maxStack) { + // this.notifications.splice(0, 1); + // } + // + // this.notifications.push(item); + // } else { + // if (this.notifications.length >= this.maxStack) { + // this.notifications.splice(this.notifications.length - 1, 1); + // } + // + // this.notifications.splice(0, 0, item); + // } + // + // this.onCreate.emit(this.buildEmit(item, true)); + // } } // Check if notifications should be prevented @@ -125,31 +149,37 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { const toCheck = item.html ? this.checkHtml : this.checkStandard; - if (this.preventDuplicates && this.notifications.length > 0) { - for (let i = 0; i < this.notifications.length; i++) { - if (toCheck(this.notifications[i], item)) { - return true; - } + this.notifications.forEach((notification) => { + if (toCheck(notification, item)) { + return true; } - } + }); - if (this.preventLastDuplicates) { - - let comp: Notification; - - if (this.preventLastDuplicates === 'visible' && this.notifications.length > 0) { - if (this.lastOnBottom) { - comp = this.notifications[this.notifications.length - 1]; - } else { - comp = this.notifications[0]; - } - } else if (this.preventLastDuplicates === 'all' && this.lastNotificationCreated) { - comp = this.lastNotificationCreated; - } else { - return false; - } - return toCheck(comp, item); - } + // if (this.notifications.length > 0) { + // for (let i = 0; i < this.notifications.length; i++) { + // if (toCheck(this.notifications[i], item)) { + // return true; + // } + // } + // } + // + // if (this.preventLastDuplicates) { + // + // let comp: Notification; + // + // if (this.preventLastDuplicates === 'visible' && this.notifications.length > 0) { + // if (this.lastOnBottom) { + // comp = this.notifications[this.notifications.length - 1]; + // } else { + // comp = this.notifications[0]; + // } + // } else if (this.preventLastDuplicates === 'all' && this.lastNotificationCreated) { + // comp = this.lastNotificationCreated; + // } else { + // return false; + // } + // return toCheck(comp, item); + // } return false; } @@ -164,11 +194,11 @@ export class NotificationsBoardComponent implements OnInit, OnDestroy { // Attach all the changes received in the options object attachChanges(options: any): void { - Object.keys(options).forEach((a) => { + Object.keys(options).forEach((a) => { if (this.hasOwnProperty(a)) { (this as any)[a] = options[a]; } else if (a === 'icons') { - this.service.icons = options[a]; + // this.service.icons = options[a]; } }); } diff --git a/src/app/shared/notifications/notifications.effects.ts b/src/app/shared/notifications/notifications.effects.ts index b8b9fca4d2..345b1084e0 100644 --- a/src/app/shared/notifications/notifications.effects.ts +++ b/src/app/shared/notifications/notifications.effects.ts @@ -24,7 +24,7 @@ export class NotificationsEffects { * Authenticate user. * @method authenticate */ - @Effect() + /* @Effect() public timer: Observable = this.actions$ .ofType(NotificationsActionTypes.NEW_NOTIFICATION_WITH_TIMER) // .debounceTime((action: any) => action.payload.options.timeOut) diff --git a/src/app/shared/notifications/notifications.service.ts b/src/app/shared/notifications/notifications.service.ts index de40aff7cf..4a82ff9eec 100644 --- a/src/app/shared/notifications/notifications.service.ts +++ b/src/app/shared/notifications/notifications.service.ts @@ -1,65 +1,116 @@ -import {Injectable, EventEmitter} from '@angular/core'; -import {Subject} from 'rxjs/Subject'; -import {NotificationEvent} from './interfaces/notification-event.type'; -import {Notification} from './interfaces/notification.type'; -import {Icons, defaultIcons} from './interfaces/icons'; +import { Injectable, EventEmitter } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; +import { NotificationEvent } from './interfaces/notification-event.type'; +import { INotification, Notification } from './models/notification.model'; +// import {Icons, defaultIcons} from './interfaces/icons'; import { NotificationType } from './models/notification-type'; +import { NotificationOptions } from './models/notification-options.model'; +import * as _ from 'lodash'; +import { Store } from '@ngrx/store'; +import { + NewNotificationAction, NewNotificationWithTimerAction, RemoveAllNotificationsAction, + RemoveNotificationAction +} from './notifications.actions'; @Injectable() export class NotificationsService { - public emitter = new Subject(); - public icons: Icons = defaultIcons; + // public emitter = new Subject(); + // public icons: Icons = defaultIcons; + constructor(private store: Store) { - set(notification: Notification, to: boolean): Notification { - notification.id = notification.override && notification.override.id ? notification.override.id : Math.random().toString(36).substring(3); - notification.click = new EventEmitter<{}>(); - notification.timeoutEnd = new EventEmitter<{}>(); + } - this.emitter.next({command: 'set', notification: notification, add: to}); - return notification; - }; + // private set(notification: Notification, to: boolean): Notification { + // notification.id = notification.override && notification.override.id ? notification.override.id : Math.random().toString(36).substring(3); + // notification.click = new EventEmitter<{}>(); + // notification.timeoutEnd = new EventEmitter<{}>(); + // + // this.emitter.next({command: 'set', notification: notification, add: to}); + // return notification; + // }; - success(title: any = '', content: any = '', override?: any): Notification { - return this.set({title: title, content: content || '', type: NotificationType.Success, override: override}, true); + private add(notification: Notification) { + let notificationAction; + if (notification.options.timeOut > 0) { + notificationAction = new NewNotificationWithTimerAction(notification); + } else { + notificationAction = new NewNotificationAction(notification); } + this.store.dispatch(notificationAction); + } - // error(title: any = '', content: any = '', override?: any): Notification { - // return this.set({title: title, content: content || '', type: NotificationType.Error, override: override}, true); - // } + success(title: any = '', content: any = '', options = new NotificationOptions()): Notification { + const notification = new Notification(_.uniqueId(), NotificationType.Success, title, content, options); + this.add(notification); + return notification; + } - danger(title: any = '', content: any = '', override?: any): Notification { - return this.set({title: title, content: content || '', type: NotificationType.Danger, override: override}, true); - } + // error(title: any = '', content: any = '', override?: any): Notification { + // return this.set({title: title, content: content || '', type: NotificationType.Error, override: override}, true); + // } - info(title: any = '', content: any = '', override?: any): Notification { - return this.set({title: title, content: content || '', type: NotificationType.Info, override: override}, true); - } + danger(title: any = '', content: any = '', options = new NotificationOptions()): Notification { + const notification = new Notification(_.uniqueId(), NotificationType.Danger, title, content, options); + this.add(notification); + return notification; + } - warn(title: any = '', content: any = '', override?: any): Notification { - return this.set({title: title, content: content || '', type: NotificationType.Warning, override: override}, true); - } + info(title: any = '', content: any = '', options = new NotificationOptions()): Notification { + const notification = new Notification(_.uniqueId(), NotificationType.Info, title, content, options); + this.add(notification); + return notification; + } - // bare(title: any = '', content: any = '', override?: any): Notification { - // return this.set({title: title, content: content || '', type: 'bare', icon: 'bare', override: override}, true); - // } + warning(title: any = '', content: any = '', options = new NotificationOptions()): Notification { + const notification = new Notification(_.uniqueId(), NotificationType.Warning, title, content, options); + this.add(notification); + return notification; + } - // With type method - create(title: any = '', content: any = '', type = 'success', override?: any): Notification { - return this.set({title: title, content: content, type: type, icon: (this.icons as any)[type], override: override}, true); - } + // bare(title: any = '', content: any = '', override?: any): Notification { + // return this.set({title: title, content: content || '', type: 'bare', icon: 'bare', override: override}, true); + // } - // HTML Notification method - html(html: any, type = 'success', override?: any, icon = 'bare'): Notification { - return this.set({html: html, type: type, icon: (this.icons as any)[icon], override: override}, true); - } + // With type method + // create(title: any = '', content: any = '', type = 'success'): Notification { + // return this.set({ + // title: title, + // content: content, + // type: type, + // icon: (this.icons as any)[type], + // override: override + // }, true); + // } + + // HTML Notification method + // html(html: any, type = 'success', override?: any, icon = 'bare'): Notification { + // return this.set({html: html, type: type, icon: (this.icons as any)[icon], override: override}, true); + // } + + html(html: any, type = NotificationType.Success, options = new NotificationOptions()): Notification { + const notification = new Notification(_.uniqueId(), type, null, null, options); + notification.html = html; + this.add(notification); + return notification; + } + + // Remove all notifications method + // remove(id?: string): void { + // if (id) { + // this.emitter.next({command: 'clean', id: id}); + // } else { + // this.emitter.next({command: 'cleanAll'}); + // } + // } + remove(notification: INotification) { + const actionRemove = new RemoveNotificationAction(notification.id); + this.store.dispatch(actionRemove); + } + + removeAll() { + const actionRemoveAll = new RemoveAllNotificationsAction(); + this.store.dispatch(actionRemoveAll); + } - // Remove all notifications method - remove(id?: string): void { - if (id) { - this.emitter.next({command: 'clean', id: id}); - } else { - this.emitter.next({command: 'cleanAll'}); - } - } }